Jelajahi Sumber

added integrationtest for ymodem module
added handles to ymodem callbacks
fixed some things on the way

stefan 9 bulan lalu
induk
melakukan
b8709a0332

+ 14 - 4
api/shellmatta.h

@@ -194,30 +194,40 @@ typedef struct shellmatta_cmd
 
 /**
  * @brief shellmatta ymodem cancel callback definition
+ * @param[in]   handle      pointer to the instance which is calling the callback
  */
-typedef void (*shellmatta_ymodem_cancel_t)(void);
+typedef void (*shellmatta_ymodem_cancel_t)(const shellmatta_handle_t handle);
 
 /**
  * @brief shellmatta ymodem header receive callback definition
+ * @param[in]   handle      pointer to the instance which is calling the callback
  * @param[in]   fileSize    file size of the file to be received
  * @param[in]   fileName    file name of the file to be received
  */
-typedef void (*shellmatta_ymodem_recvHeader_t)(uint32_t fileSize, char* fileName);
+typedef void (*shellmatta_ymodem_recvHeader_t)(const shellmatta_handle_t    handle,
+                                               uint32_t                     fileSize,
+                                               char*                        fileName);
 
 /**
  * @brief shellmatta ymodem packet receive callback definition
+ * @param[in]   handle      pointer to the instance which is calling the callback
  * @param[in]   data        received data
  * @param[in]   packetSize  size of the data in the packet
  * @param[in]   packetNum   number of the received packet
  */
-typedef void (*shellmatta_ymodem_recvPacket_t)(uint8_t *data, uint32_t packetSize, uint32_t packetNum);
+typedef void (*shellmatta_ymodem_recvPacket_t)(const shellmatta_handle_t    handle,
+                                               uint8_t                      *data,
+                                               uint32_t                     packetSize,
+                                               uint32_t                     packetNum);
 
 /**
  * @brief shellmatta ymodem transmission complete callback definition
+ * @param[in]   handle      pointer to the instance which is calling the callback
  * @param[in]   result      #SHELLMATTA_OK
  *                          #SHELLMATTA_ERROR - missing data
  */
-typedef void (*shellmatta_ymodem_complete_t)(shellmatta_retCode_t result);
+typedef void (*shellmatta_ymodem_complete_t)(const shellmatta_handle_t      handle,
+                                             shellmatta_retCode_t           result);
 
 /**
  * @brief state enumeration for ymodem receive state machine

+ 13 - 4
example/main.c

@@ -177,22 +177,28 @@ shellmatta_cmd_t busyCommand = {"busy", NULL, NULL, NULL, busy, NULL, NULL};
 
 shellmatta_retCode_t ret = SHELLMATTA_OK;
 
-void ymodemCallbackCancel() {
+void ymodemCallbackCancel(shellmatta_handle_t handle) {
+
+    (void)handle;
+
     return;
 }
 
-void ymodemCallbackReceiveHeader(uint32_t fileSize, char* fileName) {
+void ymodemCallbackReceiveHeader(shellmatta_handle_t handle, uint32_t fileSize, char* fileName) {
 
+    (void)handle;
     printf("Received Packet Header: %u %s\n", fileSize, fileName);
 
     return;
 }
 
-void ymodemCallbackReceivePacket(uint8_t *data, uint32_t packetSize, uint32_t packetNum)
+void ymodemCallbackReceivePacket(shellmatta_handle_t handle, uint8_t *data, uint32_t packetSize, uint32_t packetNum)
 {
 
     uint32_t i;
 
+    (void)handle;
+
     printf("Received Packet: %u %u\n", packetNum, packetSize);
 
     for(i = 0u; i < packetSize; i ++)
@@ -209,7 +215,10 @@ void ymodemCallbackReceivePacket(uint8_t *data, uint32_t packetSize, uint32_t pa
     return;
 }
 
-void ymodemCallbackTransmissionComplete(shellmatta_retCode_t result) {
+void ymodemCallbackTransmissionComplete(shellmatta_handle_t handle, shellmatta_retCode_t result) {
+
+    (void)handle;
+
     ret = SHELLMATTA_OK;
     printf("\nTransmission complete: %s\n", result == SHELLMATTA_OK ? "success" : "error");
     return;

+ 2 - 1
makefile

@@ -91,7 +91,8 @@ INTEGRATIONTEST_SOURCES :=  test/integrationtest/test_main.cpp
                             test/integrationtest/test_integration_continue.cpp  \
                             test/integrationtest/test_integration_busy.cpp      \
                             test/integrationtest/test_integration_history.cpp   \
-                            test/integrationtest/test_integration_help.cpp
+                            test/integrationtest/test_integration_help.cpp      \
+                            test/integrationtest/test_integration_ymodem.cpp
 
 INTEGRATIONTEST_TRANSPORT_SOURCES  :=  $(INTEGRATIONTEST_SOURCES)                           \
                                        test/integrationtest_transport/test_integration_transport.cpp

+ 2 - 7
src/shellmatta.c

@@ -79,7 +79,7 @@ static shellmatta_retCode_t shellmatta_processDataInt(shellmatta_handle_t     ha
         }
     }
     /** -# poll shellmatta ymomdem to send out the request to the sender */
-    if(SHELLMATTA_YMODEM_INACTIVE != inst->ymodem.state)
+    if((0u == size) && (SHELLMATTA_YMODEM_INACTIVE != inst->ymodem.state))
     {
         (void)shellmatta_ymodem_poll(handle);
     }
@@ -119,14 +119,9 @@ static shellmatta_retCode_t shellmatta_processDataInt(shellmatta_handle_t     ha
         if (inst->ymodem.state != SHELLMATTA_YMODEM_INACTIVE)
         {
             ret = shellmatta_ymodem_processByte(handle, data[inst->byteCounter]);
-
-            if (SHELLMATTA_OK == ret)
-            {
-                return ret;
-            }
         }
         /** -# in continuous mode - pass data directly to the command */
-        if(NULL != inst->continuousCmd)
+        else if(NULL != inst->continuousCmd)
         {
             /** -# copy data and call command function */
             inst->buffer[inst->stdinIdx]        = data[inst->byteCounter];

+ 8 - 8
src/shellmatta_ymodem.c

@@ -34,7 +34,7 @@ typedef enum {
 #define YMODEM_PACKET_SIZE          128u    /**< default packet size of ymodem transmission     */
 #define YMODEM_PACKET_SIZE_1K       1024u   /**< extended packet size of ymodem transmission    */
 #define YMODEM_CRC_SIZE             2u      /**< CRC size of the ymodem packet                  */
-#define YMODEM_EOT_NUMBER           2u      /**< Number of EOTs or polls to be received         */
+#define YMODEM_POLL_NUMBER          2u      /**< Number of polls to be received                 */
 
 /**
  * @brief               forwards the given character to write-function without formatting
@@ -63,7 +63,7 @@ static void shellmatta_ymodem_reset(shellmatta_handle_t handle, bool doCancel)
         shellmatta_ymodem_control(handle, YMODEM_CA);
         if (NULL != inst->ymodem.cancelCallback)
         {
-            inst->ymodem.cancelCallback();
+            inst->ymodem.cancelCallback(handle);
         }
     }
     /** -# reset instance variables */
@@ -100,7 +100,7 @@ shellmatta_retCode_t processPacket(shellmatta_handle_t handle)
                                        10u);
 
         /** -# pass filename and size to the callback */
-        inst->ymodem.recvHeaderCallback(inst->ymodem.fileSize, fileName);
+        inst->ymodem.recvHeaderCallback(handle, inst->ymodem.fileSize, fileName);
     }
     else
     {
@@ -115,7 +115,7 @@ shellmatta_retCode_t processPacket(shellmatta_handle_t handle)
         }
 
         /** -# pass data to the application using the callback */
-        inst->ymodem.recvPacketCallback(inst->ymodem.packet.packetData, packetSize, inst->ymodem.packetCounter);
+        inst->ymodem.recvPacketCallback(handle, inst->ymodem.packet.packetData, packetSize, inst->ymodem.packetCounter);
     }
 
     return ret;
@@ -153,7 +153,7 @@ static shellmatta_retCode_t ymodem_stateMachine(shellmatta_handle_t handle, uint
 
                     /** -# handle additional EOTs in WAIT FOR END state */
                     inst->ymodem.state = SHELLMATTA_YMODEM_WAIT_FOR_END;
-                    inst->ymodem.pollCyclesLeft = YMODEM_EOT_NUMBER;
+                    inst->ymodem.pollCyclesLeft = YMODEM_POLL_NUMBER;
                     break;
                 default:
                     /** -# ignore unexpected characters on start */
@@ -240,7 +240,7 @@ static shellmatta_retCode_t ymodem_stateMachine(shellmatta_handle_t handle, uint
             break;
         case SHELLMATTA_YMODEM_WAIT_FOR_END:
 
-            inst->ymodem.pollCyclesLeft = YMODEM_EOT_NUMBER;
+            inst->ymodem.pollCyclesLeft = YMODEM_POLL_NUMBER;
             if(YMODEM_EOT ==  byte)
             {
                 /** -# ACK the successful file reception */
@@ -312,7 +312,7 @@ shellmatta_retCode_t shellmatta_ymodem_poll(shellmatta_handle_t handle)
 #endif
 
             shellmatta_ymodem_reset(handle, false);
-            inst->ymodem.transmissionCompleteCallback(ret);
+            inst->ymodem.transmissionCompleteCallback(handle, ret);
             (void)utils_terminateInput(inst);
         }
         break;
@@ -440,7 +440,7 @@ shellmatta_retCode_t shellmatta_ymodem_resume(shellmatta_handle_t handle)
     {
         /** -# ACK the successful packet reception */
         shellmatta_ymodem_control(handle, YMODEM_ACK);
-        if(0u == inst->ymodem.packetCounter)
+        if(1u == inst->ymodem.packetCounter)
         {
             /** -# send addional CRC flag after packet 0 */
             shellmatta_ymodem_control(handle, YMODEM_CRC);

+ 228 - 0
test/integrationtest/test_integration_ymodem.cpp

@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2021 - 2024 Stefan Strobel <stefan.strobel@shimatta.net>
+ *
+ * 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 <stefan.strobel@shimatta.net>
+ */
+
+#include "test/framework/catch.hpp"
+extern "C" {
+    #include "shellmatta.h"
+}
+#include <string.h>
+
+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);
+                        }
+                    }
+                }
+            }
+        }
+    }
+}

+ 2 - 0
test/unittest/shellmatta_ymodem/test_ymodem.cpp

@@ -1,2 +1,4 @@
 #include "test/framework/catch.hpp"
 #include "src/shellmatta_ymodem.c"
+
+/* empty unittest - just added to fix linking issues - no unittests for ymodem right now */