From 9dde8da7fe491f0ea65253e9cc5e8b19ced9d7f3 Mon Sep 17 00:00:00 2001 From: gemu2015 Date: Fri, 16 Sep 2022 12:27:16 +0200 Subject: [PATCH] add kamstrup, fix mbus u32 --- tasmota/tasmota_xsns_sensor/xsns_53_sml.ino | 495 ++++++++++++-------- 1 file changed, 312 insertions(+), 183 deletions(-) diff --git a/tasmota/tasmota_xsns_sensor/xsns_53_sml.ino b/tasmota/tasmota_xsns_sensor/xsns_53_sml.ino index 617c4f09a..e3ea58164 100644 --- a/tasmota/tasmota_xsns_sensor/xsns_53_sml.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_53_sml.ino @@ -53,6 +53,8 @@ #define TMSBSIZ 256 #endif +#define MODBUS_DEBUG + // addresses a bug in meter DWS74 //#define DWS74_BUG @@ -1609,16 +1611,16 @@ 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; countread(); + uint8_t iob = (uint8_t)meter_ss[meters]->read(); if (meter_desc_p[meters].type == 'o') { #ifndef SML_OBIS_LINE @@ -1639,37 +1641,73 @@ 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') { - smltbuf[meters][meter_spos[meters]] = iob; - meter_spos[meters]++; - if (meter_spos[meters]>=SML_BSIZ) { - meter_spos[meters]=0; - } - if (meter_spos[meters]>=8) { - uint32_t mlen=smltbuf[meters][2]+5; - if (mlen>SML_BSIZ) mlen=SML_BSIZ; - if (meter_spos[meters]>=mlen) { - SML_Decode(meters); + } 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; + 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') { + } else if (meter_desc_p[meters].type == 'p') { smltbuf[meters][meter_spos[meters]] = iob; meter_spos[meters]++; - if (meter_spos[meters]>=7) { + if (meter_spos[meters] >= 7) { SML_Decode(meters); sml_empty_receiver(meters); - meter_spos[meters]=0; + meter_spos[meters] = 0; } - } else if (meter_desc_p[meters].type=='R') { + } else if (meter_desc_p[meters].type == 'R') { smltbuf[meters][meter_spos[meters]] = iob; meter_spos[meters]++; - if (meter_spos[meters]>=SML_BSIZ) { - meter_spos[meters]=0; + if (meter_spos[meters] >= SML_BSIZ) { + meter_spos[meters] = 0; } - } else if (meter_desc_p[meters].type=='v') { - if (iob==EBUS_SYNC) { + } else if (meter_desc_p[meters].type == 'v') { + if (iob == EBUS_SYNC) { sb_counter = 0; SML_Decode(meters); smltbuf[meters][0] = iob; @@ -1682,15 +1720,15 @@ void sml_shift_in(uint32_t meters,uint32_t shard) { } } else { - if (iob==EBUS_SYNC) { + if (iob == EBUS_SYNC) { // should be end of telegramm // QQ,ZZ,PB,SB,NN ..... CRC, ACK SYNC - if (meter_spos[meters]>4+5) { + if (meter_spos[meters] > 4 + 5) { // get telegramm lenght - uint16_t tlen=smltbuf[meters][4]+5; + uint16_t tlen = smltbuf[meters][4] + 5; // test crc - if (smltbuf[meters][tlen]=ebus_CalculateCRC(smltbuf[meters],tlen)) { - ebus_esc(smltbuf[meters],tlen); + if (smltbuf[meters][tlen] = ebus_CalculateCRC(smltbuf[meters], tlen)) { + ebus_esc(smltbuf[meters], tlen); SML_Decode(meters); } else { // crc error @@ -1702,15 +1740,15 @@ void sml_shift_in(uint32_t meters,uint32_t shard) { } smltbuf[meters][meter_spos[meters]] = iob; meter_spos[meters]++; - if (meter_spos[meters]>=SML_BSIZ) { - meter_spos[meters]=0; + if (meter_spos[meters] >= SML_BSIZ) { + meter_spos[meters] = 0; } } 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 } @@ -1723,7 +1761,7 @@ uint32_t meters; if (meter_desc_p[meters].type != 'c') { // poll for serial input if (!meter_ss[meters]) continue; - if (ser_act_LED_pin!=255 && (ser_act_meter_num==0 || ser_act_meter_num-1==meters)) { + if (ser_act_LED_pin != 255 && (ser_act_meter_num == 0 || ser_act_meter_num - 1 == meters)) { digitalWrite(ser_act_LED_pin, meter_ss[meters]->available() && !digitalRead(ser_act_LED_pin)); // Invert LED, if queue is continuously full } while (meter_ss[meters]->available()) { @@ -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 == '(') { @@ -2262,47 +2322,53 @@ void SML_Decode(uint8_t index) { } } else { // ebus pzem vbus or mbus or raw - if (*mp=='b') { + if (*mp == 'b') { mp++; uint8_t shift = *mp&7; ebus_dval = (uint32_t)ebus_dval>>shift; ebus_dval = (uint32_t)ebus_dval&1; mp+=2; } - if (*mp=='i') { + if (*mp == 'i') { // mbus index mp++; - uint8_t mb_index=strtol((char*)mp,(char**)&mp,10); - if (mb_index!=meter_desc_p[mindex].index) { + uint8_t mb_index = strtol((char*)mp, (char**)&mp, 10); + if (mb_index != meter_desc_p[mindex].index) { goto nextsect; } - uint16_t pos = smltbuf[mindex][2]+3; - if (pos>32) pos=32; - uint16_t crc = MBUS_calculateCRC(&smltbuf[mindex][0],pos,0xFFFF); - if (lowByte(crc)!=smltbuf[mindex][pos]) goto nextsect; - if (highByte(crc)!=smltbuf[mindex][pos+1]) goto nextsect; - 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); - if (crc!=smltbuf[mindex][6]) goto nextsect; - dval=mbus_dval; + if (meter_desc_p[mindex].type == 'k') { + // crc is already checked, get float value + dval = mbus_dval; + mp++; } else { - dval=ebus_dval; + uint16_t pos = smltbuf[mindex][2] + 3; + if (pos > 32) pos = 32; + uint16_t crc = MBUS_calculateCRC(&smltbuf[mindex][0], pos, 0xFFFF); + if (lowByte(crc) != smltbuf[mindex][pos]) goto nextsect; + if (highByte(crc) != smltbuf[mindex][pos + 1]) goto nextsect; + 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); + if (crc != smltbuf[mindex][6]) goto nextsect; + dval = mbus_dval; + } else { + dval = ebus_dval; } } } #ifdef USE_SML_MEDIAN_FILTER - if (meter_desc_p[mindex].flag&16) { - meter_vars[vindex]=sml_median(&sml_mf[vindex],dval); + if (meter_desc_p[mindex].flag & 16) { + meter_vars[vindex] = sml_median(&sml_mf[vindex], dval); } else { - meter_vars[vindex]=dval; + meter_vars[vindex] = dval; } #else - meter_vars[vindex]=dval; + meter_vars[vindex] = dval; #endif //AddLog(LOG_LEVEL_INFO, PSTR(">> %s"),mp); @@ -2356,11 +2422,11 @@ void SML_Immediate_MQTT(const char *mp,uint8_t index,uint8_t mindex) { jname[count]=*cp++; } cp++; - uint8_t dp=atoi(cp); - if (dp&0x10) { + uint8_t dp = atoi(cp); + if (dp & 0x10) { // immediate mqtt - dtostrfd(meter_vars[index],dp&0xf,tpowstr); - ResponseTime_P(PSTR(",\"%s\":{\"%s\":%s}}"),meter_desc_p[mindex].prefix,jname,tpowstr); + dtostrfd(meter_vars[index], dp & 0xf, tpowstr); + ResponseTime_P(PSTR(",\"%s\":{\"%s\":%s}}"), meter_desc_p[mindex].prefix, jname, tpowstr); MqttPublishTeleSensor(); } } @@ -2383,22 +2449,22 @@ void SML_Show(boolean json) { if (!meters_used) return; - int8_t lastmind=((*mp)&7)-1; - if (lastmind<0 || lastmind>=meters_used) lastmind=0; + int8_t lastmind = ((*mp) & 7) - 1; + if (lastmind < 0 || lastmind >= meters_used) lastmind = 0; while (mp != NULL) { - if (*mp==0) break; + if (*mp == 0) break; // setup sections - mindex=((*mp)&7)-1; + mindex = ((*mp) & 7) - 1; - if (mindex<0 || mindex>=meters_used) mindex=0; - if (meter_desc_p[mindex].prefix[0]=='*' && meter_desc_p[mindex].prefix[1]==0) { + if (mindex < 0 || mindex >= meters_used) mindex = 0; + if (meter_desc_p[mindex].prefix[0] == '*' && meter_desc_p[mindex].prefix[1] == 0) { nojson = 1; } else { nojson = 0; } - mp+=2; - if (*mp=='=' && *(mp+1)=='h') { - mp+=2; + mp += 2; + if (*mp == '=' && *(mp+1) == 'h') { + mp += 2; // html tag if (json) { mp = strchr(mp, '|'); @@ -2407,49 +2473,49 @@ void SML_Show(boolean json) { } // web ui export uint8_t i; - for (i=0;i') break; - if (*lp==0) break; + mlen += slen + 1; + if (*lp == '#') break; + if (*lp == '>') break; + if (*lp == 0) break; } //AddLog(LOG_LEVEL_INFO, PSTR("len=%d"),mlen); - return mlen+32; + return mlen + 32; } #else uint32_t SML_getscriptsize(char *lp) { - uint32_t mlen=0; - for (uint32_t cnt=0;cntrule_enabled, 0)) { - uint8_t meter_script=Run_Scripter(">M",-2,0); - if (meter_script==99) { + uint8_t meter_script=Run_Scripter(">M", -2, 0); + if (meter_script == 99) { // use script definition if (script_meter) free(script_meter); script_meter = 0; @@ -2781,23 +2847,23 @@ void SML_Init(void) { } else { if (!*lp || *lp == '#' || *lp == '>') { - if (*(tp-1) == '|') *(tp-1) = 0; + if (*(tp - 1) == '|') *(tp - 1) = 0; break; } if (*lp == '+') { // add descriptor +1,1,c,0,10,H20 //toLogEOL(">>",lp); lp++; - index = *lp&7; + index = *lp & 7; lp += 2; if (index < 1 || index > meters_used) { AddLog(LOG_LEVEL_INFO, PSTR("illegal meter number!")); goto next_line; } index--; - srcpin = strtol(lp,&lp,10); + srcpin = strtol(lp, &lp, 10); if (Gpio_used(abs(srcpin))) { - AddLog(LOG_LEVEL_INFO, PSTR("SML: Error: Duplicate GPIO %d defined. Not usable for RX in meter number %d"),abs(srcpin),index+1); + AddLog(LOG_LEVEL_INFO, PSTR("SML: Error: Duplicate GPIO %d defined. Not usable for RX in meter number %d"), abs(srcpin), index + 1); dddef_exit: if (script_meter) free(script_meter); script_meter = 0; @@ -2852,7 +2918,7 @@ dddef_exit: lp++; script_meter_desc[index].trxpin = strtol(lp, &lp, 10); if (Gpio_used(script_meter_desc[index].trxpin)) { - AddLog(LOG_LEVEL_INFO, PSTR("SML: Error: Duplicate GPIO %d defined. Not usable for TX in meter number %d"),script_meter_desc[index].trxpin,index+1); + AddLog(LOG_LEVEL_INFO, PSTR("SML: Error: Duplicate GPIO %d defined. Not usable for TX in meter number %d"), script_meter_desc[index].trxpin, index + 1); goto dddef_exit; } if (*lp != ',') goto next_line; @@ -3016,7 +3082,7 @@ dddef_exit: } next_line: - if (*lp==SCRIPT_EOL) { + if (*lp == SCRIPT_EOL) { lp++; } else { lp = strchr(lp, SCRIPT_EOL); @@ -3024,16 +3090,16 @@ next_line: lp++; } } - *tp=0; - meter_desc_p=script_meter_desc; - meter_p=script_meter; + *tp = 0; + meter_desc_p = script_meter_desc; + meter_p = script_meter; } } #endif init10: typedef void (*function)(); - uint8_t cindex=0; + uint8_t cindex = 0; // preloud counters for (byte i = 0; i < MAX_COUNTERS; i++) { RtcSettings.pulse_counter[i] = Settings->pulse_counter[i]; @@ -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); @@ -3198,7 +3264,7 @@ uint32_t SML_SetBaud(uint32_t meter, uint32_t br) { } uint32_t SML_Status(uint32_t meter) { - if (meter<1 || meter>meters_used) return 0; + if (meter < 1 || meter > meters_used) return 0; meter--; #if defined(ED300L) || defined(AS2020) || defined(DTZ541) || defined(USE_SML_SPECOPT) return sml_status[meter]; @@ -3210,20 +3276,20 @@ uint32_t SML_Status(uint32_t meter) { uint32_t SML_Write(uint32_t meter,char *hstr) { - if (meter<1 || meter>meters_used) return 0; + if (meter < 1 || meter > meters_used) return 0; meter--; if (!meter_ss[meter]) return 0; - SML_Send_Seq(meter,hstr); + SML_Send_Seq(meter, hstr); return 1; } uint32_t SML_Read(int32_t meter,char *str, uint32_t slen) { -uint8_t hflg=0; - if (meter<0) { - meter=abs(meter); - hflg=1; +uint8_t hflg = 0; + if (meter < 0) { + meter = abs(meter); + hflg = 1; } - if (meter<1 || meter>meters_used) return 0; + if (meter < 1 || meter > meters_used) return 0; meter--; if (!meter_ss[meter]) return 0; @@ -3231,26 +3297,26 @@ uint8_t hflg=0; return 0; } - smltbuf[meter][meter_spos[meter]]=0; + smltbuf[meter][meter_spos[meter]] = 0; if (!hflg) { - strlcpy(str,(char*)&smltbuf[meter][0],slen); + strlcpy(str, (char*)&smltbuf[meter][0], slen); } else { - uint32_t index=0; - for (uint32_t cnt=0; cnt=slen-2) break; + uint32_t index = 0; + for (uint32_t cnt = 0; cnt < meter_spos[meter]; cnt++) { + sprintf(str,"%02x", smltbuf[meter][cnt]); + str += 2; + index += 2; + if (index >= slen - 2) break; } } - meter_spos[meter]=0; + meter_spos[meter] = 0; return 1; } float SML_GetVal(uint32_t index) { if (index < 1 || index > SML_MAX_VARS) { index = 1;} - return meter_vars[index-1]; + return meter_vars[index - 1]; } char *SML_GetSVal(uint32_t index) { @@ -3357,13 +3423,13 @@ uint32_t ctime = millis(); #ifdef USE_SCRIPT char *SML_Get_Sequence(char *cp,uint32_t index) { if (!index) return cp; - uint32_t cindex=0; + uint32_t cindex = 0; while (cp) { - cp=strchr(cp,','); + cp = strchr(cp, ','); if (cp) { cp++; cindex++; - if (cindex==index) { + if (cindex == index) { return cp; } } @@ -3385,13 +3451,13 @@ void SML_Check_Send(void) { script_meter_desc[cnt].script_str = 0; } else { //AddLog(LOG_LEVEL_INFO, PSTR("100 ms>> 2"),cp); - if (script_meter_desc[cnt].max_index>1) { + if (script_meter_desc[cnt].max_index > 1) { script_meter_desc[cnt].index++; if (script_meter_desc[cnt].index >= script_meter_desc[cnt].max_index) { script_meter_desc[cnt].index = 0; sml_desc_cnt++; } - cp=SML_Get_Sequence(script_meter_desc[cnt].txmem,script_meter_desc[cnt].index); + cp = SML_Get_Sequence(script_meter_desc[cnt].txmem, script_meter_desc[cnt].index); //SML_Send_Seq(cnt,cp); } else { cp = script_meter_desc[cnt].txmem; @@ -3461,17 +3527,49 @@ 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 (!rflg) { + 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++ = 2; + *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; + slen += 2; + } + // append crc + uint16_t crc = MBUS_calculateCRC(sbuff, slen, 0xFFFF); + *ucp++ = lowByte(crc); + *ucp++ = highByte(crc); slen += 2; } - // append crc - uint16_t crc = MBUS_calculateCRC(sbuff, slen, 0xFFFF); - *ucp++ = lowByte(crc); - *ucp++ = highByte(crc); - slen += 2; + } if (script_meter_desc[meter].type == 'o') { for (uint32_t cnt = 0; cnt < slen; cnt++) { @@ -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++;