Compare commits
2 Commits
1608006860
...
3805df529b
Author | SHA1 | Date |
---|---|---|
|
3805df529b | |
|
0fccb086c8 |
|
@ -121,6 +121,8 @@ SLGreen implements the SLCAN (Lawicel) protocol to allow interactive communicati
|
|||
|
||||
A lot of features are yet to be integrated into this project, so any help doing this will be greatly appreciated !
|
||||
|
||||
The code also hasn't been heavily tested, so **if you encounter issues, please report them** !
|
||||
|
||||
If you wish to contribute, please fork the repository, create a new branch for your changes, and submit a pull request for review.
|
||||
|
||||
### License
|
||||
|
|
225
SLGreen.ino
225
SLGreen.ino
|
@ -15,10 +15,10 @@
|
|||
*/
|
||||
|
||||
//----- CONFIGURATION -----//
|
||||
#define MCP_CS 10;
|
||||
#define MCP_FREQUENCY MCP_8MHZ //Available values : MCP_8MHZ, MCP_16MHZ, MCP_20MHZ
|
||||
#define SERIAL_SPEED 115200 //Recommended values : 115200, 150000, 250000, 500000, 1000000, 2000000
|
||||
#DEFAULT_CAN_SPEED CAN_500KBPS; //Available values : CAN_10KBPS, CAN_20KBPS, CAN_50KBPS, CAN_100KBPS, CAN_125KBPS, CAN_250KBPS, CAN_500KBPS, CAN_1000KBPS
|
||||
#define MCP_CS 10
|
||||
#define MCP_FREQUENCY MCP_8MHZ //Available values : MCP_8MHZ, MCP_16MHZ, MCP_20MHZ
|
||||
#define SERIAL_SPEED 115200 //Recommended values : 115200, 150000, 250000, 500000, 1000000, 2000000
|
||||
#define DEFAULT_CAN_SPEED CAN_500KBPS; //Available values : CAN_10KBPS, CAN_20KBPS, CAN_50KBPS, CAN_100KBPS, CAN_125KBPS, CAN_250KBPS, CAN_500KBPS, CAN_1000KBPS
|
||||
//----------//
|
||||
|
||||
//Don't forget to search in mcp_can library sources to understand how functions works
|
||||
|
@ -38,79 +38,52 @@ uint8_t rx_buffer_len = 0;
|
|||
uint8_t CAN_speed = CAN_500KBPS;
|
||||
uint8_t CAN_freq = MCP_8MHZ;
|
||||
bool CAN_active = false;
|
||||
bool auto_poll = false;
|
||||
uint8_t buffered_frame[25] = {0};
|
||||
uint8_t buffered_frame_len = 0;
|
||||
|
||||
void loop() {
|
||||
slcanCheckRX();
|
||||
|
||||
if (CAN.checkReceive() == CAN_MSGAVAIL && CAN_active) {
|
||||
uint32_t id = 0;
|
||||
uint8_t len = 0;
|
||||
byte cdata[8] = {0};
|
||||
CAN.readMsgBuf(&id, &len, cdata);
|
||||
|
||||
id = id & 0x1FFFFFFF;
|
||||
|
||||
buffered_frame[0] = int2asciiHex((id >> 28) & 0xF);
|
||||
buffered_frame[1] = int2asciiHex((id >> 24) & 0xF);
|
||||
buffered_frame[2] = int2asciiHex((id >> 20) & 0xF);
|
||||
buffered_frame[3] = int2asciiHex((id >> 16) & 0xF);
|
||||
buffered_frame[4] = int2asciiHex((id >> 12) & 0xF);
|
||||
buffered_frame[5] = int2asciiHex((id >> 8) & 0xF);
|
||||
buffered_frame[6] = int2asciiHex((id >> 4) & 0xF);
|
||||
buffered_frame[7] = int2asciiHex(id & 0xF);
|
||||
buffered_frame[8] = int2asciiHex(len);
|
||||
|
||||
for(int i = 0; i <= len*2; i++)
|
||||
{
|
||||
buffered_frame[9+i] = (i % 2 == 1) ? int2asciiHex(cdata[i / 2] >> 4) : int2asciiHex(cdata[i / 2] & 0xF);
|
||||
}
|
||||
|
||||
if(auto_poll)
|
||||
{
|
||||
slcanFrameTX(buffered_frame, 9 + len*2);
|
||||
}
|
||||
else
|
||||
{
|
||||
buffered_frame_len = 9 + len*2;
|
||||
}
|
||||
}
|
||||
serialCheckRX();
|
||||
canCheckRX();
|
||||
}
|
||||
|
||||
void slcanCheckRX() {
|
||||
void serialCheckRX() {
|
||||
if(Serial.available())
|
||||
{
|
||||
byte received_char = Serial.read();
|
||||
if(received_char != 13)//Process the character received
|
||||
|
||||
// If the character is not a Carriage Return, we have received a character of a frame
|
||||
// The character is added to the buffer and the function ends here
|
||||
if(received_char != 13)
|
||||
{
|
||||
rx_buffer[rx_buffer_len] = received_char;
|
||||
rx_buffer_len++;
|
||||
if(rx_buffer_len > 15) rx_buffer_len = 0; //Frame too long, destroying the buffer
|
||||
|
||||
//If the frame is too long, delete the buffer content to avoid a buffer overflow
|
||||
//The length 26 has been choosen as the max length of any incoming message (excluding the CR)
|
||||
if(rx_buffer_len > 26) rx_buffer_len = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
// If the character received is a CR, the function continues and the buffer is processed
|
||||
|
||||
if(rx_buffer_len < 1)//Frame too short, drop it
|
||||
{
|
||||
rx_buffer_len = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
slcanProcessRX(rx_buffer_len, rx_buffer);
|
||||
rx_buffer_len = 0;
|
||||
serialProcessRX(rx_buffer_len, rx_buffer);
|
||||
rx_buffer_len = 0;//Reset the buffer
|
||||
}
|
||||
}
|
||||
|
||||
void slcanProcessRX(uint8_t rx_buffer_len, uint8_t *rx_buffer)
|
||||
void serialProcessRX(uint8_t rx_buffer_len, uint8_t *rx_buffer)
|
||||
{
|
||||
// No frame can be shorter than 1 character (excluding the CR)
|
||||
if(rx_buffer_len < 1)
|
||||
{
|
||||
rx_buffer_len = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if(rx_buffer[0] == 'S')
|
||||
{
|
||||
if(rx_buffer_len != 2) return slcanInvalidRX();
|
||||
if(CAN_active) return slcanInvalidRX();
|
||||
|
||||
uint8_t speed = rx_buffer[1] - 0x30;
|
||||
uint8_t speed = asciiHex2int(rx_buffer[1]);
|
||||
|
||||
switch(speed)
|
||||
{
|
||||
|
@ -138,8 +111,9 @@ void slcanProcessRX(uint8_t rx_buffer_len, uint8_t *rx_buffer)
|
|||
case 8:
|
||||
CAN_speed = CAN_1000KBPS;
|
||||
break;
|
||||
case 7:// 800kbps not implemented
|
||||
default:
|
||||
slcanInvalidRX();
|
||||
return slcanInvalidRX();
|
||||
}
|
||||
|
||||
Serial.write(13);
|
||||
|
@ -149,11 +123,10 @@ void slcanProcessRX(uint8_t rx_buffer_len, uint8_t *rx_buffer)
|
|||
{
|
||||
if(CAN_active) return slcanInvalidRX();
|
||||
|
||||
CAN_active = true;
|
||||
|
||||
if(CAN.begin(MCP_ANY, CAN_speed, CAN_freq) != CAN_OK) return slcanInvalidRX();
|
||||
CAN.setMode(MCP_NORMAL);
|
||||
|
||||
CAN_active = true;
|
||||
Serial.write(13);
|
||||
}
|
||||
|
||||
|
@ -177,50 +150,41 @@ void slcanProcessRX(uint8_t rx_buffer_len, uint8_t *rx_buffer)
|
|||
Serial.write(13);
|
||||
}
|
||||
|
||||
else if(rx_buffer[0] == 't')
|
||||
else if(rx_buffer[0] == 't' || rx_buffer[0] == 'T')
|
||||
{
|
||||
if(!CAN_active) return slcanInvalidRX();
|
||||
|
||||
uint16_t address = (asciiHex2int(rx_buffer[1]) << 8) + (asciiHex2int(rx_buffer[2]) << 4) + asciiHex2int(rx_buffer[3]);
|
||||
uint8_t length = asciiHex2int(rx_buffer[1]);
|
||||
bool extended_frame = (rx_buffer[0] == 't') ? 0 : 1;
|
||||
|
||||
if(address > 0x7FF) return slcanInvalidRX();
|
||||
if(length > 8) return slcanInvalidRX();
|
||||
if(rx_buffer_len != length * 2 + 5) return slcanInvalidRX();
|
||||
|
||||
uint8_t buf[length] = {0};
|
||||
for(int i = 5; i < rx_buffer_len; i++)
|
||||
uint32_t address = 0;
|
||||
if(!extended_frame)
|
||||
{
|
||||
buf[i] |= (i % 2 == 0) ? asciiHex2int(rx_buffer[i]) << 4 : asciiHex2int(rx_buffer[i]);
|
||||
address = (asciiHex2int(rx_buffer[1]) << 8) +
|
||||
(asciiHex2int(rx_buffer[2]) << 4) +
|
||||
asciiHex2int(rx_buffer[3]);
|
||||
}
|
||||
else
|
||||
{
|
||||
address = ((uint32_t)asciiHex2int(rx_buffer[1]) << 28) +
|
||||
((uint32_t)asciiHex2int(rx_buffer[2]) << 24) +
|
||||
((uint32_t)asciiHex2int(rx_buffer[3]) << 20) +
|
||||
((uint32_t)asciiHex2int(rx_buffer[4]) << 16) +
|
||||
((uint32_t)asciiHex2int(rx_buffer[5]) << 12) +
|
||||
((uint32_t)asciiHex2int(rx_buffer[6]) << 8) +
|
||||
((uint32_t)asciiHex2int(rx_buffer[7]) << 4) +
|
||||
((uint32_t)asciiHex2int(rx_buffer[8]) << 0);
|
||||
}
|
||||
|
||||
canTX(address, length, buf);
|
||||
|
||||
Serial.write(13);
|
||||
}
|
||||
|
||||
else if(rx_buffer[0] == 'T')
|
||||
{
|
||||
if(!CAN_active) return slcanInvalidRX();
|
||||
|
||||
uint32_t address = ((uint32_t)asciiHex2int(rx_buffer[1]) << 28) +
|
||||
((uint32_t)asciiHex2int(rx_buffer[2]) << 24) +
|
||||
((uint32_t)asciiHex2int(rx_buffer[3]) << 20) +
|
||||
((uint32_t)asciiHex2int(rx_buffer[4]) << 16) +
|
||||
((uint32_t)asciiHex2int(rx_buffer[5]) << 12) +
|
||||
((uint32_t)asciiHex2int(rx_buffer[6]) << 8) +
|
||||
((uint32_t)asciiHex2int(rx_buffer[7]) << 4) +
|
||||
((uint32_t)asciiHex2int(rx_buffer[8]) << 0);
|
||||
uint8_t length = asciiHex2int(rx_buffer[9]);
|
||||
uint8_t length = asciiHex2int(rx_buffer[4 + 5*extended_frame]);
|
||||
|
||||
if(address > 0x1FFFFFFF) return slcanInvalidRX();
|
||||
if(length > 8) return slcanInvalidRX();
|
||||
if(rx_buffer_len != length * 2 + 10) return slcanInvalidRX();
|
||||
if(length > 8) return slcanInvalidRX();
|
||||
if(rx_buffer_len != length * 2 + 5 + 5*extended_frame) return slcanInvalidRX();
|
||||
|
||||
uint8_t buf[length] = {0};
|
||||
for(int i = 10; i < rx_buffer_len; i++)
|
||||
for(int i = 5 + 5*extended_frame; i < rx_buffer_len; i++)
|
||||
{
|
||||
buf[i] |= (i % 2 == 1) ? asciiHex2int(rx_buffer[i]) << 4 : asciiHex2int(rx_buffer[i]);
|
||||
buf[i] |= ((i+extended_frame) % 2 == 0) ? asciiHex2int(rx_buffer[i]) << 4 : asciiHex2int(rx_buffer[i]);
|
||||
}
|
||||
|
||||
canTX(address, length, buf);
|
||||
|
@ -228,34 +192,6 @@ void slcanProcessRX(uint8_t rx_buffer_len, uint8_t *rx_buffer)
|
|||
Serial.write(13);
|
||||
}
|
||||
|
||||
else if(rx_buffer[0] == 'P' || rx_buffer[0] == 'A')
|
||||
{
|
||||
if(!CAN_active) return slcanInvalidRX();
|
||||
if(auto_poll) return slcanInvalidRX();
|
||||
|
||||
slcanFrameTX(buffered_frame, buffered_frame_len);
|
||||
buffered_frame_len = 0;
|
||||
Serial.write(13);
|
||||
}
|
||||
|
||||
else if(rx_buffer[0] == 'X')
|
||||
{
|
||||
if(rx_buffer_len != 2) return slcanInvalidRX();
|
||||
|
||||
switch(asciiHex2int(rx_buffer[1]))
|
||||
{
|
||||
case 0:
|
||||
auto_poll = false;
|
||||
break;
|
||||
case 1:
|
||||
auto_poll = true;
|
||||
break;
|
||||
default:
|
||||
return slcanInvalidRX();
|
||||
}
|
||||
Serial.write(13);
|
||||
}
|
||||
|
||||
else if(rx_buffer[0] == 'V')
|
||||
{
|
||||
Serial.write('V');
|
||||
|
@ -269,13 +205,6 @@ void slcanProcessRX(uint8_t rx_buffer_len, uint8_t *rx_buffer)
|
|||
Serial.print("SLGR");
|
||||
Serial.write(13);
|
||||
}
|
||||
|
||||
else if(rx_buffer[0] == 'F') return;
|
||||
else if(rx_buffer[0] == 'W') return;
|
||||
else if(rx_buffer[0] == 'M') return;
|
||||
else if(rx_buffer[0] == 'm') return;
|
||||
else if(rx_buffer[0] == 'U') return;
|
||||
else if(rx_buffer[0] == 'Q') return;
|
||||
}
|
||||
|
||||
void slcanInvalidRX()
|
||||
|
@ -283,7 +212,7 @@ void slcanInvalidRX()
|
|||
Serial.write(7);
|
||||
}
|
||||
|
||||
void slcanFrameTX(uint8_t *buf, uint8_t len)
|
||||
void serialTX(uint8_t *buf, uint8_t len)
|
||||
{
|
||||
Serial.write('T');
|
||||
for(int i = 0; i < len; i++)
|
||||
|
@ -293,6 +222,52 @@ void slcanFrameTX(uint8_t *buf, uint8_t len)
|
|||
Serial.write(13);
|
||||
}
|
||||
|
||||
void canCheckRX()
|
||||
{
|
||||
if (CAN.checkReceive() == CAN_MSGAVAIL && CAN_active) {
|
||||
uint32_t id = 0;
|
||||
uint8_t len = 0;
|
||||
bool ext = true;
|
||||
byte cdata[8] = {0};
|
||||
CAN.readMsgBuf(&id, &len, cdata);
|
||||
|
||||
id = id & 0x1FFFFFFF;
|
||||
if(id <= 0x7FF) ext = false;
|
||||
|
||||
uint8_t frame[2+len*2+ext*5] = {0};
|
||||
|
||||
if(!ext)
|
||||
{
|
||||
frame[0] = int2asciiHex((id >> 8) & 0xF);
|
||||
frame[1] = int2asciiHex((id >> 4) & 0xF);
|
||||
frame[2] = int2asciiHex(id & 0xF);
|
||||
}
|
||||
else
|
||||
{
|
||||
frame[0] = int2asciiHex((id >> 28) & 0xF);
|
||||
frame[1] = int2asciiHex((id >> 24) & 0xF);
|
||||
frame[2] = int2asciiHex((id >> 20) & 0xF);
|
||||
frame[3] = int2asciiHex((id >> 16) & 0xF);
|
||||
frame[4] = int2asciiHex((id >> 12) & 0xF);
|
||||
frame[5] = int2asciiHex((id >> 8) & 0xF);
|
||||
frame[6] = int2asciiHex((id >> 4) & 0xF);
|
||||
frame[7] = int2asciiHex(id & 0xF);
|
||||
}
|
||||
|
||||
frame[3+ext*5] = int2asciiHex(len);
|
||||
|
||||
|
||||
|
||||
for(int i = 0; i < len*2; i++)
|
||||
{
|
||||
int i_bufpos = (len*2 - (i+1)) / 2;
|
||||
frame[(4+ext*5)+i] = (i_bufpos % 2 == 1) ? int2asciiHex(cdata[i_bufpos / 2] >> 4) : int2asciiHex(cdata[i_bufpos / 2] & 0xF);
|
||||
}
|
||||
|
||||
serialTX(frame, 2+len*2+ext*5);
|
||||
}
|
||||
}
|
||||
|
||||
void canTX(uint32_t address, uint8_t len, uint8_t *buf)
|
||||
{
|
||||
CAN.sendMsgBuf(address, address > 0x7FF ? 1 : 0, len, buf);
|
||||
|
|
Loading…
Reference in New Issue