35#ifndef _TRACTIONMODEM_TRACTIONMODEM_HXX_
36#define _TRACTIONMODEM_TRACTIONMODEM_HXX_
41#include "traction_modem/TractionModemDefs.hxx"
43#include "hardware.hxx"
61 uint16_t command()
const
66 uint16_t length()
const
93 LOG(
INFO,
"[ModemTx] constructor");
110 LOG(
INFO,
"[ModemTx] no uart");
113 LOG(
INFO,
"[ModemTx] msg len %d",
114 (
int)
message()->data()->payload.size());
123 unsigned len =
message()->data()->payload.size();
125 const uint8_t *d = (
const uint8_t *)
message()->data()->payload.data();
126 LOG(
INFO,
"[ModemTx] sent E%d len %u done %u %08x %04x...",
128 (
unsigned)be32toh(*(uint16_t *)(d + 4)));
247 LOG(
INFO,
"[ModemRx] recv cmd: 0x%04x, len: %u",
255 "[ModemRx] Did not find an expected valid preamble and/or header.");
272 LOG(
INFO,
"[ModemRx] Maximum data length violation.");
284 size_t needed_len = total_len -
recvCnt_;
305 LOG(
INFO,
"[ModemRx] Timeout waiting for expected receive data, "
316 if (crc_calc != crc_recv)
318 LOG(
INFO,
"[ModemRx] CRC Error, received: 0x%04X 0x%04X 0x%04X, "
319 "calculated: 0x%04X 0x%04X 0x%04X",
326 std::string payload_tmp;
340 b->data()->payload = std::move(
payload_);
344 if (payload_tmp.size())
347 LOG(
INFO,
"[ModemRx] Remaining payload size: %zu",
369 for (
unsigned idx = 1; idx <
recvCnt_; ++idx)
376 memcpy(&p,
payload_.data() + idx, 4);
388 LOG(
INFO,
"[ModemRx] Sync on preamble first, recvCnt_: %zu",
443 size_t write(address_t destination,
const uint8_t *data,
size_t len,
444 errorcode_t *error,
Notifiable *again)
override
466 size_t read(address_t source, uint8_t *dst,
size_t len, errorcode_t *error,
493 auto& txm = *buf->
data();
497 switch (txm.command())
503 handle_read_response(txm);
511 handle_write_response(txm);
518 void handle_read_response(
TxMessage &txm)
523 unsigned data_bytes = txm.length() - 2;
535 void handle_write_response(TxMessage& txm) {
585 void start(
int uart_fd)
587 txFlow_.
start(uart_fd);
588 rxFlow_.
start(uart_fd);
595 if (isActive_ != is_active)
597 isActive_ = is_active;
642 void set_fn(uint32_t address, uint16_t value)
override
658 LOGIC_F0R_Pin::set(value ? 1 : 0);
662 LOGIC_F1_Pin::set(value ? 1 : 0);
665 LOGIC_F2_Pin::set(value ? 1 : 0);
668 LOGIC_F3_Pin::set(value ? 1 : 0);
671 LOGIC_F4_Pin::set(value ? 1 : 0);
676 LOGIC_F5_Pin::set(value ? 1 : 0);
679 LOGIC_F6_Pin::set(value ? 1 : 0);
686 LOGIC_F7_Pin::set(value ? 1 : 0);
689 LOGIC_F8_Pin::set(value ? 1 : 0);
695 bool input1 = INPUT1_Pin::get();
696 LOGIC_F5_Pin::set(INPUT2_Pin::get());
697 LOG(
INFO,
"INPUT1: %u", input1);
702 bool input2 = INPUT2_Pin::get();
703 LOGIC_F6_Pin::set(INPUT2_Pin::get());
704 LOG(
INFO,
"INPUT2: %u", input2);
712 uint16_t
get_fn(uint32_t address)
override
727 return dcc::TrainAddressType::DCC_LONG_ADDRESS;
731 inline void send_packet(Defs::Payload p)
733 auto *b = txFlow_.
alloc();
734 b->data()->payload = std::move(p);
738 bool isRunning_ =
false;
BufferPtr< T > get_buffer_deleter(Buffer< T > *b)
Helper function to create a BufferPtr of an appropriate type without having to explicitly specify the...
static void crc3_crc16_ccitt(const void *data, size_t length_bytes, uint16_t checksum[3])
Computes the triple-CRC value over a chunk of data.
#define STATE(_fn)
Turns a function name into an argument to be supplied to functions expecting a state.
Base class for all QMember types that hold data in an expandable format.
T * data()
get a pointer to the start of the data.
Abstract class for message recipients.
virtual void send(MessageType *message, unsigned priority=UINT_MAX)=0
Entry point to the flow.
MessageType * alloc()
Synchronously allocates a message buffer from the pool of this flow.
An object that can schedule itself on an executor to run.
virtual void notify()=0
Generic callback.
Collection of related state machines that pend on incoming messages.
Return type for a state flow callback.
Base class for state machines.
Action read_repeated(StateFlowSelectHelper *helper, int fd, void *buf, size_t size, Callback c, unsigned priority=Selectable::MAX_PRIO)
Blocks until size bytes are read and then invokes the next state.
Action read_repeated_with_timeout(StateFlowTimedSelectHelper *helper, long long timeout_nsec, int fd, void *buf, size_t size, Callback c, unsigned priority=Selectable::MAX_PRIO)
Blocks until size bytes are read, or a timeout expires.
Service * service()
Return a pointer to the service I am bound to.
Action exit()
Terminate current StateFlow activity.
void start_flow(Callback c)
Resets the flow to the specified state and starts it.
Action call_immediately(Callback c)
Imediately call the next state upon return.
Action write_repeated(StateFlowSelectHelper *helper, int fd, const void *buf, size_t size, Callback c, unsigned priority=Selectable::MAX_PRIO)
Writes some data into a file descriptor, repeating the operation as necessary until all bytes are wri...
Action release_and_exit()
Terminates the processing of the current message.
State flow with a given typed input queue.
void send(MessageType *msg, unsigned priority=UINT_MAX) OVERRIDE
Sends a message to the state flow for processing.
Abstract base class for the address spaces exported via the Memory Config Protocol.
static const errorcode_t ERROR_AGAIN
This error code signals that the operation was only partially completed, the again notify was used an...
Abstract base class for train implementations.
This class provides a mechanism for working with velocity in different forms.
@ REVERSE
reverse direction
void set_mph(float mph)
Sets the speed value from a given mph value.
bool direction() const
Return the direction independent of speed.
size_t write(address_t destination, const uint8_t *data, size_t len, errorcode_t *error, Notifiable *again) override
uint8_t * readBuf_
Where to put the bytes read.
unsigned actualLen_
How many bytes to put there.
address_t max_address() override
Notifiable * done_
Notifiable to mark when the pending read/write completes.
static constexpr uint8_t proxySpace_
This is the memory space we will be using on the decoder.
bool pendingRead_
true if we are waiting for a read response
bool read_only() override
PacketFlowInterface * txFlow_
We send outgoing packets to the decoder using this interface.
size_t read(address_t source, uint8_t *dst, size_t len, errorcode_t *error, Notifiable *again) override
bool doneRead_
true if we the read response arrived
void send(Buffer< TxMessage > *buf, unsigned prio) override
Handles messages coming back from the decoder via the traction modem protocol.
uint16_t errorCode_
Returned error code from the backend.
bool pendingWrite_
true if we are waiting for a write response
bool doneWrite_
true if we the write response arrived
void set_speed(openlcb::SpeedType speed) override
Sets the speed of the locomotive.
bool inEStop_
True if the last set was estop, false if it was a speed.
void set_emergencystop() override
Sets the train to emergency stop.
openlcb::SpeedType get_speed() override
Returns the last set speed of the locomotive.
uint16_t get_fn(uint32_t address) override
dcc::TrainAddressType legacy_address_type() override
void set_fn(uint32_t address, uint16_t value) override
Sets the value of a function.
uint32_t legacy_address() override
bool get_emergencystop() override
Get the current E-Stop state.
void set_is_active(bool is_active)
Set the active state of the wireless control.
int fd_
UART fd to send traffic to the device.
Object responsible for reading in a stream of bytes over the modem interface and forming the stream o...
static constexpr unsigned MIN_MESSAGE_SIZE
Minimum size of a message.
Receiver * receiver_
Incoming messages get routed to this object.
Action maybe_message_complete()
We might have a complete message if we have received enough data.
void start(int fd)
Start the flow using the given interface.
Action reset()
Resets the message reception state machine.
static constexpr unsigned MAX_DATA_LEN
Maximum size of the data portion of a message.
Action base_data_received()
Received at least as much data as the minimum message size.
long long get_character_nsec()
Get the wire time for a single character.
Action wait_for_base_data()
Wait until we have at least as much data as a minimum size message.
static constexpr long long CHARACTER_NSEC
Used to place a bounds on a timeout of a message.
Action resync()
Something went wrong in decoding the data stream.
string payload_
We assemble the message here.
StateFlowTimedSelectHelper helper_
Helper for reading in a select flow.
void set_listener(Receiver *rcv)
Register a listener to send incoming messages to.
RxFlow(Service *service)
Constructor.
size_t recvCnt_
Number of bytes that have been received into payload_, which may be less than payload_....
Action header_complete()
We think we have a complete header because we just validated a preamble.
Object responsible for writing messages to the modem interface.
void start(int fd)
Bind an interface to the flow to start transmitting to.
Action write_complete()
Finish up the write and exit.
Action entry() override
Entry point to the state flow for incoming TxMessages to transmit.
StateFlowSelectHelper helper_
Helper for performing the writes.
TxFlow(Service *service)
Constructor.
TrainAddressType
Which address type this legacy train node uses.
#define LOG(level, message...)
Conditionally write a message to the logging output.
static const int INFO
Loglevel that is printed by default, reporting some status information.
#define HASSERT(x)
Checks that the value of expression x is true, else terminates the current process.
#define SEC_TO_NSEC(_sec)
Convert a second value to a nanosecond value.
Use this class to read from an fd using select() in a state flow.
unsigned remaining_
Number of bytes still outstanding to read.
unsigned hasError_
1 if there was an error reading of writing.
Use this class to read from an fd with select and timeout.
@ SPACE_DCC_CV
proxy space for DCC functions
uint16_t even_
CRC of even bytes.
uint16_t odd_
CRC of odd bytes.
uint16_t all_
CRC of all bytes.
The definition of a message.
uint8_t data[0]
start of the message data
Header header_
packet command
static const CRC get_crc(const Payload &p, uint16_t length)
Extract the CRC value(s) from a given payload.
static bool is_valid(const Payload &p)
Verifies that a given payload is a valid packet.
static uint16_t get_uint16(const Payload &p, unsigned ofs)
Extract uint16_t value from a given offset in a wire formatted payload.
static constexpr unsigned MAX_LEN
Maximum allowed len value.
@ RESP_MEM_R
memory read response
@ RESP_MEM_W
memory write response
static constexpr unsigned OFS_LEN
Offset of the length in the packet.
static Payload get_speed_set_payload(openlcb::Velocity v)
Computes payload to set speed and direction.
static Payload get_memr_payload(uint8_t space, uint32_t address, uint8_t count)
Computes payload to read some data.
static constexpr uint32_t PREAMBLE
Every command starts with these bytes.
static constexpr unsigned OFS_CMD
Offset of the command in the packet.
static Payload get_wireless_present_payload(bool is_present)
Computes payload for the wireless present message.
static constexpr unsigned LEN_BASE
Length of a zero-payload packet.
static Payload get_fn_set_payload(unsigned fn, uint16_t value)
Computes payload to set a function.
static constexpr unsigned OFS_DATA
Offset of the first data byte in the packet.
static Payload get_estop_payload()
Computes payload to set estop.
static constexpr char PREAMBLE_FIRST
First byte of the preamble.
static Payload get_memw_payload(uint8_t space, uint32_t address, const std::string &data)
Computes payload to write some data.
uint16_t response_status()
Return the first two bytes of a response payload as an uint16_t.