mirror of https://github.com/arendst/Tasmota.git
can bus read and write support, esp32 native twai (#19934)
This commit is contained in:
parent
ceda8782c8
commit
1e4f069c3f
|
@ -90,6 +90,13 @@
|
|||
#define SML_OBIS_LINE
|
||||
#endif
|
||||
|
||||
#ifdef ESP32
|
||||
#ifndef NO_USE_SML_CANBUS
|
||||
// canbus support
|
||||
#undef USE_SML_CANBUS
|
||||
#define USE_SML_CANBUS
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef USE_SML_TCP_SECURE
|
||||
#define USE_SML_TCP_IP_STR
|
||||
|
@ -111,6 +118,27 @@
|
|||
#include "han_Parser.h"
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef USE_SML_CANBUS
|
||||
|
||||
#ifdef ESP8266
|
||||
// esp8266 uses SPI MPC2515
|
||||
#undef SML_CAN_MASKS
|
||||
#undef SML_CAN_FILTERS
|
||||
#define SML_CAN_MASKS 2
|
||||
#define SML_CAN_FILTERS 6
|
||||
#include "mcp2515.h"
|
||||
#else
|
||||
// esp32 uses native twai
|
||||
#undef SML_CAN_MASKS
|
||||
#undef SML_CAN_FILTERS
|
||||
#define SML_CAN_MASKS 1
|
||||
#define SML_CAN_FILTERS 1
|
||||
#include <can.h>
|
||||
#include "driver/twai.h"
|
||||
#endif
|
||||
#endif // USE_SML_CANBUS
|
||||
|
||||
/* special options per meter
|
||||
1:
|
||||
special binary SML option for meters that use a bit in the status register to sign import or export like ED300L, AS2020 or DTZ541
|
||||
|
@ -151,6 +179,13 @@ time serial pointer is reset to zero
|
|||
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.
|
||||
|
||||
8:
|
||||
on esp32 1 filter mask
|
||||
on esp8266 2 filter masks
|
||||
|
||||
9:
|
||||
on esp32 1 filter
|
||||
on esp8266 6 filters
|
||||
*/
|
||||
|
||||
//#define MODBUS_DEBUG
|
||||
|
@ -479,6 +514,17 @@ struct METER_DESC {
|
|||
|
||||
#endif // USE_SML_TCP
|
||||
|
||||
|
||||
#ifdef USE_SML_CANBUS
|
||||
#ifdef ESP8266
|
||||
MCP2515 *mcp2515;
|
||||
#else
|
||||
//twai_handle_t *canp;
|
||||
#endif
|
||||
uint32_t can_masks[SML_CAN_MASKS];
|
||||
uint32_t can_filters[SML_CAN_FILTERS];
|
||||
#endif // USE_SML_CANBUS
|
||||
|
||||
#ifdef ESP32
|
||||
int8_t uart_index;
|
||||
#endif
|
||||
|
@ -549,6 +595,9 @@ struct SML_GLOBS {
|
|||
struct METER_DESC *mp;
|
||||
uint8_t to_cnt;
|
||||
bool ready;
|
||||
#ifdef USE_SML_CANBUS
|
||||
uint8_t twai_installed;
|
||||
#endif // USE_SML_CANBUS
|
||||
} sml_globs;
|
||||
|
||||
|
||||
|
@ -694,8 +743,9 @@ void dump2log(void) {
|
|||
//if (!SML_SAVAILABLE) return;
|
||||
if (!sml_globs.log_data) return;
|
||||
|
||||
struct METER_DESC *mp = &meter_desc[meter];
|
||||
|
||||
#ifdef USE_SML_DECRYPT
|
||||
struct METER_DESC *mp = &meter_desc[meter];
|
||||
if (mp->use_crypt == true) {
|
||||
d_lastms = millis();
|
||||
while ((millis() - d_lastms) < 50) {
|
||||
|
@ -862,6 +912,81 @@ void dump2log(void) {
|
|||
}
|
||||
}
|
||||
break;
|
||||
#ifdef USE_SML_CANBUS
|
||||
case 'C':
|
||||
#ifdef ESP8266
|
||||
if (mp->mcp2515 == nullptr) break;
|
||||
{ struct can_frame canFrame;
|
||||
while (mp->mcp2515->checkReceive()) {
|
||||
if (mp->mcp2515->readMessage(&canFrame) == MCP2515::ERROR_OK) {
|
||||
mp->sbuff[0] = canFrame.can_id >> 24;
|
||||
mp->sbuff[1] = canFrame.can_id >> 16;
|
||||
mp->sbuff[2] = canFrame.can_id >> 8;
|
||||
mp->sbuff[3] = canFrame.can_id;
|
||||
mp->sbuff[4] = canFrame.can_dlc;
|
||||
for (int i = 0; i < canFrame.can_dlc; i++) {
|
||||
mp->sbuff[5 + i] = canFrame.data[i];
|
||||
}
|
||||
sml_dump_start(' ');
|
||||
for (uint8_t index = 0; index < canFrame.can_dlc + 5; index++) {
|
||||
sprintf(&sml_globs.log_data[sml_globs.sml_logindex], "%02x", mp->sbuff[index]);
|
||||
sml_globs.sml_logindex += 2;
|
||||
if (index == 3) {
|
||||
sml_globs.log_data[sml_globs.sml_logindex] = ':';
|
||||
sml_globs.sml_logindex++;
|
||||
sml_globs.log_data[sml_globs.sml_logindex] = ' ';
|
||||
sml_globs.sml_logindex++;
|
||||
}
|
||||
}
|
||||
sml_globs.log_data[sml_globs.sml_logindex] = 0;
|
||||
AddLogData(LOG_LEVEL_INFO, sml_globs.log_data);
|
||||
} else {
|
||||
if (mp->mcp2515->checkError()) {
|
||||
uint8_t errFlags = mp->mcp2515->getErrorFlags();
|
||||
mp->mcp2515->clearRXnOVRFlags();
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("SML CAN: Received error %d"), errFlags);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
#else
|
||||
// esp32 native CAN
|
||||
if (!sml_globs.twai_installed) break;
|
||||
{
|
||||
uint32_t alerts_triggered = sml_can_check_alerts();
|
||||
|
||||
// Check if message is received
|
||||
if (alerts_triggered & TWAI_ALERT_RX_DATA) {
|
||||
twai_message_t message;
|
||||
while (twai_receive(&message, 0) == ESP_OK) {
|
||||
mp->sbuff[0] = message.identifier >> 24;
|
||||
mp->sbuff[1] = message.identifier >> 16;
|
||||
mp->sbuff[2] = message.identifier >> 8;
|
||||
mp->sbuff[3] = message.identifier;
|
||||
mp->sbuff[4] = message.data_length_code;
|
||||
for (int i = 0; i < message.data_length_code; i++) {
|
||||
mp->sbuff[5 + i] = message.data[i];
|
||||
}
|
||||
sml_dump_start(' ');
|
||||
for (uint8_t index = 0; index < message.data_length_code + 5; index++) {
|
||||
sprintf(&sml_globs.log_data[sml_globs.sml_logindex], "%02x", mp->sbuff[index]);
|
||||
sml_globs.sml_logindex += 2;
|
||||
if (index == 3) {
|
||||
sml_globs.log_data[sml_globs.sml_logindex] = ':';
|
||||
sml_globs.sml_logindex++;
|
||||
sml_globs.log_data[sml_globs.sml_logindex] = ' ';
|
||||
sml_globs.sml_logindex++;
|
||||
}
|
||||
}
|
||||
sml_globs.log_data[sml_globs.sml_logindex] = 0;
|
||||
AddLogData(LOG_LEVEL_INFO, sml_globs.log_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#endif // USE_SML_CANBUS
|
||||
default:
|
||||
// raw dump
|
||||
d_lastms = millis();
|
||||
|
@ -1480,6 +1605,7 @@ uint32_t meters;
|
|||
|
||||
for (meters = 0; meters < sml_globs.meters_used; meters++) {
|
||||
struct METER_DESC *mp = &meter_desc[meters];
|
||||
if (mp->type == 'C') continue;
|
||||
if (mp->type != 'c') {
|
||||
if (mp->srcpin != TCP_MODE_FLG) {
|
||||
if (!mp->meter_ss) continue;
|
||||
|
@ -2184,7 +2310,7 @@ void SML_Decode(uint8_t index) {
|
|||
} else {
|
||||
double dval;
|
||||
char type = sml_globs.mp[mindex].type;
|
||||
if (type != 'e' && type != 'r' && type != 'R' && type != 'm' && type != 'M' && type != 'k' && type != 'p' && type != 'v') {
|
||||
if (type != 'C' && type != 'e' && type != 'r' && type != 'R' && type != 'm' && type != 'M' && type != 'k' && type != 'p' && type != 'v') {
|
||||
// get numeric values
|
||||
if (type == 'o' || type == 'c') {
|
||||
if (*mp == '(') {
|
||||
|
@ -2256,7 +2382,6 @@ void SML_Decode(uint8_t index) {
|
|||
dval = ebus_dval;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#ifdef USE_SML_MEDIAN_FILTER
|
||||
if (sml_globs.mp[mindex].flag & 16) {
|
||||
|
@ -2375,11 +2500,9 @@ void SML_Show(boolean json) {
|
|||
tpowstr[i] = *mp++;
|
||||
}
|
||||
tpowstr[i] = 0;
|
||||
#ifdef USE_WEBSERVER
|
||||
// export html
|
||||
//snprintf_P(b_mqtt_data, sizeof(b_mqtt_data), "%s{s}%s{e}", b_mqtt_data,tpowstr);
|
||||
WSContentSend_PD(PSTR("{s}%s{e}"), tpowstr);
|
||||
#endif // USE_WEBSERVER
|
||||
// rewind, to ensure strchr
|
||||
mp--;
|
||||
mp = strchr(mp, '|');
|
||||
|
@ -2493,12 +2616,11 @@ void SML_Show(boolean json) {
|
|||
}
|
||||
}
|
||||
}
|
||||
#ifdef USE_WEBSERVER
|
||||
|
||||
} else {
|
||||
// web ui export
|
||||
//snprintf_P(b_mqtt_data, sizeof(b_mqtt_data), "%s{s}%s %s: {m}%s %s{e}", b_mqtt_data,meter_desc[mindex].prefix,name,tpowstr,unit);
|
||||
if (strcmp(name, "*")) WSContentSend_PD(PSTR("{s}%s %s {m}%s %s{e}"), sml_globs.mp[mindex].prefix, name,tpowstr, unit);
|
||||
#endif // USE_WEBSERVER
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2515,10 +2637,8 @@ void SML_Show(boolean json) {
|
|||
if (!nojson) {
|
||||
ResponseAppend_P(PSTR("}"));
|
||||
}
|
||||
#ifdef USE_WEBSERVER
|
||||
} else {
|
||||
//WSContentSend_PD(PSTR("%s"),b_mqtt_data);
|
||||
#endif // USE_WEBSERVER
|
||||
}
|
||||
|
||||
|
||||
|
@ -2714,6 +2834,32 @@ struct METER_DESC *mp = &meter_desc[mnum];
|
|||
mp->uart_index = strtol(cp, &cp, 10);
|
||||
#endif // ESP32
|
||||
break;
|
||||
|
||||
#ifdef USE_SML_CANBUS
|
||||
case '8':
|
||||
cp += 2;
|
||||
for (uint8_t cnt = 0; cnt < SML_CAN_MASKS; cnt++) {
|
||||
mp->can_masks[cnt] = sml_hex32(cp);
|
||||
cp += 8;
|
||||
if (*cp != ',') {
|
||||
break;
|
||||
}
|
||||
cp++;
|
||||
}
|
||||
break;
|
||||
case '9':
|
||||
cp += 2;
|
||||
for (uint8_t cnt = 0; cnt < SML_CAN_FILTERS; cnt++) {
|
||||
mp->can_filters[cnt] = sml_hex32(cp);
|
||||
cp += 8;
|
||||
if (*cp != ',') {
|
||||
break;
|
||||
}
|
||||
cp++;
|
||||
}
|
||||
break;
|
||||
|
||||
#endif // USE_SML_CANBUS
|
||||
}
|
||||
return cp;
|
||||
}
|
||||
|
@ -2797,6 +2943,15 @@ void reset_sml_vars(uint16_t maxmeters) {
|
|||
mp->uart_index = -1;
|
||||
#endif
|
||||
|
||||
#ifdef USE_SML_CANBUS
|
||||
for (uint8_t cnt = 0; cnt < SML_CAN_MASKS; cnt++) {
|
||||
mp->can_masks[cnt] = 0;
|
||||
}
|
||||
for (uint8_t cnt = 0; cnt < SML_CAN_FILTERS; cnt++) {
|
||||
mp->can_filters[cnt] = 0;
|
||||
}
|
||||
#endif // USE_SML_CANBUS
|
||||
|
||||
#ifdef USE_SML_DECRYPT
|
||||
if (mp->use_crypt) {
|
||||
if (mp->hp) {
|
||||
|
@ -2850,6 +3005,17 @@ void SML_Init(void) {
|
|||
sml_globs.sml_mf = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_SML_CANBUS
|
||||
#ifdef ESP32
|
||||
if (sml_globs.twai_installed) {
|
||||
twai_stop();
|
||||
twai_driver_uninstall();
|
||||
sml_globs.twai_installed = false;
|
||||
}
|
||||
#endif
|
||||
#endif // USE_SML_CANBUS
|
||||
|
||||
reset_sml_vars(sml_globs.meters_used);
|
||||
}
|
||||
|
||||
|
@ -3176,6 +3342,119 @@ next_line:
|
|||
InjektCounterValue(meters, RtcSettings.pulse_counter[cindex], 0.0);
|
||||
cindex++;
|
||||
}
|
||||
} else if (mp->type == 'C') {
|
||||
#ifdef USE_SML_CANBUS
|
||||
|
||||
#ifdef ESP8266
|
||||
mp->mcp2515 = nullptr;
|
||||
if ( PinUsed(GPIO_SPI_MISO) && PinUsed(GPIO_SPI_MOSI) && PinUsed(GPIO_SPI_CLK) ) {
|
||||
mp->mcp2515 = new MCP2515(mp->srcpin);
|
||||
if (MCP2515::ERROR_OK != mp->mcp2515->reset()) {
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("SML CAN: Failed to reset module"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (MCP2515::ERROR_OK != mp->mcp2515->setBitrate((CAN_SPEED)(mp->params%100), (CAN_CLOCK)(mp->params/100))) {
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("SML CAN: Failed to set module bitrate"));
|
||||
return;
|
||||
}
|
||||
|
||||
//attachInterrupt(mp->trxpin, sml_canbus_irq, FALLING);
|
||||
|
||||
if (MCP2515::ERROR_OK != mp->mcp2515->setConfigMode()) {
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("SML CAN: Failed to set config mode"));
|
||||
} else {
|
||||
if (mp->can_filters[0]) mp->mcp2515->setFilter(MCP2515::RXF0, true, mp->can_filters[0]);
|
||||
if (mp->can_filters[1]) mp->mcp2515->setFilter(MCP2515::RXF1, true, mp->can_filters[1]);
|
||||
if (mp->can_filters[2]) mp->mcp2515->setFilter(MCP2515::RXF2, true, mp->can_filters[2]);
|
||||
if (mp->can_filters[3]) mp->mcp2515->setFilter(MCP2515::RXF3, true, mp->can_filters[3]);
|
||||
if (mp->can_filters[4]) mp->mcp2515->setFilter(MCP2515::RXF4, true, mp->can_filters[4]);
|
||||
if (mp->can_filters[5]) mp->mcp2515->setFilter(MCP2515::RXF5, true, mp->can_filters[5]);
|
||||
|
||||
if (mp->can_masks[0]) mp->mcp2515->setFilterMask(MCP2515::MASK0, true, mp->can_masks[0]);
|
||||
if (mp->can_masks[1]) mp->mcp2515->setFilterMask(MCP2515::MASK1, true, mp->can_masks[1]);
|
||||
|
||||
}
|
||||
|
||||
if (MCP2515::ERROR_OK != mp->mcp2515->setNormalMode()) {
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("SML CAN: Failed to set normal mode"));
|
||||
return;
|
||||
}
|
||||
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("SML CAN: Initialized"));
|
||||
} else {
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("SML CAN: SPI not configuered"));
|
||||
}
|
||||
#else
|
||||
// Initialize configuration structures using macro initializers
|
||||
twai_general_config_t g_config = TWAI_GENERAL_CONFIG_DEFAULT((gpio_num_t)mp->trxpin, (gpio_num_t)mp->srcpin, TWAI_MODE_NORMAL);
|
||||
uint8_t qlen = mp->params/100;
|
||||
if (qlen < 8) {
|
||||
qlen = 8;
|
||||
}
|
||||
g_config.rx_queue_len = qlen;
|
||||
twai_timing_config_t t_config;
|
||||
switch (mp->params%100) {
|
||||
case 0:
|
||||
t_config = TWAI_TIMING_CONFIG_25KBITS();
|
||||
break;
|
||||
case 1:
|
||||
t_config = TWAI_TIMING_CONFIG_50KBITS();
|
||||
break;
|
||||
case 2:
|
||||
t_config = TWAI_TIMING_CONFIG_100KBITS();
|
||||
break;
|
||||
case 3:
|
||||
t_config = TWAI_TIMING_CONFIG_125KBITS();
|
||||
break;
|
||||
case 4:
|
||||
t_config = TWAI_TIMING_CONFIG_250KBITS();
|
||||
break;
|
||||
case 5:
|
||||
t_config = TWAI_TIMING_CONFIG_500KBITS();
|
||||
break;
|
||||
case 6:
|
||||
t_config = TWAI_TIMING_CONFIG_800KBITS();
|
||||
break;
|
||||
case 7:
|
||||
t_config = TWAI_TIMING_CONFIG_1MBITS();
|
||||
break;
|
||||
default:
|
||||
t_config = TWAI_TIMING_CONFIG_125KBITS();
|
||||
break;
|
||||
}
|
||||
|
||||
twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL();
|
||||
|
||||
if (mp->can_filters[0]) {
|
||||
f_config.acceptance_code = mp->can_filters[0] << 3;
|
||||
f_config.acceptance_mask = mp->can_masks[0] << 3;
|
||||
f_config.single_filter = true;
|
||||
}
|
||||
sml_globs.twai_installed = false;
|
||||
// Install TWAI driver
|
||||
if (twai_driver_install(&g_config, &t_config, &f_config) == ESP_OK) {
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("Can driver installed"));
|
||||
// Start TWAI driver
|
||||
if (twai_start() == ESP_OK) {
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("Can driver started"));
|
||||
// Reconfigure alerts to detect frame receive, Bus-Off error and RX queue full states
|
||||
uint32_t alerts_to_enable = TWAI_ALERT_RX_DATA | TWAI_ALERT_RX_QUEUE_FULL | TWAI_ALERT_TX_IDLE | TWAI_ALERT_TX_SUCCESS | TWAI_ALERT_TX_FAILED | TWAI_ALERT_ERR_PASS | TWAI_ALERT_BUS_ERROR;
|
||||
if (twai_reconfigure_alerts(alerts_to_enable, NULL) == ESP_OK) {
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("CAN Alerts reconfigured"));
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("Can driver ready"));
|
||||
sml_globs.twai_installed = true;
|
||||
} else {
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("Failed to reconfigure CAN alerts"));
|
||||
}
|
||||
} else {
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("Failed to start can driver"));
|
||||
}
|
||||
} else {
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("Failed to install can driver"));
|
||||
}
|
||||
#endif
|
||||
#endif // USE_SML_CANBUS
|
||||
} else {
|
||||
// serial input, init
|
||||
if (mp->srcpin == TCP_MODE_FLG) {
|
||||
|
@ -3364,7 +3643,9 @@ uint32_t SML_Write(int32_t meter, char *hstr) {
|
|||
meter = abs(meter);
|
||||
if (meter < 1 || meter > sml_globs.meters_used) return 0;
|
||||
meter--;
|
||||
if (!meter_desc[meter].meter_ss) return 0;
|
||||
if (meter_desc[meter].type != 'C') {
|
||||
if (!meter_desc[meter].meter_ss) return 0;
|
||||
}
|
||||
if (flag > 0) {
|
||||
SML_Send_Seq(meter, hstr);
|
||||
} else {
|
||||
|
@ -3460,7 +3741,9 @@ int32_t SML_Set_WStr(uint32_t meter, char *hstr) {
|
|||
if (sml_globs.ready == false) return 0;
|
||||
if (meter < 1 || meter > sml_globs.meters_used) return -1;
|
||||
meter--;
|
||||
if (!meter_desc[meter].meter_ss) return -2;
|
||||
if (meter_desc[meter].type != 'C') {
|
||||
if (!meter_desc[meter].meter_ss) return -2;
|
||||
}
|
||||
meter_desc[meter].script_str = hstr;
|
||||
return 0;
|
||||
}
|
||||
|
@ -3564,6 +3847,123 @@ uint32_t ctime = millis();
|
|||
}
|
||||
|
||||
#ifdef USE_SCRIPT
|
||||
|
||||
#ifdef USE_SML_CANBUS
|
||||
|
||||
|
||||
#ifdef ESP32
|
||||
#define POLLING_RATE_MS 100
|
||||
uint32_t sml_can_check_alerts() {
|
||||
|
||||
uint32_t alerts_triggered;
|
||||
twai_read_alerts(&alerts_triggered, pdMS_TO_TICKS(POLLING_RATE_MS));
|
||||
twai_status_info_t twaistatus;
|
||||
twai_get_status_info(&twaistatus);
|
||||
|
||||
// Handle alerts
|
||||
if (alerts_triggered & TWAI_ALERT_ERR_PASS) {
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("Alert: TWAI controller has become error passive."));
|
||||
}
|
||||
if (alerts_triggered & TWAI_ALERT_BUS_ERROR) {
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("Alert: A (Bit, Stuff, CRC, Form, ACK) error has occurred on the bus."));
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("Bus error count: %d"), twaistatus.bus_error_count);
|
||||
}
|
||||
if (alerts_triggered & TWAI_ALERT_RX_QUEUE_FULL) {
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("Alert: The RX queue is full causing a received frame to be lost."));
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("RX buffered: %d"), twaistatus.msgs_to_rx);
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("RX missed: %d"), twaistatus.rx_missed_count);
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("RX overrun %d"), twaistatus.rx_overrun_count);
|
||||
}
|
||||
|
||||
if (alerts_triggered & TWAI_ALERT_TX_FAILED) {
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("Alert: The Transmission failed."));
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("TX buffered: %d"), twaistatus.msgs_to_tx);
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("TX error: %d"), twaistatus.tx_error_counter);
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("TX failed: %d"), twaistatus.tx_failed_count);
|
||||
}
|
||||
|
||||
if (alerts_triggered & TWAI_ALERT_TX_SUCCESS) {
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("Alert: The Transmission was successful."));
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("TX buffered: %d"), twaistatus.msgs_to_tx);
|
||||
}
|
||||
|
||||
return alerts_triggered;
|
||||
}
|
||||
|
||||
#endif // ESP32
|
||||
|
||||
|
||||
#define SML_CAN_MAX_FRAMES 8
|
||||
|
||||
void SML_CANBUS_Read() {
|
||||
#ifdef ESP8266
|
||||
struct can_frame canFrame;
|
||||
|
||||
for (uint32_t meter = 0; meter < sml_globs.meters_used; meter++) {
|
||||
struct METER_DESC *mp = &sml_globs.mp[meter];
|
||||
uint8_t nCounter = 0;
|
||||
|
||||
if (mp->type != 'C') continue;
|
||||
|
||||
if (mp->mcp2515 == nullptr) continue;
|
||||
|
||||
while (mp->mcp2515->checkReceive() && nCounter <= SML_CAN_MAX_FRAMES) {
|
||||
if (mp->mcp2515->readMessage(&canFrame) == MCP2515::ERROR_OK) {
|
||||
mp->sbuff[0] = canFrame.can_id >> 24;
|
||||
mp->sbuff[1] = canFrame.can_id >> 16;
|
||||
mp->sbuff[2] = canFrame.can_id >> 8;
|
||||
mp->sbuff[3] = canFrame.can_id;
|
||||
mp->sbuff[4] = canFrame.can_dlc;
|
||||
for (int i = 0; i < canFrame.can_dlc; i++) {
|
||||
mp->sbuff[5 + i] = canFrame.data[i];
|
||||
}
|
||||
SML_Decode(meter);
|
||||
nCounter++;
|
||||
} else {
|
||||
if (mp->mcp2515->checkError()) {
|
||||
uint8_t errFlags = mp->mcp2515->getErrorFlags();
|
||||
mp->mcp2515->clearRXnOVRFlags();
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("SML CAN: Received error %d"), errFlags);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
||||
for (uint32_t meter = 0; meter < sml_globs.meters_used; meter++) {
|
||||
struct METER_DESC *mp = &sml_globs.mp[meter];
|
||||
uint8_t nCounter = 0;
|
||||
|
||||
if (mp->type != 'C') continue;
|
||||
|
||||
if (sml_globs.twai_installed) {
|
||||
uint32_t alerts_triggered = sml_can_check_alerts();
|
||||
|
||||
// Check if message is received
|
||||
if (alerts_triggered & TWAI_ALERT_RX_DATA) {
|
||||
// One or more messages received. Handle all.
|
||||
twai_message_t message;
|
||||
while (twai_receive(&message, 0) == ESP_OK) {
|
||||
mp->sbuff[0] = message.identifier >> 24;
|
||||
mp->sbuff[1] = message.identifier >> 16;
|
||||
mp->sbuff[2] = message.identifier >> 8;
|
||||
mp->sbuff[3] = message.identifier;
|
||||
mp->sbuff[4] = message.data_length_code;
|
||||
for (int i = 0; i < message.data_length_code; i++) {
|
||||
mp->sbuff[5 + i] = message.data[i];
|
||||
}
|
||||
SML_Decode(meter);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
#endif // USE_SML_CANBUS
|
||||
|
||||
char *SML_Get_Sequence(char *cp,uint32_t index) {
|
||||
if (!index) return cp;
|
||||
uint32_t cindex = 0;
|
||||
|
@ -3651,6 +4051,18 @@ uint8_t sml_hexnibble(char chr) {
|
|||
return rVal;
|
||||
}
|
||||
|
||||
uint32_t sml_hex32(char *cp) {
|
||||
uint32_t iob = (sml_hexnibble(*cp++) << 4) | sml_hexnibble(*cp++);
|
||||
uint32_t result = iob << 24;
|
||||
iob = (sml_hexnibble(*cp++) << 4) | sml_hexnibble(*cp++);
|
||||
result |= iob << 16;
|
||||
iob = (sml_hexnibble(*cp++) << 4) | sml_hexnibble(*cp++);
|
||||
result |= iob << 8;
|
||||
iob = (sml_hexnibble(*cp++) << 4) | sml_hexnibble(*cp++);
|
||||
result |= iob;
|
||||
return result;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
uint16_t T_ID;
|
||||
uint16_t P_ID;
|
||||
|
@ -3760,6 +4172,8 @@ void SML_Send_Seq(uint32_t meter, char *seq) {
|
|||
rflg = 1;
|
||||
cp++;
|
||||
}
|
||||
|
||||
struct METER_DESC *mp = &meter_desc[meter];
|
||||
while (*cp) {
|
||||
if (!*cp || !*(cp+1)) break;
|
||||
if (*cp == ',') break;
|
||||
|
@ -3769,8 +4183,8 @@ void SML_Send_Seq(uint32_t meter, char *seq) {
|
|||
slen++;
|
||||
if (slen >= sizeof(sbuff)-6) break; // leave space for checksum
|
||||
}
|
||||
if (meter_desc[meter].type == 'm' || meter_desc[meter].type == 'M' || meter_desc[meter].type == 'k') {
|
||||
if (meter_desc[meter].type == 'k') {
|
||||
if (mp->type == 'm' || mp->type == 'M' || mp->type == 'k') {
|
||||
if (mp->type == 'k') {
|
||||
// kamstrup, append crc, cr
|
||||
*ucp++ = 0;
|
||||
*ucp++ = 0;
|
||||
|
@ -3813,12 +4227,12 @@ void SML_Send_Seq(uint32_t meter, char *seq) {
|
|||
}
|
||||
|
||||
}
|
||||
if (meter_desc[meter].type == 'o') {
|
||||
if (mp->type == 'o') {
|
||||
for (uint32_t cnt = 0; cnt < slen; cnt++) {
|
||||
sbuff[cnt] |= (CalcEvenParity(sbuff[cnt]) << 7);
|
||||
}
|
||||
}
|
||||
if (meter_desc[meter].type == 'p') {
|
||||
if (mp->type == 'p') {
|
||||
*ucp++ = 0xc0;
|
||||
*ucp++ = 0xa8;
|
||||
*ucp++ = 1;
|
||||
|
@ -3828,18 +4242,59 @@ void SML_Send_Seq(uint32_t meter, char *seq) {
|
|||
slen += 6;
|
||||
}
|
||||
|
||||
if (meter_desc[meter].srcpin == TCP_MODE_FLG) {
|
||||
if (mp->srcpin == TCP_MODE_FLG) {
|
||||
sml_tcp_send(meter, sbuff, slen);
|
||||
} else {
|
||||
if (meter_desc[meter].trx_en.trxen) {
|
||||
digitalWrite(meter_desc[meter].trx_en.trxenpin, meter_desc[meter].trx_en.trxenpol ^ 1);
|
||||
}
|
||||
meter_desc[meter].meter_ss->flush();
|
||||
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 (mp->type == 'C') {
|
||||
#ifdef USE_SML_CANBUS
|
||||
#ifdef ESP8266
|
||||
if (mp->mcp2515 != nullptr) {
|
||||
struct can_frame canMsg;
|
||||
canMsg.can_id = (uint32_t) (sbuff[0] << 24 | sbuff[1] << 16 | sbuff[2] << 8 | sbuff[3]);
|
||||
canMsg.can_dlc = sbuff[4];
|
||||
for (uint8_t i = 0; i < canMsg.can_dlc; i++) {
|
||||
canMsg.data[i] = sbuff[i + 5];
|
||||
}
|
||||
mp->mcp2515->sendMessage(&canMsg);
|
||||
}
|
||||
#else
|
||||
if (sml_globs.twai_installed) {
|
||||
twai_message_t message;
|
||||
message.identifier = (uint32_t) (sbuff[0] << 24 | sbuff[1] << 16 | sbuff[2] << 8 | sbuff[3]);
|
||||
message.data_length_code = sbuff[4];
|
||||
for (uint8_t i = 0; i < message.data_length_code; i++) {
|
||||
message.data[i] = sbuff[i + 5];
|
||||
}
|
||||
|
||||
message.flags = 0;
|
||||
if (message.identifier & 0x80000000) {
|
||||
message.extd = 1;
|
||||
message.identifier &= 0x7fffffff;
|
||||
}
|
||||
|
||||
twai_clear_receive_queue();
|
||||
|
||||
// Queue message for transmission
|
||||
if (twai_transmit(&message, pdMS_TO_TICKS(100)) == ESP_OK) {
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("Can message queued for transmission"));
|
||||
} else {
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("Failed to queue can message for transmission"));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif // USE_SML_CANBUS
|
||||
} else {
|
||||
if (mp->trx_en.trxen) {
|
||||
digitalWrite(meter_desc[meter].trx_en.trxenpin, meter_desc[meter].trx_en.trxenpol ^ 1);
|
||||
}
|
||||
mp->meter_ss->flush();
|
||||
mp->meter_ss->write(sbuff, slen);
|
||||
if (mp->trx_en.trxen) {
|
||||
// must wait for all data sent
|
||||
mp->meter_ss->flush();
|
||||
digitalWrite(mp->trx_en.trxenpin, mp->trx_en.trxenpol);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3848,14 +4303,14 @@ void SML_Send_Seq(uint32_t meter, char *seq) {
|
|||
Hexdump(sbuff, slen);
|
||||
#else
|
||||
uint8_t type = sml_globs.mp[(sml_globs.dump2log&7) - 1].type;
|
||||
if (type == 'm' || type == 'M' || type == 'k') {
|
||||
if (type == 'm' || type == 'M' || type == 'k' || type == 'C') {
|
||||
Hexdump(sbuff, slen);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef MODBUS_DEBUG
|
||||
uint8_t type = meter_desc[meter].type;
|
||||
uint8_t type = mp->type;
|
||||
if (!sml_globs.dump2log && (type == 'm' || type == 'M' || type == 'k')) {
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("transmit index >> %d"),sml_globs.mp[meter].index);
|
||||
Hexdump(sbuff, slen);
|
||||
|
@ -4051,6 +4506,9 @@ bool Xsns53(uint32_t function) {
|
|||
dump2log();
|
||||
} else {
|
||||
SML_Poll();
|
||||
#ifdef USE_SML_CANBUS
|
||||
SML_CANBUS_Read();
|
||||
#endif// USE_SML_CANBUS
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue