OK: here’s some code and screenshots of results - note, you’ll need to adjust pin values based on your setup/configuration.
Summary
/*
* Project SerialCheckout
* Description: Demonstrates observed error on reading serial from thread with ethernet enabled unless priority of thread is increased by 1
* Author: JGU
* Date: 27 March 2023
*/
SYSTEM_MODE(SEMI_AUTOMATIC);
SYSTEM_THREAD(ENABLED);
PRODUCT_VERSION(1);
#define ERRMSG_LEN_128B_MAX 128
#define SERIAL_ID_LENGTH_PARTICLE 64
#define SER_BUFF_LEN_DEMO 256
#define SER_BUFF_STR_DEMO 1024
#define MAX_TLG_LEN 20
#define RS485_DIR_PIN D2
#define RS485TX true
#define RS485RX !RS485TX
#define STX 0x02
#define ETX 0x03
SerialLogHandler loghandler;
Logger mainLogger("app.main");
#define THREADED_SERIAL_DEMO
//#define SHOW_ME_THE_ERROR
#ifdef THREADED_SERIAL_DEMO
void thread_f();
#endif
// setup() runs once, when the device is first turned on.
void setup() {
// Put initialization like pinMode and begin functions here.
System.enableFeature(FEATURE_ETHERNET_DETECTION);
System.enableFeature(FEATURE_RESET_INFO);
Particle.keepAlive(20); // attempting a lower keepalive value to get rid of online/offline spam
/* Attempting to force MTU to lower setting on ETH - this is normally 1500, but that can be problematic on celluar systems */
if_t iface = nullptr;
if_get_by_index(Ethernet, &iface);
if_set_mtu(iface, 1379);
/* end MTU adjust */
Serial.begin();
pinMode(D8,INPUT);
pinMode(D7,INPUT);
pinMode(D6,INPUT);
// Configure pin direction and level
pinMode(RS485_DIR_PIN, OUTPUT);
digitalWrite(RS485_DIR_PIN,LOW); //receive is LOW, transmit is HIGH - set to LOW by default(RECEIVE) at start
Serial1.begin(115200, SERIAL_8N1);
waitFor(Serial.isConnected, 1000);
int rstReason = System.resetReason();
char errmsg[ERRMSG_LEN_128B_MAX];
char tmp[SERIAL_ID_LENGTH_PARTICLE] = {};
int sz = hal_get_device_serial_number(tmp, sizeof(tmp), nullptr);
if (sz == 0) {
strcpy(tmp,"BadSerial");
}
Particle.connect();
switch(rstReason){
case RESET_REASON_UPDATE:
case RESET_REASON_DFU_MODE:
case RESET_REASON_USER:
case RESET_REASON_POWER_DOWN:
case RESET_REASON_PIN_RESET:
//these are of no particular concern, and part of a normal operation
sprintf(errmsg,"-- Reset Reason was considered a normal situation -- :%d",rstReason);
mainLogger.info(errmsg);
break;
default:
sprintf(errmsg,"RSTFAIL - bad reason for reset! %d",rstReason);
mainLogger.error(errmsg);
break;
}
#ifdef THREADED_SERIAL_DEMO
#ifdef SHOW_ME_THE_ERROR
new Thread("armCommThd", thread_f);
#else
new Thread("armCommThd", thread_f,OS_THREAD_PRIORITY_DEFAULT+1,OS_THREAD_STACK_SIZE_DEFAULT_NETWORK);
#endif
#endif
}
// loop() runs over and over again, as quickly as it can execute.
void loop() {
// The core of your code will likely live here.
static uint32_t lastMillis = 0;
static uint32_t longMillis =0;
uint32_t curMillis=millis();
#ifndef THREADED_SERIAL_DEMO
static unsigned char receivedData[SER_BUFF_LEN_DEMO] = {0};
static uint8_t curpos = 0;
while(Serial1.available()){
receivedData[curpos] = (unsigned char)Serial1.read();
curpos+=1;
}
if (curMillis - lastMillis > 30)
{
lastMillis=curMillis;
char infoMsg[SER_BUFF_STR_DEMO] = {0x00};
sprintf(infoMsg,"ReceivedData:");
uint8_t readpos = 0;
while (!(readpos == curpos)){
sprintf(infoMsg+strlen(infoMsg),"%02X",receivedData[readpos]);
readpos+=1;
}
mainLogger.info("%s",infoMsg);
memset(infoMsg,0x00,SER_BUFF_STR_DEMO*sizeof(char));
memset(receivedData,0x00,SER_BUFF_LEN_DEMO*sizeof(unsigned char));
curpos = 0;
uint8_t outmsg[MAX_TLG_LEN] = {0};
uint8_t dCnt = 0;
outmsg[dCnt++] =STX;
outmsg[dCnt++] =0x36;
outmsg[dCnt++] =0x10;
outmsg[dCnt++] =0x04;
outmsg[dCnt++] =0x01;
outmsg[dCnt++] =0x00;
outmsg[dCnt++] =0x95;
outmsg[dCnt++] =0x8c;
outmsg[dCnt++] =ETX;
digitalWrite(RS485_DIR_PIN,HIGH); //set the RS485 direction for enabling transmit
delayMicroseconds(100); //THVD1410 has enable time in the order of 14us, so giving margin
Serial1.write(outmsg, dCnt);
Serial1.flush();
digitalWrite(RS485_DIR_PIN,LOW);//set the RS485 direction for receive after writing is complete
}
#endif
if (curMillis-longMillis> 2000){
Particle.publish("test","bleh",NO_ACK); // forcing some form of activity out the ethernet
longMillis=curMillis;
}
}
#ifdef THREADED_SERIAL_DEMO
void thread_f(){
static uint32_t lastMillis = 0;
static uint32_t longMillis =0;
static unsigned char receivedData[SER_BUFF_LEN_DEMO] = {0};
static uint8_t curpos = 0;
while(true){
uint32_t curMillis=millis();
while(Serial1.available()){
receivedData[curpos] = (unsigned char)Serial1.read();
curpos+=1;
}
if (curMillis - lastMillis > 30)
{
lastMillis=curMillis;
char infoMsg[SER_BUFF_STR_DEMO] = {0x00};
sprintf(infoMsg,"ReceivedData:");
uint8_t readpos = 0;
while (!(readpos == curpos)){
sprintf(infoMsg+strlen(infoMsg),"%02X",receivedData[readpos]);
readpos+=1;
}
mainLogger.info("%s",infoMsg);
memset(infoMsg,0x00,SER_BUFF_STR_DEMO*sizeof(char));
memset(receivedData,0x00,SER_BUFF_LEN_DEMO*sizeof(unsigned char));
curpos = 0;
uint8_t outmsg[MAX_TLG_LEN] = {0};
uint8_t dCnt = 0; // for the purposes of the demo we aren't checking for potential overwrite condition, so don't be stupid with how many bytes sent in a message
outmsg[dCnt++] =STX;
outmsg[dCnt++] =0x36;
outmsg[dCnt++] =0x10;
outmsg[dCnt++] =0x04;
outmsg[dCnt++] =0x01;
outmsg[dCnt++] =0x00;
outmsg[dCnt++] =0x95;
outmsg[dCnt++] =0x8c;
outmsg[dCnt++] =ETX;
digitalWrite(RS485_DIR_PIN,HIGH); //set the RS485 direction for enabling transmit
delayMicroseconds(100); //THVD1410 has enable time in the order of 14us, so giving margin
Serial1.write(outmsg, dCnt);
Serial1.flush();
digitalWrite(RS485_DIR_PIN,LOW);//set the RS485 direction for receive after writing is complete
}
os_thread_yield();
}
}
#endif
Expected operation looks like this (this is how it looks in normal loop, or priority +1) (undefine SHOW_ME_THE_ERROR, and define/undefine THREADED_SERIAL_DEMO if you want it to run as a thread or in main application loop):
This is how it looks when the thread has normal default priority (define THREADED_SERIAL_DEMO and SHOW_ME_THE_ERROR):
Note how behavior of main loop and threaded with priority +1 have no issues, but threaded with priority default does.