Skip to content

Commit

Permalink
detect preamble in sniffer code
Browse files Browse the repository at this point in the history
  • Loading branch information
habazut committed Dec 24, 2024
1 parent 690fb5c commit eacd32e
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 7 deletions.
22 changes: 22 additions & 0 deletions CommandStation-EX.ino
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@

#include "DCCEX.h"
#include "Display_Implementation.h"
#include "Sniffer.h"
Sniffer *DCCSniffer = NULL;

#ifdef CPU_TYPE_ERROR
#error CANNOT COMPILE - DCC++ EX ONLY WORKS WITH THE ARCHITECTURES LISTED IN defines.h
Expand Down Expand Up @@ -124,6 +126,7 @@ void setup()
// Start RMFT aka EX-RAIL (ignored if no automnation)
RMFT::begin();

DCCSniffer = new Sniffer(16);

// Invoke any DCC++EX commands in the form "SETUP("xxxx");"" found in optional file mySetup.h.
// This can be used to create turnouts, outputs, sensors etc. through the normal text commands.
Expand Down Expand Up @@ -158,8 +161,27 @@ void looptimer(unsigned long timeout, const FSH* message)
lasttimestamp = now;
}
*********************************************/
void loopdiag(unsigned long timeout)
{
static unsigned long lasttimestamp = 0;
unsigned long now = millis();
if (timeout != 0) {
unsigned long diff = now - lasttimestamp;
if (diff > timeout) {
if (DCCSniffer)
DIAG(F("ticks=%L"), DCCSniffer->getTicks());
lasttimestamp = millis();
return;
}
}
// lasttimestamp = now;
}
void loop()
{
// Some debug for sniffer code
// loopdiag(937); // Do not use a value that does divide even in 80Mhz ticks
digitalWrite(2,LOW);

// The main sketch has responsibilities during loop()

// Responsibility 1: Handle DCC background processes
Expand Down
80 changes: 74 additions & 6 deletions Sniffer.cpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,78 @@
#ifdef ARDUINO_ARCH_ESP32
#include Sniffer.h
#include "Sniffer.h"
#include "DIAG.h"
//extern Sniffer *DCCSniffer;

static bool IRAM_ATTR cap_ISR_cb(mcpwm_unit_t mcpwm, mcpwm_capture_channel_id_t cap_channel, const cap_event_data_t *edata,void *user_data) {
if (edata->cap_edge == MCPWM_BOTH_EDGE) {
// should not happen at all
// delays here might crash sketch
for (int n=0 ; n<10; n++) {
digitalWrite(2,HIGH);
delay(500);
digitalWrite(2,LOW);
delay(500);
}
return 0;
}
if (user_data) ((Sniffer *)user_data)->processInterrupt(edata->cap_value, edata->cap_edge == MCPWM_POS_EDGE);
//if (DCCSniffer) DCCSniffer->processInterrupt(edata->cap_value, edata->cap_edge == MCPWM_POS_EDGE);

return 0;
}

Sniffer::Sniffer(byte snifferpin) {
mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM_CAP_0, snifferpin);
// set capture edge, BIT(0) - negative edge, BIT(1) - positive edge
// MCPWM_POS_EDGE|MCPWM_NEG_EDGE should be 3.
//mcpwm_capture_enable(MCPWM_UNIT_0, MCPWM_SELECT_CAP0, MCPWM_POS_EDGE|MCPWM_NEG_EDGE, 0);
//mcpwm_isr_register(MCPWM_UNIT_0, sniffer_isr_handler, NULL, ESP_INTR_FLAG_IRAM, NULL);
//MCPWM0.int_ena.cap0_int_ena = 1; // Enable interrupt on CAP0 signal

mcpwm_capture_config_t MCPWM_cap_config = { //Capture channel configuration
.cap_edge = MCPWM_BOTH_EDGE, // according to mcpwm.h
.cap_prescale = 1, // 1 to 256 (see .h file)
.capture_cb = cap_ISR_cb, // user defined ISR/callback
.user_data = (void *)this // user defined argument to callback
};
pinMode(2 ,OUTPUT);
digitalWrite(2,LOW);
ESP_ERROR_CHECK(mcpwm_capture_enable_channel(MCPWM_UNIT_0, MCPWM_SELECT_CAP0, &MCPWM_cap_config));
}

#define DCC_TOO_SHORT 4000L // 4000 ticks are 50usec
#define DCC_ONE_LIMIT 6400L // 6400 ticks are 80usec

void IRAM_ATTR Sniffer::processInterrupt(int32_t capticks, bool posedge) {
bool bit = 0;
diffticks = capticks - lastticks;
if (lastedge != posedge) {
if (diffticks < DCC_TOO_SHORT) {
return;
}
if (diffticks < DCC_ONE_LIMIT) {
bit = 1;
} else {
bit = 0;
}
lastticks = capticks;
lastedge = posedge;
bitfield = bitfield << 1;
bitfield = bitfield + bit;
if ((bitfield & 0xFFFFFF) == 0xFFFFFC){
// This detects the 24 last halfbits
// which 22 are ONE and 2 are ZERO
// so preabmle of 11 ONES and one ZERO
digitalWrite(2,HIGH);
}
}
// if (ticks > 800000000) //10sec
// DIAG(F("tick"));
}

/*
static void IRAM_ATTR sniffer_isr_handler(void *) {
DCCSniffer.processInterrupt();
}
#endif
#include <Arduino.h>
#include "driver/mcpwm.h"
#include "soc/mcpwm_struct.h"
#include "soc/mcpwm_reg.h"
*/
#endif // ESP32
13 changes: 12 additions & 1 deletion Sniffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,17 @@
class Sniffer {
public:
Sniffer(byte snifferpin);
void IRAM_ATTR processInterrupt(int32_t capticks, bool posedge);
inline int32_t getTicks() {
noInterrupts();
int32_t i = diffticks;
interrupts();
return i;
};
private:
}
int64_t bitfield = 0;
int32_t diffticks;
int32_t lastticks;
bool lastedge;
};
#endif

0 comments on commit eacd32e

Please sign in to comment.