modbus tcp, uart select (#18038)

This commit is contained in:
gemu 2023-02-25 09:58:33 +01:00 committed by GitHub
parent 29ae903f67
commit c752610bb7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 275 additions and 107 deletions

View File

@ -32,7 +32,6 @@
//#define DEBUG_CNT_LED1 2 //#define DEBUG_CNT_LED1 2
//#define DEBUG_CNT_LED1 2 //#define DEBUG_CNT_LED1 2
#include <TasmotaSerial.h> #include <TasmotaSerial.h>
@ -81,6 +80,16 @@
#define USE_SML_DECRYPT #define USE_SML_DECRYPT
#endif #endif
#ifndef NO_USE_SML_TCP
// modbus over TCP
#define USE_SML_TCP
#endif
#ifndef NO_SML_OBIS_LINE
// obis in line mode
#define SML_OBIS_LINE
#endif
// median filter eliminates outliers, but uses much RAM and CPU cycles // median filter eliminates outliers, but uses much RAM and CPU cycles
// 672 bytes extra RAM with SML_MAX_VARS = 16 // 672 bytes extra RAM with SML_MAX_VARS = 16
// default compile on, but must be enabled by descriptor flag 16 // default compile on, but must be enabled by descriptor flag 16
@ -132,6 +141,10 @@ needs USE_SML_AUTHKEY
synchronisation timout in milliseconds, after no serial data within this synchronisation timout in milliseconds, after no serial data within this
time serial pointer is reset to zero time serial pointer is reset to zero
7:
on esp32 the uart index may be set, normally it is allocated from 2 down to 0 automatically
thus you can combine serial SML with serial script , berry or serial drivers.
*/ */
//#define MODBUS_DEBUG //#define MODBUS_DEBUG
@ -409,7 +422,8 @@ struct METER_DESC {
uint8_t so_bpos1; uint8_t so_bpos1;
uint8_t so_fcode2; uint8_t so_fcode2;
uint8_t so_bpos2; uint8_t so_bpos2;
#endif #endif // USE_SML_SPECOPT
#ifdef ESP32 #ifdef ESP32
#ifndef USE_ESP32_SW_SERIAL #ifndef USE_ESP32_SW_SERIAL
HardwareSerial *meter_ss; HardwareSerial *meter_ss;
@ -417,10 +431,12 @@ struct METER_DESC {
SML_ESP32_SERIAL *meter_ss; SML_ESP32_SERIAL *meter_ss;
#endif #endif
#endif // ESP32 #endif // ESP32
// software serial pointers // software serial pointers
#ifdef ESP8266 #ifdef ESP8266
TasmotaSerial *meter_ss; TasmotaSerial *meter_ss;
#endif // ESP8266 #endif // ESP8266
#ifdef USE_SML_DECRYPT #ifdef USE_SML_DECRYPT
bool use_crypt = false; bool use_crypt = false;
uint8_t last_iob; uint8_t last_iob;
@ -428,11 +444,26 @@ struct METER_DESC {
Han_Parser *hp; Han_Parser *hp;
#ifdef USE_SML_AUTHKEY #ifdef USE_SML_AUTHKEY
uint8_t auth[SML_CRYPT_SIZE]; uint8_t auth[SML_CRYPT_SIZE];
#endif // USE_SML_AUTHKEY
#endif // USE_SML_DECRYPT
#ifdef USE_SML_TCP
IPAddress ip_addr;
#ifdef TCP_CLIENT_SECURE
WiFiClientSecure *client;
#else
WiFiClient *client;
#endif
#ifdef ESP32
int8_t uart_index;
#endif #endif
#endif #endif
}; };
#define TCP_MODE_FLG 0x7f
struct METER_DESC meter_desc[MAX_METERS]; struct METER_DESC meter_desc[MAX_METERS];
@ -573,22 +604,37 @@ double sml_median(struct SML_MEDIAN_FILTER* mf, double in) {
uint16_t Serial_available() { uint16_t Serial_available() {
uint8_t num = sml_globs.dump2log & 7; uint8_t num = sml_globs.dump2log & 7;
if (num < 1 || num > sml_globs.meters_used) num = 1; if (num < 1 || num > sml_globs.meters_used) num = 1;
if (!meter_desc[num - 1].meter_ss) return 0; num--;
return meter_desc[num - 1].meter_ss->available(); if (meter_desc[num].srcpin != TCP_MODE_FLG) {
if (!meter_desc[num].meter_ss) return 0;
return meter_desc[num].meter_ss->available();
} else {
return meter_desc[num].client->available();
}
} }
uint8_t Serial_read() { uint8_t Serial_read() {
uint8_t num = sml_globs.dump2log & 7; uint8_t num = sml_globs.dump2log & 7;
if (num < 1 || num > sml_globs.meters_used) num = 1; if (num < 1 || num > sml_globs.meters_used) num = 1;
if (!meter_desc[num - 1].meter_ss) return 0; num--;
return meter_desc[num - 1].meter_ss->read(); if (meter_desc[num].srcpin != TCP_MODE_FLG) {
if (!meter_desc[num].meter_ss) return 0;
return meter_desc[num].meter_ss->read();
} else {
return meter_desc[num].client->read();
}
} }
uint8_t Serial_peek() { uint8_t Serial_peek() {
uint8_t num = sml_globs.dump2log & 7; uint8_t num = sml_globs.dump2log & 7;
if (num < 1 || num > sml_globs.meters_used) num = 1; if (num < 1 || num > sml_globs.meters_used) num = 1;
if (!meter_desc[num - 1].meter_ss) return 0; num--;
return meter_desc[num - 1].meter_ss->peek(); if (meter_desc[num].srcpin != TCP_MODE_FLG) {
if (!meter_desc[num].meter_ss) return 0;
return meter_desc[num].meter_ss->peek();
} else {
return meter_desc[num].client->peek();
}
} }
void sml_dump_start(char c) { void sml_dump_start(char c) {
@ -599,7 +645,7 @@ void sml_dump_start(char c) {
#define SML_EBUS_SKIP_SYNC_DUMPS #define SML_EBUS_SKIP_SYNC_DUMPS
uint8_t *hdlc_decode(struct METER_DESC *mp, uint16_t *size);
void dump2log(void) { void dump2log(void) {
int16_t index = 0, hcnt = 0; int16_t index = 0, hcnt = 0;
@ -1206,7 +1252,13 @@ void sml_shift_in(uint32_t meters, uint32_t shard) {
mp->sbuff[count] = mp->sbuff[count + 1]; mp->sbuff[count] = mp->sbuff[count + 1];
} }
} }
uint8_t iob = (uint8_t)mp->meter_ss->read();
uint8_t iob;
if (mp->srcpin != TCP_MODE_FLG) {
iob = (uint8_t)mp->meter_ss->read();
} else {
iob = (uint8_t)mp->client->read();
}
switch (mp->type) { switch (mp->type) {
case 'o': case 'o':
@ -1289,6 +1341,20 @@ void sml_shift_in(uint32_t meters, uint32_t shard) {
if (mp->spos >= mp->sbsiz) { if (mp->spos >= mp->sbsiz) {
mp->spos = 0; mp->spos = 0;
} }
if (mp->srcpin == TCP_MODE_FLG) {
// tcp read
if (mp->spos >= 6) {
uint8_t tlen = (mp->sbuff[4] << 8) | mp->sbuff[5];
if (mp->spos == 6 + tlen) {
mp->spos = 0;
SML_Decode(meters);
mp->client->flush();
//Hexdump(mp->sbuff + 6, 10);
}
}
break;
}
if (mp->spos >= 3) { if (mp->spos >= 3) {
uint32_t mlen = mp->sbuff[2] + 5; uint32_t mlen = mp->sbuff[2] + 5;
if (mlen > mp->sbsiz) mlen = mp->sbsiz; if (mlen > mp->sbsiz) mlen = mp->sbsiz;
@ -1369,23 +1435,24 @@ void SML_Poll(void) {
uint32_t meters; uint32_t meters;
for (meters = 0; meters < sml_globs.meters_used; meters++) { for (meters = 0; meters < sml_globs.meters_used; meters++) {
if (sml_globs.mp[meters].type != 'c') { struct METER_DESC *mp = &meter_desc[meters];
// poll for serial input if (mp->type != 'c') {
if (!meter_desc[meters].meter_ss) continue; if (mp->srcpin != TCP_MODE_FLG) {
if (sml_globs.ser_act_LED_pin != 255 && (sml_globs.ser_act_meter_num == 0 || sml_globs.ser_act_meter_num - 1 == meters)) { if (!mp->meter_ss) continue;
digitalWrite(sml_globs.ser_act_LED_pin, meter_desc[meters].meter_ss->available() && !digitalRead(sml_globs.ser_act_LED_pin)); // Invert LED, if queue is continuously full // poll for serial input
if (sml_globs.ser_act_LED_pin != 255 && (sml_globs.ser_act_meter_num == 0 || sml_globs.ser_act_meter_num - 1 == meters)) {
digitalWrite(sml_globs.ser_act_LED_pin, mp->meter_ss->available() && !digitalRead(sml_globs.ser_act_LED_pin)); // Invert LED, if queue is continuously full
}
while (mp->meter_ss->available()) {
sml_shift_in(meters, 0);
}
} else {
#ifdef USE_SML_TCP
while (mp->client->available()){
sml_shift_in(meters, 0);
}
#endif
} }
while (meter_desc[meters].meter_ss->available()) {
sml_shift_in(meters, 0);
}
/*
if (meter_desc[meters].meter_ss->available()) {
sml_count++;
uint8_t iob = meter_desc[meters].meter_ss->read();
if (sml_count<5 || sml_count > 100) {
AddLog(LOG_LEVEL_INFO, PSTR(">> %02x - %d"),iob,sml_count);
}
}*/
} }
} }
} }
@ -1656,6 +1723,11 @@ void SML_Decode(uint8_t index) {
double ebus_dval = 99; double ebus_dval = 99;
double mbus_dval = 99; double mbus_dval = 99;
while (*mp != '@') { while (*mp != '@') {
if (found == 0) {
// skip rest of decoder part
mp++;
continue;
}
if (sml_globs.mp[mindex].type == 'o' || sml_globs.mp[mindex].type == 'c') { if (sml_globs.mp[mindex].type == 'o' || sml_globs.mp[mindex].type == 'c') {
if (*mp++ != *cp++) { if (*mp++ != *cp++) {
found=0; found=0;
@ -2545,12 +2617,18 @@ struct METER_DESC *mp = &meter_desc[mnum];
mp->auth[cnt / 2] = (sml_hexnibble(cp[cnt]) << 4) | sml_hexnibble(cp[cnt + 1]); mp->auth[cnt / 2] = (sml_hexnibble(cp[cnt]) << 4) | sml_hexnibble(cp[cnt + 1]);
} }
break; break;
#endif // USE_SML_AUTHKEY
#endif // USE_SML_DECRYPT
case '6': case '6':
cp += 2; cp += 2;
mp->tout_ms = strtol(cp, &cp, 10); mp->tout_ms = strtol(cp, &cp, 10);
break;
case '7':
cp += 2;
#ifdef ESP32
mp->uart_index = strtol(cp, &cp, 10);
#endif // ESP32
break; break;
#endif
#endif
} }
return cp; return cp;
} }
@ -2630,6 +2708,10 @@ void reset_sml_vars(uint16_t maxmeters) {
mp->lastms = millis(); mp->lastms = millis();
mp->tout_ms = SML_STIMEOUT; mp->tout_ms = SML_STIMEOUT;
#ifdef ESP32
mp->uart_index = -1;
#endif
#ifdef USE_SML_DECRYPT #ifdef USE_SML_DECRYPT
if (mp->use_crypt) { if (mp->use_crypt) {
if (mp->hp) { if (mp->hp) {
@ -2707,8 +2789,13 @@ void SML_Init(void) {
uint32_t mlen; uint32_t mlen;
uint16_t memory = 0; uint16_t memory = 0;
#ifdef ESP32
uint32_t uart_index = SOC_UART_NUM - 1;
#endif
sml_globs.sml_send_blocks = 0; sml_globs.sml_send_blocks = 0;
lp = glob_script_mem.section_ptr; lp = glob_script_mem.section_ptr;
struct METER_DESC *mmp;
while (lp) { while (lp) {
if (!section) { if (!section) {
if (*lp == '>' && *(lp + 1) == 'M') { if (*lp == '>' && *(lp + 1) == 'M') {
@ -2741,93 +2828,115 @@ void SML_Init(void) {
goto next_line; goto next_line;
} }
index--; index--;
srcpin = strtol(lp, &lp, 10); mmp = &meter_desc[index];
if (Gpio_used(abs(srcpin))) { if (*lp == '[') {
AddLog(LOG_LEVEL_INFO, PSTR("SML: Error: Duplicate GPIO %d defined. Not usable for RX in meter number %d"), abs(srcpin), index + 1); // sign TCP mode
srcpin = TCP_MODE_FLG;
lp++;
char str[32];
uint8_t cnt;
for (cnt = 0; cnt < sizeof(str) - 1; cnt++) {
if (!*lp || *lp == '\n' || *lp == ']') {
break;
}
str[cnt] = *lp++;
}
str[cnt] = 0;
lp++;
#ifdef USE_SML_TCP
mmp->ip_addr.fromString(str);
#endif
} else {
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);
dddef_exit: dddef_exit:
if (sml_globs.script_meter) free(sml_globs.script_meter); if (sml_globs.script_meter) free(sml_globs.script_meter);
sml_globs.script_meter = 0; sml_globs.script_meter = 0;
return; return;
}
} }
meter_desc[index].srcpin = srcpin; mmp->srcpin = srcpin;
if (*lp != ',') goto next_line; if (*lp != ',') goto next_line;
lp++; lp++;
meter_desc[index].type = *lp; mmp->type = *lp;
lp++; lp++;
if (*lp != ',') { if (*lp != ',') {
switch (*lp) { switch (*lp) {
case 'N': case 'N':
lp++; lp++;
meter_desc[index].sopt = 0x10 | (*lp & 3); mmp->sopt = 0x10 | (*lp & 3);
lp++; lp++;
break; break;
case 'E': case 'E':
lp++; lp++;
meter_desc[index].sopt = 0x20 | (*lp & 3); mmp->sopt = 0x20 | (*lp & 3);
lp++; lp++;
break; break;
case 'O': case 'O':
lp++; lp++;
meter_desc[index].sopt = 0x30 | (*lp & 3); mmp->sopt = 0x30 | (*lp & 3);
lp++; lp++;
break; break;
default: default:
meter_desc[index].sopt = *lp&7; mmp->sopt = *lp&7;
lp++; lp++;
} }
} else { } else {
meter_desc[index].sopt = 0; mmp->sopt = 0;
} }
lp++; lp++;
meter_desc[index].flag = strtol(lp, &lp, 10); mmp->flag = strtol(lp, &lp, 10);
if (*lp != ',') goto next_line; if (*lp != ',') goto next_line;
lp++; lp++;
meter_desc[index].params = strtol(lp, &lp, 10); mmp->params = strtol(lp, &lp, 10);
if (*lp != ',') goto next_line; if (*lp != ',') goto next_line;
lp++; lp++;
meter_desc[index].prefix[7] = 0; mmp->prefix[7] = 0;
for (uint32_t cnt = 0; cnt < 8; cnt++) { for (uint32_t cnt = 0; cnt < 8; cnt++) {
if (*lp == SCRIPT_EOL || *lp == ',') { if (*lp == SCRIPT_EOL || *lp == ',') {
meter_desc[index].prefix[cnt] = 0; mmp->prefix[cnt] = 0;
break; break;
} }
meter_desc[index].prefix[cnt] = *lp++; mmp->prefix[cnt] = *lp++;
} }
if (*lp == ',') { if (*lp == ',') {
lp++; lp++;
// get TRX pin // get TRX pin
meter_desc[index].trxpin = strtol(lp, &lp, 10); mmp->trxpin = strtol(lp, &lp, 10);
if (Gpio_used(meter_desc[index].trxpin)) { if (mmp->srcpin != TCP_MODE_FLG) {
AddLog(LOG_LEVEL_INFO, PSTR("SML: Error: Duplicate GPIO %d defined. Not usable for TX in meter number %d"), meter_desc[index].trxpin, index + 1); if (Gpio_used(mmp->trxpin)) {
goto dddef_exit; AddLog(LOG_LEVEL_INFO, PSTR("SML: Error: Duplicate GPIO %d defined. Not usable for TX in meter number %d"), meter_desc[index].trxpin, index + 1);
goto dddef_exit;
}
} }
// optional transmit enable pin // optional transmit enable pin
if (*lp == '(') { if (*lp == '(') {
lp++; lp++;
if (*lp == 'i') { if (*lp == 'i') {
lp++; lp++;
meter_desc[index].trx_en.trxenpol = 1; mmp->trx_en.trxenpol = 1;
} else { } else {
meter_desc[index].trx_en.trxenpol = 0; mmp->trx_en.trxenpol = 0;
} }
meter_desc[index].trx_en.trxenpin = strtol(lp, &lp, 10); mmp->trx_en.trxenpin = strtol(lp, &lp, 10);
if (*lp != ')') { if (*lp != ')') {
goto dddef_exit; goto dddef_exit;
} }
lp++; lp++;
if (Gpio_used(meter_desc[index].trx_en.trxenpin)) { if (Gpio_used(mmp->trx_en.trxenpin)) {
AddLog(LOG_LEVEL_INFO, PSTR("SML: Error: Duplicate GPIO %d defined. Not usable for TX enable in meter number %d"), meter_desc[index].trx_en.trxenpin, index + 1); AddLog(LOG_LEVEL_INFO, PSTR("SML: Error: Duplicate GPIO %d defined. Not usable for TX enable in meter number %d"), meter_desc[index].trx_en.trxenpin, index + 1);
goto dddef_exit; goto dddef_exit;
} }
meter_desc[index].trx_en.trxen = 1; mmp->trx_en.trxen = 1;
pinMode(meter_desc[index].trx_en.trxenpin, OUTPUT); pinMode(mmp->trx_en.trxenpin, OUTPUT);
digitalWrite(meter_desc[index].trx_en.trxenpin, meter_desc[index].trx_en.trxenpol); digitalWrite(mmp->trx_en.trxenpin, mmp->trx_en.trxenpol);
} else { } else {
meter_desc[index].trx_en.trxen = 0; mmp->trx_en.trxen = 0;
} }
if (*lp != ',') goto next_line; if (*lp != ',') goto next_line;
lp++; lp++;
meter_desc[index].tsecs = strtol(lp, &lp, 10); mmp->tsecs = strtol(lp, &lp, 10);
if (*lp == ',') { if (*lp == ',') {
lp++; lp++;
// look ahead // look ahead
@ -2851,9 +2960,9 @@ dddef_exit:
txlen++; txlen++;
} }
if (txlen) { if (txlen) {
meter_desc[index].txmem = (char*)calloc(txlen + 2, 1); mmp->txmem = (char*)calloc(txlen + 2, 1);
memory += txlen + 2; memory += txlen + 2;
if (meter_desc[index].txmem) { if (mmp->txmem) {
// now copy send blocks // now copy send blocks
char *txp = lp; char *txp = lp;
uint16_t tind = 0; uint16_t tind = 0;
@ -2861,14 +2970,14 @@ dddef_exit:
if (*txp == SCRIPT_EOL) { if (*txp == SCRIPT_EOL) {
txp++; txp++;
} else { } else {
meter_desc[index].txmem[tind] = *txp++; mmp->txmem[tind] = *txp++;
tind++; tind++;
} }
} }
} }
//AddLog(LOG_LEVEL_INFO, PSTR(">>> %s - %d"), meter_desc[index].txmem, txlen); //AddLog(LOG_LEVEL_INFO, PSTR(">>> %s - %d"), meter_desc[index].txmem, txlen);
meter_desc[index].index = 0; mmp->index = 0;
meter_desc[index].max_index = tx_entries; mmp->max_index = tx_entries;
sml_globs.sml_send_blocks++; sml_globs.sml_send_blocks++;
lp += txlen; lp += txlen;
} }
@ -2948,28 +3057,27 @@ next_line:
RtcSettings.pulse_counter[i] = Settings->pulse_counter[i]; RtcSettings.pulse_counter[i] = Settings->pulse_counter[i];
sml_counters[i].sml_cnt_last_ts = millis(); sml_counters[i].sml_cnt_last_ts = millis();
} }
#ifdef ESP32
uint32_t uart_index = SOC_UART_NUM - 1;
#endif
sml_counter_pinstate = 0; sml_counter_pinstate = 0;
for (uint8_t meters = 0; meters < sml_globs.meters_used; meters++) { for (uint8_t meters = 0; meters < sml_globs.meters_used; meters++) {
if (sml_globs.mp[meters].type == 'c') { METER_DESC *mp = &meter_desc[meters];
if (sml_globs.mp[meters].flag & 2) { if (mp->type == 'c') {
if (mp->flag & 2) {
} else { } else {
// counters, set to input with pullup // counters, set to input with pullup
if (sml_globs.mp[meters].flag & 1) { if (mp->flag & 1) {
pinMode(sml_globs.mp[meters].srcpin, INPUT_PULLUP); pinMode(mp->srcpin, INPUT_PULLUP);
} else { } else {
pinMode(sml_globs.mp[meters].srcpin, INPUT); pinMode(mp->srcpin, INPUT);
} }
// check for irq mode // check for irq mode
if (sml_globs.mp[meters].params <= 0) { if (mp->params <= 0) {
// init irq mode // init irq mode
sml_counters[cindex].sml_cnt_old_state = meters; sml_counters[cindex].sml_cnt_old_state = meters;
sml_counters[cindex].sml_debounce = -sml_globs.mp[meters].params; sml_counters[cindex].sml_debounce = -sml_globs.mp[meters].params;
attachInterruptArg(sml_globs.mp[meters].srcpin, SML_CounterIsr, &sml_cnt_index[cindex], CHANGE); attachInterruptArg(mp->srcpin, SML_CounterIsr, &sml_cnt_index[cindex], CHANGE);
if (digitalRead(sml_globs.mp[meters].srcpin) > 0) { if (digitalRead(mp->srcpin) > 0) {
sml_counter_pinstate |= (1 << cindex); sml_counter_pinstate |= (1 << cindex);
} }
sml_counters[cindex].sml_counter_ltime = millis(); sml_counters[cindex].sml_counter_ltime = millis();
@ -2981,86 +3089,108 @@ next_line:
} }
} else { } else {
// serial input, init // serial input, init
if (mp->srcpin == TCP_MODE_FLG) {
#ifdef USE_SML_TCP
// tcp mode
#ifdef TCP_CLIENT_SECURE
mp->client = new WiFiClientSecure;
//client(new BearSSL::WiFiClientSecure_light(1024,1024)) {
mp->client->setInsecure();
#else
mp->client = new WiFiClient;
#endif
int32_t err = mp->client->connect(mp->ip_addr, mp->params);
if (!err) {
AddLog(LOG_LEVEL_INFO, PSTR("SML: could not connect TCP to %s:%d"),mp->ip_addr.toString().c_str(), mp->params);
}
#endif
} else {
// serial mode
#ifdef ESP8266 #ifdef ESP8266
#ifdef SPECIAL_SS #ifdef SPECIAL_SS
char type = sml_globs.mp[meters].type; char type = mp->type;
if (type == 'm' || type == 'M' || type == 'k' || type == 'p' || type == 'R' || type == 'v') { if (type == 'm' || type == 'M' || type == 'k' || type == 'p' || type == 'R' || type == 'v') {
meter_desc[meters].meter_ss = new TasmotaSerial(sml_globs.mp[meters].srcpin,sml_globs.mp[meters].trxpin, 1, 0, meter_desc[meters].sibsiz); mp->meter_ss = new TasmotaSerial(mp->srcpin, mp->trxpin, 1, 0, mp->sibsiz);
} else { } else {
meter_desc[meters].meter_ss = new TasmotaSerial(sml_globs.mp[meters].srcpin,sml_globs.mp[meters].trxpin, 1, 1, meter_desc[meters].sibsiz); mp->meter_ss = new TasmotaSerial(mp->srcpin, mp->trxpin, 1, 1, mp->sibsiz);
} }
#else #else
meter_desc[meters].meter_ss = new TasmotaSerial(sml_globs.mp[meters].srcpin,sml_globs.mp[meters].trxpin, 1, 0, meter_desc[meters].sibsiz); mp->meter_ss = new TasmotaSerial(mp->srcpin, mp->trxpin, 1, 0, mp->sibsiz);
#endif // SPECIAL_SS #endif // SPECIAL_SS
#endif // ESP8266 #endif // ESP8266
#ifdef ESP32 #ifdef ESP32
// use hardware serial // use hardware serial
if (mp->uart_index >= 0) {
uart_index = mp->uart_index;
}
AddLog(LOG_LEVEL_INFO, PSTR("SML: uart used: %d"),uart_index);
#ifdef USE_ESP32_SW_SERIAL #ifdef USE_ESP32_SW_SERIAL
meter_desc[meters].meter_ss = new SML_ESP32_SERIAL(uart_index); mp->meter_ss = new SML_ESP32_SERIAL(uart_index);
if (sml_globs.mp[meters].srcpin >= 0) { if (mp->srcpin >= 0) {
if (uart_index == 0) { ClaimSerial(); } if (uart_index == 0) { ClaimSerial(); }
uart_index--; uart_index--;
if (uart_index < 0) uart_index = 0; if (uart_index < 0) uart_index = 0;
} }
#else #else
meter_desc[meters].meter_ss = new HardwareSerial(uart_index); mp->meter_ss = new HardwareSerial(uart_index);
if (uart_index == 0) { ClaimSerial(); } if (uart_index == 0) { ClaimSerial(); }
uart_index--; uart_index--;
if (uart_index < 0) uart_index = 0; if (uart_index < 0) uart_index = 0;
meter_desc[meters].meter_ss->setRxBufferSize(meter_desc[meters].sibsiz); mp->meter_ss->setRxBufferSize(mp->sibsiz);
#endif // USE_ESP32_SW_SERIAL #endif // USE_ESP32_SW_SERIAL
#endif // ESP32 #endif // ESP32
SerialConfig smode = SERIAL_8N1; SerialConfig smode = SERIAL_8N1;
if (sml_globs.mp[meters].sopt & 0xf0) { if (mp->sopt & 0xf0) {
// new serial config // new serial config
switch (sml_globs.mp[meters].sopt >> 4) { switch (mp->sopt >> 4) {
case 1: case 1:
if ((sml_globs.mp[meters].sopt & 1) == 1) smode = SERIAL_8N1; if ((mp->sopt & 1) == 1) smode = SERIAL_8N1;
else smode = SERIAL_8N2; else smode = SERIAL_8N2;
break; break;
case 2: case 2:
if ((sml_globs.mp[meters].sopt & 1) == 1) smode = SERIAL_8E1; if ((mp->sopt & 1) == 1) smode = SERIAL_8E1;
else smode = SERIAL_8E2; else smode = SERIAL_8E2;
break; break;
case 3: case 3:
if ((sml_globs.mp[meters].sopt & 1) == 1) smode = SERIAL_8O1; if ((mp->sopt & 1) == 1) smode = SERIAL_8O1;
else smode = SERIAL_8O2; else smode = SERIAL_8O2;
break; break;
} }
} else { } else {
// deprecated serial config // deprecated serial config
if (sml_globs.mp[meters].sopt == 2) { if (mp->sopt == 2) {
smode = SERIAL_8N2; smode = SERIAL_8N2;
} }
if (sml_globs.mp[meters].type=='M') { if (mp->type=='M') {
smode = SERIAL_8E1; smode = SERIAL_8E1;
if (sml_globs.mp[meters].sopt == 2) { if (mp->sopt == 2) {
smode = SERIAL_8E2; smode = SERIAL_8E2;
} }
} }
} }
#ifdef ESP8266 #ifdef ESP8266
if (meter_desc[meters].meter_ss->begin(sml_globs.mp[meters].params)) { if (mp->meter_ss->begin(mp->params)) {
meter_desc[meters].meter_ss->flush(); mp->meter_ss->flush();
} }
if (meter_desc[meters].meter_ss->hardwareSerial()) { if (mp->meter_ss->hardwareSerial()) {
Serial.begin(sml_globs.mp[meters].params, smode); Serial.begin(mp->params, smode);
ClaimSerial(); ClaimSerial();
//Serial.setRxBufferSize(512); //Serial.setRxBufferSize(512);
} }
#endif // ESP8266 #endif // ESP8266
#ifdef ESP32 #ifdef ESP32
meter_desc[meters].meter_ss->begin(sml_globs.mp[meters].params, smode, sml_globs.mp[meters].srcpin, sml_globs.mp[meters].trxpin); mp->meter_ss->begin(mp->params, smode, mp->srcpin, mp->trxpin);
#ifdef USE_ESP32_SW_SERIAL #ifdef USE_ESP32_SW_SERIAL
meter_desc[meters].meter_ss->setRxBufferSize(meter_desc[meters].sibsiz); mp->meter_ss->setRxBufferSize(mp->sibsiz);
#endif #endif
#endif // ESP32 #endif // ESP32
}
} }
} }
@ -3439,8 +3569,43 @@ uint8_t sml_hexnibble(char chr) {
return rVal; return rVal;
} }
typedef struct {
uint16_t T_ID;
uint16_t P_ID;
uint16_t SIZE;
uint8_t U_ID;
uint8_t payload[8];
} MODBUS_TCP_HEADER;
uint16_t sml_swap(uint16_t in) {
return (in << 8) || in >> 8;
}
// send modbus TCP frame with payload
// given ip addr and port in baudrate
void sml_tcp_send(uint32_t meter, uint8_t *sbuff, uint16_t slen) {
MODBUS_TCP_HEADER tcph;
tcph.T_ID = sml_swap(0x1234);
tcph.P_ID = 0;
tcph.SIZE = sml_swap(6);
tcph.U_ID = *sbuff;
sbuff++;
for (uint8_t cnt = 0; cnt < slen - 3; cnt++) {
tcph.payload[cnt] = *sbuff++;
}
#ifdef USE_SML_TCP
// AddLog(LOG_LEVEL_INFO, PSTR("slen >> %d "),slen);
if (meter_desc[meter].client->connected()) {
meter_desc[meter].client->write((uint8_t*)&tcph, 7 + slen - 3);
}
#endif
}
// send sequence every N Seconds // send sequence every N Seconds
void SML_Send_Seq(uint32_t meter,char *seq) { void SML_Send_Seq(uint32_t meter, char *seq) {
uint8_t sbuff[48]; uint8_t sbuff[48];
uint8_t *ucp = sbuff, slen = 0; uint8_t *ucp = sbuff, slen = 0;
char *cp = seq; char *cp = seq;
@ -3517,16 +3682,19 @@ void SML_Send_Seq(uint32_t meter,char *seq) {
slen += 6; slen += 6;
} }
if (meter_desc[meter].trx_en.trxen) { if (meter_desc[meter].srcpin == TCP_MODE_FLG) {
digitalWrite(meter_desc[meter].trx_en.trxenpin, meter_desc[meter].trx_en.trxenpol ^ 1); sml_tcp_send(meter, sbuff, slen);
} } else {
meter_desc[meter].meter_ss->flush(); if (meter_desc[meter].trx_en.trxen) {
meter_desc[meter].meter_ss->write(sbuff, slen); digitalWrite(meter_desc[meter].trx_en.trxenpin, meter_desc[meter].trx_en.trxenpol ^ 1);
}
if (meter_desc[meter].trx_en.trxen) {
// must wait for all data sent
meter_desc[meter].meter_ss->flush(); meter_desc[meter].meter_ss->flush();
digitalWrite(meter_desc[meter].trx_en.trxenpin, meter_desc[meter].trx_en.trxenpol); meter_desc[meter].meter_ss->write(sbuff, slen);
if (meter_desc[meter].trx_en.trxen) {
// must wait for all data sent
meter_desc[meter].meter_ss->flush();
digitalWrite(meter_desc[meter].trx_en.trxenpin, meter_desc[meter].trx_en.trxenpol);
}
} }
if (sml_globs.dump2log) { if (sml_globs.dump2log) {