VLCB SDK
An opinionated SDK for VLCB protocol
Loading...
Searching...
No Matches
module.c
Go to the documentation of this file.
1#include "./module.h"
2
3#include <assert.h>
4#include <time.h>
5
6#include "param.h"
7#include "state_machine.h"
9#include "vlcb/module.h"
10#include "vlcb/module/param.h"
11#include "vlcb/module/state.h"
14#include "vlcb/net/socket.h"
17#include "vlcb/platform/log.h"
18#include "vlcb/platform/time.h"
19
20#ifndef VLCB_MODULE_HEARTBEAT_MS
21#define VLCB_MODULE_HEARTBEAT_MS 5000
22#endif /* ifndef VLCB_MODULE_HEARTBEAT_MS */
23
24static inline void HandleHeartbeat(VlcbModule *const self, const clock_t now) {
25 // send heartbeat if module is in normal mode, heartbeat is enabled and
26 // heartbeat timeout passed (or if it's the first heartbeat) heartbeatSequence
27 // increments, until it overflows, which is expected
28 if (self->sm.state == VLCB_MODULE_STATE_NORMAL &&
30 (self->lastHeartbeat == 0 ||
34 vlcb_net_pkt_dgram_module_Heartbeat_Serialize(
35 &packet, (VlcbNetDgramHeartbeat){
36 .nodeNumber = self->config.nodeNumber,
37 .sequence = self->heartbeatSequence,
38 .status = 0, // TODO: replace with diagnostic status
39 .statusBits = 0});
40
42 vlcb_net_sock_dgram_Send(self->socket, &packet);
43 // we can ignore misseed heartbeats due to socket buffer being full
47 }
48 return; // ensure that when socket errors out, we don't update heartbeat
49 // stats
50 }
51
52 self->lastHeartbeat = now;
53 self->heartbeatSequence++;
54 }
55}
56
57static inline void HandleQueryNodeParameters(VlcbModule *const self) {
58 // RQNP, targets only modules in Setup mode
59 if (self->sm.state == VLCB_MODULE_STATE_SETUP) {
60 VlcbNetPacketDatagram response;
61 const VlcbModuleParams *const params = self->params;
62 vlcb_net_pkt_dgram_module_NodeParams_Serialize(
63 &response,
64 (VlcbNetDgramNodeParams){
65 .manuId = ModuleParamGetByte(params,
67 .moduleType =
69 .majorVersion =
71 .minorVersion =
73 .eventCount =
75 .eventVariableCount = ModuleParamGetByte(
77 .nodeVariableCount = ModuleParamGetByte(
80 vlcb_net_sock_dgram_Send(self->socket, &response);
84 } else {
86 }
87 return; // at the moment we don't do anything, just drop the packet
88 }
89 }
90}
91
92static inline void
94 const VlcbNetPacketDatagram *const packet) {
95 // RQNPN, index 0 should return number of available params, followed by each
96 // param as a separate packet
97}
98
99static inline void
101 const VlcbNetPacketDatagram *const packet) {
102 // SNN - set only in response to RQNN by the setup tool, only to node in setup
103 // mode
104 if (self->sm.state == VLCB_MODULE_STATE_SETUP) {
105 }
106}
107
108static inline void AbortSetup(VlcbModule *const self, clock_t now) {
109 // Abort setup mode, if another mode entered setup (MNS Spec 3.2.1)
110 if (self->sm.state == VLCB_MODULE_STATE_SETUP) {
111 state_Dispatch(self, (ModuleStateEvent){.sig = MSE_ABORT_SETUP}, now);
112 }
113}
114
115static inline void HandleQueryNodeInfo(VlcbModule *const self) {
116 // QNN - only initialized modules should respond
117 if (self->sm.state == VLCB_MODULE_STATE_NORMAL) {
118 }
119}
120
121static inline void HandleQueryModuleName(VlcbModule *const self) {
122 // only respond in setup node or if node is in normal mode and the learn flag
123 // is set
124 if (self->sm.state == VLCB_MODULE_STATE_SETUP ||
128 VlcbNetPacketDatagram response;
129
130 // 11 - request for node module name, excluding "CAN" prefix
131 // sent during module transition, so no node number check
132 // DEBUG_SERIAL << F("> RQMN received") << endl;
133
134 // only respond if in transition to Normal, i.e. Setup mode, or in learn
135 // mode.
136
137 // if (instantMode == MODE_SETUP ||
138 // (controller->getParam(PAR_FLAGS) & PF_LRN)) {
139 // // respond with NAME
140 // VlcbMessage response;
141 // response.len = 8;
142 // response.data[0] = OPC_NAME;
143 // memcpy(response.data + 1, controller->getModuleName(), 7);
144 // controller->sendMessage(&response);
145 // }
146 // request for module name, sent during transition to normal or during learn
147 // mode
148 }
149}
150
151static inline void
153 const VlcbNetPacketDatagram *const packet) {
154 if (packet->opc == VLCB_OPC_RESTART_ALL_NODES) {
155 self->restart();
156 return;
157 }
158
159 VlcbNetDgramRestartNode request =
160 vlcb_net_pkt_dgram_module_RestartNode_Deserialize(packet);
161 if (self->config.nodeNumber == request.nodeNumber) {
162 self->restart();
163 }
164}
165
166static inline void HandleMnsMessages(VlcbModule *const self,
167 const VlcbNetPacketDatagram *const packet,
168 clock_t now) {
169 switch (packet->opc) {
172 break;
175 break;
177 HandleSetNodeNumber(self, packet);
178 break;
180 AbortSetup(self, now);
181 break;
184 break;
187 break;
188
189 // case OPC_RQSD:
190 // 78 - Request Service Definitions.
191 // handleRequestServiceDefinitions(msg, nn);
192 break;
193
194 // case OPC_RDGN:
195 // 87 - Request Diagnostic Data
196 // handleRequestDiagnostics(msg, nn);
197 break;
198
199 // case OPC_MODE:
200 // 76 - Set Operating Mode
201 // handleModeMessage(msg, nn);
202 break;
203
204 // case OPC_NNRSM:
205 // 4F - reset to manufacturer's defaults
206 // if (nn == module_config->nodeNum) {
207 // controller->sendMessageWithNN(OPC_NNREL); // release node number first
208 // module_config->resetModule();
209 // }
210 break;
211
214 HandleRebootRequest(self, packet);
215 break;
216 }
217}
218
219VlcbModule vlcb_module_New(const char *const name, VlcbNetIface *const iface,
220 VlcbNetSocketDatagram *const socket,
221 const IVlcbModuleUi ui,
222 VlcbModuleParams *const params,
223 RestartRequestHandler restartHandler) {
224 assert(iface != NULL && socket != NULL && params != NULL &&
225 restartHandler != NULL && name != NULL);
226
227 return (VlcbModule){.name = name,
228 .iface = iface,
229 .socket = socket,
230 .params = params,
231 .ui = ui,
232 .config =
233 {
234 .operationFlags = 0,
236 .hwAddr = 0,
237 .nodeNumber = VLCB_NODE_NUMBER_UNINITIALIZED,
238 },
239 .restart = restartHandler};
240}
241
242void vlcb_module_Init(VlcbModule *const module, const clock_t now) {
243 assert(module != NULL);
244 // todo: load config from persistent storage
245 state_Dispatch(module, (ModuleStateEvent){.sig = MSE_INIT}, now);
246 _INTERFACE_CALL(module->ui, Poll, now);
247}
248
249void vlcb_module_Poll(VlcbModule *const module, const clock_t now) {
250 assert(module != NULL && module->iface != NULL);
251
253
254 while (1) {
255 const VlcbNetSocketDgramRecvErr err =
256 vlcb_net_sock_dgram_Recv(module->socket, &packet);
259 break; // nothing to receive
260 }
261 }
262 HandleMnsMessages(module, &packet, now);
263
264 if (module->sm.state == VLCB_MODULE_STATE_NORMAL) {
265 // TODO: handle services
266 }
267 }
268
269 HandleHeartbeat(module, now);
270
271 _INTERFACE_CALL(module->ui, Poll, now);
272}
@ VLCB_MODULE_PARAM_NODE_VARIABLE_COUNT
@ VLCB_MODULE_PARAM_MINOR_VERSION
@ VLCB_MODULE_PARAM_MAX_EVENT_COUNT
@ VLCB_MODULE_PARAM_MAJOR_VERSION
@ VLCB_MODULE_PARAM_EVENT_VARIABLE_COUNT
@ VLCB_MODULE_PARAM_MODULE_MANUFACTURER
#define _INTERFACE_CALL(o, m,...)
Definition interface.h:29
#define VLCBLOG_ERROR(msg)
Definition log.h:31
#define VLCBLOG_INFO(msg)
Definition log.h:30
@ VLCB_MODULE_FLAGS_HEARTBEAT
void(* RestartRequestHandler)(void)
static void HandleQueryNodeParameters(VlcbModule *const self)
Definition module.c:57
void vlcb_module_Init(VlcbModule *const module, const clock_t now)
Definition module.c:242
static void HandleMnsMessages(VlcbModule *const self, const VlcbNetPacketDatagram *const packet, clock_t now)
Definition module.c:166
static void HandleRebootRequest(VlcbModule *const self, const VlcbNetPacketDatagram *const packet)
Definition module.c:152
#define VLCB_MODULE_HEARTBEAT_MS
Definition module.c:21
static void HandleHeartbeat(VlcbModule *const self, const clock_t now)
Definition module.c:24
static void HandleQueryNodeInfo(VlcbModule *const self)
Definition module.c:115
void vlcb_module_Poll(VlcbModule *const module, const clock_t now)
Definition module.c:249
static void AbortSetup(VlcbModule *const self, clock_t now)
Definition module.c:108
static void HandleQueryModuleName(VlcbModule *const self)
Definition module.c:121
static void HandleQueryNodeParameterByIndex(VlcbModule *const self, const VlcbNetPacketDatagram *const packet)
Definition module.c:93
static void HandleSetNodeNumber(VlcbModule *const self, const VlcbNetPacketDatagram *const packet)
Definition module.c:100
VlcbModule vlcb_module_New(const char *const name, VlcbNetIface *const iface, VlcbNetSocketDatagram *const socket, const IVlcbModuleUi ui, VlcbModuleParams *const params, RestartRequestHandler restartHandler)
Definition module.c:219
#define VLCB_NODE_NUMBER_UNINITIALIZED
Definition node.h:10
VlcbModuleParam ModuleParamGetByte(const VlcbModuleParams *const params, const VlcbModuleParam param)
Definition param.c:12
VlcbNetSocketDgramRecvErr vlcb_net_sock_dgram_Recv(VlcbNetSocketDatagram *const sock, VlcbNetPacketDatagram *const packet)
VlcbNetSocketDgramSendErr
@ VLCB_NET_SOCK_DGRAM_SEND_ERR_OK
@ VLCB_NET_SOCK_DGRAM_SEND_ERR_BUF_FULL
vlcb_error vlcb_net_sock_dgram_SendErrToStr(VlcbNetSocketDgramSendErr err)
VlcbNetSocketDgramSendErr vlcb_net_sock_dgram_Send(VlcbNetSocketDatagram *const sock, const VlcbNetPacketDatagram *const packet)
VlcbNetSocketDgramRecvErr
@ VLCB_NET_SOCK_DGRAM_RECV_ERR_WOULD_BLOCK
@ VLCB_NET_SOCK_DGRAM_RECV_ERR_OK
@ VLCB_MODULE_STATE_SETUP
Definition state.h:11
@ VLCB_MODULE_STATE_UNINITIALIZED
Definition state.h:10
@ VLCB_MODULE_STATE_NORMAL
Definition state.h:12
void state_Dispatch(VlcbModule *const self, const ModuleStateEvent e, const clock_t now)
@ MSE_ABORT_SETUP
@ MSE_INIT
VlcbModuleOpFlags operationFlags
VlcbModuleState state
Definition state.h:26
VlcbModuleStateMachine sm
RestartRequestHandler restart
VlcbNetIface *const iface
VlcbModuleParams *const params
VlcbModuleConfig config
VlcbNetSocketDatagram *const socket
static double vlcb_platform_time_DiffInMs(const clock_t start, const clock_t end)
Definition time.h:10
@ VLCB_OPC_QUERY_MODULE_INFO
Definition vlcb_defs.h:607
@ VLCB_OPC_QUERY_MODULE_PARAMETERS
Definition vlcb_defs.h:616
@ VLCB_OPC_REQUEST_NEW_NODE_NUMBER
Definition vlcb_defs.h:803
@ VLCB_OPC_RESTART_ALL_NODES
Definition vlcb_defs.h:565
@ VLCB_OPC_QUERY_NODE_PARAMETER_BY_INDEX
Definition vlcb_defs.h:1014
@ VLCB_OPC_SET_NODE_NUMBER
Definition vlcb_defs.h:699
@ VLCB_OPC_RESTART_NODE
Definition vlcb_defs.h:929
@ VLCB_OPC_QUERY_MODULE_NAME
Definition vlcb_defs.h:626