eive_arduino_interface/main.cpp

173 lines
4.0 KiB
C++
Raw Normal View History

2020-04-02 18:32:37 +02:00
#include <Arduino.h>
#include "helper/SimpleRingBuffer.h"
#include "helper/DleEncoder.h"
#include "helper/crc_ccitt.h"
2020-04-15 17:50:30 +02:00
#include <avr/io.h>
2020-04-02 18:32:37 +02:00
//SPI is formally a library, so it is not part of the objects compiled
//from the core and we need to include it explicitly
#include "arduino_core/ArduinoCore-avr/libraries/SPI/src/SPI.h"
//Define which port to use for the SPI Chip Select
#define CS_PORT PORTC
#define CS_DDR DDRC
#define RING_BUFFER_SIZE 100
2020-04-20 12:34:41 +02:00
#define MAX_PACKET_LENGTH 100
2020-04-21 18:38:38 +02:00
#define SERIAL_RX_BUFFER_SIZE 256
2020-04-02 18:32:37 +02:00
static const uint8_t COMMAND_TRANSFER_SPI = 1;
SimpleRingBuffer ringBuffer(RING_BUFFER_SIZE, true);
uint8_t rawData[2 * RING_BUFFER_SIZE];
size_t rawDataSize = 0;
/**
* Encode and send the data, last two bytes of data are assumed to be for the checksum
* and will be overwritten with it
*/
void sendData(uint8_t *data, size_t len) {
2020-04-15 17:50:30 +02:00
uint16_t crc = Calculate_CRC(data, len - 2);
data[len - 2] = crc >> 8;
data[len - 1] = crc;
2020-04-02 18:32:37 +02:00
//we're being conservative here
//TODO move this to global so other protocols can use it too
2020-04-15 17:50:30 +02:00
uint8_t buffer[2 * len + 2];
2020-04-02 18:32:37 +02:00
buffer[0] = DleEncoder::STX;
size_t writtenLen;
2020-04-15 17:50:30 +02:00
ReturnValue_t result = DleEncoder::encode(data, len, buffer, sizeof(buffer),
&writtenLen, true);
if (result != HasReturnvaluesIF::RETURN_OK) {
2020-04-02 18:32:37 +02:00
return;
}
Serial.write(buffer, writtenLen);
}
void transferSPI(uint8_t address, uint8_t *data, size_t datalen) {
SPI.beginTransaction(SPISettings(14000000, MSBFIRST, SPI_MODE3));
2020-04-02 18:32:37 +02:00
CS_PORT = ~address;
2020-04-15 17:50:30 +02:00
SPI.transfer(data, datalen);
2020-04-02 18:32:37 +02:00
delay(100);
CS_PORT = 0xff;
SPI.endTransaction();
}
void handlePacket(uint8_t *packet, size_t packetLen) {
//Paket layout is:
// 8 bit command | 8 bit address | 16bit length | <length> byte data | 16 bit crc
2020-04-20 12:34:41 +02:00
2020-04-21 18:38:38 +02:00
2020-04-02 18:32:37 +02:00
uint16_t crc = Calculate_CRC(packet, packetLen);
2020-04-21 18:38:38 +02:00
2020-04-02 18:32:37 +02:00
if (crc != 0) {
Serial.println("invalid Checksum");
2020-04-02 18:32:37 +02:00
return;
}
uint16_t payloadLen = (packet[2] << 8) | packet[3];
2020-04-15 17:50:30 +02:00
if (payloadLen != packetLen - 6) {
Serial.println("invalid len");
2020-04-02 18:32:37 +02:00
return;
}
uint8_t command = packet[0];
uint8_t address = packet[1];
2020-04-21 18:38:38 +02:00
2020-04-02 18:32:37 +02:00
switch (command) {
case COMMAND_TRANSFER_SPI:
transferSPI(address, packet + 4, payloadLen);
//echo the data back, no need to change the header fields, they are the same
//checksum will be written by sendData()
2020-04-21 18:38:38 +02:00
//check reply:
Serial.println("Data response check: ");
for(size_t i =0; i< packetLen; i++){
Serial.print("packet nr ");Serial.print(i);Serial.print(" ");Serial.println(packet[i]);
}
2020-04-15 17:50:30 +02:00
sendData(packet, packetLen);
2020-04-02 18:32:37 +02:00
break;
default:
Serial.println("invalid command");
2020-04-02 18:32:37 +02:00
break;
}
}
void handleNewData() {
ringBuffer.readData(rawData, sizeof(rawData), true, &rawDataSize);
if (rawDataSize == 0) {
return;
}
//look for STX
size_t firstSTXinRawData = 0;
while ((firstSTXinRawData < rawDataSize)
&& (rawData[firstSTXinRawData] != DleEncoder::STX)) {
2020-04-21 18:38:38 +02:00
Serial.println(rawData[firstSTXinRawData]);
2020-04-02 18:32:37 +02:00
firstSTXinRawData++;
}
if (rawData[firstSTXinRawData] != DleEncoder::STX) {
//there is no STX in our data, throw it away...
2020-04-21 18:38:38 +02:00
Serial.println("NO STX");
2020-04-02 18:32:37 +02:00
ringBuffer.deleteData(rawDataSize);
return;
}
uint8_t packet[MAX_PACKET_LENGTH];
size_t packetLen;
size_t readSize;
ReturnValue_t result = DleEncoder::decode(rawData + firstSTXinRawData,
rawDataSize - firstSTXinRawData, &readSize, packet, sizeof(packet),
&packetLen);
size_t toDelete = firstSTXinRawData;
if (result == HasReturnvaluesIF::RETURN_OK) {
handlePacket(packet, packetLen);
//after handling the packet, we can delete it from the raw stream, it has been copied to packet
toDelete += readSize;
}
//remove Data which was processed
ringBuffer.deleteData(toDelete);
}
//TODO check if this is thread safe by arduino
void serialEvent() {
2020-04-20 12:34:41 +02:00
//Serial.println(ringBuffer.availableWriteSpace());
2020-04-21 18:38:38 +02:00
uint8_t i = 0;
while (Serial.available()>0) {
2020-04-02 18:32:37 +02:00
uint8_t byte = Serial.read();
ringBuffer.writeData(&byte, 1);
}
2020-04-20 12:34:41 +02:00
//Serial.println(ringBuffer.availableWriteSpace());
2020-04-02 18:32:37 +02:00
}
void setup() {
CS_DDR = 0xff;
CS_PORT = 0xff;
Serial.begin(9600);
SPI.begin();
}
void loop() {
2020-04-21 18:38:38 +02:00
;
2020-04-02 18:32:37 +02:00
handleNewData();
2020-04-21 18:38:38 +02:00
delay(1000);
2020-04-02 18:32:37 +02:00
}