LIN_master_portable_Arduino 1.4
Arduino library for Local Interconnect Network master node emulation
Loading...
Searching...
No Matches
LIN_master_Base.cpp
Go to the documentation of this file.
1
10// include files
11#include <LIN_master_Base.h>
12
13// warn if debug interface is active (see LIN_master_Base.h)
14#if defined(LIN_MASTER_DEBUG_SERIAL)
15 #warning Debug interface is active, see file 'LIN_master_Base.h'
16#endif
17
18
19
20/**************************
21 * PROTECTED METHODS
22**************************/
23
30{
31 uint8_t pid_tmp; // calculated protected frame ID
32 uint8_t tmp; // temporary variable for calculating parity bits
33
34 // protect ID with parity bits
35 pid_tmp = (uint8_t) (this->id & 0x3F); // clear upper bits 6 & 7
36 tmp = (uint8_t) ((pid_tmp ^ (pid_tmp>>1) ^ (pid_tmp>>2) ^ (pid_tmp>>4)) & 0x01); // pid[6] = PI0 = ID0^ID1^ID2^ID4
37 pid_tmp |= (uint8_t) (tmp << 6);
38 tmp = (uint8_t) (~((pid_tmp>>1) ^ (pid_tmp>>3) ^ (pid_tmp>>4) ^ (pid_tmp>>5)) & 0x01); // pid[7] = PI1 = ~(ID1^ID3^ID4^ID5)
39 pid_tmp |= (uint8_t) (tmp << 7);
40
41 // print debug message
42 DEBUG_PRINT(3, "PID=0x%02X", pid_tmp);
43
44 // return protected ID
45 return pid_tmp;
46
47} // LIN_Master_Base::_calculatePID()
48
49
50
58uint8_t LIN_Master_Base::_calculateChecksum(uint8_t NumData, uint8_t Data[])
59{
60 uint16_t chk = 0x00; // frame checksum
61
62 // LIN2.x uses extended checksum which includes protected ID, i.e. including parity bits
63 // LIN1.x uses classical checksum only over data bytes
64 // Diagnostic frames with ID=0x3C/PID=0x3C and ID=0x3D/PID=0x7D always use classical checksum (see LIN spec "2.3.1.5 Checkum")
65 if (!((this->version == LIN_V1) || (id == 0x3C) || (id == 0x3D)))
66 chk = (uint16_t) this->_calculatePID();
67
68 // loop over data bytes
69 for (uint8_t i = 0; i < NumData; i++)
70 {
71 chk += (uint16_t) (Data[i]);
72 if (chk>255)
73 chk -= 255;
74 }
75 chk = (uint8_t)(0xFF - ((uint8_t) chk)); // bitwise invert and strip upper byte
76
77 // print debug message
78 DEBUG_PRINT(3, "CHK=0x%02X", chk);
79
80 // return frame checksum
81 return (uint8_t) chk;
82
83} // LIN_Master_Base::_calculateChecksum()
84
85
86
93{
94 // check echo of sent bytes (frame or header). Exit on mismatch
95 for (uint8_t i = 0; i < this->lenTx; i++)
96 {
97 if (this->bufTx[i] != this->bufRx[i])
98 {
99 // print debug message
100 DEBUG_PRINT(1, "echo error: Tx[%d]=0x%02X, Rx[%d]=0x%02X", (int) i, (int) this->bufTx[i], (int) i, (int) this->bufRx[i]);
101
102 // return error code
104
105 } // echo error
106
107 } // loop over frame bytes
108
109
110 // check frame checksum
111 if (this->bufRx[this->lenRx-1] != this->_calculateChecksum(this->lenRx-4, this->bufRx+3))
112 {
113 // print debug message
114 DEBUG_PRINT(1, "checksum error: expect 0x%02X, received 0x%02X", (int) _calculateChecksum(this->lenRx-4, this->bufRx+3),
115 (int) this->bufRx[this->lenRx-1]);
116
117 // return error code
119
120 } // checksum error
121
122 // print debug message
123 DEBUG_PRINT(3, "ok");
124
125 // return result of check
127
128} // LIN_Master_Base::_checkFrame()
129
130
131
138{
139 // if bus is not idle, return immediately
141 {
142 // print debug message
143 DEBUG_PRINT(1, "wrong state 0x%02X", this->state);
144
145 // set error state and return immediately
148 this->_disableTransmitter();
149 return this->state;
150
151 } // wrong state
152
153 // progress state
155
156 // print debug message
157 DEBUG_PRINT(3, "ok");
158
159 // return state machine state
160 return this->state;
161
162} // LIN_Master_Base::_sendBreak()
163
164
165
172{
173 // progress state
175
176 // print debug message
177 DEBUG_PRINT(2, "ok");
178
179 // return state
180 return this->state;
181
182} // LIN_Master_Base::_sendFrame()
183
184
185
192{
193 // dummy: just progress state
194 this->_disableTransmitter();
196
197 // print debug message
198 DEBUG_PRINT(2, "ok");
199
200 // return state
201 return this->state;
202
203} // LIN_Master_Base::_receiveFrame()
204
205
206
207/**************************
208 * PUBLIC METHODS
209**************************/
210
219LIN_Master_Base::LIN_Master_Base(const char NameLIN[], const int8_t PinTxEN)
220{
221 // Debug serial initialized in begin() -> no debug output here
222
223 // store parameters in class variables
224 memcpy(this->nameLIN, NameLIN, LIN_MASTER_BUFLEN_NAME); // node name e.g. for debug
225 this->pinTxEN = PinTxEN; // optional Tx enable pin for RS485
226
227 // initialize master node properties
228 this->error = LIN_Master_Base::NO_ERROR; // last LIN error. Is latched
229 this->state = LIN_Master_Base::STATE_OFF; // status of LIN state machine
230
231} // LIN_Master_Base::LIN_Master_Base()
232
233
234
240void LIN_Master_Base::begin(uint16_t Baudrate)
241{
242 // initialize debug interface with optional timeout
243 #if defined(LIN_MASTER_DEBUG_SERIAL)
244 LIN_MASTER_DEBUG_SERIAL.begin(115200);
245 #if defined(LIN_MASTER_DEBUG_PORT_TIMEOUT) && (LIN_MASTER_DEBUG_PORT_TIMEOUT > 0)
246 uint32_t startMillis = millis();
247 while ((!LIN_MASTER_DEBUG_SERIAL) && (millis() - startMillis < LIN_MASTER_DEBUG_PORT_TIMEOUT));
248 #else
249 while (!LIN_MASTER_DEBUG_SERIAL);
250 #endif
251 #endif
252
253 // store parameters in class variables
254 this->baudrate = Baudrate; // communication baudrate [Baud]
255
256 // initialize master node properties
257 this->error = LIN_Master_Base::NO_ERROR; // last LIN error. Is latched
258 this->state = LIN_Master_Base::STATE_IDLE; // status of LIN state machine
259 this->timePerByte = 10000000L / (uint32_t) this->baudrate; // time [us] per byte (for performance)
260
261 // initialize optional TxEN pin to low (=transmitter off)
262 if (this->pinTxEN >= 0)
263 {
264 digitalWrite(this->pinTxEN, LOW);
265 pinMode(this->pinTxEN, OUTPUT);
266 }
267
268 // print debug message
269 DEBUG_PRINT(2, "BR=%d", (int) Baudrate);
270
271} // LIN_Master_Base::begin()
272
273
274
280{
281 // set master node properties
282 this->error = LIN_Master_Base::NO_ERROR; // last LIN error. Is latched
283 this->state = LIN_Master_Base::STATE_OFF; // status of LIN state machine
284
285 // optionally disable RS485 transmitter
286 this->_disableTransmitter();
287
288 // print debug message
289 DEBUG_PRINT(2, " ");
290
291} // LIN_Master_Base::end()
292
293
294
306{
307 // construct Tx frame
309 this->version = Version;
310 this->id = Id;
311 this->lenTx = NumData + 4; // Frame length
312 this->bufTx[0] = 0x00; // BREAK
313 this->bufTx[1] = 0x55; // SYNC
314 this->bufTx[2] = this->_calculatePID(); // PID
315 memcpy(this->bufTx+3, Data, NumData); // DATA[]
316 this->bufTx[this->lenTx-1] = this->_calculateChecksum(NumData, Data); // CHK
317 this->lenRx = this->lenTx; // just receive LIN echo
318
319 // init receive buffer
320 memset(this->bufRx, 0, 12);
321
322 // set break timeout (= 200% nominal) and start timeout
323 this->timeStart = micros();
324 this->timeoutFrame = ((this->lenRx + 1) * this->timePerByte) * 2;
325
326 // print debug message
327 DEBUG_PRINT(2, " ");
328
329 // start LIN frame by sending a Sync Break
330 this->_sendBreak();
331
332 // return state machine state
333 return this->state;
334
335} // LIN_Master_Base::sendMasterRequest()
336
337
338
350{
351 // print debug message
352 DEBUG_PRINT(2, " ");
353
354 // start master request frame
355 this->sendMasterRequest(Version, Id, NumData, Data);
356
357 // wait until frame is completed
358 do
359 this->handler();
360 while (this->state != LIN_Master_Base::STATE_DONE);
361
362 // return LIN error
363 return this->error;
364
365} // LIN_Master_Base::sendMasterRequestBlocking()
366
367
368
379{
380 // construct Tx frame
382 this->version = Version;
383 this->id = Id;
384 this->lenTx = 3; // Frame header length
385 this->bufTx[0] = 0x00; // BREAK
386 this->bufTx[1] = 0x55; // SYNC
387 this->bufTx[2] = this->_calculatePID(); // PID
388 this->lenRx = NumData + 4; // receive LIN header echo + DATA[] + CHK
389
390 // init receive buffer
391 memset(this->bufRx, 0, 12);
392
393 // set break timeout (= 200% nominal) and start timeout
394 this->timeoutFrame = ((this->lenRx + 1) * this->timePerByte) * 2;
395 this->timeStart = micros();
396
397 // print debug message
398 DEBUG_PRINT(2, " ");
399
400 // start LIN frame by sending BREAK
401 this->_sendBreak();
402
403 // return state machine state
404 return this->state;
405
406} // LIN_Master_Base::sendMasterRequestBlocking()
407
408
409
421{
422 // print debug message
423 DEBUG_PRINT(2, " ");
424
425 // start slave response frame
426 this->receiveSlaveResponse(Version, Id, NumData);
427
428 // wait until frame is completed
429 do
430 this->handler();
431 while (this->state != LIN_Master_Base::STATE_DONE);
432
433 // copy received data
434 this->getFrame(this->type, this->id, NumData, Data);
435
436 // return LIN error
437 return this->error;
438
439} // LIN_Master_Base::sendMasterRequestBlocking()
440
441
442
450{
451 // print debug message
452 DEBUG_PRINT(3, "state=%d", (int) this->state);
453
454 // act according to current state
455 switch (this->state)
456 {
457 // idle or done -> don't do anything
460 break;
461
462 // when sync break done, send rest of frame
464 this->_sendFrame();
465 break;
466
468 this->_receiveFrame();
469 break;
470
471 // this should never happen..
472 default:
473
474 // print debug message
475 DEBUG_PRINT(1, "wrong state 0x%02X", this->state);
476
477 // set error state
478 this->error = (LIN_Master_Base::error_t) ((int) this->error | (int) LIN_Master_Base::ERROR_MISC);
479 this->state = LIN_Master_Base::STATE_DONE;
480 this->_disableTransmitter();
481
482 } // switch (this->state)
483
484 // return state machine state
485 return this->state;
486
487} // LIN_Master_Base::handler()
488
489/*-----------------------------------------------------------------------------
490 END OF FILE
491-----------------------------------------------------------------------------*/
Base class for LIN master emulation (non-functional)
uint8_t lenRx
receive buffer length (max. 12)
virtual void begin(uint16_t Baudrate=19200)
Open serial interface.
uint16_t baudrate
communication baudrate [Baud]
@ MASTER_REQUEST
LIN master request frame.
@ SLAVE_RESPONSE
LIN slave response frame.
void getFrame(LIN_Master_Base::frame_t &Type, uint8_t &Id, uint8_t &NumData, uint8_t Data[])
Getter for LIN frame.
uint8_t bufTx[12]
send buffer incl. BREAK, SYNC, DATA and CHK (max. 12B)
LIN_Master_Base::state_t receiveSlaveResponse(LIN_Master_Base::version_t Version=LIN_Master_Base::LIN_V2, uint8_t Id=0x00, uint8_t NumData=0)
Start sending a LIN slave response frame in background (if supported)
version_t
LIN protocol version.
@ LIN_V1
LIN protocol version 1.x.
uint8_t _calculatePID(void)
Calculate protected frame ID.
LIN_Master_Base::error_t _checkFrame(void)
Check received LIN frame.
LIN_Master_Base::error_t error
error state. Is latched until cleared
char nameLIN[LIN_MASTER_BUFLEN_NAME]
LIN node name, e.g. for debug.
LIN_Master_Base::error_t receiveSlaveResponseBlocking(LIN_Master_Base::version_t Version=LIN_Master_Base::LIN_V2, uint8_t Id=0x00, uint8_t NumData=0, uint8_t *Data=NULL)
Send a blocking LIN slave response frame (no background operation)
uint32_t timeStart
starting time [us] for frame timeout
int8_t pinTxEN
optional Tx direction pin, e.g. for LIN via RS485
uint8_t lenTx
send buffer length (max. 12)
LIN_Master_Base::state_t handler(void)
Handle LIN background operation (call until STATE_DONE is returned)
uint8_t _calculateChecksum(uint8_t NumData, uint8_t Data[])
Calculate LIN frame checksum.
LIN_Master_Base::state_t state
status of LIN state machine
virtual LIN_Master_Base::state_t _sendFrame(void)
Send LIN frame body.
void _disableTransmitter(void)
Disable RS485 transmitter (DE=low)
error_t
LIN error codes. Use bitmasks, as error is latched. Use same as LIN_slave_portable.
@ ERROR_STATE
error in LIN state machine
@ ERROR_CHK
LIN checksum error.
@ ERROR_ECHO
error reading response echo
@ ERROR_MISC
misc error, should not occur
virtual LIN_Master_Base::state_t _receiveFrame(void)
Receive LIN frame.
uint32_t timePerByte
time [us] per byte at specified baudrate
LIN_Master_Base::state_t sendMasterRequest(LIN_Master_Base::version_t Version=LIN_Master_Base::LIN_V2, uint8_t Id=0x00, uint8_t NumData=0, uint8_t Data[]=NULL)
Start sending a LIN master request frame in background (if supported)
LIN_Master_Base::version_t version
LIN protocol version.
state_t
state of LIN master state machine. Use bitmasks for fast checking multiple states
@ STATE_BODY
rest of frame is being sent/received
@ STATE_OFF
LIN interface closed.
@ STATE_BREAK
sync break is being transmitted
@ STATE_IDLE
no LIN transmission ongoing
@ STATE_DONE
frame completed
virtual void end(void)
Close serial interface.
uint8_t bufRx[12]
receive buffer incl. BREAK, SYNC, DATA and CHK (max. 12B)
LIN_Master_Base::frame_t type
LIN frame type.
LIN_Master_Base(const char NameLIN[]="Master", const int8_t PinTxEN=INT8_MIN)
LIN master node constructor.
virtual LIN_Master_Base::state_t _sendBreak(void)
Send LIN break.
LIN_Master_Base::error_t sendMasterRequestBlocking(LIN_Master_Base::version_t Version=LIN_Master_Base::LIN_V2, uint8_t Id=0x00, uint8_t NumData=0, uint8_t Data[]=NULL)
Send a blocking LIN master request frame (no background operation)
uint32_t timeoutFrame
max. frame duration [us]