/** * @file shellmatta_transport.c * @brief transport layer functions of shellmatta * @author Simon Fischer */ #include "shellmatta_transport.h" #include "shellmatta_crc.h" #include /* init global variables */ uint8_t protocolVersion = 0u; shellmatta_transport_packet_t packetType = 0u; uint8_t payloadLength = 0u; uint8_t source = 0u; uint8_t destination = 0u; uint32_t crc32 = 0u; uint8_t payloadCounter = 0u; uint8_t crcCounter = 0u; uint32_t packetSequenceCounter_h2s = 0u; uint32_t packetSequenceCounter_s2h = 0u; shellmatta_transport_layer_t transportLayerInst = { 0, 0, STATE_GET_SOH, false, false, false, NULL }; char payloadBuffer[SHELLMATTA_PAYLOAD_MAXLENGTH + 1]; shellmatta_retCode_t shellmatta_init_transport_inst() { transportLayerInst.h2s_sequenceCnt = 0; transportLayerInst.s2h_sequenceCnt = 0; transportLayerInst.state = STATE_GET_SOH; transportLayerInst.mandatory = false; transportLayerInst.active = false; transportLayerInst.continueStep = false; memset(payloadBuffer, 0, SHELLMATTA_PAYLOAD_MAXLENGTH + 1); return SHELLMATTA_OK; } shellmatta_retCode_t shellmatta_reset_transport() { transportLayerInst.state = STATE_GET_SOH; protocolVersion = 0u; packetType = 0u; payloadLength = 0u; source = 0u; destination = 0u; crc32 = 0u; payloadCounter = 0u; crcCounter = 0u; transportLayerInst.active = false; memset(payloadBuffer, 0, SHELLMATTA_PAYLOAD_MAXLENGTH + 1); return SHELLMATTA_OK; } shellmatta_retCode_t shellmatta_handle_transport_fsm(char *data) { switch (transportLayerInst.state) { case STATE_GET_SOH: if (SHELLMATTA_START_OF_HEADER == *data) { transportLayerInst.state = STATE_GET_PROTOCOL_VERSION; transportLayerInst.active = true; } else { transportLayerInst.state = STATE_MANUAL_INPUT; transportLayerInst.active = false; } break; case STATE_MANUAL_INPUT: break; case STATE_GET_PROTOCOL_VERSION: transportLayerInst.state = STATE_GET_PACKET_TYPE; break; case STATE_GET_PACKET_TYPE: transportLayerInst.state = STATE_GET_PAYLOAD_LENGTH; break; case STATE_GET_PAYLOAD_LENGTH: transportLayerInst.state = STATE_GET_SOURCE; break; case STATE_GET_SOURCE: transportLayerInst.state = STATE_GET_DESTINATION; break; case STATE_GET_DESTINATION: transportLayerInst.state = STATE_GET_H2S_SEQUENCE_CNT; break; case STATE_GET_H2S_SEQUENCE_CNT: transportLayerInst.state = STATE_GET_S2H_SEQUENCE_CNT; break; case STATE_GET_S2H_SEQUENCE_CNT: transportLayerInst.state = STATE_GET_PAYLOAD; break; case STATE_GET_PAYLOAD: if ( (payloadLength <= payloadCounter) && (true == transportLayerInst.active)) { transportLayerInst.state = STATE_GET_CRC; } break; case STATE_GET_CRC: if (SHELLMATTA_LENGTH_CRC <= crcCounter) { char data[SHELLMATTA_PAYLOAD_MAXLENGTH + 1 + SHELLMATTA_HEADER_LENGTH]; memset(data, 0, SHELLMATTA_PAYLOAD_MAXLENGTH + 1 + SHELLMATTA_HEADER_LENGTH); data[0] = SHELLMATTA_START_OF_HEADER; data[1] = protocolVersion; data[2] = packetType; data[3] = payloadLength; data[4] = source; data[5] = destination; data[6] = transportLayerInst.h2s_sequenceCnt; data[7] = transportLayerInst.s2h_sequenceCnt; strncat(&data[8], payloadBuffer, payloadLength); uint32_t refCrc; refCrc = crc32Calc(data, SHELLMATTA_HEADER_LENGTH + payloadLength); if (crc32 == refCrc) { /* crc is correct */ switch (packetType) { case PACKET_DATA: transportLayerInst.state = STATE_PROCESS_PAYLOAD; transportLayerInst.h2s_sequenceCnt++; break; case PACKET_SEQ_CNT_REQUEST: transportLayerInst.h2s_sequenceCnt++; break; case PACKET_SEQ_CNT_RESPOND: transportLayerInst.h2s_sequenceCnt++; break; case PACKET_MAX_BUFFERSIZE_REQUEST: transportLayerInst.h2s_sequenceCnt++; break; case PACKET_MAX_BUFFERSIZE_RESPOND: transportLayerInst.h2s_sequenceCnt++; break; case PACKET_SEARCH_DEVICE_REQUEST: transportLayerInst.h2s_sequenceCnt++; break; case PACKET_SEARCH_DEVICE_RESPOND: transportLayerInst.h2s_sequenceCnt++; break; case PACKET_SET_ADDRESS_REQUEST: transportLayerInst.h2s_sequenceCnt++; break; case PACKET_SET_ADDRESS_RESPOND: transportLayerInst.h2s_sequenceCnt++; break; /* should not happen */ default: break; } break; } else { /* crc is incorrect */ return SHELLMATTA_ERROR; } } break; case STATE_PROCESS_PAYLOAD: transportLayerInst.state = STATE_GET_SOH; protocolVersion = 0u; packetType = 0u; payloadLength = 0u; source = 0u; destination = 0u; crc32 = 0u; payloadCounter = 0u; crcCounter = 0u; transportLayerInst.active = false; memset(payloadBuffer, 0, SHELLMATTA_PAYLOAD_MAXLENGTH + 1); break; default: break; } return SHELLMATTA_OK; } shellmatta_retCode_t shellmatta_write_transport(const char* data, uint32_t length) { uint8_t outputBuffer[ SHELLMATTA_HEADER_LENGTH + /* length of header */ SHELLMATTA_PAYLOAD_MAXLENGTH + 1 + /* max length of payload */ SHELLMATTA_LENGTH_CRC]; /* length of crc */ uint8_t outPayloadLength = length + SHELLMATTA_HEADER_LENGTH + SHELLMATTA_LENGTH_CRC; outputBuffer[0] = SHELLMATTA_START_OF_HEADER; outputBuffer[1] = 0x01u; outputBuffer[2] = 0x00u; outputBuffer[3] = length; outputBuffer[4] = 0x01u; outputBuffer[5] = 0x00u; outputBuffer[6] = transportLayerInst.h2s_sequenceCnt; outputBuffer[7] = ++transportLayerInst.s2h_sequenceCnt; memcpy(&outputBuffer[8], data, length); uint32_t outCrc = crc32Calc((char*) outputBuffer, SHELLMATTA_HEADER_LENGTH + length); outputBuffer[length + SHELLMATTA_HEADER_LENGTH + 0] = (uint8_t)(outCrc >> 0); outputBuffer[length + SHELLMATTA_HEADER_LENGTH + 1] = (uint8_t)(outCrc >> 8); outputBuffer[length + SHELLMATTA_HEADER_LENGTH + 2] = (uint8_t)(outCrc >> 16); outputBuffer[length + SHELLMATTA_HEADER_LENGTH + 3] = (uint8_t)(outCrc >> 24); shellmatta_retCode_t ret = transportLayerInst.originalWrite((char*) outputBuffer, outPayloadLength); return ret; }