#include #include "ArduinoConfig.h" #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 //Define which port to use for the SPI Chip Select #define CS_PORT PORTC #define CS_DDR DDRC 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(14000000, MSBFIRST, SPI_MODE3)); CS_PORT = ~address; SPI.transfer(data, datalen); 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 | 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: 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]); } 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; Serial.begin(BAUD_RATE); Serial.println("Setting up Arduino IO interface board."); Serial.print("Configured baud rate for serial communication: "); Serial.println(BAUD_RATE, DEC); Serial.print("Size of serial receiver buffer: "); Serial.print(SERIAL_RX_BUFFER_SIZE, DEC);Serial.print(" bytes"); SPI.begin(); } void loop() { ; handleNewData(); delay(1000); }