#include #include "helper/SimpleRingBuffer.h" #include "helper/DleEncoder.h" #include "helper/crc_ccitt.h" #include //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 PORTB #define CS_DDR DDRB #define RING_BUFFER_SIZE 100 #define MAX_PACKET_LENGTH 100 #define SERIAL_RX_BUFFER_SIZE 256 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) { uint16_t crc = Calculate_CRC(data, len - 2); data[len - 2] = crc >> 8; data[len - 1] = crc; //we're being conservative here //TODO move this to global so other protocols can use it too uint8_t buffer[2 * len + 2]; buffer[0] = DleEncoder::STX; size_t writtenLen; ReturnValue_t result = DleEncoder::encode(data, len, buffer, sizeof(buffer), &writtenLen, true); if (result != HasReturnvaluesIF::RETURN_OK) { return; } Serial.write(buffer, writtenLen); } void transferSPI(uint8_t address, uint8_t *data, size_t datalen) { SPI.beginTransaction(SPISettings(100000, MSBFIRST, SPI_MODE3)); //CS_PORT = ~address; digitalWrite(10, LOW); //included for (size_t i = 0; i < datalen; i++) { //Serial.print("SentData is: ");Serial.println(data[i]); data[i] = SPI.transfer(data[i]); //Serial.print("Back from n-1 ");Serial.println(data[i]); } //SPI.transfer(data, datalen); delay(100); digitalWrite(10, HIGH); //CS_PORT = 0xff; SPI.endTransaction(); } void handlePacket(uint8_t *packet, size_t packetLen) { //Paket layout is: // 8 bit command | 8 bit address | 16bit length | byte data | 16 bit crc uint16_t crc = Calculate_CRC(packet, packetLen); if (crc != 0) { //Serial.println("invalid Checksum"); return; } uint16_t payloadLen = (packet[2] << 8) | packet[3]; if (payloadLen != packetLen - 6) { //Serial.println("invalid len"); return; } uint8_t command = packet[0]; uint8_t address = packet[1]; 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() //check reply: sendData(packet, packetLen); break; default: //Serial.println("invalid command"); 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)) { //Serial.println(rawData[firstSTXinRawData]); firstSTXinRawData++; } if (rawData[firstSTXinRawData] != DleEncoder::STX) { //there is no STX in our data, throw it away... //Serial.println("NO STX"); 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() { //Serial.println(ringBuffer.availableWriteSpace()); uint8_t i = 0; while (Serial.available()>0) { uint8_t byte = Serial.read(); ringBuffer.writeData(&byte, 1); } //Serial.println(ringBuffer.availableWriteSpace()); } void setup() { //CS_DDR = 0xff; //CS_PORT = 0xff; //CS_DDR |= (1<<); //CS_PORT |= (1<