40#if defined(__linux__) || defined(__MACH__)
53#include "openlcb/NodeInitializeFlow.hxx"
57#include "utils/HubDeviceSelect.hxx"
63SimpleStackBase::SimpleStackBase(
64 std::function<std::unique_ptr<SimpleStackBase::PhysicalIf>()>
66 : ifaceHolder_(create_if_helper())
94 , node_(iface(), node_id, false)
99 : SimpleTcpStackBase(node_id)
100 , node_(iface(), node_id, false)
116#if OPENMRN_HAVE_POSIX_FD
137 memoryConfigHandler_.registry()->
insert(
152 memoryConfigHandler_.registry()->
insert(
156#if OPENMRN_HAVE_POSIX_FD
167 memoryConfigHandler_.registry()->
insert(
176 reinterpret_cast<const uint8_t *
>(&
CDI_DATA), cdi_size + 1);
177 memoryConfigHandler_.registry()->
insert(
181#if OPENMRN_HAVE_POSIX_FD
199 , trainNode_(&tractionService_, train, node_id)
200 , fdiBlock_(reinterpret_cast<const uint8_t *>(fdi_xml), strlen(fdi_xml))
207 memoryConfigHandler_.registry()->
insert(
251 uint16_t expected_version,
unsigned file_size)
268 printf(
"Failed to create config file: fd %d errno %d: %s\n", fd,
269 errno, strerror(errno));
276 HASSERT(fstat(fd, &statbuf) == 0);
277 if (statbuf.st_size < (ssize_t)file_size)
284 if ((
long)statbuf.st_size < (
long)cfg.version().end_offset())
286 LOG(
VERBOSE,
"%s is too short (%d vs %d), forcing reset.",
290 if (!reset && cfg.version().read(fd) != expected_version)
292 uint16_t current_version = cfg.version().read(fd);
293 if (current_version != expected_version)
295 LOG(
VERBOSE,
"config version mismatch (%d vs %d), forcing reset.",
296 current_version, expected_version);
300 if (!reset && !extend)
306 if (extend && !reset)
308 auto ret = lseek(fd, statbuf.st_size, SEEK_SET);
309 HASSERT(ret == statbuf.st_size);
310 file_size -= statbuf.st_size;
312 else if (statbuf.st_size >= 128)
314 auto ret = lseek(fd, 128, SEEK_SET);
320 lseek(fd, 0, SEEK_SET);
323 static const unsigned bufsize = 128;
324 char *buf = (
char *)malloc(bufsize);
326 memset(buf, 0xff, bufsize);
327 unsigned len = file_size;
330 ssize_t c = write(fd, buf, std::min(len, bufsize));
337 cfg.version().write(fd, expected_version);
338 cfg.next_event().write(fd, 0);
350 const InternalConfigData &cfg, uint16_t expected_version,
bool force)
359 if (cfg.version().read(fd) != expected_version)
364 cfg.next_event().write(fd, 0);
376 cfg.version().write(fd, expected_version);
391 cdi_event_offsets_ptr = &(*offsets)[0];
395 const InternalConfigData &cfg, uint64_t node_id,
int fd)
398 uint16_t new_next_event = cfg.next_event().read(fd);
399 uint16_t next_event = new_next_event;
400 for (
unsigned i = 0; cdi_event_offsets_ptr[i]; ++i)
405 cfg.next_event().write(fd, new_next_event);
407 for (
unsigned i = 0; cdi_event_offsets_ptr[i]; ++i)
409 EventId
id = node_id;
419 int fd = ::open(path, O_RDWR);
421 LOG(
INFO,
"Adding device %s as fd %d", path, fd);
425#if defined(__linux__) || defined(__MACH__)
426void SimpleCanStackBase::add_gridconnect_tty(
429 int fd = ::open(device, O_RDWR);
431 LOG(
INFO,
"Adding device %s as fd %d", device, fd);
434 HASSERT(!tcflush(fd, TCIOFLUSH));
435 struct termios settings;
436 HASSERT(!tcgetattr(fd, &settings));
437 cfmakeraw(&settings);
438 cfsetspeed(&settings, B115200);
439 HASSERT(!tcsetattr(fd, TCSANOW, &settings));
442#if defined(__linux__)
443void SimpleCanStackBase::add_socketcan_port_select(
444 const char *device,
int loopback)
446 int s = socketcan_open(device, loopback);
Pool * init_main_buffer_pool()
Initializes the main buffer pool.
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.
int bind(int socket, const struct sockaddr *address, socklen_t address_len)
Bind a name to a socket.
Base class of everything with a virtual destructor.
HubPort that connects a select-aware device to a strongly typed Hub.
An object that can schedule itself on an executor to run.
Pool of previously allocated, but currently unused, items.
void insert(Node *node, uint32_t id, Handler *handler)
Inserts a handler into the map.
void send(MessageType *msg, unsigned priority=UINT_MAX) OVERRIDE
Sends a message to the state flow for processing.
void reinit_seed()
Resets the alias allocator to the state it was at construction.
void clear()
Reinitializes the entire map.
int open_file(const char *path)
Must be called once (only) before calling anything else.
void init_flow()
Asynchronously invokes all update listeners with the config FD.
void factory_reset()
Synchronously invokes all update listeners to factory reset.
Implementation class for event ID configuration entries.
Memory space implementation that exports the contents of a file as a memory space.
AliasCache * local_aliases()
AliasAllocator * alias_allocator()
AliasCache * remote_aliases()
Node * next_local_node(NodeID previous)
Iterator helper on the local nodes map.
Handler for the stream read/write commands in the memory config protocol (server side).
Base class for NMRAnet nodes conforming to the asynchronous interface.
virtual void clear_initialized()=0
Callback from the simple stack when the node has to return to uninitialized state.
void initialize()
Callback from the simple stack to start the initialization process.
void write(int fd, TR d) const
Writes the data to the configuration file.
Memory space implementation that exports a some memory-mapped data as a read-only memory space.
StateFlow that iterates through all local nodes and sends out node initialization complete for each o...
SimpleStack with a CAN-bus based interface and IO functions for CAN-bus.
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 start_iface(bool restart) override
Helper function for start_stack et al.
void default_start_node()
Exports the memory config spaces that are typically used for a complex node.
ConfigUpdateFlow configUpdateFlow_
Calls the config listeners with the configuration FD.
void start_after_delay()
Call this function when you used delay_start upon starting the executor.
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.
virtual void start_iface(bool restart)=0
Hook for descendant classes to start the interface.
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.
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_stack(bool delay_start)
Call this function once after the actual IO ports are set up.
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...
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.
TrainNodeWithId trainNode_
The actual node.
void start_node() override
Hook for clients to initialize the node-specific components.
SimpleTrainCanStack(openlcb::TrainImpl *train, const char *fdi_xml, NodeID node_id)
Creates a train node OpenLCB stack.
CAN-specific implementation of the stream transport interface.
Abstract base class for train implementations.
#define CONSTANT_TRUE
We cannot compare constants to zero, so we use 1 and 2 as constant values for booleans.
#define LOG(level, message...)
Conditionally write a message to the logging output.
static const int VERBOSE
Loglevel that is usually not printed, reporting debugging information.
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 DIE(MSG)
Unconditionally terminates the current process with a message.
NumericConfigEntry< uint8_t > Uint8ConfigEntry
Unsigned numeric config entry with 1 byte width.
const SimpleNodeStaticValues SNIP_STATIC_DATA
This static data will be exported as the first block of SNIP.
uint64_t NodeID
48-bit NMRAnet Node ID type
const char CDI_DATA[]
This symbol contains the embedded text of the CDI xml file.
const uint16_t CDI_EVENT_OFFSETS[]
Contains an array describing each position in the Configuration space that is occupied by an Event ID...
const char *const SNIP_DYNAMIC_FILENAME
The SNIP dynamic data will be read from this file.
Pool *const g_incoming_datagram_allocator
Allocator to be used for Buffer<IncomingDatagram> objects.
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.
@ SPACE_FDI
read-only for function definition XML
@ SPACE_ALL_MEMORY
all memory space
@ SPACE_ACDI_USR
read-write ACDI space
@ SPACE_CONFIG
config memory space
@ SPACE_ACDI_SYS
read-only ACDI space
Structure representing the layout of the memory space for Simple Node Identification user-editable da...