Open Model Railroad Network (OpenMRN)
Loading...
Searching...
No Matches
DirectHubLegacy.cxx
Go to the documentation of this file.
1
35#include "utils/DirectHub.hxx"
36#include "utils/Hub.hxx"
37#include "utils/gc_format.h"
38
40
43class HubToGcPort : public CanHubPort, public DirectHubPort<uint8_t[]>
44{
45public:
46 HubToGcPort(DirectHubInterface<uint8_t[]> *gc_hub, CanHubFlow *can_hub)
47 : CanHubPort(gc_hub->get_service())
48 , targetHub_(gc_hub)
49 , sourceHub_(can_hub)
50 {
53 }
54
56 {
59 }
60
62 Action entry() override
63 {
64 // Allocates output buffer if needed.
65 if (buf_.free() < MIN_GC_FREE)
66 {
67 // Need more output buffer.
68 DataBuffer *b;
71 }
72 // Generates gridconnect message and commits to buffer.
73 char *start = (char *)buf_.data_write_pointer();
74 char *end = gc_format_generate(message()->data(), start, 0);
75 packetSize_ = end - start;
78 release();
79 // Sends off output message.
81 inlineRun_ = true;
82 inlineComplete_ = false;
84 inlineRun_ = false;
86 {
87 return exit();
88 }
89 else
90 {
91 return wait();
92 }
93 }
94
98 {
99 auto *m = targetHub_->mutable_message();
100 m->buf_ = buf_.transfer_head(packetSize_);
101 m->source_ = (DirectHubPort<uint8_t[]> *)this;
102 m->done_ = pktDone_;
104 if (inlineRun_)
105 {
106 inlineComplete_ = true;
107 return wait();
108 }
109 else
110 {
111 return exit();
112 }
113 }
114
117 void send(MessageAccessor<uint8_t[]> *msg) override
118 {
119 auto &buf = msg->buf_;
120 uint8_t *p;
121 unsigned available;
122 buf.head()->get_read_pointer(buf.skip(), &p, &available);
123 if (buf.size() == 0 || *p != ':')
124 {
125 // Not a gridconnect packet. Do not do anything.
126 return;
127 }
128 Buffer<CanHubData> *can_buf = sourceHub_->alloc();
129 if (msg->done_)
130 {
131 can_buf->set_done(msg->done_->new_child());
132 }
133 can_buf->data()->skipMember_ = (CanHubPort *)this;
134 const char *text_packet = nullptr;
135 string assembled_packet;
136 if (available == buf.size())
137 {
138 // One block of data. Convert in place.
139 text_packet = (const char *)p;
140 }
141 else
142 {
143 buf.append_to(&assembled_packet);
144 text_packet = assembled_packet.c_str();
145 }
146 if (gc_format_parse(text_packet, can_buf->data()) < 0)
147 {
148 string debug(text_packet, buf.size());
149 LOG(INFO, "Failed to parse gridconnect packet: '%s'",
150 debug.c_str());
151 can_buf->unref();
152 return;
153 }
155 sourceHub_->send(can_buf, 0);
156 }
157
158private:
172 bool inlineRun_ : 1;
176 uint16_t packetSize_;
179 static constexpr unsigned MIN_GC_FREE = 29;
180};
181
183 DirectHubInterface<uint8_t[]> *gc_hub, CanHubFlow *can_hub)
184{
185
186 return new HubToGcPort(gc_hub, can_hub);
187}
Destructable * create_gc_to_legacy_can_bridge(DirectHubInterface< uint8_t[]> *gc_hub, CanHubFlow *can_hub)
Creates a bridge between a gridconnect-based DirectHub and an old style CAN hub flow.
DataBufferPool g_direct_hub_kbyte_pool(1024)
This object forwards allocations to mainBufferPool.
StateFlow< Buffer< CanHubData >, QList< 1 > > CanHubPort
Base class for a port to an CAN hub that is implemented as a stateflow.
Definition Hub.hxx:143
#define STATE(_fn)
Turns a function name into an argument to be supplied to functions expecting a state.
Definition StateFlow.hxx:61
A BarrierNotifiable allows to create a number of child Notifiable and wait for all of them to finish.
BarrierNotifiable * new_child()
Call this for each child task.
void set_done(BarrierNotifiable *done)
Specifies that a given BarrierNotifiable must be called when the Buffer is deallocated (unreffed to z...
Definition Buffer.hxx:97
Base class for all QMember types that hold data in an expandable format.
Definition Buffer.hxx:195
void unref()
Decrement count.
Definition Buffer.hxx:675
T * data()
get a pointer to the start of the data.
Definition Buffer.hxx:215
Proxy Pool that can allocate DataBuffer objects of a certain size.
void alloc(DataBuffer **result)
Get a free item out of the pool with untyped data of the size specified in the constructor.
Specialization of the Buffer class that is designed for storing untyped data arrays.
Base class of everything with a virtual destructor.
Interface for a the central part of a hub.
virtual MessageAccessor< T > * mutable_message()=0
Accessor to fill in the message payload.
virtual void register_port(DirectHubPort< T > *port)=0
Adds a port to this hub.
virtual void enqueue_send(Executable *caller)=0
Signals that the caller wants to send a message to the hub.
virtual void unregister_port(DirectHubPort< T > *port)=0
Synchronously removes a port from this hub.
virtual void do_send()=0
Sends a message to the hub.
Interface for a downstream port of a hub (aka a target to send data to).
MessageType * alloc()
Synchronously allocates a message buffer from the pool of this flow.
void register_port(port_type *port)
Adds a new port.
Definition Hub.hxx:167
void unregister_port(port_type *port)
Removes a previously added port.
Definition Hub.hxx:174
Empty class that can be used as a pointer for identifying where a piece of data came from.
Definition DirectHub.hxx:48
Bridge component that converts the outgoing CAN packets into gridconnect format and enqueues them int...
HubSource * me_
The source pointer we need to use for sending messages to the target hub.
BarrierNotifiable * pktDone_
Done notifiable from the source packet.
LinkedDataBufferPtr buf_
Output buffer of gridconnect bytes that will be sent to the GC DirectHub.
void send(MessageAccessor< uint8_t[]> *msg) override
GC to binary path.
bool inlineComplete_
True if the send completed inline.
CanHubFlow * sourceHub_
Hub where we get the input data from (registered).
Action do_send()
Handles the callback from the direct hub when it is ready for us to send the message.
uint16_t packetSize_
Number of bytes this gridconnect packet is.
DirectHubInterface< uint8_t[]> * targetHub_
Where to send the target data.
Action entry() override
Handles the next CAN packet that we need to send.
bool inlineRun_
True while we are calling the target hub send method.
static constexpr unsigned MIN_GC_FREE
Minimum amount of free bytes in the current send buffer in order to use it for gridconnect rendering.
A class that keeps ownership of a chain of linked DataBuffer references.
uint8_t * data_write_pointer()
LinkedDataBufferPtr transfer_head(size_t len)
Transfers the ownership of the prefix of this buffer.
void append_empty_buffer(DataBuffer *buf)
Adds an empty buffer to the end of this buffer chain.
void data_write_advance(size_t len)
Advances the tail pointer after a write occurred into the tail.
size_t free() const
Return type for a state flow callback.
Action wait()
Wait for an asynchronous call.
Action wait_and_call(Callback c)
Wait for resource to become available before proceeding to next state.
Action exit()
Terminates the processing of this flow.
State flow with a given typed input queue.
void release() OVERRIDE
Unrefs the current buffer.
void send(MessageType *msg, unsigned priority=UINT_MAX) OVERRIDE
Sends a message to the state flow for processing.
char * gc_format_generate(const struct can_frame *can_frame, char *buf, int double_format)
Formats a can frame in the GridConnect protocol.
int gc_format_parse(const char *buf, struct can_frame *can_frame)
Parses a GridConnect packet.
Definition gc_format.cxx:82
#define LOG(level, message...)
Conditionally write a message to the logging output.
Definition logging.h:99
static const int INFO
Loglevel that is printed by default, reporting some status information.
Definition logging.h:57
Typed message class.
Definition DirectHub.hxx:93