Merge pull request #16538 from gemu2015/sml_update

add kamstrup, fix mbus u32
This commit is contained in:
Jason2866 2022-09-16 13:11:23 +02:00 committed by GitHub
commit 9c7e536618
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 312 additions and 183 deletions

View File

@ -53,6 +53,8 @@
#define TMSBSIZ 256
#endif
#define MODBUS_DEBUG
// addresses a bug in meter DWS74
//#define DWS74_BUG
@ -1609,9 +1611,9 @@ void sml_empty_receiver(uint32_t meters) {
void sml_shift_in(uint32_t meters,uint32_t shard) {
uint32_t count;
#ifndef SML_OBIS_LINE
if (meter_desc_p[meters].type!='e' && meter_desc_p[meters].type!='m' && meter_desc_p[meters].type!='M' && meter_desc_p[meters].type!='p' && meter_desc_p[meters].type!='R' && meter_desc_p[meters].type!='v') {
if (meter_desc_p[meters].type != 'e' && meter_desc_p[meters].type != 'k' && meter_desc_p[meters].type != 'm' && meter_desc_p[meters].type != 'M' && meter_desc_p[meters].type != 'p' && meter_desc_p[meters].type != 'R' && meter_desc_p[meters].type != 'v') {
#else
if (meter_desc_p[meters].type!='o' && meter_desc_p[meters].type!='e' && meter_desc_p[meters].type!='m' && meter_desc_p[meters].type!='M' && meter_desc_p[meters].type!='p' && meter_desc_p[meters].type!='R' && meter_desc_p[meters].type!='v') {
if (meter_desc_p[meters].type!= 'o' && meter_desc_p[meters].type != 'e' && meter_desc_p[meters].type != 'k' && meter_desc_p[meters].type != 'm' && meter_desc_p[meters].type != 'M' && meter_desc_p[meters].type != 'p' && meter_desc_p[meters].type != 'R' && meter_desc_p[meters].type != 'v') {
#endif
// shift in
for (count = 0; count < SML_BSIZ - 1; count++) {
@ -1639,21 +1641,57 @@ void sml_shift_in(uint32_t meters,uint32_t shard) {
smltbuf[meters][SML_BSIZ-1]=iob;
} else if (meter_desc_p[meters].type=='r') {
smltbuf[meters][SML_BSIZ-1]=iob;
} else if (meter_desc_p[meters].type=='m' || meter_desc_p[meters].type=='M') {
} else if (meter_desc_p[meters].type=='m' || meter_desc_p[meters].type=='M' || meter_desc_p[meters].type=='k') {
if (meter_desc_p[meters].type=='k') {
// Kamstrup
if (iob == 0x40) {
meter_spos[meters] = 0;
} else if (iob == 0x0d) {
uint16_t crc = KS_calculateCRC(&smltbuf[meters][0], meter_spos[meters]);
if (!crc) {
uint8_t *ucp = &smltbuf[meters][0];
for (uint16_t cnt = 0; cnt < meter_spos[meters]; cnt++) {
uint8_t iob = smltbuf[meters][cnt];
if (iob == 0x1b) {
*ucp++ = smltbuf[meters][cnt + 1] ^ 0xff;
cnt++;
} else {
*ucp++ = iob;
}
}
SML_Decode(meters);
}
sml_empty_receiver(meters);
meter_spos[meters] = 0;
} else {
smltbuf[meters][meter_spos[meters]] = iob;
meter_spos[meters]++;
if (meter_spos[meters] >= SML_BSIZ) {
meter_spos[meters] = 0;
}
}
} else {
smltbuf[meters][meter_spos[meters]] = iob;
meter_spos[meters]++;
if (meter_spos[meters] >= SML_BSIZ) {
meter_spos[meters] = 0;
}
// modbus
if (meter_spos[meters] >= 8) {
uint32_t mlen = smltbuf[meters][2] + 5;
if (mlen > SML_BSIZ) mlen = SML_BSIZ;
if (meter_spos[meters] >= mlen) {
#ifdef MODBUS_DEBUG
AddLog(LOG_LEVEL_INFO, PSTR("receive index >> %d"),meter_desc_p[meters].index);
Hexdump(smltbuf[meters], 10);
#endif
SML_Decode(meters);
sml_empty_receiver(meters);
meter_spos[meters] = 0;
}
}
}
} else if (meter_desc_p[meters].type == 'p') {
smltbuf[meters][meter_spos[meters]] = iob;
meter_spos[meters]++;
@ -1708,9 +1746,9 @@ void sml_shift_in(uint32_t meters,uint32_t shard) {
}
sb_counter++;
#ifndef SML_OBIS_LINE
if (meter_desc_p[meters].type!='e' && meter_desc_p[meters].type!='m' && meter_desc_p[meters].type!='M' && meter_desc_p[meters].type!='p' && meter_desc_p[meters].type!='R' && meter_desc_p[meters].type!='v') SML_Decode(meters);
if (meter_desc_p[meters].type != 'e' && meter_desc_p[meters].type != 'm' && meter_desc_p[meters].type != 'M' && meter_desc_p[meters].type != 'k' && meter_desc_p[meters].type != 'p' && meter_desc_p[meters].type != 'R' && meter_desc_p[meters].type != 'v') SML_Decode(meters);
#else
if (meter_desc_p[meters].type!='o' && meter_desc_p[meters].type!='e' && meter_desc_p[meters].type!='m' && meter_desc_p[meters].type!='M' && meter_desc_p[meters].type!='p' && meter_desc_p[meters].type!='R' && meter_desc_p[meters].type!='v') SML_Decode(meters);
if (meter_desc_p[meters].type != 'o' && meter_desc_p[meters].type != 'e' && meter_desc_p[meters].type != 'm' && meter_desc_p[meters].type != 'M' && meter_desc_p[meters].type != 'k' && meter_desc_p[meters].type != 'p' && meter_desc_p[meters].type != 'R' && meter_desc_p[meters].type != 'v') SML_Decode(meters);
#endif
}
@ -1944,7 +1982,7 @@ void SML_Decode(uint8_t index) {
// compare value
uint8_t found = 1;
double ebus_dval = 99;
float mbus_dval = 99;
double mbus_dval = 99;
while (*mp != '@') {
if (meter_desc_p[mindex].type == 'o' || meter_desc_p[mindex].type == 'c') {
if (*mp++ != *cp++) {
@ -2083,6 +2121,28 @@ void SML_Decode(uint8_t index) {
mbus_dval = (float)((cp[0]<<8) | cp[1]);
mp += 4;
cp += 2;
} else if (!strncmp(mp, "kstr", 4)) {
mp += 4;
// decode the mantissa
uint32_t x = 0;
for (uint16_t i = 0; i < cp[5]; i++) {
x <<= 8;
x |= cp[i + 7];
}
// decode the exponent
int32_t i = cp[6] & 0x3f;
if (cp[6] & 0x40) {
i = -i;
};
//float ifl = pow(10, i);
float ifl = 1;
for (uint16_t x = 1; x <= i; ++x) {
ifl *= 10;
}
if (cp[6] & 0x80) {
ifl = -ifl;
}
mbus_dval = (double )(x * ifl);
} else if (!strncmp(mp, "bcd", 3)) {
mp += 3;
uint8_t digits = strtol((char*)mp, (char**)&mp, 10);
@ -2229,7 +2289,7 @@ void SML_Decode(uint8_t index) {
}
} else {
double dval;
if (meter_desc_p[mindex].type!='e' && meter_desc_p[mindex].type!='r' && meter_desc_p[mindex].type!='m' && meter_desc_p[mindex].type!='M' && meter_desc_p[mindex].type!='p' && meter_desc_p[mindex].type!='v') {
if (meter_desc_p[mindex].type!='e' && meter_desc_p[mindex].type!='r' && meter_desc_p[mindex].type!='m' && meter_desc_p[mindex].type!='M' && meter_desc_p[mindex].type!='k' && meter_desc_p[mindex].type!='p' && meter_desc_p[mindex].type!='v') {
// get numeric values
if (meter_desc_p[mindex].type=='o' || meter_desc_p[mindex].type=='c') {
if (*mp == '(') {
@ -2276,6 +2336,11 @@ void SML_Decode(uint8_t index) {
if (mb_index != meter_desc_p[mindex].index) {
goto nextsect;
}
if (meter_desc_p[mindex].type == 'k') {
// crc is already checked, get float value
dval = mbus_dval;
mp++;
} else {
uint16_t pos = smltbuf[mindex][2] + 3;
if (pos > 32) pos = 32;
uint16_t crc = MBUS_calculateCRC(&smltbuf[mindex][0], pos, 0xFFFF);
@ -2284,6 +2349,7 @@ void SML_Decode(uint8_t index) {
dval = mbus_dval;
//AddLog(LOG_LEVEL_INFO, PSTR(">> %s"),mp);
mp++;
}
} else {
if (meter_desc_p[mindex].type == 'p') {
uint8_t crc = SML_PzemCrc(&smltbuf[mindex][0],6);
@ -3078,7 +3144,7 @@ init10:
} else {
// serial input, init
#ifdef SPECIAL_SS
if (meter_desc_p[meters].type=='m' || meter_desc_p[meters].type=='M' || meter_desc_p[meters].type=='p' || meter_desc_p[meters].type=='R' || meter_desc_p[meters].type=='v') {
if (meter_desc_p[meters].type=='m' || meter_desc_p[meters].type=='M' || meter_desc_p[meters].type=='k' || meter_desc_p[meters].type=='p' || meter_desc_p[meters].type=='R' || meter_desc_p[meters].type=='v') {
meter_ss[meters] = new TasmotaSerial(meter_desc_p[meters].srcpin,meter_desc_p[meters].trxpin,1,0,TMSBSIZ);
} else {
meter_ss[meters] = new TasmotaSerial(meter_desc_p[meters].srcpin,meter_desc_p[meters].trxpin,1,1,TMSBSIZ);
@ -3461,7 +3527,37 @@ void SML_Send_Seq(uint32_t meter,char *seq) {
slen++;
if (slen >= sizeof(sbuff)-6) break; // leave space for checksum
}
if (script_meter_desc[meter].type == 'm' || script_meter_desc[meter].type == 'M') {
if (script_meter_desc[meter].type == 'm' || script_meter_desc[meter].type == 'M' || script_meter_desc[meter].type == 'k') {
if (script_meter_desc[meter].type == 'k') {
// kamstrup, append crc, cr
*ucp++ = 0;
*ucp++ = 0;
slen += 2;
uint16_t crc = KS_calculateCRC(sbuff, slen);
ucp -= 2;
*ucp++ = highByte(crc);
*ucp++ = lowByte(crc);
// now check for escapes
uint8_t ksbuff[24];
ucp = ksbuff;
*ucp++ = 0x80;
uint8_t klen = 1;
for (uint16_t cnt = 0; cnt < slen; cnt++) {
uint8_t iob = sbuff[cnt];
if ((iob == 0x80) || (iob == 0x40) || (iob == 0x0d) || (iob == 0x06) || (iob == 0x1b)) {
*ucp++ = 0x1b;
*ucp++ = iob ^= 0xff;
klen += 2;
} else {
*ucp++ = iob;
klen++;
}
}
*ucp++ = 0xd;
slen = klen + 1;
memcpy(sbuff, ksbuff, slen);
} else {
if (!rflg) {
*ucp++ = 0;
*ucp++ = 2;
@ -3473,6 +3569,8 @@ void SML_Send_Seq(uint32_t meter,char *seq) {
*ucp++ = highByte(crc);
slen += 2;
}
}
if (script_meter_desc[meter].type == 'o') {
for (uint32_t cnt = 0; cnt < slen; cnt++) {
sbuff[cnt] |= (CalcEvenParity(sbuff[cnt]) << 7);
@ -3487,18 +3585,28 @@ void SML_Send_Seq(uint32_t meter,char *seq) {
*ucp++ = SML_PzemCrc(sbuff, 6);
slen += 6;
}
meter_ss[meter]->flush();
meter_ss[meter]->write(sbuff, slen);
if (dump2log) {
#ifdef SML_DUMP_OUT_ALL
Hexdump(sbuff, slen);
#else
uint8_t type = meter_desc_p[(dump2log&7) - 1].type;
if (type == 'm' || type == 'M') {
if (type == 'm' || type == 'M' || type == 'k') {
Hexdump(sbuff, slen);
}
#endif
}
#ifdef MODBUS_DEBUG
uint8_t type = script_meter_desc[meter].type;
if (!dump2log && (type == 'm' || type == 'M' || type == 'k')) {
AddLog(LOG_LEVEL_INFO, PSTR("transmit index >> %d"),meter_desc_p[meter].index);
Hexdump(sbuff, slen);
}
#endif
}
#endif // USE_SCRIPT
@ -3520,6 +3628,27 @@ uint16_t MBUS_calculateCRC(uint8_t *frame, uint8_t num, uint16_t start) {
return crc;
}
uint16_t KS_calculateCRC(const uint8_t *frame, uint8_t num) {
uint32_t crc = 0;
for (uint32_t i = 0; i < num; i++) {
uint8_t mask = 0x80;
uint8_t iob = frame[i];
while (mask) {
crc <<= 1;
if (iob & mask) {
crc |= 1;
}
mask >>= 1;
if (crc & 0x10000) {
crc &= 0xffff;
crc ^= 0x1021;
}
}
}
return crc;
}
uint8_t SML_PzemCrc(uint8_t *data, uint8_t len) {
uint16_t crc = 0;
for (uint32_t i = 0; i < len; i++) crc += *data++;