Kaynağa Gözat

cleaned up shellmatta ymodem - still some things missing
added a pausable interface to pause ACK sending if the application is not ready

stefan 9 ay önce
ebeveyn
işleme
64be9d7af6

+ 54 - 22
api/shellmatta.h

@@ -192,16 +192,42 @@ typedef struct shellmatta_cmd
     struct shellmatta_cmd   *next;      /**< pointer to next command or NULL        */
 } shellmatta_cmd_t;
 
-/** 
- * @brief state enumeration for ymodem receive state machine 
+/**
+ * @brief shellmatta ymodem cancel callback definition
+ */
+typedef void (*shellmatta_ymodem_cancel_t)(void);
+
+/**
+ * @brief shellmatta ymodem header receive callback definition
+ * @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);
+
+/**
+ * @brief shellmatta ymodem packet receive callback definition
+ * @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);
+
+/**
+ * @brief shellmatta ymodem transmission complete callback definition
+ */
+typedef void (*shellmatta_ymodem_complete_t)(void);
+
+/**
+ * @brief state enumeration for ymodem receive state machine
  */
 typedef enum
-{ 
+{
     SHELLMATTA_YMODEM_INACTIVE,         /**< YModem module not initialised  */
     SHELLMATTA_YMODEM_WAIT_FOR_START,   /**< waiting for start of header    */
     SHELLMATTA_YMODEM_RECEIVE_HEADER,   /**< reading header data            */
     SHELLMATTA_YMODEM_RECEIVE_DATA,     /**< reading payload                */
-    SHELLMATTA_YMODEM_RECEIVE_CRC       /**< reading crc                    */
+    SHELLMATTA_YMODEM_RECEIVE_CRC,      /**< reading crc                    */
+    SHELLMATTA_YMODEM_PAUSE             /**< pause after a packet           */
 } shellmatta_ymodem_state_t;
 
 /** @brief packet structure that holds several information about its content */
@@ -218,16 +244,18 @@ typedef struct
  */
 typedef struct
 {
-    shellmatta_ymodem_state_t state;
-    uint32_t byteCounter;
-    uint32_t packetCounter;
-    uint32_t totalBytesReceived;
-    char *fileName;
-    uint32_t fileSize;
-    shellmatta_ymodem_packet_t packet;
-    void (*cancelCallback)(void);
-    void (*recvPacketCallback)(void);
-    void (*transmissionCompleteCallback)(void);
+    shellmatta_ymodem_state_t state;                            /**< todo */
+    uint32_t byteCounter;                                       /**< todo */
+    uint32_t packetCounter;                                     /**< todo */
+    uint32_t totalBytesReceived;                                /**< todo */
+    char *fileName;                                             /**< todo */
+    uint32_t fileSize;                                          /**< todo */
+    bool pauseRequested;                                        /**< todo */
+    shellmatta_ymodem_packet_t packet;                          /**< todo */
+    shellmatta_ymodem_cancel_t cancelCallback;                  /**< todo */
+    shellmatta_ymodem_recvHeader_t recvHeaderCallback;          /**< todo */
+    shellmatta_ymodem_recvPacket_t recvPacketCallback;          /**< todo */
+    shellmatta_ymodem_complete_t transmissionCompleteCallback;  /**< todo */
 } shellmatta_ymodem_t;
 
 #ifdef SHELLMATTA_TRANSPORT
@@ -357,7 +385,7 @@ typedef struct
 #endif
 #ifdef SHELLMATTA_TRANSPORT
     bool                            transportEnabled;   /**< if true the transport layer is enabled */
-    uint32_t                        transportBusyMark;  /**< transport processing position during 
+    uint32_t                        transportBusyMark;  /**< transport processing position during
                                                              busy cmd execution                     */
     shellmatta_transport_layer_t    transportLayer;     /**< transport layer instance               */
 #endif
@@ -465,13 +493,17 @@ shellmatta_retCode_t shellmatta_auth_chpasswd(              shellmatta_handle_t
 
 #endif
 
-shellmatta_retCode_t shellmatta_ymodem_init(shellmatta_handle_t handle, 
-                                            uint8_t*            recvBuffer, 
-                                            void                (*cancelCallback)(void),
-                                            void                (*recvPacketCallback)(void),
-                                            void                (*transmissionCompleteCallback)(void));
-
-void shellmatta_ymodem_cancel(              shellmatta_handle_t handle);
+shellmatta_retCode_t shellmatta_ymodem_init(    shellmatta_handle_t                 handle,
+                                                uint8_t*                            recvBuffer,
+                                                shellmatta_ymodem_cancel_t          cancelCallback,
+                                                shellmatta_ymodem_recvHeader_t      recvHeaderCallback,
+                                                shellmatta_ymodem_recvPacket_t      recvPacketCallback,
+                                                shellmatta_ymodem_complete_t        transmissionCompleteCallback);
+
+shellmatta_retCode_t shellmatta_ymodem_pause(   shellmatta_handle_t                 handle);
+shellmatta_retCode_t shellmatta_ymodem_resume(  shellmatta_handle_t                 handle);
+shellmatta_retCode_t shellmatta_ymodem_cancel(  shellmatta_handle_t                 handle,
+                                                bool                                doCancel);
 
 #endif
 

+ 12 - 2
example/main.c

@@ -95,7 +95,7 @@ static shellmatta_retCode_t reset(shellmatta_handle_t handle, const char *argume
     uint32_t argLen;
     bool printPrompt = false;
 
-    static const shellmatta_opt_long_t options[] = 
+    static const shellmatta_opt_long_t options[] =
     {
         {"prompt",  'p',    SHELLMATTA_OPT_ARG_REQUIRED},
         {NULL,      '\0',   SHELLMATTA_OPT_ARG_NONE}
@@ -181,7 +181,16 @@ void ymodemCallbackCancel() {
     return;
 }
 
-void ymodemCallbackReceivePacket() {
+void ymodemCallbackReceiveHeader(uint32_t fileSize, char* fileName) {
+    (void)fileSize;
+    (void)fileName;
+    return;
+}
+
+void ymodemCallbackReceivePacket(uint8_t *data, uint32_t packetSize, uint32_t packetNum) {
+    (void)data;
+    (void)packetSize;
+    (void)packetNum;
     return;
 }
 
@@ -201,6 +210,7 @@ static shellmatta_retCode_t ymodem(shellmatta_handle_t handle, const char *argum
     shellmatta_ymodem_init(handle,
                       ymodemBuffer,
                       ymodemCallbackCancel,
+                      ymodemCallbackReceiveHeader,
                       ymodemCallbackReceivePacket,
                       ymodemCallbackTransmissionComplete);
 

+ 27 - 26
src/shellmatta_utils.c

@@ -90,40 +90,41 @@ uint32_t utils_shellItoa(int32_t value, char *buffer, uint32_t base)
 
 /**
  * @brief       turns a string of digits into an unsigned 32-bit integer
- * @warning     length must match amount of digits
  * @warning     will overflow if number is larger than UINT32_MAX
- * @note        will return 0 in case of parameter error or invalid characters in string
  * @param[in]   str     pointer to the string
- * @param[in]   size    length of the string excluding null-terminator
- * @return      the value of the string as unsigned 32-bit integer
+ * @param[out]  result  the value of the string as unsigned 32-bit integer
+ * @return      errorcode   #SHELLMATTA_OK
+ *                          #SHELLMATTA_USE_FAULT (param err)
+ *                          #SHELLMATTA_ERROR (invalid characters)
 */
-uint32_t utils_shellAsciiToUInt32(char* str, uint8_t size)
+shellmatta_retCode_t utils_shellAsciiToUInt32(char* str, uint32_t *result)
 {
-    uint8_t i, j;
-    char c;
-    uint32_t ret = 0u;
-    uint16_t pot = 0u;
-    uint32_t val = 0u;
-    /* parameter check */
-    if (size == 0u || str == (void*)0u) return ret;
-    for (i = 0; i < size; i++)
+    shellmatta_retCode_t ret = SHELLMATTA_OK;
+    uint32_t val;
+
+    if((NULL != str) && (NULL != result))
     {
-        c = str[i];
-        /* check character for digit */
-        if (c >= 48 && c <= 57)
-        {
-            val = c - 48;
-        }
-        else return 0;
-        pot = size - i - 1;
-        /* compute val to the power of pot */
-        for (j = 0; j < pot; j++)
+        *result = 0u;
+
+        while(*str && (SHELLMATTA_OK == ret))
         {
-            val *= 10;
+            val = ((uint32_t)*str - 48u);
+
+            if(val > 9u)
+            {
+                ret = SHELLMATTA_ERROR;
+            }
+            else
+            {
+                *result = (*result * 10u) + val;
+            }
         }
-        /* add result to ret */
-        ret += val;
     }
+    else
+    {
+        ret = SHELLMATTA_USE_FAULT;
+    }
+
     return ret;
 }
 

+ 2 - 2
src/shellmatta_utils.h

@@ -114,8 +114,8 @@ uint32_t utils_shellItoa(           int32_t value,
                                     char *buffer, 
                                     uint32_t base);
 
-uint32_t utils_shellAsciiToUInt32(  char* str, 
-                                    uint8_t size);
+shellmatta_retCode_t utils_shellAsciiToUInt32(  char* str,
+                                                uint32_t *result);
 
 void utils_saveCursorPos(           shellmatta_instance_t *inst);
 

+ 199 - 513
src/shellmatta_ymodem.c

@@ -1,3 +1,11 @@
+/*
+ * Copyright (c) 2023 - 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    shellmatta_ymodem.c
  * @brief   ymodem functions of shellmatta
@@ -39,330 +47,68 @@ static void shellmatta_ymodem_control(shellmatta_handle_t handle, const uint8_t
 }
 
 /**
- * @brief                                           Initialise the ymodem prior to actually receiving data
- * @param[in, out]  handle                          shellmatta instance handle
- * @param[in]       recvBuffer                      pointer to the buffer to save the received payload in
- * @param[in]       recvPacketCallback              pointer to the file size variable
- * @param[in]       recvPacketCallback              pointer to the packet size variable
- * @param[in]       transmissionCompleteCallback    callback functions for the ymodem module
- * @return          todo
- * @note            Disables the tranport layer if inactive or sets it to mandatory if active
+ * @brief                       reset function for the ymodem module
+ * @param[in, out]  handle      shellmatta instance handle
+ * @param[in]       doCancel    flag to execute the cancel-callback
 */
-shellmatta_retCode_t shellmatta_ymodem_init(shellmatta_handle_t handle,
-                                            uint8_t* recvBuffer,
-                                            void (*cancelCallback)(void),
-                                            void (*recvPacketCallback)(void),
-                                            void (*transmissionCompleteCallback)(void))
+static void shellmatta_ymodem_reset(shellmatta_handle_t handle, bool doCancel)
 {
-    shellmatta_retCode_t ret = SHELLMATTA_OK;
     shellmatta_instance_t *inst = (shellmatta_instance_t *)handle;
-    (void)memset((void *)&inst->ymodem, 0, sizeof(shellmatta_ymodem_t));
 
-    /** -# check parameters for plausibility  */
-    if(     (NULL               != inst)
-        &&  (SHELLMATTA_MAGIC   == inst->magic))
+    /** -# call cancel callback function */
+    if (doCancel)
     {
-        /** -# use instances buffer if no buffer is given */
-        if(NULL == recvBuffer)
+        /* send cancel symbol */
+        shellmatta_ymodem_control(handle, YMODEM_CA);
+        if (NULL != inst->ymodem.cancelCallback)
         {
-            if(inst->bufferSize <= YMODEM_PACKET_SIZE_1K)
-            {
-                /** -# return use fault if buffer is too small */
-                ret = SHELLMATTA_USE_FAULT;
-            }
-            else
-            {
-                inst->ymodem.packet.packetData = (uint8_t*)inst->buffer;
-            }
+            inst->ymodem.cancelCallback();
         }
+    }
+    /** -# reset instance variables */
+    inst->ymodem.state = SHELLMATTA_YMODEM_INACTIVE;
+    inst->ymodem.byteCounter = 0u;
+    inst->ymodem.packetCounter = 0u;
+    inst->ymodem.totalBytesReceived = 0u;
+    inst->ymodem.fileName = NULL;
+    inst->ymodem.fileSize = 0u;
+    inst->ymodem.pauseRequested = false;
+    (void)memset((void *)&inst->ymodem.packet, 0, sizeof(shellmatta_ymodem_packet_t));
+}
 
-        /** -# store buffer */
-        inst->ymodem.packet.packetData = recvBuffer;
+shellmatta_retCode_t processPacket(shellmatta_handle_t handle)
+{
+    shellmatta_retCode_t ret = SHELLMATTA_OK;
+    shellmatta_instance_t *inst = (shellmatta_instance_t *)handle;
+    char *fileName;
+    uint32_t packetSize;
 
-        /** -# init callbacks */
-        inst->ymodem.cancelCallback = cancelCallback;
-        inst->ymodem.recvPacketCallback = recvPacketCallback;
-        inst->ymodem.transmissionCompleteCallback = transmissionCompleteCallback;
+    /** -# read filesize and name from first packet - ignore rest */
+    if(0u == inst->ymodem.packetCounter)
+    {
+        fileName = (char*)inst->ymodem.packet.packetData;
 
-        inst->ymodem.state = SHELLMATTA_YMODEM_WAIT_FOR_START;
+        ret = utils_shellAsciiToUInt32((char*)&inst->ymodem.packet.packetData[strlen(fileName)],
+                                       &inst->ymodem.fileSize);
 
-        /* send initial ymodem symbol to start transmission */
-        shellmatta_ymodem_control(handle, YMODEM_CRC);
+        /** -# pass filename and size to the callback */
+        inst->ymodem.recvHeaderCallback(inst->ymodem.fileSize, fileName);
     }
     else
     {
-        ret = SHELLMATTA_USE_FAULT;
-    }
-
-    return ret;
-}
+        /** -# calculate packet size - when it is the last packet this is limited by the file size */
+        packetSize = SHELLMATTA_MAX((inst->ymodem.totalBytesReceived + inst->ymodem.packet.size),
+                                    inst->ymodem.fileSize);
+        packetSize = packetSize % inst->ymodem.packet.size;
 
-// /**
-//  * @brief                   State machine that processes bytewise input during active ymodem transmission
-//  * @param[in, out]  handle  shellmatta handle of the instance
-//  * @param[in]       byteIn  the byte to be processed
-//  * @note                    won't do anything if ymodem module is not initialized
-// */
-// void shellmatta_ymodem_receive_packet(shellmatta_handle_t handle, uint8_t byteIn)
-// {
-//     static uint32_t fileSize = 0u;
-//     static char fileSizeStr[7u]; /* hopefully no more bytes than a million will ever be transmitted */
-//     shellmatta_ymodem_rcv_retcode_t recvRetCode;
-
-//     //recvRetCode = shellmatta_ymodem_receive_byte(handle, byteIn);
-//     switch (shellmatta_ymodem_get_state(handle))
-//     {
-//     case SHELLMATTA_YMODEM_INACTIVE:
-//         /* cant do anything if ymodem module was not correctly initialized */
-//         return;
-//     case SHELLMATTA_YMODEM_WAIT_FOR_START:
-//         /* wait for start symbol of a packet */
-//         switch (shellmatta_ymodem_current_data_type)
-//         {
-//         case YMODEM_NONE: /* go here if the header packet is to be expected */
-//             if (recvRetCode == SOH_RECEIVED || recvRetCode == STX_RECEIVED)
-//             {
-//                 /* reset packet counter */
-//                 shellmatta_ymodem_packet_counter = 0u;
-//                 shellmatta_ymodem_byte_counter = 0u;
-//                 shellmatta_ymodem_set_state(handle, SHELLMATTA_YMODEM_RECEIVE_PACKET);
-//                 shellmatta_ymodem_current_data_type = YMODEM_HEADER;
-//             }
-//             break;
-        
-//         case YMODEM_HEADER: /* go here if the first body packet is to be expected */
-//             if (recvRetCode == STX_RECEIVED || recvRetCode == SOH_RECEIVED)
-//             {
-//                 shellmatta_ymodem_byte_counter = 0u;
-//                 shellmatta_ymodem_set_state(handle, SHELLMATTA_YMODEM_RECEIVE_PACKET);
-//                 shellmatta_ymodem_current_data_type = YMODEM_BODY;
-//             }
-//             break;
-
-//         case YMODEM_BODY: /* go here if the data transmission loop is active */
-//             if (recvRetCode == SOH_RECEIVED || recvRetCode == STX_RECEIVED)
-//             {
-//                 shellmatta_ymodem_byte_counter = 0u;
-//                 /* stay in body when SOH was received */
-//                 shellmatta_ymodem_set_state(handle, SHELLMATTA_YMODEM_RECEIVE_PACKET);
-//                 shellmatta_ymodem_current_data_type = YMODEM_BODY;
-//             }
-//             else /* go here if the end of transmission symbol is received */
-//             if (recvRetCode == EOT_RECEIVED)
-//             {
-//                 shellmatta_ymodem_byte_counter = 0u;
-//                 /* answer with ACK */
-//                 shellmatta_ymodem_ack(handle);
-//                 /* then send 0x43 symbol */
-//                 shellmatta_ymodem_control(handle, YMODEM_CRC);
-//                 /* go to footer when EOT was received */
-//                 shellmatta_ymodem_current_data_type = YMODEM_FOOTER;
-//                 /* then wait for SOH */
-//             }
-//             break;
-//         case YMODEM_FOOTER: /* go here if the end of transmission packet is to be expected */
-//             /* it _may_ be, that EOT is sent multiple times, repeat previous procedure */
-//             if (recvRetCode == EOT_RECEIVED)
-//             {
-//                 /* answer with ACK */
-//                 shellmatta_ymodem_ack(handle);
-//                 /* then send 0x43 symbol */
-//                 shellmatta_ymodem_control(handle, YMODEM_CRC);
-//             }
-//             if (recvRetCode == SOH_RECEIVED)
-//             {
-//                 /* reset packet counter */
-//                 shellmatta_ymodem_packet_counter = 0u;
-//                 /* reset byte counter to avoid error by one caused by previously received EOT symbol */
-//                 shellmatta_ymodem_byte_counter = 0u;
-//                 shellmatta_ymodem_set_state(handle, SHELLMATTA_YMODEM_RECEIVE_PACKET);
-//             }
-//             break;
-
-//         default:
-//             break;
-//         }
-//         break;
-//     case SHELLMATTA_YMODEM_RECEIVE_PACKET:
-//         /* receiving data */
-//         if (recvRetCode == DATA_RECEIVED)
-//         {
-//             switch (shellmatta_ymodem_current_data_type)
-//             {
-//             case YMODEM_HEADER:
-//                 switch (shellmatta_ymodem_byte_counter)
-//                 {
-//                 /* first two bytes are packet number and reverse packet number */
-//                 case 0:
-//                     shellmatta_ymodem_packet.packetNumber = byteIn;
-//                     break;
-//                 case 1:
-//                     shellmatta_ymodem_packet.reversePacketNumber = byteIn;
-//                     break;
-//                 default:
-//                     break;
-//                 }
-//                 /* after packet numbers, data field begins */
-//                 if ((shellmatta_ymodem_byte_counter >= YMODEM_HEADER_DATA_OFFSET) && 
-//                     (shellmatta_ymodem_byte_counter < YMODEM_HEADER_CRC_POSITION))
-//                 {
-//                     shellmatta_ymodem_packet.packetData[shellmatta_ymodem_byte_counter - YMODEM_HEADER_DATA_OFFSET] = byteIn;
-//                     /* check for filename */
-//                     if (shellmatta_ymodem_byte_counter < fileNameDelimiterPosition)
-//                     {
-//                         /* find NULL-Terminator in filename */
-//                         if (byteIn == YMODEM_NULL)
-//                         {
-//                             fileNameDelimiterPosition = shellmatta_ymodem_byte_counter + 1;
-//                         }
-//                     }
-//                     /* after filename the filesize begins */
-//                     else
-//                     if (shellmatta_ymodem_byte_counter >= fileNameDelimiterPosition && 
-//                         (shellmatta_ymodem_byte_counter < fileSizeDelimiterPosition))
-//                     {
-//                         /* find space as delimiter after filesize */
-//                         if (byteIn == YMODEM_SPACE)
-//                         {
-//                             fileSizeDelimiterPosition = shellmatta_ymodem_byte_counter;
-//                             /* convert file size string to actual number */
-//                             fileSize = utils_shellAsciiToUInt32(fileSizeStr, fileSizeDelimiterPosition - fileNameDelimiterPosition);
-//                             shellmatta_ymodem_packet.fileSize = fileSize;
-//                         }
-//                         /* save characters in string otherwise */
-//                         else
-//                         {
-//                             fileSizeStr[shellmatta_ymodem_byte_counter - fileNameDelimiterPosition] = byteIn;
-//                         }
-//                     }
-//                     else
-//                     {
-//                         /* some meta data from sender, possibly file date */
-//                         /* not needed for now */
-//                     }
-//                 }
-//                 /* after data field, crc begins */
-//                 if (shellmatta_ymodem_byte_counter >= YMODEM_HEADER_CRC_POSITION)
-//                 {
-//                     if (shellmatta_ymodem_byte_counter == YMODEM_HEADER_CRC_POSITION)
-//                     {
-//                         /* upper byte */
-//                         shellmatta_ymodem_packet.packetCrc = byteIn << 8u;
-//                     }
-//                     if (shellmatta_ymodem_byte_counter == YMODEM_HEADER_CRC_POSITION + 1)
-//                     {
-//                         /* lower byte */
-//                         shellmatta_ymodem_packet.packetCrc |= byteIn;
-//                         /* change ymodem state to check packet */
-//                         shellmatta_ymodem_check_packet(handle);
-//                     }
-//                 }
-//                 shellmatta_ymodem_byte_counter++;
-//                 break;
-
-//             case YMODEM_BODY:
-//                 switch (shellmatta_ymodem_byte_counter)
-//                 {
-//                 case 0:
-//                     shellmatta_ymodem_packet.packetNumber = byteIn;
-//                     break;
-//                 case 1:
-//                     shellmatta_ymodem_packet.reversePacketNumber = byteIn;
-//                     break;
-//                 default:
-//                     break;
-//                 }
-
-//                 /* after data field, crc begins */
-//                 if (shellmatta_ymodem_byte_counter >= yModemPacketSize + YMODEM_HEADER_DATA_OFFSET)
-//                 {
-//                     if (shellmatta_ymodem_byte_counter == yModemPacketSize + YMODEM_HEADER_DATA_OFFSET)
-//                     {
-//                         /* upper byte */
-//                         shellmatta_ymodem_packet.packetCrc = byteIn << 8u;
-//                     }
-//                     if (shellmatta_ymodem_byte_counter == yModemPacketSize + YMODEM_HEADER_DATA_OFFSET + 1)
-//                     {
-//                         /* lower byte */
-//                         shellmatta_ymodem_packet.packetCrc |= byteIn;
-//                         /* change ymodem state to check packet */
-//                         shellmatta_ymodem_check_packet(handle);
-//                     }
-//                 }
-//                 else
-//                 if ((shellmatta_ymodem_byte_counter > 1) && 
-//                     (shellmatta_ymodem_byte_counter < (yModemPacketSize + YMODEM_HEADER_DATA_OFFSET)))
-//                 {
-//                     shellmatta_ymodem_packet.packetData[shellmatta_ymodem_byte_counter - YMODEM_HEADER_DATA_OFFSET] = byteIn;
-//                 }
-//                 shellmatta_ymodem_byte_counter++;
-//                 break;
-
-//             case YMODEM_FOOTER:
-//                 /* reset packet counter */
-//                 shellmatta_ymodem_packet_counter = 0;
-
-//                 switch (shellmatta_ymodem_byte_counter)
-//                 {
-//                 case 0:
-//                     shellmatta_ymodem_packet.packetNumber = byteIn;
-//                     break;
-//                 case 1:
-//                     shellmatta_ymodem_packet.reversePacketNumber = byteIn;
-//                     break;
-//                 default:
-//                     break;
-//                 }
-
-//                 /* after data field, crc begins */
-//                 if (shellmatta_ymodem_byte_counter >= yModemPacketSize + YMODEM_HEADER_DATA_OFFSET)
-//                 {
-//                     if (shellmatta_ymodem_byte_counter == yModemPacketSize + YMODEM_HEADER_DATA_OFFSET)
-//                     {
-//                         /* upper byte */
-//                         shellmatta_ymodem_packet.packetCrc = byteIn << 8u;
-//                     }
-//                     if (shellmatta_ymodem_byte_counter == yModemPacketSize + YMODEM_HEADER_DATA_OFFSET + 1)
-//                     {
-//                         /* lower byte */
-//                         shellmatta_ymodem_packet.packetCrc |= byteIn;
-//                         /* change ymodem state to check packet */
-//                         shellmatta_ymodem_check_packet(handle);
-//                     }
-//                 }
-//                 else
-//                 if ((shellmatta_ymodem_byte_counter > 1) && 
-//                     (shellmatta_ymodem_byte_counter < (yModemPacketSize + YMODEM_HEADER_DATA_OFFSET)))
-//                 {
-//                     /* save data */
-//                     shellmatta_ymodem_packet.packetData[shellmatta_ymodem_byte_counter - YMODEM_HEADER_DATA_OFFSET] = byteIn;
-//                 }
-//                 shellmatta_ymodem_byte_counter++;
-//                 break;
-            
-//             default:
-//                 break;
-//             }
-//         }
-//         break;
-
-
-//     default:
-//         break;
-//     }
-// }
-
-shellmatta_retCode_t processPacket(shellmatta_handle_t *handle)
-{
-    shellmatta_retCode_t ret = SHELLMATTA_OK;
-    shellmatta_instance_t *inst = (shellmatta_instance_t *)handle;
-
-    (void)inst;
+        /** -# pass data to the application using the callback */
+        inst->ymodem.recvPacketCallback(inst->ymodem.packet.packetData, packetSize, inst->ymodem.packetCounter);
+    }
 
     return ret;
 }
 
-static shellmatta_retCode_t ymodem_stateMachine(shellmatta_handle_t *handle, uint8_t byte)
+static shellmatta_retCode_t ymodem_stateMachine(shellmatta_handle_t handle, uint8_t byte)
 {
     shellmatta_retCode_t ret = SHELLMATTA_OK;
     shellmatta_instance_t *inst = (shellmatta_instance_t *)handle;
@@ -386,11 +132,9 @@ static shellmatta_retCode_t ymodem_stateMachine(shellmatta_handle_t *handle, uin
                     inst->ymodem.packet.size = YMODEM_PACKET_SIZE_1K;
                     inst->ymodem.state = SHELLMATTA_YMODEM_RECEIVE_HEADER;
                     break;
-                case YMODEM_EOT:
-                    if(NULL != inst->ymodem.transmissionCompleteCallback)
-                    {
-                        inst->ymodem.transmissionCompleteCallback();
-                    }
+
+                    inst->ymodem.transmissionCompleteCallback();
+
                     /** -# ACK the successful file reception */
                     shellmatta_ymodem_control(handle, YMODEM_ACK);
                     shellmatta_ymodem_control(handle, YMODEM_CRC);
@@ -414,6 +158,7 @@ static shellmatta_retCode_t ymodem_stateMachine(shellmatta_handle_t *handle, uin
                 {
                     /** -# return error on packet number mismatch or on unexpected packet numbers */
                     inst->ymodem.state = SHELLMATTA_YMODEM_WAIT_FOR_START;
+                    shellmatta_ymodem_control(handle, YMODEM_NAK);
                     ret = SHELLMATTA_ERROR;
                 }
                 else
@@ -443,11 +188,14 @@ static shellmatta_retCode_t ymodem_stateMachine(shellmatta_handle_t *handle, uin
 
             if(inst->ymodem.byteCounter >= YMODEM_CRC_SIZE)
             {
+                inst->ymodem.state = SHELLMATTA_YMODEM_WAIT_FOR_START;
+
                 /** -# check CRC */
                 computedCrc = crc16Calc((const char*)inst->ymodem.packet.packetData,
                                         inst->ymodem.packet.size);
                 if(computedCrc != inst->ymodem.packet.crc)
                 {
+                    shellmatta_ymodem_control(handle, YMODEM_NAK);
                     ret = SHELLMATTA_ERROR;
                 }
                 else
@@ -455,30 +203,25 @@ static shellmatta_retCode_t ymodem_stateMachine(shellmatta_handle_t *handle, uin
                     ret = processPacket(handle);
                     if(SHELLMATTA_OK == ret)
                     {
-                        /** -# pass data to the application using the callback */
-                        if(NULL != inst->ymodem.recvPacketCallback)
-                        {
-                            inst->ymodem.recvPacketCallback();
-                        }
-
-                        //todo - wait - or is it enough to block the recvPacketCallback?
+                        inst->ymodem.packetCounter ++;
 
-                        /** -# ACK the successful packet reception */
-                        shellmatta_ymodem_control(handle, YMODEM_ACK);
-                        if(0u == inst->ymodem.packetCounter)
-                        {
-                            /** -# send addional CRC flag after packet 0 */
-                            shellmatta_ymodem_control(handle, YMODEM_CRC);
-                        }
-                        else
+                        if(0u != inst->ymodem.packetCounter)
                         {
                             /** -# Calculate the total bytes received */
                             inst->ymodem.totalBytesReceived += inst->ymodem.packet.size;
                         }
-                        inst->ymodem.packetCounter ++;
+                        if(true != inst->ymodem.pauseRequested)
+                        {
+                            /** -# ACK the successful packet reception */
+                            shellmatta_ymodem_control(handle, YMODEM_ACK);
+                            if(0u == inst->ymodem.packetCounter)
+                            {
+                                /** -# send addional CRC flag after packet 0 */
+                                shellmatta_ymodem_control(handle, YMODEM_CRC);
+                            }
+                        }
                     }
                 }
-                inst->ymodem.state = SHELLMATTA_YMODEM_WAIT_FOR_START;
             }
             break;
         default:
@@ -489,7 +232,6 @@ static shellmatta_retCode_t ymodem_stateMachine(shellmatta_handle_t *handle, uin
     return ret;
 }
 
-
 shellmatta_retCode_t shellmatta_ymodem_processByte(shellmatta_handle_t handle, char byte)
 {
     shellmatta_instance_t *inst = (shellmatta_instance_t*)handle;
@@ -513,7 +255,6 @@ shellmatta_retCode_t shellmatta_ymodem_processByte(shellmatta_handle_t handle, c
     return ret;
 }
 
-
 shellmatta_retCode_t shellmatta_ymodem_poll(shellmatta_handle_t handle)
 {
     shellmatta_retCode_t ret = SHELLMATTA_ERROR;
@@ -529,211 +270,156 @@ shellmatta_retCode_t shellmatta_ymodem_poll(shellmatta_handle_t handle)
     return ret;
 }
 
+/**
+ * @brief                                           Initialise the ymodem prior to actually receiving data
+ * @param[in, out]  handle                          shellmatta instance handle
+ * @param[in]       recvBuffer                      pointer to the buffer to save the received payload in
+ * @param[in]       recvPacketCallback              pointer to the file size variable
+ * @param[in]       recvPacketCallback              pointer to the packet size variable
+ * @param[in]       transmissionCompleteCallback    callback functions for the ymodem module
+ * @return          errorcode   #SHELLMATTA_OK
+ *                              #SHELLMATTA_USE_FAULT (param err)
+ * @note            Disables the tranport layer if inactive or sets it to mandatory if active
+*/
+shellmatta_retCode_t shellmatta_ymodem_init(shellmatta_handle_t             handle,
+                                            uint8_t*                        recvBuffer,
+                                            shellmatta_ymodem_cancel_t      cancelCallback,
+                                            shellmatta_ymodem_recvHeader_t  recvHeaderCallback,
+                                            shellmatta_ymodem_recvPacket_t  recvPacketCallback,
+                                            shellmatta_ymodem_complete_t    transmissionCompleteCallback)
+{
+    shellmatta_retCode_t ret = SHELLMATTA_OK;
+    shellmatta_instance_t *inst = (shellmatta_instance_t *)handle;
+
+    /** -# check parameters for plausibility  */
+    if(     (NULL               != inst)
+        &&  (SHELLMATTA_MAGIC   == inst->magic)
+        &&  (NULL               != cancelCallback)
+        &&  (NULL               != recvHeaderCallback)
+        &&  (NULL               != recvPacketCallback)
+        &&  (NULL               != transmissionCompleteCallback))
+    {
+        /** -# use instances buffer if no buffer is given */
+        if(NULL == recvBuffer)
+        {
+            if(inst->bufferSize <= YMODEM_PACKET_SIZE_1K)
+            {
+                /** -# return use fault if buffer is too small */
+                ret = SHELLMATTA_USE_FAULT;
+            }
+            else
+            {
+                inst->ymodem.packet.packetData = (uint8_t*)inst->buffer;
+            }
+        }
 
+        (void)memset((void *)&inst->ymodem, 0, sizeof(shellmatta_ymodem_t));
 
-// /**
-//  * @brief                   Gives a return code depending on symbol received at different states of the ymodem module
-//  * @param[in, out]  handle  shellmatta handle of the instance
-//  * @param[in]       byteIn  currently processed input byte
-// */
-// shellmatta_ymodem_rcv_retcode_t shellmatta_ymodem_receive_byte(shellmatta_handle_t handle, uint8_t byteIn)
-// {
-//     shellmatta_ymodem_rcv_retcode_t ret;
-//     if (SHELLMATTA_YMODEM_WAIT_FOR_START == shellmatta_ymodem_get_state(handle))
-//     {
-//         switch (byteIn)
-//         {
-//         case YMODEM_SOH:
-//             /* start of header -> default packet size */
-//             yModemPacketSize = YMODEM_PACKET_SIZE;
-//             ret = SOH_RECEIVED;
-//             break;
-        
-//         case YMODEM_STX:
-//             /* start of header -> extended packet size */
-//             yModemPacketSize = YMODEM_PACKET_SIZE_1K;
-//             ret = STX_RECEIVED;
-//             break;
-
-//         case YMODEM_EOT:
-//             /* end of transmission -> data transmission complete */
-//             ret = EOT_RECEIVED;
-//             break;
-        
-//         case YMODEM_CA:
-//             /* cancel transmssion -> reset state machine */
-//             ret = CA_RECEIVED;
-//             break;
-
-//         default:
-//             /* no other data should be received in this state */
-//             ret = ERROR;
-//             break;
-//         }
-//         /* give packet size back to upper layer */
-//         shellmatta_ymodem_packet.packetSize = yModemPacketSize;
-//     }
-//     else if (SHELLMATTA_YMODEM_RECEIVE_PACKET == shellmatta_ymodem_get_state(handle))
-//     {
-//         ret = DATA_RECEIVED;
-//     }
-//     return ret;
-// }
-
-// /**
-//  * @brief                   Checks packet data for validity and sends ACK or NAK accordingly
-//  * @param[in, out]  handle  shellmatta handle of the instance
-//  * @note                    Only to be called after full packet is received
-//  * @note                    Will call yModemRecvPacketCallback when packet is received correctly
-//  * @note                    Will call ymodemTransmissionCompleteCallback when transmission is completed
-// */
-// void shellmatta_ymodem_check_packet(shellmatta_handle_t handle)
-// {
-//     uint16_t computedCrc = 0u;
-//     if (shellmatta_ymodem_packet.packetNumber != (0xFF - shellmatta_ymodem_packet.reversePacketNumber))
-//     {
-//         shellmatta_ymodem_nak(handle);
-//         return;
-//     }
-//     /* compare to internal packet counter */
-//     if (shellmatta_ymodem_packet.packetNumber != ((uint8_t)shellmatta_ymodem_packet_counter)) /* uint8_t cast to cause overflow */
-//     {
-//         shellmatta_ymodem_nak(handle);
-//         return;
-//     }
-//     /* compare packet crc only after other checks succeeded */
-//     computedCrc = crc16Calc((const char*)shellmatta_ymodem_packet.packetData, yModemPacketSize);
-//     //! uncomment to ignore crc check for debug purposes
-//     if (shellmatta_ymodem_packet.packetCrc != computedCrc)
-//     {
-//         shellmatta_ymodem_nak(handle);
-//         return;
-//     }
-//     /* if previous checks passed, packet is acknowledged */
-//     (void) computedCrc;
-//     shellmatta_ymodem_total_bytes_received += shellmatta_ymodem_byte_counter;
-//     shellmatta_ymodem_byte_counter = 0u;
-//     shellmatta_ymodem_ack(handle);
-//     if (shellmatta_ymodem_current_data_type == YMODEM_HEADER)
-//     {
-//         /* send additional CRC symbol if the packet was a header packet */
-//         shellmatta_ymodem_control(handle, YMODEM_CRC);
-//     }
-
-//     /* callback handling */
-//     switch (shellmatta_ymodem_current_data_type)
-//     {
-//     case YMODEM_NONE:
-//         /* shouldn't happen */
-//         break;
-    
-//     case YMODEM_HEADER:
-//         /* nothing to do after receiving the header packet */
-//         break;
-
-//     case YMODEM_BODY:
-//         /* call the ymodem receive packet callback */
-//         if (NULL != shellmatta_ymodem_callbacks.yModemRecvPacketCallback)
-//         {
-//             shellmatta_ymodem_callbacks.yModemRecvPacketCallback();
-//         }
-//         break;
-
-//     case YMODEM_FOOTER:
-//         /* call the ymodem transmission complete callback */
-//         if (NULL != shellmatta_ymodem_callbacks.ymodemTransmissionCompleteCallback)
-//         {
-//             shellmatta_ymodem_callbacks.ymodemTransmissionCompleteCallback();
-//         }
-//         break;
-//     default:
-//         break;
-//     }
-// }
+        /** -# store buffer */
+        inst->ymodem.packet.packetData = recvBuffer;
 
-/**
- * @brief                   Acknowledge handling. Will send ACK and set ymodem state back to SHELLMATTA_YMODEM_WAIT_FOR_START
- * @param[in, out]  handle  shellmatta handle of the instance
-*/
-// void shellmatta_ymodem_ack(shellmatta_handle_t handle)
-// {
-//     shellmatta_ymodem_control(handle, YMODEM_ACK);
-//     shellmatta_ymodem_packet_counter++;
-//     shellmatta_ymodem_set_state(handle, SHELLMATTA_YMODEM_WAIT_FOR_START);
-// }
+        /** -# init callbacks */
+        inst->ymodem.cancelCallback = cancelCallback;
+        inst->ymodem.recvHeaderCallback = recvHeaderCallback;
+        inst->ymodem.recvPacketCallback = recvPacketCallback;
+        inst->ymodem.transmissionCompleteCallback = transmissionCompleteCallback;
+
+        inst->ymodem.state = SHELLMATTA_YMODEM_WAIT_FOR_START;
+
+        /** -# send initial ymodem symbol to start transmission */
+        shellmatta_ymodem_control(handle, YMODEM_CRC);
+    }
+    else
+    {
+        ret = SHELLMATTA_USE_FAULT;
+    }
+
+    return ret;
+}
 
 /**
- * @brief                   Not-Acknowledge handling. Will send NAK and set ymodem state back to SHELLMATTA_YMODEM_WAIT_FOR_START
- * @param[in, out]  handle  shellmatta handle of the instance
+ * @brief                   pauses the shellmatta reception until #shellmatta_ymodem_resume resume is called
+ * @param[in, out]  handle  shellmatta instance handle
+ * @return      errorcode   #SHELLMATTA_OK
+ *                          #SHELLMATTA_USE_FAULT (param err)
+ * @note                    This can be used when an application needs processing time before accepting the next packet
 */
-// void shellmatta_ymodem_nak(shellmatta_handle_t handle)
-// {
-//     shellmatta_ymodem_set_state(handle, SHELLMATTA_YMODEM_WAIT_FOR_START);
-//     /* set back current data type to prevent false forward stepping */
-//     switch (shellmatta_ymodem_current_data_type)
-//     {
-//     case YMODEM_NONE:
-//         /* no handling needed */
-//         break;
-    
-//     case YMODEM_HEADER:
-//         shellmatta_ymodem_control(handle, YMODEM_NAK);
-//         break;
-
-//     case YMODEM_BODY:
-//         /* YMODEM_BODY stays in YMODEM_BODY */
-//         shellmatta_ymodem_control(handle, YMODEM_NAK);
-//         shellmatta_ymodem_current_data_type = YMODEM_BODY;
-//         break;
-
-//     case YMODEM_FOOTER:
-//         /* YMODEM_FOOTER as well */
-//         shellmatta_ymodem_current_data_type = YMODEM_FOOTER;
-//         break;
-
-//     default:
-//         break;
-//     }
-// }
+shellmatta_retCode_t shellmatta_ymodem_pause(shellmatta_handle_t handle)
+{
+    shellmatta_retCode_t ret = SHELLMATTA_OK;
+    shellmatta_instance_t *inst = (shellmatta_instance_t *)handle;
 
+    /** -# check parameters for plausibility  */
+    if(     (NULL               != inst)
+        &&  (SHELLMATTA_MAGIC   == inst->magic))
+    {
+        inst->ymodem.pauseRequested = true;
+    }
+    else
+    {
+        ret = SHELLMATTA_USE_FAULT;
+    }
+
+    return ret;
+}
 
 /**
- * @brief                       reset function for the ymodem module
- * @param[in, out]  ymodem      shellmatta ymomdem instance
- * @param[in]       doCancel    flag to execute the cancel-callback
+ * @brief                   Resume the ymodem module
+ * @param[in, out]  handle  shellmatta instance handle
+ * @return      errorcode   #SHELLMATTA_OK
+ *                          #SHELLMATTA_USE_FAULT (param err)
+ * @note                    This can be used when an application needs processing time before accepting the next packet
 */
-void shellmatta_ymodem_reset(shellmatta_ymodem_t *ymodem, bool doCancel)
+shellmatta_retCode_t shellmatta_ymodem_resume(shellmatta_handle_t handle)
 {
-    /** -# call cancel callback function */
-    if (doCancel)
+    shellmatta_retCode_t ret = SHELLMATTA_OK;
+    shellmatta_instance_t *inst = (shellmatta_instance_t *)handle;
+
+    /** -# check parameters for plausibility  */
+    if(     (NULL               != inst)
+        &&  (SHELLMATTA_MAGIC   == inst->magic))
     {
-        /* send cancel symbol */
-        //todo - write... shellmatta_ymodem_control(handle, YMODEM_CA);
-        if (NULL != ymodem->cancelCallback)
+        /** -# ACK the successful packet reception */
+        shellmatta_ymodem_control(handle, YMODEM_ACK);
+        if(0u == inst->ymodem.packetCounter)
         {
-            ymodem->cancelCallback();
+            /** -# send addional CRC flag after packet 0 */
+            shellmatta_ymodem_control(handle, YMODEM_CRC);
         }
+        inst->ymodem.pauseRequested = false;
     }
-    /** -# reset instance variables */
-    ymodem->state = SHELLMATTA_YMODEM_INACTIVE;
-    ymodem->byteCounter = 0u;
-    ymodem->packetCounter = 0u;
-    ymodem->totalBytesReceived = 0u;
-    ymodem->fileName = NULL;
-    ymodem->fileSize = 0u;
-    (void)memset((void *)&ymodem->packet, 0, sizeof(shellmatta_ymodem_packet_t));
+    else
+    {
+        ret = SHELLMATTA_USE_FAULT;
+    }
+
+    return ret;
 }
 
 /**
- * @brief       Resets the ymodem module
+ * @brief                   Resets the ymodem module
  * @param[in]   doCancel    Set this flag to execute the cancel-callback function within the ymodem-reset function
- * @note        call this function after file transmission is done or cancelled
+ * @return      errorcode   #SHELLMATTA_OK
+ *                          #SHELLMATTA_USE_FAULT (param err)
+ * @note                    call this function after file transmission is done or cancelled
 */
-void shellmatta_ymodem_end(shellmatta_handle_t handle, bool doCancel)
+shellmatta_retCode_t shellmatta_ymodem_cancel(shellmatta_handle_t handle, bool doCancel)
 {
+    shellmatta_retCode_t ret = SHELLMATTA_OK;
     shellmatta_instance_t *inst = (shellmatta_instance_t *)handle;
 
-    shellmatta_ymodem_reset(&inst->ymodem, doCancel);
-    /* clear any possibly leftover inputs */
-    utils_clearInput((shellmatta_instance_t*)handle);
+    /** -# check parameters for plausibility  */
+    if(     (NULL               != inst)
+        &&  (SHELLMATTA_MAGIC   == inst->magic))
+    {
+        shellmatta_ymodem_reset(handle, doCancel);
+        /* clear any possibly leftover inputs */
+        utils_clearInput((shellmatta_instance_t*)handle);
+    }
+    else
+    {
+        ret = SHELLMATTA_USE_FAULT;
+    }
+
+    return ret;
 }

+ 8 - 42
src/shellmatta_ymodem.h

@@ -1,3 +1,11 @@
+/*
+ * Copyright (c) 2023 - 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    shellmatta_ymodem.h
  * @brief   ymodem functions of shellmatta
@@ -10,51 +18,9 @@
 #include <stdint.h>
 #include "shellmatta.h"
 
-/**
- * @brief return codes for receive byte function of ymodem module
-*/
-typedef enum {
-    SOH_RECEIVED,
-    STX_RECEIVED,
-    EOT_RECEIVED,
-    CA_RECEIVED,
-    DATA_RECEIVED,
-    ERROR
-} shellmatta_ymodem_rcv_retcode_t;
-
-typedef enum {
-    YMODEM_NONE,   /* no data is transmitted */
-    YMODEM_HEADER, /* header packet is transmittet */
-    YMODEM_BODY,   /* data packet is transmitted */
-    YMODEM_FOOTER  /* end of transmission packet is transmitted */
-} shellmatta_ymodem_datatype_t;
-
-
-void shellmatta_ymodem_receive_packet(  shellmatta_handle_t             handle, 
-                                        uint8_t                         byteIn);
-
 shellmatta_retCode_t shellmatta_ymodem_processByte( shellmatta_handle_t handle,
                                                     char                byte);
 
 shellmatta_retCode_t shellmatta_ymodem_poll(        shellmatta_handle_t handle);
 
-void shellmatta_ymodem_set_state(       shellmatta_handle_t             handle, 
-                                        shellmatta_ymodem_state_t       newState);
-
-shellmatta_ymodem_state_t shellmatta_ymodem_get_state(          shellmatta_handle_t handle);
-
-shellmatta_ymodem_rcv_retcode_t shellmatta_ymodem_receive_byte( shellmatta_handle_t handle, 
-                                                                uint8_t             byteIn);
-
-void shellmatta_ymodem_ack(             shellmatta_handle_t handle);
-
-void shellmatta_ymodem_nak(             shellmatta_handle_t handle);
-
-void shellmatta_ymodem_check_packet(    shellmatta_handle_t handle);
-
-void shellmatta_ymodem_reset(           shellmatta_ymodem_t *ymodem,
-                                        bool                doCancel);
-
-shellmatta_ymodem_datatype_t shellmatta_ymodem_get_current_datatype(void);
-
 #endif /* _SHELLMATTA_YMODEM_H_ */

+ 1 - 1
test/unittest/shellmatta_autocomplete/test_autocomplete_run.cpp

@@ -7,7 +7,7 @@ TEST_CASE( "shellmatta_autocomplete_run dummy" ) {
     shellmatta_instance_t inst;
     inst.inputCount = 0u;
 
-    autocomplete_run(&inst);
+    // autocomplete_run(&inst);
 
     REQUIRE( inst.inputCount == 0u);
 }