Code style updates for Norgo NGE101

This commit is contained in:
Christian W. Zuckschwerdt 2019-04-08 20:33:15 +02:00 committed by Christian W. Zuckschwerdt
parent 3a970d6644
commit 563ef58e11
4 changed files with 151 additions and 146 deletions

View file

@ -213,6 +213,7 @@ Read the Test Data section at the bottom.
[136] ESIC EMT7110 power meter
[137] Globaltronics QUIGG GT-TMBBQ-05
[138] Globaltronics GT-WT-03 Sensor
[139] Norgo NGE101
* Disabled by default, use -R n or -G

View file

@ -325,6 +325,7 @@ stop_after_successful_events false
protocol 136 # ESIC EMT7110 power meter
protocol 137 # Globaltronics QUIGG GT-TMBBQ-05
protocol 138 # Globaltronics GT-WT-03 Sensor
protocol 139 # Norgo NGE101
## Flex devices (command line option "-X")

View file

@ -538,6 +538,9 @@ Globaltronics QUIGG GT\-TMBBQ\-05
.TP
[ \fB138\fI\fP ]
Globaltronics GT\-WT\-03 Sensor
.TP
[ \fB139\fI\fP ]
Norgo NGE101
* Disabled by default, use \-R n or \-G
.SS "Input device selection"

View file

@ -1,13 +1,16 @@
/** Norgo Energy NGE101
*
* Copyright (C) 2019 jamaron
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
/** @file
Norgo Energy NGE101 decoder.
Copyright (C) 2019 jamaron
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
*/
/** @fn int norgo_decode(r_device *decoder, bitbuffer_t *bitbuffer)
Norgo Energy NGE101 decoder.
/**
The code is based on info and code from Jesper Hansen's pages (used with
his permission):
http://blog.bitheap.net/p/this-is-overview-of-data-norge-nge101.html
@ -36,202 +39,199 @@ every 43 seconds 2 packets (55 bit packet twice or 71 bit packet together
with 55 bit packet).
55 bit packet contents:
1111 1010 | 0000 1101 | 1010 1000 | 0000 1000 | 0000 0000 /
xxxx xxxx | fccc dddd | dddd tttt | tttt tttt | tttt tttu /
1010 1101 / 1010 000
pppp pppp / pppp ppp
x - constant
f - packet type (0 = 55 bit packet)
c - channel (LSbit first)
d - device ID (LSbit first)
t - time in 1/1024 seconds between the last two impulses (LSbit first)
u - unknown
p - parity
1111 1010 | 0000 1101 | 1010 1000 | 0000 1000 | 0000 0000 /
ssss ssss | fccc dddd | dddd tttt | tttt tttt | tttt tttu /
1010 1101 / 1010 000?
xxxx xxxx / pppp ppp?
Captured time can be converted to momentary power usage (kW) using formula
- s: sync byte, 0xfa
- f: packet type (0 = 55 bit packet)
- c: channel (LSbit first)
- d: device ID (LSbit first)
- t: time in 1/1024 seconds between the last two impulses (LSbit first)
- u: unknown
- x: xor sum (starting at byte 1)
- p: parity
Captured time can be converted to momentary power usage (kW) using formula:
(3686400/(n_imp_per_kwh)/captured_time
71 bit packet contents:
1111 1010 | 1000 1101 | 1010 0001 | 0010 0001 | 1101 1111 /
xxxx xxxx | fccc dddd | dddd kkkk | kkkk kkkk | kkkk kkkk /
1100 0000 / 0000 0000 / 0001 0010 / 1101 111
kkkk kkkk | kkkk kkbo / pppp pppp / pppp ppp
x - constant
f - packet type (1 = 71 bit packet)
c - channel (LSbit first)
d - device ID (LSbit first)
k - impulse count since transmitter started (LSbit first)
b - low battery
o - overflow?
p - parity
1111 1010 | 1000 1101 | 1010 0001 | 0010 0001 | 1101 1111 /
ssss ssss | fccc dddd | dddd kkkk | kkkk kkkk | kkkk kkkk /
1100 0000 / 0000 0000 / 0001 0010 / 1101 111?
kkkk kkkk | kkkk kkbo / xxxx xxxx / pppp ppp?
Captured impulse count can be converted to energy usage (kWh) using formula
- s: sync byte, 0xfa
- f: packet type (1 = 71 bit packet)
- c: channel (LSbit first)
- d: device ID (LSbit first)
- k: impulse count since transmitter started (LSbit first)
- b: low battery
- o: overflow?
- x: xor sum (starting at byte 1)
- p: parity
Captured impulse count can be converted to energy usage (kWh) using formula:
pulse_count/(n_imp_per_kwh)
*/
#include "decoder.h"
static uint8_t nibble_reverse[] = {
0x0,0x8,0x4,0xC,0x2,0xA,0x6,0xE,0x1,0x9,0x5,0xD,0x3,0xB,0x7,0xF
};
static uint16_t checksum_taps[] = {
0x4880, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x2080, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000
0x4880, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x2080, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000,
};
static uint8_t reverse(uint8_t b) {
b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
return b;
}
static uint16_t next_mask(uint32_t mask) {
static uint16_t next_mask(uint32_t mask)
{
uint16_t i;
uint16_t next_mask;
next_mask = mask>>1;
next_mask = mask >> 1;
for (i = 0; i < 15; i++) {
if (mask&(1<<i)) {
if (mask & (1 << i)) {
next_mask ^= checksum_taps[i];
}
}
return next_mask;
}
static uint16_t calc_checksum(uint8_t *data, uint8_t datalen) {
static uint8_t calc_checksum(uint8_t *data, uint8_t datalen)
{
uint16_t i;
uint32_t mask = 0x0001;
uint16_t checksum = 0;
uint16_t chks = 0;
for (i = datalen-1; i > 7; i--) {
for (i = datalen - 1; i > 7; i--) {
mask = next_mask(mask);
if ((data[i/8]>>(7-i%8))&1)
checksum ^= mask;
if ((data[i / 8] >> (i % 8)) & 1)
chks ^= mask;
}
return checksum;
return chks >> 8;
}
static int norgo_callback(r_device *decoder, bitbuffer_t *bitbuffer) {
bitrow_t *bb = bitbuffer->bb;
uint8_t *b = bb[0];
uint16_t device_id = 0;
uint8_t channel = 0;
uint32_t impulse_gap = 0;
uint64_t impulses = 0;
uint8_t low_battery = 0;
uint8_t bit;
uint16_t checksum = 0;
uint16_t calculated_checksum = 0;
static int norgo_decode(r_device *decoder, bitbuffer_t *bitbuffer)
{
data_t *data;
uint8_t *b = bitbuffer->bb[0];
if ( bitbuffer->bits_per_row[0] != 56 && bitbuffer->bits_per_row[0] != 72 &&
bitbuffer->bits_per_row[0] != 55 && bitbuffer->bits_per_row[0] != 71) {
if (decoder->verbose)
fprintf(stderr, "norgo_callback: wrong size of bit per row %d\n",
bitbuffer->bits_per_row[0] );
return 0;
int device_id;
int channel;
int impulse_gap;
uint64_t impulses;
int low_battery;
int maybe_overflow;
int checksum;
int calc_chk;
if (bitbuffer->bits_per_row[0] != 56
&& bitbuffer->bits_per_row[0] != 72
&& bitbuffer->bits_per_row[0] != 55
&& bitbuffer->bits_per_row[0] != 71) {
if (decoder->verbose)
fprintf(stderr, "%s: wrong size of bit per row %d\n",
__func__, bitbuffer->bits_per_row[0]);
return DECODE_ABORT_LENGTH;
}
if ( b[0] != (uint8_t)~0xFA ) {
if (decoder->verbose) {
fprintf(stderr, "norgo_callback: wrong preamble\n");
bitbuffer_print(bitbuffer);
}
return 0;
if (b[0] != (uint8_t)~0xFA) {
if (decoder->verbose)
bitbuffer_printf(bitbuffer, "%s: wrong preamble: ", __func__);
return DECODE_ABORT_EARLY;
}
bitbuffer_invert(bitbuffer); /* inverted OOK_PULSE_DMC modulation */
int xor = xor_bytes(b + 1, (bitbuffer->bits_per_row[0] - 15) / 8);
if (xor != 0xff) { // before invert 0 is ff
if (decoder->verbose)
bitrow_printf(b, bitbuffer->bits_per_row[0], "%s: XOR fail (%02x): ",
__func__, xor);
return DECODE_FAIL_MIC;
}
device_id = (nibble_reverse[(b[1]&0xF)]<<0) + (nibble_reverse[b[2]>>4]<<4);
channel = (nibble_reverse[((b[1] >> 4) & 0x7)]>>1) + 1;
if (0 == (b[1] & 0x80)) {
calculated_checksum = calc_checksum(&b[0],5*8);
checksum = (reverse(b[5])<<0) + ((uint16_t)reverse(b[6])<<8);
if ( calculated_checksum != checksum ) {
if (decoder->verbose) {
fprintf(stderr, "norgo_callback: wrong checksum %02X vs. %02X\n",
calculated_checksum,checksum);
bitbuffer_print(bitbuffer);
}
return 0;
bitbuffer_invert(bitbuffer); // inverted OOK_PULSE_DMC modulation
reflect_bytes(b, (bitbuffer->bits_per_row[0] + 1) / 8);
device_id = ((b[1] & 0xF0) >> 4) | ((b[2] & 0x0f) << 4);
channel = ((b[1] & 0x0e) >> 1) + 1;
if (0 == (b[1] & 0x1)) {
calc_chk = calc_checksum(b, 5 * 8);
checksum = b[6];
if (calc_chk != checksum) {
if (decoder->verbose)
bitbuffer_printf(bitbuffer, "%s: wrong checksum %02X vs. %02X: ",
__func__, calc_chk, checksum);
return DECODE_FAIL_MIC;
}
impulse_gap = (nibble_reverse[b[2]&0xF]<<0) +
((uint32_t)reverse(b[3])<<4) +
(((uint32_t)reverse(b[4])&0x7F)<<12);
impulse_gap = (b[2] >> 4) | (b[3] << 4) | ((b[4] & 0x7F) << 12);
/* clang-format off */
data = data_make(
"brand", "", DATA_STRING, "Norgo Energy",
"model", "", DATA_STRING, "NGE101",
"id", "Device ID", DATA_INT, device_id,
"channel", "Channel", DATA_INT, channel,
"gap", "Impulse gap", DATA_INT, impulse_gap,
NULL);
decoder_output_data(decoder,data);
"model", "", DATA_STRING, "Norgo-NGE101",
"id", "Device ID", DATA_INT, device_id,
"channel", "Channel", DATA_INT, channel,
"gap", "Impulse gap", DATA_INT, impulse_gap,
"mic", "Integrity", DATA_STRING, "CRC",
NULL);
/* clang-format on */
decoder_output_data(decoder, data);
return 1;
}
else {
calculated_checksum = calc_checksum(&b[0],7*8);
checksum = (reverse(b[7])<<0) + ((uint16_t)reverse(b[8])<<8);
if ( calculated_checksum != checksum ) {
if (decoder->verbose) {
fprintf(stderr, "norgo_callback: wrong checksum %02X vs. %02X\n",
checksum,calculated_checksum);
bitbuffer_print(bitbuffer);
}
return 0;
calc_chk = calc_checksum(b, 7 * 8);
checksum = b[8];
if (calc_chk != checksum) {
if (decoder->verbose)
bitbuffer_printf(bitbuffer, "%s: wrong checksum %02X vs. %02X: ",
__func__, checksum, calc_chk);
return DECODE_FAIL_MIC;
}
impulses = (nibble_reverse[b[2]&0xF]<<0) +
((uint64_t)reverse(b[3])<<4) +
((uint64_t)reverse(b[4])<<12) +
((uint64_t)reverse(b[5])<<20) +
(((uint64_t)reverse(b[6])&0x3F)<<28);
low_battery = (b[6]&0x2) >> 1;
impulses = (b[2] >> 4) | (b[3] << 4) | (b[4] << 12) | (b[5] << 20) | (((uint64_t)b[6] & 0x3F) << 28);
/* Pulse count is totally 34 bits but we report only 32 bits (long int not
* supported), which should be enough for the duration of battery */
low_battery = (b[6] & 0x40) >> 6;
maybe_overflow = (b[6] & 0x80) >> 7;
// Pulse count is totally 34 bits but we report only 32 bits,
// should be enough for the duration of battery.
/* clang-format off */
data = data_make(
"brand", "", DATA_STRING, "Norgo Energy",
"model", "", DATA_STRING, "NGE101",
"id", "Id", DATA_INT, device_id,
"channel", "Channel", DATA_INT, channel,
"impulses", "Impulses", DATA_INT, (uint32_t) impulses,
"battery", "Battery", DATA_STRING, !low_battery?"OK":"LOW",
"model", "", DATA_STRING, "Norgo-NGE101",
"id", "Id", DATA_INT, device_id,
"channel", "Channel", DATA_INT, channel,
"impulses", "Impulses", DATA_INT, (uint32_t)impulses,
"battery_ok", "Battery", DATA_INT, !low_battery,
"mic", "Integrity", DATA_STRING, "CRC",
NULL);
decoder_output_data(decoder,data);
/* clang-format on */
decoder_output_data(decoder, data);
return 1;
}
}
static char *output_fields[] = {
"brand",
"model",
"id",
"channel",
"model",
"id",
"channel",
"gap",
"impulses",
"battery",
NULL
"battery_ok",
NULL,
};
r_device norgo = {
.name = "Norgo NGE101",
.modulation = OOK_PULSE_DMC,
.short_width = 486,
.long_width = 972,
.reset_limit = 2100,
.sync_width = 0,
.tolerance = 120,
.decode_fn = &norgo_callback,
.disabled = 0,
.fields = output_fields
.name = "Norgo NGE101",
.modulation = OOK_PULSE_DMC,
.short_width = 486,
.long_width = 972,
.reset_limit = 2100,
.sync_width = 0,
.tolerance = 120,
.decode_fn = &norgo_decode,
.disabled = 0,
.fields = output_fields,
};