Dawn Framework 1.0
Universal data acquisition framework for embedded systems
pulsecount.cxx
1// dawn/src/io/pulsecount.cxx
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5
6#include "dawn/io/pulsecount.hxx"
7
8#include <cinttypes>
9#include <cerrno>
10#include <cstdio>
11
12using namespace dawn;
13
14namespace
15{
16/* Keep pulsecount frequency above 0 Hz: NSEC_PER_SEC / period must not
17 * round down to zero in the NuttX driver.
18 */
19constexpr uint64_t PULSECOUNT_MAX_PERIOD_NS = 1000000000ull;
20}
21
22int CIOPulseCount::validateTimings(uint32_t high, uint32_t low) const
23{
24 uint64_t period;
25
26 if (high == 0 || low == 0)
27 {
28 DAWNERR("pulsecount timings must be > 0\n");
29 return -EINVAL;
30 }
31
32 period = static_cast<uint64_t>(high) + static_cast<uint64_t>(low);
33 if (period > PULSECOUNT_MAX_PERIOD_NS)
34 {
35 DAWNERR("pulsecount period too large: %" PRIu64 " ns\n", period);
36 return -EINVAL;
37 }
38
39 return OK;
40}
41
42int CIOPulseCount::configureDesc(const CDescObject &desc)
43{
44 const SObjectCfg::SObjectCfgItem *item = nullptr;
45 size_t offset = 0;
46 int ret;
47
48 for (size_t i = 0; i < desc.getSize(); i++)
49 {
50 item = desc.objectCfgItemAtOffset(offset);
51
52 switch (item->cfgid.s.cls)
53 {
55 {
56 offset += cfgCmnOffset(item);
57 break;
58 }
59
61 {
62 if (item->cfgid.s.size != 1)
63 {
64 DAWNERR("invalid pulsecount config size %d\n", item->cfgid.s.size);
65 return -EINVAL;
66 }
67
68 switch (item->cfgid.s.id)
69 {
71 {
72 highNs = *reinterpret_cast<const uint32_t *>(&item->data);
73 offset += item->cfgid.s.size + 1;
74 break;
75 }
76
78 {
79 lowNs = *reinterpret_cast<const uint32_t *>(&item->data);
80 offset += item->cfgid.s.size + 1;
81 break;
82 }
83
84 default:
85 {
86 DAWNERR("Unsupported pulsecount config 0x%08" PRIx32 "\n", item->cfgid.v);
87 return -EINVAL;
88 }
89 }
90
91 break;
92 }
93
94 default:
95 {
96 DAWNERR("Unsupported pulsecount config 0x%08" PRIx32 "\n", item->cfgid.v);
97 return -EINVAL;
98 }
99 }
100 }
101
102 ret = validateTimings(highNs, lowNs);
103 if (ret < 0)
104 {
105 return ret;
106 }
107
108 return OK;
109}
110
111int CIOPulseCount::writeCurrentConfig(uint32_t count)
112{
114
115 info.high_ns = highNs;
116 info.low_ns = lowNs;
117 info.count = count;
118
119 return pulsecount_write(fd, &info);
120}
121
122CIOPulseCount::~CIOPulseCount()
123{
124 deinit();
125}
126
128{
129 int ret;
130
131 ret = configureDesc(getDesc());
132 if (ret != OK)
133 {
134 DAWNERR("pulsecount configure failed (error %d)\n", ret);
135 return ret;
136 }
137
138 if (getCmnDevno() == -1)
139 {
140 DAWNERR("pulsecount device number not configured\n");
141 return -EINVAL;
142 }
143
144 snprintf(path, sizeof(path), PULSECOUNT_PATH_FMT, getCmnDevno());
145
146 fd = pulsecount_open(path);
147 if (fd < 0)
148 {
149 DAWNERR("failed to open file %d\n", -errno);
150 return -errno;
151 }
152
153 pulsecount_init(fd);
154
155 return OK;
156}
157
159{
161 {
162 DAWNERR("pulsecount requires DTYPE_UINT32\n");
163 return -EINVAL;
164 }
165
166 return OK;
167}
168
170{
171 if (fd >= 0)
172 {
173 pulsecount_close(fd);
174 fd = -1;
175 }
176
177 return OK;
178}
179
181{
182 uint32_t *tmp = static_cast<uint32_t *>(data.getDataPtr());
183 int ret;
184
185 if (data.getItems() < getDataDim())
186 {
187 return -EINVAL;
188 }
189
190 if (tmp[0] == 0)
191 {
192 return -EINVAL;
193 }
194
195 ret = writeCurrentConfig(tmp[0]);
196 if (ret < 0)
197 {
198 DAWNERR("pulsecount_write failed %d\n", ret);
199 return ret;
200 }
201
202 ret = pulsecount_start(fd);
203 if (ret < 0)
204 {
205 DAWNERR("pulsecount_start failed %d\n", ret);
206 return ret;
207 }
208
209 lastCount = tmp[0];
210
211#ifdef CONFIG_DAWN_IO_TIMESTAMP
212 if (isTimestamp())
213 {
214 ts = getTimestamp();
215 }
216#endif
217
218 return OK;
219}
220
221int CIOPulseCount::onSetObjConfig(SObjectCfg::ObjectCfgId objcfg, uint32_t *data, size_t len)
222{
223 uint32_t newHigh;
224 uint32_t newLow;
225 int ret;
226
227 if (len != 1 || data == nullptr)
228 {
229 return -EINVAL;
230 }
231
232 switch (SObjectCfg::objectCfgGetId(objcfg))
233 {
235 newHigh = data[0];
236 newLow = lowNs;
237 break;
238
240 newHigh = highNs;
241 newLow = data[0];
242 break;
243
244 default:
245 return OK;
246 }
247
248 ret = validateTimings(newHigh, newLow);
249 if (ret < 0)
250 {
251 return ret;
252 }
253
254 if (lastCount != 0 && fd >= 0)
255 {
256 uint32_t oldHigh = highNs;
257 uint32_t oldLow = lowNs;
258
259 highNs = newHigh;
260 lowNs = newLow;
261 ret = writeCurrentConfig(lastCount);
262 if (ret < 0)
263 {
264 highNs = oldHigh;
265 lowNs = oldLow;
266 return ret;
267 }
268 }
269
270 highNs = newHigh;
271 lowNs = newLow;
272 return OK;
273}
274
276{
277 return sizeof(uint32_t);
278}
279
281{
282 return 1;
283}
Descriptor wrapper for individual object configuration.
size_t getSize() const
Get number of configuration items for this object.
SObjectCfg::SObjectCfgItem * objectCfgItemAtOffset(size_t offset) const
Get configuration item at specified offset.
uint64_t getTimestamp()
Get current timestamp.
Definition common.cxx:194
bool isTimestamp() const
Check if I/O supports timestamp.
Definition common.cxx:189
int getCmnDevno() const
Get device number for this I/O.
Definition common.hxx:817
size_t cfgCmnOffset(const SObjectCfg::SObjectCfgItem *cfg)
Get offset of configuration item in descriptor.
Definition common.cxx:144
@ IO_CLASS_ANY
Any I/O class.
Definition common.hxx:86
@ IO_CLASS_PULSECOUNT
Finite pulse-train output.
Definition common.hxx:181
size_t getDataDim() const
Get data vector dimension.
@ IO_PULSECOUNT_CFG_HIGH_NS
Pulse high time in nanoseconds.
@ IO_PULSECOUNT_CFG_LOW_NS
Pulse low time in nanoseconds.
int onSetObjConfig(SObjectCfg::ObjectCfgId objcfg, uint32_t *data, size_t len)
Pre-update hook for runtime configuration writes.
int init()
One-time initialize object after bindings are resolved.
int setDataImpl(IODataCmn &data)
Set data implementation (override in derived classes).
size_t getDataSize() const
Get data size in bytes.
int configure()
Configure object from descriptor data.
int deinit()
De-initialize object.
CDescObject & getDesc()
Get descriptor object for this object.
Definition object.cxx:190
uint8_t getDtype() const
Get data type field.
Definition object.cxx:175
uint32_t ObjectCfgId
ConfigID type - single 32-bit value.
Definition objectcfg.hxx:60
static uint8_t objectCfgGetId(const ObjectCfgId objcfg)
Extract configuration identifier from ConfigID.
Out-of-tree user-extension hooks for Dawn.
Definition bindable.hxx:13
Base interface for I/O data buffers (static and dynamic).
Definition idata.hxx:21
virtual size_t getItems()=0
Get number of items per batch.
virtual void * getDataPtr(size_t batch=0)=0
Get pointer to data only (skips timestamp if present).
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).
@ DTYPE_UINT32
Unsigned 32-bit integer (0 to 4294967295).
Definition objectid.hxx:96
Pulse-count output settings.
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.