XfcTransportProtocol/Src/XfcProtRequester.c

149 lines
4.1 KiB
C

//
// Created by xemon on 07.11.23.
//
#include <SystemDelayInterface.h>
#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;
}