Unit tests for decoding requests and responses

+errors on requests
pull/10/head
D.R.racer 2021-05-14 15:38:06 +02:00
parent 0633dea881
commit 30fbf6d870
4 changed files with 184 additions and 19 deletions

View File

@ -117,13 +117,13 @@ endif()
add_compile_options(-g) add_compile_options(-g)
# optimizations # optimizations
if(CMAKE_CROSSCOMPILING)
if(CMAKE_BUILD_TYPE STREQUAL "Debug") if(CMAKE_BUILD_TYPE STREQUAL "Debug")
add_compile_options(-Og) add_compile_options(-Og)
else() else()
add_compile_options(-Os) add_compile_options(-Os)
endif() endif()
if(CMAKE_CROSSCOMPILING)
# mcu related settings # mcu related settings
set(MCU_FLAGS -mmcu=atmega32u4 -DF_CPU=16000000L) set(MCU_FLAGS -mmcu=atmega32u4 -DF_CPU=16000000L)
add_compile_options(${MCU_FLAGS}) add_compile_options(${MCU_FLAGS})
@ -136,6 +136,12 @@ if(CMAKE_CROSSCOMPILING)
# disable exceptions and related metadata # disable exceptions and related metadata
add_compile_options(-fno-exceptions -fno-unwind-tables) add_compile_options(-fno-exceptions -fno-unwind-tables)
add_link_options(-Wl,--defsym,__exidx_start=0,--defsym,__exidx_end=0) add_link_options(-Wl,--defsym,__exidx_start=0,--defsym,__exidx_end=0)
else()
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
add_compile_options(-O0)
else()
add_compile_options(-O2)
endif()
endif() endif()
# enable all warnings (well, not all, but some) # enable all warnings (well, not all, but some)
@ -165,10 +171,13 @@ add_executable(firmware)
set_target_properties(firmware PROPERTIES CXX_STANDARD 14) set_target_properties(firmware PROPERTIES CXX_STANDARD 14)
if(CMAKE_CROSSCOMPILING)
# generate firmware.bin file # generate firmware.bin file
objcopy(firmware "ihex" ".hex") objcopy(firmware "ihex" ".hex")
add_custom_command(
add_custom_command(TARGET firmware POST_BUILD COMMAND avr-objdump ARGS -CSd firmware > firmware.txt) TARGET firmware POST_BUILD COMMAND avr-objdump ARGS -CSd firmware > firmware.txt
)
endif()
add_custom_command(TARGET firmware POST_BUILD COMMAND avr-size ARGS -C --mcu=atmega32u4 firmware) add_custom_command(TARGET firmware POST_BUILD COMMAND avr-size ARGS -C --mcu=atmega32u4 firmware)

View File

@ -45,6 +45,7 @@ Protocol::DecodeStatus Protocol::DecodeRequest(uint8_t c) {
rqState = RequestStates::Value; rqState = RequestStates::Value;
return DecodeStatus::NeedMoreData; return DecodeStatus::NeedMoreData;
default: default:
requestMsg.code = RequestMsgCodes::unknown;
rqState = RequestStates::Error; rqState = RequestStates::Error;
return DecodeStatus::Error; return DecodeStatus::Error;
} }
@ -57,6 +58,7 @@ Protocol::DecodeStatus Protocol::DecodeRequest(uint8_t c) {
rqState = RequestStates::Code; rqState = RequestStates::Code;
return DecodeStatus::MessageCompleted; return DecodeStatus::MessageCompleted;
} else { } else {
requestMsg.code = RequestMsgCodes::unknown;
rqState = RequestStates::Error; rqState = RequestStates::Error;
return DecodeStatus::Error; return DecodeStatus::Error;
} }
@ -65,6 +67,7 @@ Protocol::DecodeStatus Protocol::DecodeRequest(uint8_t c) {
rqState = RequestStates::Code; rqState = RequestStates::Code;
return DecodeStatus::MessageCompleted; return DecodeStatus::MessageCompleted;
} else { } else {
requestMsg.code = RequestMsgCodes::unknown;
rqState = RequestStates::Error; rqState = RequestStates::Error;
return DecodeStatus::Error; return DecodeStatus::Error;
} }
@ -108,17 +111,10 @@ Protocol::DecodeStatus Protocol::DecodeResponse(uint8_t c) {
responseMsg.request.value += c - '0'; responseMsg.request.value += c - '0';
return DecodeStatus::NeedMoreData; return DecodeStatus::NeedMoreData;
} else if (c == ' ') { } else if (c == ' ') {
rspState = ResponseStates::Space;
return DecodeStatus::NeedMoreData;
} else {
rspState = ResponseStates::Error;
return DecodeStatus::Error;
}
case ResponseStates::Space:
if (c == ' ') {
rspState = ResponseStates::ParamCode; rspState = ResponseStates::ParamCode;
return DecodeStatus::NeedMoreData; return DecodeStatus::NeedMoreData;
} else { } else {
rspState = ResponseStates::Error;
return DecodeStatus::Error; return DecodeStatus::Error;
} }
case ResponseStates::ParamCode: case ResponseStates::ParamCode:
@ -129,6 +125,7 @@ Protocol::DecodeStatus Protocol::DecodeResponse(uint8_t c) {
case 'A': case 'A':
case 'R': case 'R':
rspState = ResponseStates::ParamValue; rspState = ResponseStates::ParamValue;
responseMsg.params.code = (RequestMsgCodes)c; // @@TODO this is not clean
responseMsg.params.value = 0; responseMsg.params.value = 0;
return DecodeStatus::NeedMoreData; return DecodeStatus::NeedMoreData;
default: default:

View File

@ -113,6 +113,12 @@ public:
/// @returns number of bytes written into txbuff /// @returns number of bytes written into txbuff
static uint8_t EncodeResponseQueryOperation(const RequestMsg &msg, ResponseMsgParamCodes code, uint8_t value, uint8_t *txbuff); static uint8_t EncodeResponseQueryOperation(const RequestMsg &msg, ResponseMsgParamCodes code, uint8_t value, uint8_t *txbuff);
/// @returns the most recently lexed request message
inline const RequestMsg GetRequestMsg() const { return requestMsg; }
/// @returns the most recently lexed response message
inline const ResponseMsg GetResponseMsg() const { return responseMsg; }
private: private:
enum class RequestStates : uint8_t { enum class RequestStates : uint8_t {
Code, ///< starting state - expects message code Code, ///< starting state - expects message code
@ -126,7 +132,6 @@ private:
enum class ResponseStates : uint8_t { enum class ResponseStates : uint8_t {
RequestCode, ///< starting state - expects message code RequestCode, ///< starting state - expects message code
RequestValue, ///< expecting code value RequestValue, ///< expecting code value
Space, ///< expecting space
ParamCode, ///< expecting param code ParamCode, ///< expecting param code
ParamValue, ///< expecting param value ParamValue, ///< expecting param value
Error ///< automaton in error state Error ///< automaton in error state

View File

@ -200,3 +200,157 @@ TEST_CASE("protocol::EncodeResponseQueryOperation", "[protocol]") {
CHECK(txbuff[msglen - 1] == '\n'); CHECK(txbuff[msglen - 1] == '\n');
} }
} }
TEST_CASE("protocol::DecodeRequest", "[protocol]") {
using namespace modules;
Protocol p;
const char *rxbuff = GENERATE(
"B0\n", "B1\n", "B2\n",
"E0\n", "E1\n", "E2\n", "E3\n", "E4\n",
"K0\n",
"L0\n", "L1\n", "L2\n", "L3\n", "L4\n",
"M0\n", "M1\n",
"P0\n",
"Q0\n",
"S0\n", "S1\n", "S2\n", "S3\n",
"T0\n", "T1\n", "T2\n", "T3\n",
"U0\n",
"W0\n",
"X0\n");
const char *pc = rxbuff;
for (;;) {
uint8_t c = *pc++;
if (c == 0) {
// end of input test data
break;
} else if (c == '\n') {
// regular end of message line
CHECK(p.DecodeRequest(c) == Protocol::DecodeStatus::MessageCompleted);
} else {
CHECK(p.DecodeRequest(c) == Protocol::DecodeStatus::NeedMoreData);
}
}
// check the message type
const RequestMsg &rq = p.GetRequestMsg();
CHECK((uint8_t)rq.code == rxbuff[0]);
CHECK(rq.value == rxbuff[1] - '0');
}
TEST_CASE("protocol::DecodeResponseReadFinda", "[protocol]") {
using namespace modules;
Protocol p;
const char *rxbuff = GENERATE(
"P0 A0\n",
"P0 A1\n");
const char *pc = rxbuff;
for (;;) {
uint8_t c = *pc++;
if (c == 0) {
// end of input test data
break;
} else if (c == '\n') {
// regular end of message line
CHECK(p.DecodeResponse(c) == Protocol::DecodeStatus::MessageCompleted);
} else {
CHECK(p.DecodeResponse(c) == Protocol::DecodeStatus::NeedMoreData);
}
}
// check the message type
const ResponseMsg &rsp = p.GetResponseMsg();
CHECK((uint8_t)rsp.request.code == rxbuff[0]);
CHECK(rsp.request.value == rxbuff[1] - '0');
CHECK((uint8_t)rsp.params.code == rxbuff[3]);
CHECK((uint8_t)rsp.params.value == rxbuff[4] - '0');
}
TEST_CASE("protocol::DecodeResponseQueryOperation", "[protocol]") {
using namespace modules;
Protocol p;
const char *cmdReference = GENERATE(
"E0", "E1", "E2", "E3", "E4",
"K0",
"L0", "L1", "L2", "L3", "L4",
"T0", "T1", "T2", "T3",
"U0",
"W0");
const char *status = GENERATE(
"P0", "P1", "E0", "E1", "E9", "F");
std::string rxbuff(cmdReference);
rxbuff += ' ';
rxbuff += status;
rxbuff += '\n';
const char *pc = rxbuff.c_str();
for (;;) {
uint8_t c = *pc++;
if (c == 0) {
// end of input test data
break;
} else if (c == '\n') {
// regular end of message line
CHECK(p.DecodeResponse(c) == Protocol::DecodeStatus::MessageCompleted);
} else {
CHECK(p.DecodeResponse(c) == Protocol::DecodeStatus::NeedMoreData);
}
}
// check the message type
const ResponseMsg &rsp = p.GetResponseMsg();
CHECK((uint8_t)rsp.request.code == rxbuff[0]);
CHECK(rsp.request.value == rxbuff[1] - '0');
CHECK((uint8_t)rsp.params.code == rxbuff[3]);
if ((uint8_t)rsp.params.code != (uint8_t)ResponseMsgParamCodes::Finished) { //@@TODO again, not clean, need to define a separate msg struct for the params to make it type-safe and clean
CHECK((uint8_t)rsp.params.value == rxbuff[4] - '0');
}
}
TEST_CASE("protocol::DecodeRequestErrors", "[protocol]") {
using namespace modules;
Protocol p;
const char b0[] = "b0";
CHECK(p.DecodeRequest(b0[0]) == Protocol::DecodeStatus::Error);
CHECK(p.GetRequestMsg().code == RequestMsgCodes::unknown);
CHECK(p.DecodeRequest(b0[1]) == Protocol::DecodeStatus::Error);
CHECK(p.GetRequestMsg().code == RequestMsgCodes::unknown);
// reset protokol decoder
CHECK(p.DecodeRequest('\n') == Protocol::DecodeStatus::MessageCompleted);
CHECK(p.GetRequestMsg().code == RequestMsgCodes::unknown);
const char B1_[] = "B1 \n";
CHECK(p.DecodeRequest(B1_[0]) == Protocol::DecodeStatus::NeedMoreData);
CHECK(p.DecodeRequest(B1_[1]) == Protocol::DecodeStatus::NeedMoreData);
CHECK(p.DecodeRequest(B1_[2]) == Protocol::DecodeStatus::Error);
CHECK(p.GetRequestMsg().code == RequestMsgCodes::unknown);
CHECK(p.DecodeRequest(B1_[3]) == Protocol::DecodeStatus::MessageCompleted);
CHECK(p.GetRequestMsg().code == RequestMsgCodes::unknown);
const char _B2[] = " B2\n";
CHECK(p.DecodeRequest(_B2[0]) == Protocol::DecodeStatus::Error);
CHECK(p.GetRequestMsg().code == RequestMsgCodes::unknown);
CHECK(p.DecodeRequest(_B2[1]) == Protocol::DecodeStatus::Error);
CHECK(p.GetRequestMsg().code == RequestMsgCodes::unknown);
CHECK(p.GetRequestMsg().code == RequestMsgCodes::unknown);
CHECK(p.DecodeRequest(_B2[2]) == Protocol::DecodeStatus::Error);
CHECK(p.GetRequestMsg().code == RequestMsgCodes::unknown);
CHECK(p.DecodeRequest(_B2[3]) == Protocol::DecodeStatus::MessageCompleted);
CHECK(p.GetRequestMsg().code == RequestMsgCodes::unknown);
const char _B0_[] = " B0 ";
CHECK(p.DecodeRequest(_B0_[0]) == Protocol::DecodeStatus::Error);
CHECK(p.GetRequestMsg().code == RequestMsgCodes::unknown);
CHECK(p.DecodeRequest(_B0_[1]) == Protocol::DecodeStatus::Error);
CHECK(p.GetRequestMsg().code == RequestMsgCodes::unknown);
CHECK(p.DecodeRequest(_B0_[2]) == Protocol::DecodeStatus::Error);
CHECK(p.GetRequestMsg().code == RequestMsgCodes::unknown);
CHECK(p.DecodeRequest(_B0_[3]) == Protocol::DecodeStatus::Error);
CHECK(p.GetRequestMsg().code == RequestMsgCodes::unknown);
CHECK(p.DecodeRequest('\n') == Protocol::DecodeStatus::MessageCompleted);
CHECK(p.GetRequestMsg().code == RequestMsgCodes::unknown);
}