35#ifndef _OPENLCB_SIMPLESTACK_HXX_
36#define _OPENLCB_SIMPLESTACK_HXX_
53#include "openlcb/NodeInitializeFlow.hxx"
62#include "utils/HubDeviceNonBlock.hxx"
63#ifdef OPENMRN_FEATURE_FD_CAN_DEVICE
64#include "utils/HubDeviceSelect.hxx"
67namespace openmrn_arduino
105 static const unsigned EXECUTOR_PRIORITIES = 5;
108 std::function<std::unique_ptr<PhysicalIf>()> create_if_helper);
150 return &memoryConfigHandler_;
173 friend class ::openmrn_arduino::OpenMRN;
194 size_t stack_size,
bool delay_start =
false)
213 uint16_t expected_version,
unsigned file_size);
219 uint16_t expected_version,
bool force =
false);
223 const InternalConfigData &ofs, uint64_t node_id,
int fd);
240 b->data()->reset(Defs::MTI_EVENT_REPORT,
node()->node_id(),
255 b->data()->reset(mti,
node()->node_id(), dst, payload);
332 int can_fd = ::open(device, O_RDWR);
339#ifdef OPENMRN_FEATURE_FD_CAN_DEVICE
344 void add_can_port_async(
const char *device)
346 auto *port =
new HubDeviceNonBlock<CanHubFlow>(
can_hub(), device);
351 void add_can_port_select(
const char *device)
360 void add_can_port_select(
int fd,
Notifiable *on_error =
nullptr)
370#if defined(__linux__) || defined(__MACH__)
376 void add_gridconnect_tty(
const char *device,
Notifiable *on_exit =
nullptr);
378#if defined(__linux__)
384 void add_socketcan_port_select(
const char *device,
int loopback = 1);
446 return &
static_cast<CanPhysicalIf *
>(
ifaceHolder_.get())->ifCan_;
479 config_local_alias_cache_size(),
480 config_remote_alias_cache_size(), config_local_nodes_count())
482 config_num_datagram_clients())
566 config_num_datagram_clients())
625 static const auto PIP_RESPONSE = Defs::EVENT_EXCHANGE | Defs::DATAGRAM |
626 Defs::MEMORY_CONFIGURATION | Defs::ABBREVIATED_DEFAULT_CDI |
627 Defs::SIMPLE_NODE_INFORMATION | Defs::CDI;
662 static const auto PIP_RESPONSE = Defs::EVENT_EXCHANGE | Defs::DATAGRAM |
663 Defs::MEMORY_CONFIGURATION | Defs::ABBREVIATED_DEFAULT_CDI |
664 Defs::SIMPLE_NODE_INFORMATION | Defs::CDI;
705 static const auto PIP_RESPONSE = openlcb::Defs::SIMPLE_PROTOCOL_SUBSET |
706 openlcb::Defs::DATAGRAM | openlcb::Defs::MEMORY_CONFIGURATION |
707 openlcb::Defs::EVENT_EXCHANGE | openlcb::Defs::SIMPLE_NODE_INFORMATION |
708 openlcb::Defs::TRACTION_CONTROL | openlcb::Defs::TRACTION_FDI |
709 Defs::ABBREVIATED_DEFAULT_CDI | Defs::CDI;
void create_gc_port_for_can_hub(CanHubFlow *can_hub, int fd, Notifiable *on_exit, bool use_select)
Creates a new port on a CAN hub in gridconnect format for a select-compatible file descriptor.
GenericHubFlow< HubData > HubFlow
A generic hub that proxies packets of untyped (aka string) data.
Operates an LED to visually display some activity.
void activity()
Call this function when activity happens.
Virtual interface for the config update listeners to register themselves for receiving configuration ...
This port prints all traffic from a (string-typed) hub to stdout.
static Notifiable * DefaultInstance()
Implementation the ExecutorBase with a specific number of priority bands.
void start_thread(const char *name, int priority, size_t stack_size)
Creates a new thread for running this executor.
void thread_body()
If the executor was created with NO_THREAD, then this function needs to be called to run the executor...
HubPort that connects a raw device to a strongly typed Hub.
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.
static GCAdapterBase * CreateGridConnectAdapter(HubFlow *gc_side, CanHubFlow *can_side, bool double_bytes)
This function connects an ASCII (GridConnect-format) CAN adapter to a binary CAN adapter,...
This class runs a CAN-bus HUB listening on TCP socket using the gridconnect format.
void register_port(port_type *port)
Adds a new port.
OS-independent abstraction for GPIO.
HubPort that connects a select-aware device to a strongly typed Hub.
An object that can schedule itself on an executor to run.
Collection of related state machines that pend on incoming messages.
ExecutorBase * executor()
Create this object statically to add an alias allocator to an already statically allocated interface.
Implementation of the DatagramService with the CANbus-specific OpenLCB datagram protocol.
Implementation of the ConfigUpdateService: state flow issuing all the calls to the registered ConfigU...
Transport-agnostic dispatcher of datagrams.
Trivial implementation of a virtual Node.
Class that advertises an event ID to be produced.
Implementation of the OpenLCB interface abstraction for the CAN-bus interface standard.
Network interface class for a character stream link that speaks the (point-to-point) TcpTransfer prot...
void add_network_fd(int fd, Notifiable *on_error=nullptr)
Adds a network client connection to the device.
Abstract class representing an OpenLCB Interface.
MessageHandler * global_message_write_flow()
void set_tx_hook(std::function< void()> hook)
Sets a transmit hook.
MessageHandler * addressed_message_write_flow()
Performs upon-startup initialization of virtual nodes.
Implementation of the Memory Access Configuration Protocol for OpenLCB.
Base class for NMRAnet nodes conforming to the asynchronous interface.
An instance of this class will add Protocol Identification Protocol to an NMRAnet Node.
Memory space implementation that exports a some memory-mapped data as a read-only memory space.
Handler for the Simple Node Information Protocol requests.
IfCan ifCan_
Implementation of OpenLCB interface.
DatagramService * datagram_service() override
CanDatagramService datagramService_
Datagram service (and clients) matching the interface.
CanHubFlow canHub0_
This flow is the connection between the stack and the device drivers.
Helper class to add stream support straight after construction.
SimpleStack with a CAN-bus based interface and IO functions for CAN-bus.
void add_can_port_blocking(const char *device)
Adds a CAN bus port with synchronous driver API.
void start_tcp_hub_server(int port=12021)
Starts a TCP server on the specified port in listening mode.
void shutdown_tcp_hub_server()
Shuts down the GridConnect Hub server, if previously started.
void connect_tcp_gridconnect_hub(const char *host, int port)
Connects to a CAN hub using TCP with the gridconnect protocol.
std::unique_ptr< GcTcpHub > gcHubServer_
Holds the ownership of the TCP hub server (if one was created).
GcTcpHub * get_tcp_hub_server()
Retrieve the instance of the GridConnect Hub server, which was started with start_tcp_hub_server().
void add_stream_support()
Enables stream transport in the interface and in the memory config protocol.
std::unique_ptr< PhysicalIf > create_if(const openlcb::NodeID node_id)
Constructor helper function.
void add_gridconnect_port(const char *path, Notifiable *on_exit=nullptr)
Adds a gridconnect port to the CAN bus.
void print_all_packets(bool timestamped=false)
Causes all CAN packets to be printed to stdout.
void start_iface(bool restart) override
Helper function for start_stack et al.
HubFlow * gridconnect_hub()
Returns the hub to be used for gridconnect-format CANbus.
Helper class for bringing up all components needed for a typical OpenLCB node.
ProtocolIdentificationHandler pipHandler_
Handles PIP requests.
void start_node() override
Hook for clients to initialize the node-specific components.
uint64_t get_pip() override
Get the PIP response value.
SNIPHandler snipHandler_
Handles SNIP requests.
DefaultNode node_
The actual node.
StateFlow for sending out medium-sized data payloads like the Simple Node Ident Info protocol.
Polymorphic class that can be implemented by CAN and TCP interfaces separately for appropriate constr...
virtual DatagramService * datagram_service()=0
void set_tx_activity_led(const Gpio *led, long long period=MSEC_TO_NSEC(33))
Adds an activiy LED which will be flashed every time a message is sent from this node to the network.
SimpleInfoFlow infoFlow_
General flow for simple info requests.
void default_start_node()
Exports the memory config spaces that are typically used for a complex node.
std::unique_ptr< GCAdapterBase > gcAdapter_
Bridge between canHub_ and gcHub_. Lazily initialized.
If * iface_
The OpenLCB interface object. Owned by ifaceHolder_;.
ConfigUpdateFlow configUpdateFlow_
Calls the config listeners with the configuration FD.
void loop_executor(bool delay_start=false)
Donates the current thread to the executor.
std::unique_ptr< PhysicalIf > ifaceHolder_
Pointer to the polymorphic implementation of the OpenLCB If.
DatagramService * dg_service()
void send_event(uint64_t event_id)
Helper function to send an event report to the bus.
Service service_
Default service on the particular executor.
void start_after_delay()
Call this function when you used delay_start upon starting the executor.
Executor< EXECUTOR_PRIORITIES > * executor()
std::unique_ptr< HubFlow > gcHub_
All packets are forwarded to this hub in gridconnect format, if needed.
int create_config_file_if_needed(const InternalConfigData &ofs, uint16_t expected_version, unsigned file_size)
Tries to open the config file; if not existant, the size too small, or the version number is mismatch...
void restart_stack()
Reinitializes the node.
Executor< EXECUTOR_PRIORITIES > executor_
This executor's threads will be handled.
virtual void start_iface(bool restart)=0
Hook for descendant classes to start the interface.
EventService eventService_
Dispatches event protocol requests to the event handlers.
virtual void start_node()=0
Hook for clients to initialize the node-specific components.
std::vector< std::unique_ptr< Destructable > > additionalComponents_
Stores and keeps ownership of optional components.
DatagramService * datagramService_
The datagram service bound to the interface object.
int check_version_and_factory_reset(const InternalConfigData &ofs, uint16_t expected_version, bool force=false)
Checks the version information in the EEPROM and performs a factory reset if incorrect or if force is...
static void factory_reset_all_events(const InternalConfigData &ofs, uint64_t node_id, int fd)
Overwrites all events in the eeprom with a brand new event ID.
void start_executor_thread(const char *name, int priority, size_t stack_size, bool delay_start=false)
Instructs the executor to create a new thread and run in there.
SimpleInfoFlow * info_flow()
Accessor for clients that have their custom SNIP-like handler.
void start_stack(bool delay_start)
Call this function once after the actual IO ports are set up.
virtual uint64_t get_pip()
Get the PIP response value.
InitializeFlow initFlow_
The initialization flow takes care for node startup duties.
void send_message_to(Defs::MTI mti, NodeHandle dst, const string &payload=EMPTY_PAYLOAD)
Sends an addressed message to the bus.
MemoryConfigHandler * memory_config_handler()
static void set_event_offsets(const vector< uint16_t > *offsets)
Call this function at the beginning of appl_main, just before {} or { create_config_file_if_needed} i...
TcpDatagramService datagramService_
Datagram service (and clients) matching the interface.
IfTcp ifTcp_
Implementation of OpenLCB interface.
HubFlow tcpHub_
This flow is the connection between the stack and the device drivers.
DatagramService * datagram_service() override
void start_iface(bool restart) override
Helper function for start_stack et al.
std::unique_ptr< PhysicalIf > create_if(const openlcb::NodeID node_id)
Constructor helper function.
HubFlow * tcp_hub()
This function is not safe to use.
void add_tcp_port_select(int fd, Notifiable *on_error=nullptr)
Adds a new link to the TCP interface.
SNIPHandler snipHandler_
Handles SNIP requests.
uint64_t get_pip() override
Get the PIP response value.
DefaultNode node_
The actual node.
void start_node() override
Hook for clients to initialize the node-specific components.
ProtocolIdentificationHandler pipHandler_
Handles PIP requests.
CAN-based stack with TrainNode.
ProtocolIdentificationHandler pipHandler_
Handles PIP requests.
TrainNodeWithId trainNode_
The actual node.
void start_node() override
Hook for clients to initialize the node-specific components.
SNIPHandler snipHandler_
Handles SNIP requests.
uint64_t get_pip() override
Get the PIP response value.
Implementation of the DatagramService on TCP transfer.
Abstract base class for train implementations.
Train node class with a fixed OpenLCB Node ID.
Collection of control flows necessary for implementing the Traction Protocol.
#define HASSERT(x)
Checks that the value of expression x is true, else terminates the current process.
string EMPTY_PAYLOAD
A global class / variable for empty or not-yet-initialized payloads.
uint64_t NodeID
48-bit NMRAnet Node ID type
const char CDI_DATA[]
This symbol contains the embedded text of the CDI xml file.
Payload eventid_to_buffer(uint64_t eventid)
Converts an Event ID to a Payload suitable to be sent as an event report.
const char *const CONFIG_FILENAME
This symbol must be defined by the application to tell which file to open for the configuration liste...
const size_t CONFIG_FILE_SIZE
This symbol must be defined by the application.
#define MSEC_TO_NSEC(_msec)
Convert a millisecond value to a nanosecond value.
int ConnectSocket(const char *host, int port)
Connects a tcp socket to the specified remote host:port.
MTI
Known Message type indicators.
Container of both a NodeID and NodeAlias.