/* * Copyright (c) 2021 - 2024 Stefan Strobel * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ /** * @file test_integration_ymodem.cpp * @brief integration test implementation for the ymodem module of the shellmatta * @author Stefan Strobel */ #include "test/framework/catch.hpp" extern "C" { #include "shellmatta.h" } #include static uint32_t write_callCnt = 0u; static char write_data[1024]; static uint32_t write_length; static bool cancelled; static uint32_t receivedFileSize; static char *receivedFileName; static uint8_t *receivedPacketData; static uint32_t receivedPacketSize; static uint32_t receivedPacketNum; static bool transmissionCompleted; static shellmatta_retCode_t transmissionCompletedResult; static shellmatta_retCode_t writeFct(const char* data, uint32_t length) { write_callCnt ++; while((length > 0) && (write_length < sizeof(write_data))) { write_data[write_length] = *data; data ++; length --; write_length ++; } return SHELLMATTA_OK; } static void ymodemCallbackCancel(shellmatta_handle_t handle) { (void)handle; cancelled = true; } static void ymodemCallbackReceiveHeader(shellmatta_handle_t handle, uint32_t fileSize, char* fileName) { shellmatta_ymodem_pause(handle); receivedFileSize = fileSize; receivedFileName = fileName; } static void ymodemCallbackReceivePacket(shellmatta_handle_t handle, uint8_t *data, uint32_t packetSize, uint32_t packetNum) { (void)handle; receivedPacketData = data; receivedPacketSize = packetSize; receivedPacketNum = packetNum; return; } static void ymodemCallbackTransmissionComplete(shellmatta_handle_t handle, shellmatta_retCode_t result) { (void)handle; transmissionCompleted = true; transmissionCompletedResult = result; } SCENARIO("Test successful transmissions in ymodem") { GIVEN("An initialized and empty Shellmatta instance") { shellmatta_retCode_t ret; shellmatta_instance_t inst; shellmatta_handle_t handle; char buffer[1024u]; char historyBuffer[1024u]; uint8_t ymodemBuffer[1024u]; cancelled = false; receivedFileSize = 0u; receivedFileName = NULL; receivedPacketData = NULL; receivedPacketSize = 0u; receivedPacketNum = 0u; transmissionCompleted = false; transmissionCompletedResult = SHELLMATTA_USE_FAULT; CHECK(SHELLMATTA_OK == shellmatta_doInit( &inst, &handle, buffer, sizeof(buffer), historyBuffer, sizeof(historyBuffer), "shellmatta->", NULL, writeFct)); WHEN("Starting a ymodem session and passing data.") { ret = shellmatta_ymodem_init(handle, ymodemBuffer, ymodemCallbackCancel, ymodemCallbackReceiveHeader, ymodemCallbackReceivePacket, ymodemCallbackTransmissionComplete); AND_WHEN("ymodem is polled") { write_length = 0u; ret = shellmatta_processData(handle, (char *)"", 0); CHECK(ret == SHELLMATTA_OK); THEN("ymodem sends C starting character") { CHECK(write_length == 1u); REQUIRE(write_data[0] == 'C'); } } AND_WHEN("Packet 0 is sent") { char packet0[1029u] = "\x02\x00\xFF" "Filename\0" "1044 \0"; packet0[1027u] = '\x55'; packet0[1028u] = '\x2E'; char packet1[133u] = "\x01\x01\xFE" "Some data...\0"; packet1[131u] = '\x09'; packet1[132u] = '\x75'; char packet2[1029u] = "\x02\x02\xFD" "Some additional data\0"; packet2[1027u] = '\xCD'; packet2[1028u] = '\xD4'; write_length = 0u; ret = shellmatta_processData(handle, packet0, sizeof(packet0)); CHECK(ret == SHELLMATTA_OK); CHECK(write_length == 0u); ret = shellmatta_ymodem_resume(handle); CHECK(ret == SHELLMATTA_OK); THEN("ymodem calls the received header callback and sends an ACK") { CHECK_THAT(receivedFileName, Catch::Matchers::Equals("Filename")); CHECK(receivedFileSize == 1044); CHECK(write_length == 2u); CHECK(write_data[0] == '\x06'); REQUIRE(write_data[1] == 'C'); AND_WHEN("The rest of the packets is sent") { write_length = 0u; ret = shellmatta_processData(handle, packet1, sizeof(packet1)); CHECK(ret == SHELLMATTA_OK); CHECK_THAT((char *)receivedPacketData, Catch::Matchers::Equals("Some data...")); CHECK(receivedPacketSize == 128); CHECK(receivedPacketNum == 1); receivedPacketData = NULL; receivedPacketSize = 0u; receivedPacketNum = 0u; ret = shellmatta_processData(handle, packet2, sizeof(packet2)); CHECK(ret == SHELLMATTA_OK); CHECK_THAT((char *)receivedPacketData, Catch::Matchers::Equals("Some additional data")); CHECK(receivedPacketSize == 20); CHECK(receivedPacketNum == 2); ret = shellmatta_processData(handle, (char*)"\x04", 1); CHECK(ret == SHELLMATTA_OK); ret = shellmatta_processData(handle, (char*)"\x04", 1); CHECK(ret == SHELLMATTA_OK); ret = shellmatta_processData(handle, (char*)"\x04", 1); CHECK(ret == SHELLMATTA_OK); CHECK(write_length == 8u); CHECK(write_data[0] == '\x06'); CHECK(write_data[1] == '\x06'); CHECK(write_data[2] == '\x06'); CHECK(write_data[3] == 'C'); CHECK(write_data[4] == '\x06'); CHECK(write_data[5] == 'C'); CHECK(write_data[6] == '\x06'); CHECK(write_data[7] == 'C'); write_length = 0u; memset(write_data, 0, sizeof(write_data)); ret = shellmatta_processData(handle, (char*)"", 0); CHECK(ret == SHELLMATTA_OK); ret = shellmatta_processData(handle, (char*)"", 0); CHECK(ret == SHELLMATTA_OK); ret = shellmatta_processData(handle, (char*)"", 0); CHECK(ret == SHELLMATTA_OK); THEN("The transmission finishes successfully") { CHECK(write_length == 14); CHECK_THAT(write_data, Catch::Matchers::Equals("\r\nshellmatta->")); CHECK(transmissionCompleted == true); REQUIRE(transmissionCompletedResult == SHELLMATTA_OK); } } } } } } }