Dawn Framework 1.0
Universal data acquisition framework for embedded systems
can.cxx
1// dawn/src/proto/can/can.cxx
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5
6#include "can_internal.hxx"
7
8#include "dawn/common/poll_loop.hxx"
9#include "dawn/io/common.hxx"
10#include "dawn/porting/can.hxx"
11
12using namespace dawn;
13
14int CProtoCan::configureDesc(const CDescObject &desc)
15{
16 SObjectCfg::SObjectCfgItem *item = nullptr;
17 size_t offset = 0;
18
19 for (size_t i = 0; i < desc.getSize(); i++)
20 {
21 item = desc.objectCfgItemNext(offset);
22
24 {
25 DAWNERR("Unsupported CAN config 0x%08" PRIx32 "\n", item->cfgid.v);
26 return -EINVAL;
27 }
28
29 switch (item->cfgid.s.id)
30 {
32 {
33 for (size_t j = 0; j < item->cfgid.s.size;)
34 {
35 SProtoCanIOBind *tmp = reinterpret_cast<SProtoCanIOBind *>(item->data + j);
36
37 allocObject(tmp);
38
39 j += sizeof(SProtoCanIOBind) / 4 + tmp->size;
40 }
41
42 break;
43 }
44
46 {
47 devno = static_cast<uint32_t>(item->data[0]);
48 break;
49 }
50
52 {
53 nodeid = static_cast<uint32_t>(item->data[0]);
54 break;
55 }
56
57 default:
58 {
59 DAWNERR("Unsupported CAN config 0x%08" PRIx32 "\n", item->cfgid.v);
60 return -EINVAL;
61 }
62 }
63 }
64
65 return OK;
66}
67
68void CProtoCan::allocObject(SProtoCanIOBind *alloc)
69{
70 for (size_t i = 0; i < alloc->size; i++)
71 {
72 DAWNINFO("allocate object 0x%" PRIx32 "\n", alloc->objid[i]);
73 setObjectMapItem(alloc->objid[i], nullptr);
74 }
75
76 valloc.push_back(alloc);
77};
78
79void CProtoCan::thread()
80{
81 struct pollfd fds[1];
82 SPollLoopCallbacks callbacks;
83
84 DAWNINFO("start CAN thread\n");
85
86 std::memset(fds, 0, sizeof(fds));
87
88 fds[0].fd = fd;
89 fds[0].events = POLLIN;
90
91 callbacks.beforePoll = beforePoll;
92 callbacks.afterPoll = afterPoll;
93 callbacks.onPollReady = onPollReady;
94
95 CPollLoopRunner::run(workerThread(), fds, 1, DAWN_POLL_TIMEOUT_MS, callbacks, this);
96}
97
98int CProtoCan::beforePoll(void *priv, struct pollfd *pfds, nfds_t nfds)
99{
100 (void)priv;
101
102 if (pfds == nullptr || nfds == 0)
103 {
104 return -EINVAL;
105 }
106
107 pfds[0].revents = 0;
108 return OK;
109}
110
111void CProtoCan::afterPoll(void *priv, struct pollfd *pfds, nfds_t nfds, int ret)
112{
113 (void)priv;
114 (void)pfds;
115 (void)nfds;
116
117 if (ret < 0)
118 {
119 DAWNERR("CAN poll failed %d\n", -errno);
120 }
121}
122
123int CProtoCan::onPollReady(void *priv, struct pollfd *pfds, nfds_t nfds, int pollRet)
124{
125 CProtoCan *self;
127 int ret;
128
129 if (priv == nullptr || pfds == nullptr || nfds == 0 || pollRet <= 0)
130 {
131 return -EINVAL;
132 }
133
134 if ((pfds[0].revents & POLLIN) == 0)
135 {
136 return OK;
137 }
138
139 self = static_cast<CProtoCan *>(priv);
140
141 ret = can_read(self->fd, &msg);
142 if (ret > 0)
143 {
144 if (msg.error)
145 {
146 DAWNERR("CAN error frame id=0x%03" PRIx32 " len=%u\n",
147 static_cast<uint32_t>(msg.id),
148 static_cast<unsigned>(msg.len));
149 pfds[0].revents = 0;
150 return OK;
151 }
152
153 ret = self->msgRecv(msg);
154 if (ret < 0)
155 {
156 DAWNERR("Failed to handle msg %d\n", ret);
157 }
158 }
159
160 pfds[0].revents = 0;
161 return OK;
162}
163
164int CProtoCan::canInitialize()
165{
166 int ret;
167
168 if (devno == static_cast<uint32_t>(-1))
169 {
170 DAWNERR("Invalid CAN device number configuration\n");
171 return -EINVAL;
172 }
173
174 snprintf(path, sizeof(path), CAN_PATH_FMT, devno);
175
176 fd = can_open(path);
177 if (fd < 0)
178 {
179 DAWNERR("can_open failed %d\n", -errno);
180 return -errno;
181 }
182
183 ret = can_init(fd);
184 if (ret < 0)
185 {
186 DAWNERR("can_init failed %d\n", ret);
187 return ret;
188 }
189
190 return OK;
191}
192
193CProtoCan::~CProtoCan()
194{
195 deinit();
196}
197
199{
200 int ret;
201
202 ret = configureDesc(getDesc());
203 if (ret != OK)
204 {
205 DAWNERR("CAN configure failed (error %d)\n", ret);
206 return ret;
207 }
208
209 return OK;
210}
211
213{
214 int ret;
215
216 ret = canInitialize();
217 if (ret != OK)
218 {
219 return ret;
220 }
221
222 ret = createRegs();
223 if (ret < 0)
224 {
225 DAWNERR("failed to create registers %d\n", ret);
226 return ret;
227 }
228
229 return OK;
230}
231
233{
234 destroyRegs();
235
236 if (fd >= 0)
237 {
238 can_close(fd);
239 fd = -1;
240 }
241
242 return OK;
243}
244
246{
247 return startWorkerThread([this]() { thread(); });
248};
249
251{
252 return stopWorkerThread();
253};
254
256{
257 return workerThreadRunning();
258}
void setObjectMapItem(SObjectId::ObjectId id, CObject *obj)
Set an item in the object map.
Definition bindable.cxx:23
Descriptor wrapper for individual object configuration.
size_t getSize() const
Get number of configuration items for this object.
SObjectCfg::SObjectCfgItem * objectCfgItemNext(size_t &offset) const
Get config item at current offset and advance past it.
CDescObject & getDesc()
Get descriptor object for this object.
Definition object.cxx:190
static int run(CThreadedObject &threadCtl, struct pollfd *pfds, nfds_t nfds, int timeoutMs, const SPollLoopCallbacks &callbacks, void *priv)
Run poll loop until quit is requested.
Definition poll_loop.hxx:61
CAN bus protocol for industrial automation.
Definition can.hxx:36
int deinit()
De-initialize object.
Definition can.cxx:232
int configure()
Configure object from descriptor data.
Definition can.cxx:198
int init()
One-time initialize object after bindings are resolved.
Definition can.cxx:212
int doStop()
Stop implementation hook.
Definition can.cxx:250
bool hasThread() const
Check if a background thread is active.
Definition can.cxx:255
int doStart()
Start implementation hook.
Definition can.cxx:245
@ PROTO_CAN_CFG_DEVNO
CAN device number (0=can0)
Definition can.hxx:42
@ PROTO_CAN_CFG_IOBIND
I/O object binding.
Definition can.hxx:41
@ PROTO_CAN_CFG_NODEID
CAN node ID base address.
Definition can.hxx:43
@ PROTO_CLASS_CAN
CAN bus protocol.
Definition common.hxx:75
bool workerThreadRunning() const
Check if the worker thread is running.
Definition thread.hxx:269
int stopWorkerThread()
Stop the worker thread.
Definition thread.hxx:258
int startWorkerThread(Func &&func)
Start the worker thread with a given function.
Definition thread.hxx:246
CThreadedObject & workerThread()
Get a reference to this thread controller.
Definition thread.hxx:280
Out-of-tree user-extension hooks for Dawn.
Definition bindable.hxx:13
Single configuration item within object.
ObjectCfgData_t data[]
Configuration data array (flexible, size from cfgid.s.size).
UObjectCfgId cfgid
Configuration ID header (type, class, id, size, rw, dtype).
Callback set for poll-based worker loops.
Definition poll_loop.hxx:28
Common CAN message format for chardev and socketCAN.
Definition can.hxx:20
ObjectCfgId v
Raw 32-bit ConfigID value (for storage, comparison).
Definition objectcfg.hxx:82
uint32_t cls
Object class (bits 21-29, max 511).
uint32_t id
Configuration identifier (bits 0-4, max 31).
Definition objectcfg.hxx:94
uint32_t size
Configuration data size in 32-bit words (bits 5-14, max 1023).
struct dawn::SObjectCfg::UObjectCfgId::@10 s
Bit-field structure for named member access.