Skip to content

Commit 14c5dae

Browse files
committed
fixed index bug in storing data to ring buffer
1 parent 49d1112 commit 14c5dae

17 files changed

+404
-37
lines changed

.gitattributes

-17
This file was deleted.

.gitignore

100644100755
File mode changed.

LICENSE

100644100755
File mode changed.

README.md

100644100755
+4-5
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
The **NeoHWSerial** class is a drop-in replacement for the Arduino built-in class `HardwareSerial`. It adds the capability to handle received characters with a user-defined function *during* the RX interrupt. This can improve performance significantly by eliminating all processing associated with storing and retrieving characters in the ring buffer **and** all polling code that constantly checked for new characters: `available` and `read` are unnecessary.
22

33
Note: This is a minor update of [NeoHWSerial by SlashDevin](https://github.com/SlashDevin/NeoHWSerial) for AVR. Changes:
4-
- updated to Arduino IDE >=v1.5.6 library format (see [here](https://arduino.github.io/arduino-cli/latest/library-specification/))
5-
- pass UART status byte to user receive function. Required e.g. for break detection in [LIN bus](https://en.wikipedia.org/wiki/Local_Interconnect_Network)
4+
- updated library structure to Arduino IDE >=v1.5.6 library format (see [here](https://arduino.github.io/arduino-cli/latest/library-specification/))
5+
- pass UART status byte to user receive function. Required e.g. for break detection for [LIN bus](https://en.wikipedia.org/wiki/Local_Interconnect_Network)
66
- support optional storing to ring buffer after return from user routine via return value
77

88

99
### Installation
1010

11-
1. Download the NeoHWSerial master zip file.
12-
2. Extract all files into a tempory working directory.
13-
3. Create a `NeoHWSerial` subdirectory in your `Arduino/libraries` directory.
11+
This library can be installed via the library manager of the Arduino IDE.
12+
1413

1514
### Usage
1615

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
Simple LIN 2.x master to generate frames for the LIN sniffer
3+
Create alternating frames of lengths 8 and 2.
4+
*/
5+
6+
// include files
7+
#include "LIN_master3.h" // send LIN frames via Serial3
8+
9+
// pause between LIN frames
10+
#define LIN_PAUSE 200
11+
12+
13+
void setup(void)
14+
{
15+
// initialize LIN master (blocking operation)
16+
LIN_master3.begin(19200, LIN_V2, false);
17+
18+
} // setup()
19+
20+
21+
22+
void loop(void)
23+
{
24+
static uint32_t lastCall = LIN_PAUSE;
25+
static uint8_t count = 0;
26+
static uint8_t Tx[8] = {0,0,0,0,0,0,0,0}; // daty bytes
27+
28+
29+
// simple LIN scheduler
30+
if (millis() - lastCall > LIN_PAUSE) {
31+
lastCall = millis();
32+
33+
// send frame 1
34+
if (count == 0)
35+
{
36+
// increase frame index
37+
count++;
38+
39+
// send master request
40+
LIN_master3.sendMasterRequest(0x07, 8, Tx);
41+
42+
// increase data_byte[0]
43+
Tx[0]++;
44+
45+
}
46+
47+
// send frame 2
48+
else
49+
{
50+
// revert frame index
51+
count = 0;
52+
53+
// send master request
54+
LIN_master3.sendMasterRequest(0x04, 2, Tx);
55+
56+
// decrease data_byte[1]
57+
Tx[1]--;
58+
59+
}
60+
61+
} // scheduler
62+
63+
} // loop()

examples/LIN_sniffer/LIN_sniffer.ino

+212
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
////////////////
2+
// INCLUDE LIBRARIES
3+
////////////////
4+
5+
#include <NeoHWSerial.h>
6+
7+
8+
////////////////
9+
// GLOBAL MACROS / DEFINES
10+
////////////////
11+
12+
// LIN versions (required for checksum calculation)
13+
#define LIN_V1 1
14+
#define LIN_V2 2
15+
16+
17+
////////////////
18+
// GLOBAL STRUCTS / TYPEDEFS
19+
////////////////
20+
21+
// frame type
22+
typedef struct
23+
{
24+
int numData; // number of data bytes
25+
26+
union
27+
{
28+
uint8_t bufRx[12]; // raw frame: BRK, SYNC, ID, DATA0..8, CHK
29+
30+
// access to individual bytes by name
31+
struct
32+
{
33+
uint8_t BRK; // sync break (always 0x00)
34+
uint8_t SYNC; // sync field (always 0x55)
35+
uint8_t ID; // frame ID
36+
uint8_t DATA[8]; // data bytes (max. 8)
37+
uint8_t CHK; // frame checksum
38+
};
39+
40+
};
41+
42+
} frame_t;
43+
44+
45+
////////////////
46+
// GLOBAL VARIABLES
47+
////////////////
48+
49+
// global frame buffer
50+
frame_t frame;
51+
52+
// flag to indicate that frame was received. Set in Serial Rx-ISR on reception of next BRK
53+
bool flagFrame = false;
54+
55+
56+
////////////////
57+
// GLOBAL FUNCTIONS
58+
////////////////
59+
60+
/////////////////////
61+
// calculate the LIN frame checksum
62+
// note: checksum is different for v1.x and v2.x; exceptions are diagnostic frames which use v1.x checksum
63+
/////////////////////
64+
uint8_t LIN_checksum(uint8_t version, uint8_t id, uint8_t numData, uint8_t *data)
65+
{
66+
uint16_t chk=0x00;
67+
68+
// LIN2.x uses extended checksum which includes protected ID, i.e. including parity bits
69+
// LIN1.x uses classical checksum only over data bytes
70+
// Diagnostic frames with ID 0x3C and 0x3D/0x7D always use classical checksum (see LIN spec "2.3.1.5 Checkum")
71+
if (!((version == LIN_V1) || (id == 0x3C) || (id == 0x7D))) // if version 2 & no diagnostic frames (0x3C=60 (PID=0x3C) or 0x3D=61 (PID=0x7D))
72+
chk = (uint16_t) id;
73+
74+
// loop over data bytes
75+
for (uint8_t i = 0; i < numData; i++)
76+
{
77+
chk += (uint16_t) (data[i]);
78+
if (chk>255)
79+
chk -= 255;
80+
}
81+
chk = (uint8_t)(0xFF - ((uint8_t) chk)); // bitwise invert
82+
83+
// return frame checksum
84+
return chk;
85+
86+
} // LIN_checksum()
87+
88+
89+
90+
/////////////////////
91+
// custom Serial receive interrupt function
92+
/////////////////////
93+
static bool ISR_Rx( uint8_t rx, uint8_t UCSRA )
94+
{
95+
static uint8_t idx = 0; // byte index in frame
96+
static uint8_t Rx[12];
97+
98+
// check for LIN sync break (=0x00 with framing error)
99+
if ((rx == 0x00) && (UCSRA & (1<<FE0)))
100+
{
101+
// previous frame complete -> set flag. Skip for first frame
102+
if (frame.BRK != 0xFF)
103+
flagFrame = true;
104+
105+
// copy previous frame to global variables to avoid conflict
106+
frame.numData = (int) idx - 3;
107+
memcpy(frame.bufRx, Rx, 12);
108+
frame.CHK = Rx[idx];
109+
110+
// reset byte index in frame
111+
idx=0;
112+
113+
} // sync break received
114+
115+
116+
// normal frame bytes -> just increase byte index in frame
117+
else
118+
{
119+
// avoid buffer overrun
120+
if (idx<11)
121+
idx++;
122+
123+
} // normal frame bytes
124+
125+
126+
// copy received byte to local buffer
127+
Rx[idx] = rx;
128+
129+
// do not store received data to Serial ring buffer
130+
return false;
131+
132+
} // ISR_Rx()
133+
134+
135+
136+
/////////////////////
137+
// initialization
138+
/////////////////////
139+
void setup()
140+
{
141+
// initialize BRK to 0xFF to indicate 1st frame
142+
frame.BRK = 0xFF;
143+
144+
// initilize PC connection
145+
NeoSerial.begin(115200);
146+
147+
// initialize LIN interface
148+
NeoSerial2.begin(19200);
149+
150+
// attach protocol handler to used Serial
151+
NeoSerial2.attachInterrupt( ISR_Rx );
152+
153+
} // setup()
154+
155+
156+
157+
/////////////////////
158+
// main loop
159+
/////////////////////
160+
void loop()
161+
{
162+
// a LIN frame was received --> handle it
163+
if (flagFrame)
164+
{
165+
// handle each frame only once
166+
flagFrame = false;
167+
168+
// check sync break (must be 0x00 w/ framing error)
169+
if (frame.BRK != 0x00)
170+
{
171+
NeoSerial.print("error: wrong BRK, expect 0x00, read 0x");
172+
NeoSerial.println((int) (frame.BRK), HEX);
173+
}
174+
175+
// check sync field (must be 0x55)
176+
else if (frame.SYNC != 0x55)
177+
{
178+
NeoSerial.print("error: wrong SYNC, expect 0x55, read 0x");
179+
NeoSerial.println((int) (frame.SYNC), HEX);
180+
}
181+
182+
// check frame checksum (different for LIN v1.x and v2.x!)
183+
else if (frame.CHK != LIN_checksum(LIN_V2, frame.ID, frame.numData, frame.DATA))
184+
{
185+
NeoSerial.print("error: checksum error, expect 0x");
186+
NeoSerial.print((int) (LIN_checksum(LIN_V2, frame.ID, frame.numData, frame.DATA)), HEX);
187+
NeoSerial.print(", read 0x");
188+
NeoSerial.println((int) (frame.CHK), HEX);
189+
}
190+
191+
// no error -> handle frame (here only print)
192+
else {
193+
194+
// print ID
195+
NeoSerial.print("ID:");
196+
NeoSerial.print((int) frame.ID, HEX);
197+
NeoSerial.print(" ");
198+
199+
// print data bytes
200+
NeoSerial.print("DATA:");
201+
for (int i=0; i<frame.numData; i++)
202+
{
203+
NeoSerial.print((int) (frame.DATA[i]), HEX);
204+
NeoSerial.print(" ");
205+
}
206+
NeoSerial.println();
207+
208+
} // no error
209+
210+
} // handle previous LIN frame
211+
212+
} // loop()

0 commit comments

Comments
 (0)