mirror of https://github.com/arendst/Tasmota.git
modbus tcp, uart select (#18038)
This commit is contained in:
parent
29ae903f67
commit
c752610bb7
|
@ -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) {
|
||||||
|
|
Loading…
Reference in New Issue