So i'm trying to program a DCC sniffer that would come from model railway sensors that takes the DCC values and sends to my MQTT broker on a RPI. This code is being used on Arduino Mega with built in ESP 8266.
I have the sniffer working as expected on its own. Also I have the connection to MQTT working fine on its own. However when i put the two together the main loop stops once I publish a message and I can't for the life of me figure out what is causing the conflict.
#include "WiFiEsp.h"
#include <ArduinoMqttClient.h>
#include "arduino_secrets.h"
#include "Sensor.h"
#include <PubSubClient.h>
char ssid[] = ""; // your network SSID (name)
char pass[] = ""; // your network password
int status = WL_IDLE_STATUS; // the Wifi radio's status
//========================
IPAddress mqtt_server = {};
const int mqtt_port = 1883;
//const char broker[] = "";
//int port = 1883;
const char topic[] = "track/sensor/1001";
WiFiEspClient espClient;
PubSubClient client(espClient);
//MqttClient mqttClient(espClient);
//========================
byte refreshTime = 4; // Time between DCC packets buffer refreshes in s
byte packetBufferSize = 32; // DCC packets buffer size
#define TIMER_PRESCALER 64
#define DccBitTimerCount (F_CPU * 80L / TIMER_PRESCALER / 1000000L)
// 16000000 * 80 / 64 / 1000000 = 20; 20 x 4usecs = 80us
boolean packetEnd;
boolean preambleFound;
const byte bitBufSize = 50; // number of slots for bits
volatile byte bitBuffer[bitBufSize];
volatile byte bitBuffHead = 1;
volatile byte bitBuffTail = 0;
byte pktByteCount=0;
byte packetBytesCount;
byte preambleOneCount;
byte dccPacket[6]; // buffer to hold a packet
byte instrByte1;
byte decoderType; //0=Loc, 1=Acc
byte bufferCounter=0;
byte isDifferentPacket=0;
byte showLoc=1;
byte showAcc=1;
unsigned int decoderAddress;
unsigned int packetBuffer[64];
unsigned int packetNew=0;
unsigned long timeToRefresh = millis() + refreshTime*1000;
long lastReconnectAttempt = 0;
boolean reconnect() {
if (client.connect("arduinoClient")) {
// Once connected, publish an announcement...
client.publish("outTopic","hello world");
// ... and resubscribe
client.subscribe("inTopic");
}
return client.connected();
}
//========================
void getPacket() {
preambleFound = false;
packetEnd = false;
packetBytesCount = 0;
preambleOneCount = 0;
while (! packetEnd) {
if (preambleFound) getNextByte();
else checkForPreamble();
}
}
//========================
void checkForPreamble() {
byte nextBit = getBit();
if (nextBit == 1) preambleOneCount++;
if (preambleOneCount < 10 && nextBit == 0) preambleOneCount = 0;
if (preambleOneCount >= 10 && nextBit == 0) preambleFound = true;
}
//========================
void getNextByte() {
byte newByte = 0;
for (byte n = 0; n < 8; n++) newByte = (newByte << 1) + getBit();
packetBytesCount ++;
dccPacket[packetBytesCount] = newByte;
dccPacket[0] = packetBytesCount;
if (getBit() == 1) packetEnd = true;
}
//========================
byte getBit() {
// gets the next bit from the bitBuffer
// if the buffer is empty it will wait indefinitely for bits to arrive
byte nbs = bitBuffHead;
while (nbs == bitBuffHead) byte nbs = nextBitSlot(bitBuffTail); //Buffer empty
bitBuffTail = nbs;
return (bitBuffer[bitBuffTail]);
}
//========================
void beginBitDetection() {
TCCR0A &= B11111100;
attachInterrupt(0, startTimer, RISING);
}
//========================
void startTimer() {
OCR0B = TCNT0 + DccBitTimerCount;
TIMSK0 |= B00000100;
TIFR0 |= B00000100;
}
//========================
ISR(TIMER0_COMPB_vect) {
byte bitFound = ! ((PINE & B00010000) >> 4);
TIMSK0 &= B11111011;
byte nbs = nextBitSlot(bitBuffHead);
if (nbs == bitBuffTail) return;
else {
bitBuffHead = nbs;
bitBuffer[bitBuffHead] = bitFound;
}
}
//========================
byte nextBitSlot(byte slot) {
slot ++;
if (slot >= bitBufSize) slot = 0;
return(slot);
}
//========================
void printPacket() {
Serial.print("PP ");
for (byte n=1; n<pktByteCount; n++) {
Serial.print(" ");
Serial.print(dccPacket[n],BIN);
}
Serial.println(" ");
}
//========================
void refreshBuffer() {
timeToRefresh = millis() + refreshTime*1000;
for (byte n=0; n<packetBufferSize; n++) packetBuffer[n]=0;
bufferCounter=0;
Serial.println("-");
/*
Serial.print("Loc ");
Serial.print(showLoc);
Serial.print(" / Acc ");
Serial.print(showAcc);
Serial.print(" / Time ");
Serial.print(refreshTime);
Serial.print(" / Buff ");
Serial.println(packetBufferSize);
Serial.println(" ");
*/
}
/***** Call back Method for Receiving MQTT messages****/
void callback(char* topic, byte* payload, unsigned int length) {
String incommingMessage = "";
for (int i = 0; i < length; i++) incommingMessage+=(char)payload[i];
Serial.println("Message arrived ["+String(topic)+"]"+incommingMessage);
}
/**** Method for Publishing MQTT Messages **********/
void publishMessage(const char* topic, String payload , boolean retained){
if (client.publish(topic, payload.c_str(), true))
Serial.println("Message publised ["+String(topic)+"]: "+payload);
}
//========================
void setup() {
// initialize serial for debugging
Serial.begin(38400);
// initialize serial for ESP module
Serial3.begin(115200);
// initialize ESP module
WiFi.init(&Serial3);
// attempt to connect to WiFi network
while ( status != WL_CONNECTED) {
Serial.print("Attempting to connect to WPA SSID: ");
Serial.println(ssid);
// Connect to WPA/WPA2 network
status = WiFi.begin(ssid, pass);
}
Serial.println("You're connected to the network");
client.setServer(mqtt_server, mqtt_port);
client.setCallback(callback);
client.setKeepAlive(5000);
delay(1500);
lastReconnectAttempt = 0;
if (!client.connected()) {
long now = millis();
if (now - lastReconnectAttempt > 5000) {
lastReconnectAttempt = now;
// Attempt to reconnect
if (reconnect()) {
lastReconnectAttempt = 0;
}
}
} else {
// Client connected
client.loop();
}
// Setup DCC Sniff
Serial.println("---");
Serial.println("DCC Packet Analyze started");
Serial.print("Updates every ");
Serial.print(refreshTime);
Serial.println(" seconds");
Serial.println("---");
beginBitDetection();
}
//====================
void loop() {
getPacket();
byte speed;
byte checksum = 0;
if (millis() > timeToRefresh) refreshBuffer();
pktByteCount = dccPacket[0];
if (!pktByteCount) return; // No new packet available
for (byte n = 1; n <= pktByteCount; n++) checksum ^= dccPacket[n];
//checksum=0; //Comment this line when on DCC !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
if (checksum) return; // Invalid Checksum
else { // There is a new packet with a correct checksum
isDifferentPacket=1;
for (byte n=0; n<packetBufferSize ; n++) {// Check if packet is not already in the buffer.
// The checksum byte is used for the test, not ideal, some new packets may not show (only 256 different checksums)
if (dccPacket[pktByteCount]==packetBuffer[n]) isDifferentPacket=0;
}
if (isDifferentPacket) { // packet does not yet exist in the packet buffer
packetBuffer[bufferCounter] = dccPacket[pktByteCount]; // add new packet to the buffer
bufferCounter = (++bufferCounter)&(packetBufferSize-1);
if (dccPacket[1]==B11111111) { //Idle packet
Serial.println("Idle ");
return;
}
if (!bitRead(dccPacket[1],7)) { //bit7=0 -> Loc Decoder Short Address
decoderAddress = dccPacket[1];
instrByte1 = dccPacket[2];
decoderType = 0;
}
else {
if (bitRead(dccPacket[1],6)) { //bit7=1 AND bit6=1 -> Loc Decoder Long Address
decoderAddress = 256 * (dccPacket[1] & B00000111) + dccPacket[2];
instrByte1 = dccPacket[3];
decoderType = 0;
}
else { //bit7=1 AND bit6=0 -> Accessory Decoder
decoderAddress = dccPacket[1]&B00111111;
instrByte1 = dccPacket[2];
decoderType = 1;
}
}
if (decoderType) { // Accessory Basic
if (showAcc) {
if (instrByte1&B10000000) { // Basic Accessory
decoderAddress = (((~instrByte1)&B01110000)<<2) + decoderAddress;
byte port = (instrByte1&B00000110)>>1;
Serial.print("Acc ");
Serial.print((decoderAddress-1)*4 + port + 5);
int accAdd = (decoderAddress-1)*4 + port + 5;
Serial.print(" ");
Serial.print(decoderAddress);
Serial.print(":");
Serial.print(port);
Serial.print(" ");
Serial.print(bitRead(instrByte1,3));
if (bitRead(instrByte1,0)) Serial.print(" On");
else Serial.print(" Off");
Serial.println("");
String publishMessage = "INACTIVE";
if (bitRead(instrByte1,0)) publishMessage = "ACTIVE";
else publishMessage = "INACTIVE";
String topic = "track/sensor/"+ String(decoderAddress);
Serial.println(topic);
Serial.println(publishMessage);
//client.publish(topic.c_str(), publishMessage.c_str());
}
else { // Accessory Extended NMRA spec is not clear about address and instruction format !!!
Serial.print("Acc Ext ");
decoderAddress = (decoderAddress<<5) + ((instrByte1&B01110000)>>2) + ((instrByte1&B00000110)>>1);
Serial.print(decoderAddress);
Serial.print(" Asp ");
Serial.print(dccPacket[3],BIN);
}
printPacket();
}
}
}
}
}
//=====================
It seems to start the next loop but doesn't get past getPacket(). If I comment out the publish message it works fine again. If I keep it commented out and add client.loop() again it will stop at the second getPacket(). So seems like any interaction with client in the main loop causes it to stop working.