// // Created by CFIF on 07.11.23. // #include #include "XfcProtRequester.h" #include "SerialPort.h" #define XFC_PROT_REQUESTER_DEFAULT_TIMEOUT (1000); void XfcProtRequester_reset(tXfcProtRequester *env) { XfcArrayClear(&env->requestBuffer); XfcArrayClear(&env->responseBuffer); } void XfcProtRequester_init( tXfcProtRequester *env, tSerialPortIO *io, tXfcArray requestBuffer, tXfcArray responseBuffer, tXfcProtMagicNumbers magicNumbers ) { env->io = io; env->transmitTimeout = XFC_PROT_REQUESTER_DEFAULT_TIMEOUT; env->requestBuffer = requestBuffer; env->responseBuffer = responseBuffer; env->encoder.magic = magicNumbers.request; env->decoder.magic = magicNumbers.response; env->encoder.buffer = &env->requestBuffer; env->decoder.buffer = &env->responseBuffer; XfcProtRequester_reset(env); } eXfcProtRequesterStatus XfcProtRequester_makeRequest( tXfcProtRequester *env, uint16_t id, void *builder, tXfcRequesterMethod buildMethod, void *parser, tXfcRequesterMethod parseMethod, int32_t timeout ) { SerialPortClearRxBuffer(env->io); XfcArrayClear(env->decoder.buffer); XfcArrayClear(env->encoder.buffer); tXfcArray request = XfcTransPackEncoderGetDataSegmentAsArray(&env->encoder); XfcArrayClear(&request); if (buildMethod) { switch (buildMethod(builder, &request)) { case XFC_TRANSPORT_PROTOCOL_RESPONSE_RESULT_OK: break; case XFC_TRANSPORT_PROTOCOL_RESPONSE_RESULT_CMD_OVERFLOW: return eXfcProtRequesterStatus_REQUEST_BUILD_OVERFLOW; case XFC_TRANSPORT_PROTOCOL_RESPONSE_RESULT_EXECUTION_ERROR: return eXfcProtRequesterStatus_BUILD_EXECUTION_ERROR; default: return eXfcProtRequesterStatus_UNKNOWN_ERROR; } } XfcTransPackEncoderSetId(&env->encoder, id); XfcTransPackEncoderSetDataSegmentLength(&env->encoder, XfcArrayGetDataSize(&request)); XfcTransPackEncoderFinalizeAndSignCrc(&env->encoder); uint16_t transmitted = SerialPortTransmit( env->io, env->encoder.buffer->data, XfcArrayGetDataSize(env->encoder.buffer), env->transmitTimeout ); if (transmitted != XfcArrayGetDataSize(env->encoder.buffer)) { return eXfcProtRequesterStatus_TRANSMIT_ERROR; } uint8_t byte; int32_t timeEnd = SystemGetMs() + timeout; while (timeEnd >= SystemGetMs()) { if (!SerialPortReceive(env->io, &byte, 1, timeout)) { continue; } if (!XfcArrayAddByte(env->decoder.buffer, byte)) { return eXfcProtRequesterStatus_RECIVE_BUFFER_OVERFLOW; } if (!XfcTransPackDecoderIsStartsWithMagick(&env->decoder)) { return eXfcProtRequesterStatus_PREFIX_MISMATCH; } if (!XfcTransPackDecoderHasHeader(&env->decoder)) { continue; } if (XfcTransPackDecoderGetRequiredFullPackLength(&env->decoder) > env->decoder.buffer->limit) { return eXfcProtRequesterStatus_RECIVE_BUFFER_OVERFLOW; } if (!XfcTransPackDecoderHasRequiredLength(&env->decoder)) { continue; } if (!XfcTransPackDecoderIsCrcCorrect(&env->decoder)) { return eXfcProtRequesterStatus_CRC_ERROR; } tXfcArray response = XfcTransPackDecoderGetDataSegmentAsArray(&env->decoder); if (parseMethod) { switch (parseMethod(parser, &response)) { case XFC_TRANSPORT_PROTOCOL_RESPONSE_RESULT_OK: break; case XFC_TRANSPORT_PROTOCOL_REQUEST_UNEXPECTEDLY_SHORT: return eXfcProtRequesterStatus_RESPONSE_SHORT; case XFC_TRANSPORT_PROTOCOL_RESPONSE_RESULT_EXECUTION_ERROR: return eXfcProtRequesterStatus_PARSING_EXECUTION_ERROR; default: return eXfcProtRequesterStatus_UNKNOWN_ERROR; } } return eXfcProtRequesterStatus_OK; } return eXfcProtRequesterStatus_RECIVE_TIMEOUT; }