|
@@ -10,31 +10,91 @@
|
|
|
#include <stddef.h>
|
|
|
#include <string.h>
|
|
|
|
|
|
+/** @brief symbols needed for ymodem protocol */
|
|
|
+typedef enum {
|
|
|
+ YMODEM_NULL = 0x00, /**< NULL-terminator */
|
|
|
+ YMODEM_SOH = 0x01, /**< Start of header */
|
|
|
+ YMODEM_STX = 0x02, /**< Start of header for 1k packet */
|
|
|
+ YMODEM_EOT = 0x04, /**< End of transmission */
|
|
|
+ YMODEM_ACK = 0x06, /**< Acknowledge */
|
|
|
+ YMODEM_NAK = 0x15, /**< Negative acknowledge */
|
|
|
+ YMODEM_CA = 0x18, /**< Cancel */
|
|
|
+ YMODEM_SPACE = 0x20, /**< Space */
|
|
|
+ YMODEM_CRC = 0x43 /**< 'C' to indicate CRC type */
|
|
|
+} YMODEM_SYMBOLS;
|
|
|
+
|
|
|
+#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 */
|
|
|
+
|
|
|
+/**
|
|
|
+ * @brief forwards the given character to write-function without formatting
|
|
|
+ * @param[in] handle shellmatta handle of the instance
|
|
|
+ * @param[in] c character to be sent
|
|
|
+*/
|
|
|
+static void shellmatta_ymodem_control(shellmatta_handle_t handle, const uint8_t c)
|
|
|
+{
|
|
|
+ shellmatta_instance_t *inst = (shellmatta_instance_t*)handle;
|
|
|
+ SHELLMATTA_WRITE((char*)&c, 1);
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* @brief Initialise the ymodem prior to actually receiving data
|
|
|
- * @param[in, out] ymodem shellmatta ymodem instance
|
|
|
+ * @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
|
|
|
*/
|
|
|
-void shellmatta_ymodem_init(shellmatta_ymodem_t *ymodem,
|
|
|
- uint8_t* recvBuffer,
|
|
|
- void (*cancelCallback)(void),
|
|
|
- void (*recvPacketCallback)(void),
|
|
|
- void (*transmissionCompleteCallback)(void))
|
|
|
+shellmatta_retCode_t shellmatta_ymodem_init(shellmatta_handle_t handle,
|
|
|
+ uint8_t* recvBuffer,
|
|
|
+ void (*cancelCallback)(void),
|
|
|
+ void (*recvPacketCallback)(void),
|
|
|
+ void (*transmissionCompleteCallback)(void))
|
|
|
{
|
|
|
- memset((void *)&ymodem, 0, sizeof(shellmatta_ymodem_t));
|
|
|
+ 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))
|
|
|
+ {
|
|
|
+ /** -# 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;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- /** -# store buffer */
|
|
|
- ymodem->packet.packetData = recvBuffer;
|
|
|
+ /** -# store buffer */
|
|
|
+ inst->ymodem.packet.packetData = recvBuffer;
|
|
|
|
|
|
- /** -# init callbacks */
|
|
|
- ymodem->cancelCallback = cancelCallback;
|
|
|
- ymodem->recvPacketCallback = recvPacketCallback;
|
|
|
- ymodem->transmissionCompleteCallback = transmissionCompleteCallback;
|
|
|
+ /** -# init callbacks */
|
|
|
+ inst->ymodem.cancelCallback = cancelCallback;
|
|
|
+ inst->ymodem.recvPacketCallback = recvPacketCallback;
|
|
|
+ inst->ymodem.transmissionCompleteCallback = transmissionCompleteCallback;
|
|
|
|
|
|
- ymodem->state = SHELLMATTA_YMODEM_WAIT_FOR_START;
|
|
|
+ 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;
|
|
|
}
|
|
|
|
|
|
// /**
|
|
@@ -286,15 +346,154 @@ void shellmatta_ymodem_init(shellmatta_ymodem_t *ymodem,
|
|
|
// }
|
|
|
// 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;
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+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;
|
|
|
+ uint16_t computedCrc;
|
|
|
+
|
|
|
+ switch(inst->ymodem.state)
|
|
|
+ {
|
|
|
+ case SHELLMATTA_YMODEM_INACTIVE:
|
|
|
+ /** -# skip state machine if inactive */
|
|
|
+ break;
|
|
|
+ case SHELLMATTA_YMODEM_WAIT_FOR_START:
|
|
|
+ /** -# Wait for start character */
|
|
|
+ inst->ymodem.byteCounter = 0u;
|
|
|
+ switch(byte)
|
|
|
+ {
|
|
|
+ case YMODEM_SOH:
|
|
|
+ inst->ymodem.packet.size = YMODEM_PACKET_SIZE;
|
|
|
+ inst->ymodem.state = SHELLMATTA_YMODEM_RECEIVE_HEADER;
|
|
|
+ break;
|
|
|
+ case YMODEM_STX:
|
|
|
+ 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();
|
|
|
+ }
|
|
|
+ /** -# ACK the successful file reception */
|
|
|
+ shellmatta_ymodem_control(handle, YMODEM_ACK);
|
|
|
+ shellmatta_ymodem_control(handle, YMODEM_CRC);
|
|
|
+ inst->ymodem.state = SHELLMATTA_YMODEM_INACTIVE;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ /** -# ignore unexpected characters on start */
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case SHELLMATTA_YMODEM_RECEIVE_HEADER:
|
|
|
+ if(0u == inst->ymodem.byteCounter)
|
|
|
+ {
|
|
|
+ inst->ymodem.packet.packetNumber = byte;
|
|
|
+ inst->ymodem.byteCounter ++;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if(((0xffu - byte) != inst->ymodem.packet.packetNumber) ||
|
|
|
+ (inst->ymodem.packetCounter % 256u != inst->ymodem.packet.packetNumber))
|
|
|
+ {
|
|
|
+ /** -# return error on packet number mismatch or on unexpected packet numbers */
|
|
|
+ inst->ymodem.state = SHELLMATTA_YMODEM_WAIT_FOR_START;
|
|
|
+ ret = SHELLMATTA_ERROR;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ /** -# start receiving the payload */
|
|
|
+ inst->ymodem.state = SHELLMATTA_YMODEM_RECEIVE_DATA;
|
|
|
+ inst->ymodem.byteCounter = 0u;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case SHELLMATTA_YMODEM_RECEIVE_DATA:
|
|
|
+ inst->ymodem.packet.packetData[inst->ymodem.byteCounter] = byte;
|
|
|
+ inst->ymodem.byteCounter ++;
|
|
|
+
|
|
|
+ /** -# load payload until the packet is full */
|
|
|
+ if(inst->ymodem.byteCounter >= inst->ymodem.packet.size)
|
|
|
+ {
|
|
|
+ inst->ymodem.state = SHELLMATTA_YMODEM_RECEIVE_CRC;
|
|
|
+ inst->ymodem.byteCounter = 0u;
|
|
|
+ inst->ymodem.packet.crc = 0u;
|
|
|
+ }
|
|
|
+
|
|
|
+ break;
|
|
|
+ case SHELLMATTA_YMODEM_RECEIVE_CRC:
|
|
|
+ inst->ymodem.byteCounter ++;
|
|
|
+ inst->ymodem.packet.crc |= (uint16_t)byte << (8u * (YMODEM_CRC_SIZE - inst->ymodem.byteCounter));
|
|
|
+
|
|
|
+ if(inst->ymodem.byteCounter >= YMODEM_CRC_SIZE)
|
|
|
+ {
|
|
|
+ /** -# check CRC */
|
|
|
+ computedCrc = crc16Calc((const char*)inst->ymodem.packet.packetData,
|
|
|
+ inst->ymodem.packet.size);
|
|
|
+ if(computedCrc != inst->ymodem.packet.crc)
|
|
|
+ {
|
|
|
+ ret = SHELLMATTA_ERROR;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ 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?
|
|
|
+
|
|
|
+ /** -# 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
|
|
|
+ {
|
|
|
+ /** -# Calculate the total bytes received */
|
|
|
+ inst->ymodem.totalBytesReceived += inst->ymodem.packet.size;
|
|
|
+ }
|
|
|
+ inst->ymodem.packetCounter ++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ inst->ymodem.state = SHELLMATTA_YMODEM_WAIT_FOR_START;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ /** -# unexpected state - should never happen */
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
|
|
|
shellmatta_retCode_t shellmatta_ymodem_processByte(shellmatta_handle_t handle, char byte)
|
|
|
{
|
|
|
shellmatta_instance_t *inst = (shellmatta_instance_t*)handle;
|
|
|
+ shellmatta_retCode_t ret;
|
|
|
|
|
|
/** -# check if session is cancelled -accept only if ymodem is between packets */
|
|
|
if(('\x03' == byte) && (inst->ymodem.state == SHELLMATTA_YMODEM_WAIT_FOR_START))
|
|
@@ -304,12 +503,14 @@ shellmatta_retCode_t shellmatta_ymodem_processByte(shellmatta_handle_t handle, c
|
|
|
|
|
|
utils_terminateInput(inst);
|
|
|
|
|
|
- return SHELLMATTA_ERROR;
|
|
|
+ ret = SHELLMATTA_ERROR;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ ret = ymodem_stateMachine(handle, (uint8_t)byte);
|
|
|
}
|
|
|
|
|
|
- //shellmatta_ymodem_receive_packet(handle, byte);
|
|
|
-
|
|
|
- return SHELLMATTA_OK;
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
|
|
@@ -495,15 +696,6 @@ shellmatta_retCode_t shellmatta_ymodem_poll(shellmatta_handle_t handle)
|
|
|
// }
|
|
|
// }
|
|
|
|
|
|
-/**
|
|
|
- * @brief forwards the given character to write-function without formatting
|
|
|
- * @param[in] handle shellmatta handle of the instance
|
|
|
- * @param[in] c character to be sent
|
|
|
-*/
|
|
|
-void shellmatta_ymodem_control(shellmatta_handle_t handle, const char c)
|
|
|
-{
|
|
|
- ((shellmatta_instance_t*)handle)->write(&c, 1);
|
|
|
-}
|
|
|
|
|
|
/**
|
|
|
* @brief reset function for the ymodem module
|
|
@@ -532,30 +724,6 @@ void shellmatta_ymodem_reset(shellmatta_ymodem_t *ymodem, bool doCancel)
|
|
|
(void)memset((void *)&ymodem->packet, 0, sizeof(shellmatta_ymodem_packet_t));
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * @brief starts the ymodem receive module
|
|
|
- * @param[in] handle shellmatta instance handle
|
|
|
- * @param[in] buffer pointer to where the received data is stored
|
|
|
- * @param[in] callbacks callback functions for ymodem module
|
|
|
- * @note disables the transport layer if active
|
|
|
-*/
|
|
|
-uint8_t shellmatta_ymodem( shellmatta_handle_t handle,
|
|
|
- uint8_t* buffer,
|
|
|
- void (*cancelCallback)(void),
|
|
|
- void (*recvPacketCallback)(void),
|
|
|
- void (*transmissionCompleteCallback)(void))
|
|
|
-{
|
|
|
- shellmatta_instance_t *inst = (shellmatta_instance_t *)handle;
|
|
|
-
|
|
|
- // todo check magic
|
|
|
-
|
|
|
- shellmatta_ymodem_init(&inst->ymodem, buffer, cancelCallback, recvPacketCallback, transmissionCompleteCallback);
|
|
|
-
|
|
|
- /* send initial ymodem symbol to start transmission */
|
|
|
- shellmatta_ymodem_control(handle, YMODEM_CRC);
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
/**
|
|
|
* @brief Resets the ymodem module
|
|
|
* @param[in] doCancel Set this flag to execute the cancel-callback function within the ymodem-reset function
|