ApraLinuxUtils 1.0.0
C++ utility library for embedded Linux systems
 
Loading...
Searching...
No Matches
I2CInterface.cpp
Go to the documentation of this file.
1/*
2 * I2CInterface.cpp
3 *
4 * Copyright (c) 2024 Apra Labs
5 *
6 * This file is part of ApraUtils.
7 *
8 * Licensed under the MIT License.
9 * See LICENSE file in the project root for full license information.
10 */
11
12#include <algorithm>
13#include <stdexcept>
14#include "utils/Macro.h"
15#include "utils/ScopeLock.h"
17
18namespace apra
19{
20
21I2C_Interface::I2C_Interface(string i2cPath, string name, uint64_t fpsHz,
22 bool shouldPrint) :
23 ProcessThread(name, fpsHz), m_i2cPath(i2cPath), m_i2cBus(i2cPath,
24 shouldPrint), m_lastProcessedEventTs(0), m_setupSuccess(false)
25{
26 I2CError i2cError = m_i2cBus.openBus();
27 if (i2cError.isError())
28 {
29 string error = "Unable to open i2c bus " + m_i2cPath + "\n";
30 error += i2cError.getMessage() + "\n";
31 error += i2cError.getDebugMessage();
32 throw std::invalid_argument(error);
33 }
34 else
35 {
36 m_setupSuccess = true;
37 }
38}
39
44
46{
48 I2CError response;
50 m_setupSuccess = false;
51 response = m_i2cBus.openBus();
52 m_setupSuccess = !response.isError();
53 return response;
54}
55
60
62{
64 m_registeredEvents[message.getHandle()] = message;
65 return message.getHandle();
66}
67
68void I2C_Interface::unregisterEvent(uint64_t messageHandle)
69{
71 m_registeredEvents.erase(messageHandle);
72}
73
75{
76 if (!m_setupSuccess)
77 {
78 return;
79 }
81 if (!obj)
82 {
83 return;
84 }
86 processMessage(txMessage);
87 std::queue<I2C_Transaction_Message*> requests;
88 {
90 while (!m_requestQueue.empty())
91 {
92 Message *item = m_requestQueue.front();
93 m_requestQueue.pop();
94 if (item)
95 {
96 requests.push((I2C_Transaction_Message*) item);
97 }
98 }
99 }
100 while (!requests.empty())
101 {
102 I2C_Transaction_Message *item = requests.front();
103 requests.pop();
104 if (item)
105 {
106 processMessage(item);
107 }
108 }
109}
110
112{
113 MONOCURRTIME(timeNow);
114 if ((timeNow - m_lastProcessedEventTs) < m_frequSec)
115 {
116 return;
117 }
118 map<uint64_t, I2C_Transaction_Message> eventMessages;
119 {
121 eventMessages = m_registeredEvents;
122 }
123 bool isAnyEventProcessed = false;
124 for (map<uint64_t, I2C_Transaction_Message>::iterator eventItr =
125 eventMessages.begin(); eventItr != eventMessages.end(); eventItr++)
126 {
127 if (std::find(m_processedEvents.begin(), m_processedEvents.end(),
128 eventItr->first) != m_processedEvents.end())
129 {
130 continue;
131 }
132 isAnyEventProcessed = true;
133 I2C_Transaction_Message i2cTxMessage = eventItr->second;
134 processI2CTransaction(&i2cTxMessage);
135 i2cTxMessage.publishTransaction();
136 }
137
138 m_processedEvents.clear();
139 if (isAnyEventProcessed)
140 {
142 }
143}
144
146{
147 MONOCURRTIME(timeNow);
148 if ((timeNow - m_lastProcessedEventTs) < m_frequSec)
149 {
150 return;
151 }
152 map<uint64_t, I2C_Transaction_Message> eventMessages;
153 {
155 eventMessages = m_registeredEvents;
156 }
157 for (map<uint64_t, I2C_Transaction_Message>::iterator eventItr =
158 eventMessages.begin(); eventItr != eventMessages.end(); eventItr++)
159 {
160 if (std::find(m_processedEvents.begin(), m_processedEvents.end(),
161 eventItr->first) != m_processedEvents.end())
162 {
163 continue;
164 }
165 I2C_Transaction_Message i2cTxMessage = eventItr->second;
166 processI2CTransaction(&i2cTxMessage);
167 i2cTxMessage.publishTransaction();
168 m_processedEvents.push_back(eventItr->first);
169 break;
170 }
171 if (m_processedEvents.size() >= m_registeredEvents.size())
172 {
173 m_processedEvents.clear();
175 }
176}
177
179{
180 processI2CTransaction(txMessage);
181 enqueResponse(txMessage);
182 if (txMessage->m_transactionDelayUsec > 0)
183 {
184 MONOCURRTIME(timeNow);
185 uint64_t timeDelay = txMessage->m_transactionDelayUsec;
186 if ((timeNow - m_lastProcessedEventTs) > m_frequSec)
187 {
189 timeDelay = getNormalizedDelay(m_lastProcessedEventTs, timeNow,
190 txMessage->m_transactionDelayUsec);
191 }
192 if (timeDelay)
193 {
194 usleep(timeDelay);
195 }
196 }
197 else
198 {
200 }
201}
202
204{
205 I2CError response;
206 uint64_t retryCount = message.m_retryCount;
207 do
208 {
209 if (retryCount != message.m_retryCount)
210 {
211 if (message.m_allowOtherProcessOnIdle)
212 {
214 }
215 else if (message.m_retryDelayInUsec)
216 {
217 usleep(message.m_retryDelayInUsec);
218 }
219 }
220 {
222 m_i2cBus.setSize(message.m_registerNumber.size(),
223 message.getDataSize());
224 response = m_i2cBus.genericRead(chipNumber,
225 message.m_registerNumber, message.m_data);
226 }
227 if (!response.isError())
228 {
229 break;
230 }
231 } while (retryCount-- > 0);
232 message.m_error = response;
233 return response;
234}
235
237 I2C_Message &message, bool compareEquals)
238{
239 I2CError response;
240 uint64_t retryCount = message.m_retryCount;
241 do
242 {
243 if (retryCount != message.m_retryCount)
244 {
245 if (message.m_allowOtherProcessOnIdle)
246 {
248 }
249 else if (message.m_retryDelayInUsec)
250 {
251 usleep(message.m_retryDelayInUsec);
252 }
253 }
254 {
256 m_i2cBus.setSize(message.m_registerNumber.size(),
257 message.getDataSize());
258 response = m_i2cBus.genericRead(chipNumber,
259 message.m_registerNumber, message.m_data);
260 }
261 if (!response.isError())
262 {
263 if (compareEquals
264 && (message.m_data.size() == message.m_compareData.size())
265 && (message.m_data == message.m_compareData))
266 {
267 break;
268 }
269 else if (!compareEquals
270 && ((message.m_data.size() != message.m_compareData.size())
271 || (message.m_data == message.m_compareData)))
272 {
273 break;
274 }
275 }
276 } while (retryCount-- > 0);
277 message.m_error = response;
278 return response;
279}
280
282{
283 I2CError response;
284 uint64_t retryCount = message.m_retryCount;
285 do
286 {
287 if (retryCount != message.m_retryCount)
288 {
289 if (message.m_allowOtherProcessOnIdle)
290 {
292 }
293 else if (message.m_retryDelayInUsec)
294 {
295 usleep(message.m_retryDelayInUsec);
296 }
297 }
298 {
300 m_i2cBus.setSize(message.m_registerNumber.size(),
301 message.m_data.size());
302 response = m_i2cBus.genericWrite(chipNumber,
303 message.m_registerNumber, message.m_data);
304 }
305 if (!response.isError())
306 {
307 break;
308 }
309 } while (retryCount-- > 0);
310 message.m_error = response;
311 return response;
312}
313
315{
316 I2CError transactionError;
317 for (size_t messageIndex = 0; messageIndex < txMessage->m_messages.size();
318 messageIndex++)
319 {
320 I2CError i2cError;
321 switch (txMessage->m_messages[messageIndex].m_type)
322 {
323 case I2C_READ:
324 {
325 i2cError = performRead(txMessage->m_chipNumber,
326 txMessage->m_messages[messageIndex]);
327 break;
328 }
331 {
332 i2cError = performCompareRead(txMessage->m_chipNumber,
333 txMessage->m_messages[messageIndex],
334 txMessage->m_messages[messageIndex].m_type
336 break;
337 }
338 case I2C_WRITE:
339 {
340 i2cError = performWrite(txMessage->m_chipNumber,
341 txMessage->m_messages[messageIndex]);
342 break;
343 }
344 }
345 if (i2cError.isError())
346 {
347 transactionError = i2cError;
348 if (txMessage->m_stopOnAnyTransactionFailure)
349 {
350 break;
351 }
352 }
353 if (txMessage->m_messages[messageIndex].m_delayInUsec)
354 {
355 if (txMessage->m_messages[messageIndex].m_allowOtherProcessOnIdle)
356 {
358 txMessage->m_messages[messageIndex].m_delayInUsec);
359 }
360 else
361 {
362 usleep(txMessage->m_messages[messageIndex].m_delayInUsec);
363 }
364 }
365 }
366 txMessage->setError(transactionError);
367}
368
369void I2C_Interface::performTransactionDelay(const uint64_t timeDelay)
370{
371 if (!timeDelay)
372 {
373 return;
374 }
375 MONOCURRTIME(startTime);
376 int64_t timeNow = startTime;
377 uint64_t pendingEvents = m_registeredEvents.size()
378 - m_processedEvents.size();
379
380 uint64_t delayInUsec = getNormalizedDelay(timeNow, startTime, timeDelay);
381 while ((delayInUsec > 0) && (pendingEvents-- > 0))
382 {
384 MONOTIMEUS(timeNow);
385 delayInUsec = getNormalizedDelay(timeNow, startTime, timeDelay);
386 }
387 if (delayInUsec > 0)
388 {
389 usleep(delayInUsec);
390 }
391}
392
393uint64_t I2C_Interface::getNormalizedDelay(int64_t largerTime,
394 int64_t smallerTime, uint64_t timeDelay)
395{
396 int64_t signedDiff = largerTime - smallerTime;
397 uint64_t timeDiff = signedDiff > -1 ? signedDiff : 0;
398 return (timeDiff < timeDelay) ? (timeDelay - timeDiff) : 0;
399}
400
401} /* namespace apra */
402
#define MONOTIMEUS(ret)
Definition Macro.h:75
#define MONOCURRTIME(ret)
Definition Macro.h:81
std::string getDebugMessage()
std::string getMessage()
void closeBus()
Definition I2CBus.cpp:69
I2CError genericWrite(uint8_t chipAddress, vector< uint8_t > registerAddress, vector< uint8_t > data)
Definition I2CBus.cpp:80
I2CError genericRead(uint8_t chipAddress, vector< uint8_t > registerAddress, vector< uint8_t > &readData)
Definition I2CBus.cpp:140
I2CError openBus()
Definition I2CBus.cpp:49
void setSize(uint8_t registerSize, uint8_t dataSize)
Definition I2CBus.cpp:43
void processI2CTransaction(I2C_Transaction_Message *txMessage)
uint64_t registerEvent(I2C_Transaction_Message message)
I2CError performCompareRead(uint8_t chipNumber, I2C_Message &message, bool compareEquals)
void unregisterEvent(uint64_t messageHandle)
virtual void processEvents()
apra::Mutex m_eventMessageLock
virtual void processSingleEvent()
I2CError performWrite(uint8_t chipNumber, I2C_Message &message)
vector< uint64_t > m_processedEvents
void processMessage(I2C_Transaction_Message *txMessage)
int64_t m_lastProcessedEventTs
map< uint64_t, I2C_Transaction_Message > m_registeredEvents
apra::Mutex m_processLock
void performTransactionDelay(const uint64_t timeDelay)
virtual void process(Message *obj)
uint64_t getNormalizedDelay(int64_t largerTime, int64_t smallerTime, uint64_t timeDelay)
I2CError performRead(uint8_t chipNumber, I2C_Message &message)
I2C_Interface(string i2cPath, string processName, uint64_t processFpsHz, bool shouldPrint)
vector< uint8_t > m_compareData
Definition I2CMessage.h:52
uint64_t m_retryDelayInUsec
Definition I2CMessage.h:55
uint64_t getDataSize()
vector< uint8_t > m_registerNumber
Definition I2CMessage.h:50
vector< uint8_t > m_data
Definition I2CMessage.h:51
bool m_allowOtherProcessOnIdle
Definition I2CMessage.h:56
uint64_t m_retryCount
Definition I2CMessage.h:53
uint64_t getHandle()
Definition Message.cpp:37
void enqueResponse(Message *message)
std::queue< Message * > m_requestQueue
@ I2C_READ_COMPARE_EQUAL
@ I2C_READ_COMPARE_NOT_EQUAL