149 lines
4.1 KiB
C
149 lines
4.1 KiB
C
//
|
|
// Created by CFIF 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;
|
|
|
|
}
|