11enum class NMT : uint8_t {
38 .data =
cmd |
ix << 8 |
sub << 24 | (uint64_t)
data << 32,
39 .
id = (uint32_t)0x600 +
nodeID,
40 .opts = { .rtr = 0, .ide = 0, .dlc = 8},
43 static SDO fromMessage(Message msg) {
45 .
data = (uint32_t)(msg.data >> 32),
46 .ix = (uint16_t)(msg.data >> 8),
47 .sub = (uint8_t)(msg.data >> 24),
48 .cmd = (uint8_t)msg.data,
49 .nodeID = (uint8_t)(msg.id % 0x80),
72 Message toMessage()
const {
76 data |= (i.data & (((uint64_t)1 << i.len)-1)) << shift;
79 return {.data=data, .id =
COB, .opts = {.dlc=(uint8_t)(shift / 8)}};
89 void receive(uint64_t d) {
92 i.data = d >> shift & (((uint64_t)1 << i.len) - 1);
109 enum LOGLEVEL { NONE, WARN, INFO} log;
110 Dispatch(CAN &can, LOGLEVEL=NONE) : can(can) { }
121 can.trypush({.data = (uint64_t)(nodeid & 0x7f) << 8 | (uint8_t)command,
122 .
id = 0, .opts = {.dlc = 2}});
126 can.trypush({.id = 0x80, .opts = {.dlc = 0}});
130 can.trypush({.data = (uint8_t)state, .
id = (uint32_t)0x700 + id, .opts = {.dlc = 1}});
134 can.trypush({.id = (uint32_t)0x700 +
id, .opts = {.rtr =
true}});
139 while (!can.empty()) {
140 auto msg = can.pop();
141 if (handlePDO(msg))
continue;
142 if (handleSDO(msg))
continue;
144 if (log > NONE) k.log.warn(
"unhandled: [id: %x] [%02x %02x %02x %02x %02x %02x %02x %02x]\n",
147 (uint8_t)(msg.data>>8),
148 (uint8_t)(msg.data>>16),
149 (uint8_t)(msg.data>>24),
150 (uint8_t)(msg.data>>32),
151 (uint8_t)(msg.data>>40),
152 (uint8_t)(msg.data>>48),
153 (uint8_t)(msg.data>>56)
162 void push(
SDO &&rq)
override {
164 if (ids[rq.nodeID] ==
nullptr) {
165 if (log > NONE) k.log.warn(
"ID [0x%x] NOT registered!\n", rq.nodeID);
168 can.push(rq.toMessage());
170 using Sink<Message>::push;
171 void push(Message &&rq)
override { can.push(rq); }
173 void registerSDO(uint16_t nodeID,
Sink<SDO> *dev) {
175 assert(ids[nodeID] ==
nullptr);
178 void registerPDO(TPDO *tpdo,
Sink<TPDO> *dev) {
179 for (uint8_t i = 0; i < pdo.n; i++) {
180 if (pdo.pdo[i] == tpdo) {
181 assert(pdo.dev[i] == dev);
185 assert ( pdo.n < 8 );
186 pdo.dev[pdo.n] = dev;
187 pdo.pdo[pdo.n] = tpdo;
191 bool handlePDO(Message msg) {
192 for (
int i = 0; i < pdo.n; ++i) {
193 auto tpdo = pdo.pdo[i];
194 if (tpdo->COB == msg.id
196 tpdo->receive(msg.data);
197 pdo.dev[i]->push(*tpdo);
199 k.log.info(
"handled PDO id: %x\n", msg.id);
200 k.log.info(
" data: %x\n", msg.data);
201 k.log.info(
" TPDO data0: %x\n",tpdo->map[0].data);
202 k.log.info(
" TPDO data1: %x\n",tpdo->map[1].data);
209 bool handleSDO(Message msg) {
210 uint16_t service = msg.id & ~0x7f;
211 uint8_t
id = msg.id & 0x7f;
212 if (
id == 0)
return false;
219 ids[id]->
push(SDO::fromMessage(msg));
221 if (log > WARN) k.log.info(
"handled SDO id: %x\n", msg.id);
236 assert(
id > 0 &&
id < 128);
237 canopen.registerSDO(
id,
this);
251 void read(uint16_t ix, uint8_t sub) {
252 pushorqueue({.ix=ix, .sub=sub, .cmd=0x40, .nodeID=
id});
255 void w8(uint16_t ix, uint8_t sub, uint8_t val) {
256 pushorqueue({.data=(uint32_t)val, .ix=ix, .sub=sub, .cmd=0x2f, .nodeID=
id});
259 void w16(uint16_t ix, uint8_t sub, uint16_t val) {
260 pushorqueue({.data=(uint32_t)val, .ix=ix, .sub=sub, .cmd=0x2b, .nodeID=
id});
263 void w32(uint16_t ix, uint8_t sub, uint32_t val) {
264 pushorqueue({.data=(uint32_t)val, .ix=ix, .sub=sub, .cmd=0x23, .nodeID=
id});
272 if (pdo.
COB == 0) pdo.
COB =
id + 0x100 * (pdo.
N+1);
274 w8(0x1400+pdo.
N-1, 0x2, pdo.
type);
275 w8(0x1600+pdo.
N-1, 0x0, 0);
276 for (
size_t i = 0; i < pdo.
map.len; ++i) {
277 auto &d = pdo.
map[i];
278 w32(0x1600+pdo.
N-1, i+1, d.ix << 16 | d.sub << 8 | d.len);
280 w8(0x1600+pdo.
N-1, 0x0, pdo.
map.len);
281 w32(0x1400+pdo.
N-1, 0x1, 1<<30 | pdo.
COB);
285 w32(0x1400+pdo.
N-1, 0x1, 1<<31);
289 if (pdo.
COB == 0) pdo.
COB =
id + 0x80 + 0x100 * pdo.
N;
291 w8(0x1800+pdo.
N-1, 0x2, pdo.
type);
294 w8(0x1a00+pdo.
N-1, 0x0, 0);
295 for (
size_t i = 0; i < pdo.
map.len; ++i) {
296 auto &d = pdo.
map[i];
297 w32(0x1a00+pdo.
N-1, i+1, d.ix << 16 | d.sub << 8 | d.len);
299 w8(0x1a00+pdo.
N-1, 0x0, pdo.
map.len);
300 w32(0x1800+pdo.
N-1, 0x1, 1<<30 | pdo.
COB);
301 out.registerPDO(&pdo,
this);
305 w32(0x1800+pdo.
N-1, 0x1, 1<<31);
311 void push(
SDO &&sdo)
override {
316 using Sink<TPDO>::push;
317 void push(TPDO &&pdo)
override {
322 if (state.q.empty())
return;
323 if (state.next.when && !state.next(k.
time))
return;
324 out.push(state.q.pop());
325 state.next = {k.
time + 2};
327 void pushorqueue(SDO &&sdo) {
328 if (state.next.when && !state.next(k.
time)) {
329 state.q.trypush(std::move(sdo));
331 (*(
Sink<SDO>*)&out).trypush(std::move(sdo));
332 state.next = {k.
time + 2};
const uint32_t & time
const access to global uptime
Definition kern.h:30
simple Buffer backed queue implementation
Definition queue.h:12
int32_t data
received data // data to send
Definition canopen.h:58
STATE
CANOpen Device states.
Definition canopen.h:19
@ OPERATIONAL
OPERATIONAL.
uint8_t sub
subindex of Data Object
Definition canopen.h:56
uint16_t ix
index of Data Object
Definition canopen.h:55
uint8_t len
length of object [bits] {8, 16, 32}
Definition canopen.h:57
PDOType
Type of PDO transmission.
Definition canopen.h:61
@ SYNC
synchronous == on every NMT SYNC message
Definition canopen.h:62
@ CYCLIC
cyclic == after inhibit_time
Definition canopen.h:63
@ CHANGE
change == ASAP on change of parameters
Definition canopen.h:64
NMT
CANOpen Network ManagemenT Commands.
Definition canopen.h:11
@ START
enter OPERATIONAL 0x5
Single Entry in PDO Data List.
Definition canopen.h:54
dynamically allocated, but fixed-size buffer template
Definition buffer.h:18
CANOpen device wrapper class.
Definition canopen.h:232
void read(uint16_t ix, uint8_t sub)
read DO with given index and subindex of this device
Definition canopen.h:251
void disablePDO(TPDO &pdo)
disable sending PDO on device
Definition canopen.h:304
void wPDO(const RPDO &rpdo)
send PDO
Definition canopen.h:267
void enablePDO(TPDO &pdo)
enable sending PDO on device
Definition canopen.h:288
void w16(uint16_t ix, uint8_t sub, uint16_t val)
write given value to DO at given index and subindex
Definition canopen.h:259
virtual void callback(TPDO rq)
implement the callback method to handle incoming data
Definition canopen.h:249
void w8(uint16_t ix, uint8_t sub, uint8_t val)
write given value to DO at given index and subindex
Definition canopen.h:255
bool full() override
check if sink is full
Definition canopen.h:307
Device(Dispatch &canopen, uint8_t id)
Construct new CANOpen Device on network with given ID.
Definition canopen.h:234
void w32(uint16_t ix, uint8_t sub, uint32_t val)
write given value to DO at given index and subindex
Definition canopen.h:263
void disablePDO(RPDO &pdo)
disable receiving PDO on device
Definition canopen.h:284
virtual void callback(SDO rq)
implement the callback method to handle incoming data
Definition canopen.h:247
void enablePDO(RPDO &pdo)
enable receiving PDO on device
Definition canopen.h:271
uint8_t const id
CANOpen node ID [1 - 127].
Definition canopen.h:239
CANOpen dispatch class.
Definition canopen.h:108
void heartbeat(uint8_t id, STATE state)
send HEARTBEAT message to node id, signal own state
Definition canopen.h:129
void nmt(NMT command, uint8_t nodeid)
send NMT command to nodeid, rsp broadcast it (id = 0)
Definition canopen.h:120
void sync()
send SYNC message on network
Definition canopen.h:125
bool full() override
check if sink is full
Definition canopen.h:158
void guard(uint8_t id)
send GUARD message to node id
Definition canopen.h:133
void process()
call directly after CAN interrupt handler processed
Definition canopen.h:137
CANOpen Receive Process Data Object Type.
Definition canopen.h:67
uint32_t COB
CAN OBject ID – leave empty for defaults.
Definition canopen.h:70
uint8_t N
Index of PDO [1 .. x].
Definition canopen.h:68
PDOType type
reception type
Definition canopen.h:69
Buffer< PDOMap > map
PDO Data Map.
Definition canopen.h:71
CANOpen Service Data Object xfer request.
Definition canopen.h:29
uint16_t ix
index of DO
Definition canopen.h:31
uint8_t cmd
type of request
Definition canopen.h:33
uint8_t sub
subindex of DO
Definition canopen.h:32
uint8_t nodeID
node ID of device
Definition canopen.h:34
uint32_t data
up to 4 bytes of data
Definition canopen.h:30
CANOpen Transmit Process Data Object Type.
Definition canopen.h:83
uint8_t N
Index of PDO [1 .. x].
Definition canopen.h:84
uint32_t COB
CAN OBject ID – leave empty for defaults.
Definition canopen.h:86
uint32_t inhibit_time
inhibit time in 0.1ms steps
Definition canopen.h:87
Buffer< PDOMap > map
PDO Data Map.
Definition canopen.h:88
PDOType type
transmission type
Definition canopen.h:85
simple solution for keeping track of timeouts
Definition deadline.h:15
generic object sink, i.e.
Definition streams.h:15
virtual void push(const T &t)
copy semantics does not check for space. guard by using 'if (!full) { ... }'
Definition streams.h:20