LIN_master_portable_Arduino 1.9
Arduino library for Local Interconnect Network master node emulation
Loading...
Searching...
No Matches
LIN_master_SoftwareSerial.cpp
Go to the documentation of this file.
1
9// assert platform which supports SoftwareSerial. Note: ARDUINO_ARCH_ESP32 requires library ESPSoftwareSerial
10#if defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) || \
11 defined(ARDUINO_ARCH_MEGAAVR) || defined(ARDUINO_ARCH_STM32) || defined(ARDUINO_ARCH_RENESAS)
12
13// include files
15
16
23{
24 // if state is wrong, exit immediately
26 {
27 // print debug message
28 DEBUG_PRINT(1, "wrong state 0x%02X", this->state);
29
30 // set error state and return immediately
33 this->_disableTransmitter();
34 return this->state;
35 }
36
37 // empty buffers, just in case...
38 this->SWSerial.flush();
39 while (this->SWSerial.available())
40 this->SWSerial.read();
41
42 // Renesas core does not support listen()/stopListening(), see https://github.com/arduino/ArduinoCore-renesas/issues/522
43 #if !defined(ARDUINO_ARCH_RENESAS)
44 this->SWSerial.stopListening();
45 #endif
46
47 // optionally enable transmitter
48 this->_enableTransmitter();
49
50 // start BREAK directly via GPIO (less overhead than begin()). End BREAK in _sendFrame()
51 // Also bug in Renesas core: https://github.com/arduino/ArduinoCore-renesas/issues/523
52 digitalWrite(this->pinTx, this->inverseLogic ? HIGH : LOW);
53
54 // store BREAK start time
55 this->startBreak = micros();
56
57 // progress state
59
60 // print debug message
61 DEBUG_PRINT(3, " ");
62
63 // return state
64 return this->state;
65
66} // LIN_master_SoftwareSerial::_sendBreak()
67
68
69
76{
77 // if state is wrong, exit immediately
79 {
80 // print debug message
81 DEBUG_PRINT(1, "wrong state 0x%02X", this->state);
82
83 // set error state and return immediately
86 this->_disableTransmitter();
87 return this->state;
88 }
89
90 // after BREAK duration elapsed, release GPIO again and check for LIN echo
91 if ((micros() - this->startBreak) > this->durationBreak)
92 {
93 // terminate BREAK
94 digitalWrite(this->pinTx, this->inverseLogic ? LOW : HIGH);
95
96 // assert >=1b BREAK delimiter
97 delayMicroseconds(50);
98
99 // For STM32, listen must be before write
100 #if defined(ARDUINO_ARCH_STM32)
101 this->SWSerial.listen();
102 #endif
103
104 // blocking send rest of frame (response: SYNC+ID; request: SYNC+ID+DATA[]+CHK)
105 this->SWSerial.write(this->bufTx+1, this->lenTx-1);
106 //this->SWSerial.flush(); // not required because write() is blocking. Causes issue on STM32
107
108 // optionally disable RS485 transmitter after frame is completed
109 this->_disableTransmitter();
110
111 // Renesas core does not support listen()/stopListening(), see https://github.com/arduino/ArduinoCore-renesas/issues/522
112 // For STM32, listen must be before write above
113 #if !defined(ARDUINO_ARCH_RENESAS) && !defined(ARDUINO_ARCH_STM32)
114 this->SWSerial.listen();
115 #endif
116
117 // progress state
119
120 } // after BREAK elapsed
121
122 // print debug message
123 DEBUG_PRINT(2, " ");
124
125 // return state
126 return this->state;
127
128} // LIN_master_SoftwareSerial::_sendFrame()
129
130
131
138{
139 // if state is wrong, exit 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
152// Renesas core does not support listen()/stopListening() --> receive echo & response
153#if defined(ARDUINO_ARCH_RENESAS)
154
155 // echo + frame body received
156 if (this->SWSerial.available() >= this->lenRx)
157 {
158 // read into buffer
159 this->SWSerial.readBytes(this->bufRx, this->lenRx);
160
161// STM32 core receives echo w/o BREAK & response
162#elif defined(ARDUINO_ARCH_STM32)
163
164 // echo (w/o BREAK) + frame body received
165 if (this->SWSerial.available() >= this->lenRx-1)
166 {
167 // read into buffer
168 this->SWSerial.readBytes(this->bufRx+1, this->lenRx-1);
169
170 // emulate only ignored BREAK
171 this->bufRx[0] = this->bufTx[0];
172
173// other cores only receive slave response
174#else
175
176 // only response received
177 if (this->SWSerial.available() >= this->lenRx - this->lenTx) {
178
179 // read into buffer
180 this->SWSerial.readBytes(this->bufRx + this->lenTx, this->lenRx - this->lenTx);
181
182 // emulate ignored echo for sent bytes (incl. BREAK)
183 memcpy(this->bufRx, this->bufTx, this->lenTx);
184
185#endif // ARDUINO_ARCH_RENESAS
186
187 // check frame for errors
188 this->error = (LIN_Master_Base::error_t) ((int) this->error | (int) this->_checkFrame());
189
190 // progress state
192
193 } // frame body received
194
195 // frame body received not yet received
196 else
197 {
198 // check for timeout
199 if (micros() - this->timeStart > this->timeoutFrame)
200 {
201 // print debug message
202 DEBUG_PRINT(1, "Rx timeout");
203
204 // set error state and return immediately
207 this->_disableTransmitter();
208 return this->state;
209 }
210
211 } // not enough bytes received
212
213 // print debug message
214 DEBUG_PRINT(2, " ");
215
216 // return state
217 return this->state;
218
219} // LIN_master_SoftwareSerial::_receiveFrame()
220
221
222
232#if defined(ARDUINO_ARCH_RENESAS) // for Renesas core inverse logic is parameter for begin()
233 LIN_master_SoftwareSerial::LIN_master_SoftwareSerial(uint8_t PinRx, uint8_t PinTx, bool InverseLogic, const char NameLIN[], const int8_t PinTxEN) :
234 LIN_Master_Base::LIN_Master_Base(NameLIN, PinTxEN), SWSerial(PinRx, PinTx)
235#else
236 LIN_master_SoftwareSerial::LIN_master_SoftwareSerial(uint8_t PinRx, uint8_t PinTx, bool InverseLogic, const char NameLIN[], const int8_t PinTxEN) :
237 LIN_Master_Base::LIN_Master_Base(NameLIN, PinTxEN), SWSerial(PinRx, PinTx, InverseLogic)
238#endif
239{
240 // Debug serial initialized in begin() -> no debug output here
241
242 // store pins used for SW serial
243 this->pinRx = PinRx;
244 this->pinTx = PinTx;
245 this->inverseLogic = InverseLogic;
246
247 // must not open connection here, else (at least) ESP32 and ESP8266 fail
248
249 // cannot print debug message, as constructor is called before setup()
250
251} // LIN_master_SoftwareSerial::LIN_master_SoftwareSerial()
252
253
254
260void LIN_master_SoftwareSerial::begin(uint16_t Baudrate)
261{
262 // call base class method
263 LIN_Master_Base::begin(Baudrate);
264
265 // open serial interface. Timeout not required here
266 this->SWSerial.end();
267 #if defined(ARDUINO_ARCH_RENESAS)
268 this->SWSerial.begin(this->baudrate, SERIAL_8N1, this->inverseLogic);
269 #else
270 this->SWSerial.begin(this->baudrate);
271 #endif
272
273 // calculate duration of BREAK
274 this->durationBreak = this->timePerByte * 16 / 10;
275
276 // print debug message
277 DEBUG_PRINT(2, "ok");
278
279} // LIN_master_SoftwareSerial::begin()
280
281
282
288{
289 // call base class method
291
292 // close serial interface
293 this->SWSerial.end();
294
295 // print debug message
296 DEBUG_PRINT(2, " ");
297
298} // LIN_master_SoftwareSerial::end()
299
300
301#endif // ARDUINO_ARCH_AVR || ARDUINO_ARCH_ESP8266 || ARDUINO_ARCH_ESP32 || ARDUINO_ARCH_MEGAAVR || ARDUINO_ARCH_STM32 || ARDUINO_ARCH_RENESAS
302
303
304/*-----------------------------------------------------------------------------
305 END OF FILE
306-----------------------------------------------------------------------------*/
LIN master emulation library for SoftwareSerial.
uint8_t lenRx
receive buffer length (max. 12)
virtual void begin(uint16_t Baudrate=19200)
Open serial interface.
uint16_t baudrate
communication baudrate [Baud]
uint8_t bufTx[12]
send buffer incl. BREAK, SYNC, DATA and CHK (max. 12B)
LIN_Master_Base::error_t _checkFrame(void)
Check received LIN frame.
LIN_Master_Base::error_t error
error state. Is latched until cleared
void _enableTransmitter(void)
Enable RS485 transmitter (DE=high)
uint32_t timeStart
starting time [us] for frame timeout
uint8_t lenTx
send buffer length (max. 12)
LIN_Master_Base::state_t state
status of LIN state machine
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_TIMEOUT
frame timeout error
uint32_t timePerByte
time [us] per byte at specified baudrate
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_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(const char NameLIN[]="Master", const int8_t PinTxEN=INT8_MIN)
LIN master node constructor.
uint32_t timeoutFrame
max. frame duration [us]
LIN_master_SoftwareSerial(uint8_t PinRx, uint8_t PinTx, bool InverseLogic=false, const char NameLIN[]="Master", const int8_t PinTxEN=INT8_MIN)
Class constructor.
LIN_Master_Base::state_t _sendBreak(void)
Send LIN break.
LIN_Master_Base::state_t _sendFrame(void)
Send LIN bytes (request frame: SYNC+ID+DATA[]+CHK; response frame: SYNC+ID)
void end(void)
Close serial interface.
LIN_Master_Base::state_t _receiveFrame(void)
Read and check LIN frame.
void begin(uint16_t Baudrate=19200)
Open serial interface.