Skip to content

Commit

Permalink
Adds some example railcom feedback (#552)
Browse files Browse the repository at this point in the history
Updates the dcc decoder app for the stm32f0 to send back some railcom data.

===

* Adds a railcom UART transmitter to the f091 dcc decoder.

* Adds support for F0 command decoding.

* Switches uart1 to the stm32 railcom driver.

* Implements the railcom sender in the main for the dcc-decoder app.

* Sends all zeros to check timing.
  • Loading branch information
balazsracz committed Aug 2, 2021
1 parent 9efe188 commit d1c544d
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 8 deletions.
104 changes: 103 additions & 1 deletion applications/dcc_decoder/main.cxx
Expand Up @@ -41,12 +41,102 @@
#include "dcc/DccDebug.hxx"
#include "utils/constants.hxx"
#include "utils/StringPrintf.hxx"
#include "dcc/PacketProcessor.hxx"
#include "dcc/RailCom.hxx"
#include "freertos_drivers/common/RailcomDriver.hxx"
#include "freertos/tc_ioctl.h"

#include "hardware.hxx"

Executor<1> executor("executor", 0, 2048);

// We reserve a lot of buffer for transmit to cover for small hiccups in the
// host reading data.
OVERRIDE_CONST(serial_tx_buffer_size, 2048);
OVERRIDE_CONST(main_thread_priority, 3);

// The DCC address to listen at. This is in wire format. The first address byte
// is the high byte.
static const uint16_t dcc_address_wire = 3 << 8;

uint8_t f0 = 0;

void process_packet(const DCCPacket& p) {
if (p.packet_header.csum_error) {
return;
}
if (p.dlc < 3) {
return;
}
if (p.payload[0] != (dcc_address_wire >> 8)) {
return;
}
unsigned ofs = 1;
if ((dcc_address_wire >> 8) > 127) {
// Two byte address.
ofs++;
if (p.payload[1] != (dcc_address_wire & 0xff)) {
return;
}
}
if ((p.payload[ofs] >> 5) == 0b100)
{
// F0-F4 packet
ofs++;
f0 = p.payload[ofs] & 0b00010000 ? 1 : 0;
}
}

class IrqProcessor : public dcc::PacketProcessor {
public:
IrqProcessor() {
}

/// Called in the main to prepare the railcom feedback packets.
void init()
{
ch1_.reset(0);
ch1_.add_ch1_data(0x00);
ch1_.add_ch1_data(0x00);

ch2_.reset(0);
ch2_.add_ch2_data(0);
ch2_.add_ch2_data(0);
ch2_.add_ch2_data(0);
ch2_.add_ch2_data(0);
ch2_.add_ch2_data(0);
ch2_.add_ch2_data(0);
#if 0
ch2_.add_ch2_data(dcc::RailcomDefs::ACK);
ch2_.add_ch2_data(dcc::RailcomDefs::ACK);
ch2_.add_ch2_data(dcc::RailcomDefs::ACK);
ch2_.add_ch2_data(dcc::RailcomDefs::ACK);
ch2_.add_ch2_data(dcc::RailcomDefs::ACK);
ch2_.add_ch2_data(dcc::RailcomDefs::ACK);
#endif
}

void packet_arrived(
const DCCPacket *pkt, RailcomDriver *railcom) override {
DEBUG1_Pin::set(true);
if (pkt->packet_header.csum_error) {
return;
}
ch1_.feedbackKey = pkt->feedback_key;
ch2_.feedbackKey = pkt->feedback_key;
railcom->send_ch1(&ch1_);
railcom->send_ch2(&ch2_);
DEBUG1_Pin::set(false);
}

private:
dcc::Feedback ch1_;
dcc::Feedback ch2_;
} irqProc;

extern "C" {
void set_dcc_interrupt_processor(dcc::PacketProcessor *p);
}

/** Entry point to application.
* @param argc number of command line arguments
Expand All @@ -61,12 +151,22 @@ int appl_main(int argc, char *argv[])
//int wfd = ::open("/dev/serUSB0", O_RDWR);
int wfd = ::open("/dev/ser0", O_RDWR);
HASSERT(wfd >= 0);
int rcfd = ::open("/dev/ser1", O_WRONLY);
HASSERT(rcfd >= 0);
auto ret = ::ioctl(rcfd, TCBAUDRATE, 250000);
HASSERT(ret == 0);

irqProc.init();
set_dcc_interrupt_processor(&irqProc);

int cnt = 0;
while (1)
{
DCCPacket packet_data;
int sret = ::read(fd, &packet_data, sizeof(packet_data));
HASSERT(sret == sizeof(packet_data));
DEBUG1_Pin::set(true);
process_packet(packet_data);
long long t = os_get_time_monotonic();
string txt = StringPrintf("\n%02d.%06d %04d ",
(unsigned)((t / 1000000000) % 100),
Expand All @@ -78,7 +178,9 @@ int appl_main(int argc, char *argv[])
// not enough space in the serial write buffer, we need to throw away
// data.
++cnt;
resetblink((cnt >> 3) & 1);
uint8_t blink = ((cnt >> 3) & 15) == 1u ? 1 : 0;
resetblink(f0 ^ blink);
DEBUG1_Pin::set(false);
}
return 0;
}
Expand Up @@ -48,6 +48,7 @@
#include "Stm32Uart.hxx"
#include "Stm32Can.hxx"
#include "Stm32EEPROMEmulation.hxx"
#include "Stm32RailcomSender.hxx"
#include "hardware.hxx"
#include "DummyGPIO.hxx"

Expand All @@ -73,6 +74,9 @@ const char *STDERR_DEVICE = "/dev/ser0";
/** UART 0 serial driver instance */
static Stm32Uart uart0("/dev/ser0", USART2, USART2_IRQn);

/** RailCom sender UART */
static Stm32RailcomSender railcomUart("/dev/ser1", USART1, USART1_IRQn);

/** CAN 0 CAN driver instance */
static Stm32Can can0("/dev/can0");

Expand Down Expand Up @@ -125,13 +129,13 @@ struct DccDecoderHW
/// How many usec later/earlier should the railcom cutout start happen.
static int time_delta_railcom_pre_usec()
{
return 0;
return 80 - 26;
}

/// How many usec later/earlier should the railcom cutout middle happen.
static int time_delta_railcom_mid_usec()
{
return 0;
return 193 - 185;
}

/// How many usec later/earlier should the railcom cutout end happen.
Expand Down Expand Up @@ -160,14 +164,16 @@ struct DccDecoderHW
static constexpr auto OS_IRQn = TSC_IRQn;
};

// Dummy implementation because we are not a railcom detector.
NoRailcomDriver railcom_driver;

Stm32DccDecoder<DccDecoderHW> dcc_decoder0(
"/dev/dcc_decoder0", &railcom_driver);
"/dev/dcc_decoder0", &railcomUart);

extern "C" {

void set_dcc_interrupt_processor(dcc::PacketProcessor *p)
{
dcc_decoder0.set_packet_processor(p);
}

/** Blink LED */
uint32_t blinker_pattern = 0;
static uint32_t rest_pattern = 0;
Expand Down Expand Up @@ -274,6 +280,7 @@ void hw_preinit(void)
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_USART1_CLK_ENABLE();
__HAL_RCC_USART2_CLK_ENABLE();
__HAL_RCC_CAN1_CLK_ENABLE();
__HAL_RCC_TIM14_CLK_ENABLE();
Expand All @@ -293,6 +300,14 @@ void hw_preinit(void)
gpio_init.Pin = GPIO_PIN_3;
HAL_GPIO_Init(GPIOA, &gpio_init);

/* USART1 pinmux on railCom TX pin PB6 */
gpio_init.Mode = GPIO_MODE_AF_PP;
gpio_init.Pull = GPIO_PULLUP;
gpio_init.Speed = GPIO_SPEED_FREQ_HIGH;
gpio_init.Alternate = GPIO_AF0_USART1;
gpio_init.Pin = GPIO_PIN_6;
HAL_GPIO_Init(GPIOB, &gpio_init);

/* CAN pinmux on PB8 and PB9 */
gpio_init.Mode = GPIO_MODE_AF_PP;
gpio_init.Pull = GPIO_PULLUP;
Expand Down Expand Up @@ -339,6 +354,7 @@ void timer3_interrupt_handler(void) {

void touch_interrupt_handler(void) {
dcc_decoder0.os_interrupt_handler();
portYIELD_FROM_ISR(true);
}

}
Expand Up @@ -8,8 +8,18 @@ GPIO_PIN(LED_GREEN_RAW, LedPin, A, 5);
GPIO_PIN(SW_USER, GpioInputPU, C, 13);

GPIO_PIN(DCC_IN, GpioInputPU, A, 6);
GPIO_PIN(RAILCOM_TX, GpioOutputSafeHigh, B, 6);

typedef GpioInitializer<LED_GREEN_RAW_Pin, SW_USER_Pin, DCC_IN_Pin> GpioInit;
GPIO_PIN(DEBUG1, GpioOutputSafeLow, C, 9);
GPIO_PIN(DEBUG2, GpioOutputSafeLow, C, 8);

typedef GpioInitializer< //
LED_GREEN_RAW_Pin, //
SW_USER_Pin, //
DCC_IN_Pin, //
DEBUG1_Pin, //
DEBUG2_Pin>
GpioInit;

typedef LED_GREEN_RAW_Pin BLINKER_RAW_Pin;
typedef BLINKER_Pin LED_GREEN_Pin;

0 comments on commit d1c544d

Please sign in to comment.