/** *! * \file b_mod_ymodem.c * \version v0.0.1 * \date 2020/02/12 * \author Bean(notrynohigh@outlook.com) ******************************************************************************* * @attention * * Copyright (c) 2020 Bean * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. ******************************************************************************* */ /*Includes ----------------------------------------------*/ #include "modules/inc/b_mod_ymodem.h" #include "core/inc/b_section.h" #if _YMODEM_ENABLE #include <string.h> #include "hal/inc/b_hal.h" /** * \addtogroup BABYOS * \{ */ /** * \addtogroup MODULES * \{ */ /** * \addtogroup YMODEM * \{ */ /** * \defgroup YMODEM_Private_TypesDefinitions * \{ */ /** * \} */ /** * \defgroup YMODEM_Private_Defines * \{ */ #define YM_S_NULL 0 #define YM_S_WAIT_NAME 1 #define YM_S_WAIT_START 2 #define YM_S_WAIT_DATA 3 #define YM_S_WAIT_END 4 /** * \} */ /** * \defgroup YMODEM_Private_Macros * \{ */ /** * \} */ /** * \defgroup YMODEM_Private_Variables * \{ */ static bYmodemInfo_t bYmodemInfo = { .cb = NULL, .send_f = NULL, .statu = YM_S_NULL, .tt_count = 0, .next_number = 0, .tick = 0, }; /** * \} */ /** * \defgroup YMODEM_Private_FunctionPrototypes * \{ */ /** * \} */ /** * \defgroup YMODEM_Private_Functions * \{ */ static uint16_t _bYmodemCalCheck(uint8_t *pbuf, uint16_t len) { uint16_t crc = 0; uint16_t i, j; for (i = 0; i < len; i++) { crc = crc ^ pbuf[i] << 8; for (j = 0; j < 8; j++) { if (crc & 0x8000) { crc = crc << 1 ^ 0x1021; } else { crc = crc << 1; } } } return crc; } static int _bYmodemISValid(uint8_t *pbuf, uint16_t len) { bYmodem128Struct_t *ptmp = (bYmodem128Struct_t *)pbuf; static uint16_t check; if (pbuf == NULL || (len != sizeof(bYmodem128Struct_t) && len != sizeof(bYmodem1kStruct_t))) { return -1; } if ((ptmp->soh != YMODEM_SOH && ptmp->soh != YMODEM_STX) || (ptmp->number + ptmp->xnumber) != 0xff) { return -1; } check = _bYmodemCalCheck(pbuf + 3, len - 5); if (((check & 0xff00) >> 8) != pbuf[len - 2] || (check & 0xff) != pbuf[len - 1]) { return -1; } return ptmp->soh; } static void _bYmodemTimeout() { if (bYmodemInfo.statu == YM_S_NULL) { return; } if (bHalGetSysTick() - bYmodemInfo.tick >= MS2TICKS(2000)) { bYmodemInfo.tick = bHalGetSysTick(); if (bYmodemInfo.tt_count >= 10) { bYmodemInfo.tt_count = 0; if (bYmodemInfo.cb) { bYmodemInfo.cb(0, NULL, 0); } bYmodemInfo.statu = YM_S_NULL; return; } bYmodemInfo.tt_count++; switch (bYmodemInfo.statu) { case YM_S_WAIT_NAME: case YM_S_WAIT_START: bYmodemInfo.send_f(YMODEM_C); break; case YM_S_WAIT_DATA: case YM_S_WAIT_END: bYmodemInfo.send_f(YMODEM_NAK); break; default: break; } } } BOS_REG_POLLING_FUNC(_bYmodemTimeout); /** * \} */ /** * \addtogroup YMODEM_Exported_Functions * \{ */ int bYmodemInit(pymcb_t fcb, pymsend fs) { if (fcb == NULL || fs == NULL) { return -1; } bYmodemInfo.cb = fcb; bYmodemInfo.send_f = fs; bYmodemInfo.statu = YM_S_NULL; return 0; } int bYmodemStart() { if (bYmodemInfo.send_f == NULL) { return -1; } if (bYmodemInfo.statu == YM_S_NULL) { bYmodemInfo.send_f(YMODEM_C); bYmodemInfo.tick = bHalGetSysTick(); bYmodemInfo.statu = YM_S_WAIT_NAME; bYmodemInfo.next_number = 0; bYmodemInfo.tt_count = 0; } return 0; } int bYmodemStop() { if (bYmodemInfo.send_f == NULL) { return -1; } if (bYmodemInfo.statu != YM_S_NULL) { bYmodemInfo.send_f(YMODEM_CAN); bYmodemInfo.statu = YM_S_NULL; } return 0; } int bYmodemParse(uint8_t *pbuf, uint16_t len) { int t; bYmodem128Struct_t *pxm = (bYmodem128Struct_t *)pbuf; if (pbuf == NULL || bYmodemInfo.cb == NULL || bYmodemInfo.send_f == NULL || bYmodemInfo.statu == YM_S_NULL) { return -1; } bYmodemInfo.tick = bHalGetSysTick(); bYmodemInfo.tt_count = 0; if (bYmodemInfo.statu == YM_S_WAIT_NAME) { if (_bYmodemISValid(pbuf, len) == YMODEM_SOH) { if (pxm->number == 0) { if (pxm->dat[0] == 0) { bYmodemInfo.send_f(YMODEM_ACK); bYmodemInfo.cb(YMODEM_FILEDATA, NULL, 0); bYmodemInfo.statu = YM_S_NULL; } else { bYmodemInfo.cb(YMODEM_FILENAME, pxm->dat, 128); // [%s %s] [name file_size] bYmodemInfo.send_f(YMODEM_ACK); bYmodemInfo.send_f(YMODEM_C); bYmodemInfo.statu = YM_S_WAIT_START; } } } else { bYmodemInfo.send_f(YMODEM_ACK); bYmodemInfo.cb(YMODEM_FILEDATA, NULL, 0); bYmodemInfo.statu = YM_S_NULL; } } else if (bYmodemInfo.statu == YM_S_WAIT_START) { t = _bYmodemISValid(pbuf, len); if (t > 0 && pxm->number == 1) { bYmodemInfo.statu = YM_S_WAIT_DATA; bYmodemInfo.next_number = 1; } } if (bYmodemInfo.statu == YM_S_WAIT_DATA) { t = _bYmodemISValid(pbuf, len); if (t > 0) { if (pxm->number == bYmodemInfo.next_number) { if (t == YMODEM_SOH) { bYmodemInfo.cb(YMODEM_FILEDATA, pxm->dat, 128); } else if (t == YMODEM_STX) { bYmodemInfo.cb(YMODEM_FILEDATA, pxm->dat, 1024); } bYmodemInfo.next_number += 1; bYmodemInfo.send_f(YMODEM_ACK); } else if (pxm->number > bYmodemInfo.next_number) { bYmodemInfo.cb(0, NULL, 0); bYmodemInfo.statu = YM_S_NULL; bYmodemInfo.send_f(YMODEM_CAN); return -1; } } else if (len == 1 && *pbuf == YMODEM_EOT) { bYmodemInfo.send_f(YMODEM_NAK); bYmodemInfo.statu = YM_S_WAIT_END; } } else if (bYmodemInfo.statu == YM_S_WAIT_END) { if (len == 1 && *pbuf == YMODEM_EOT) { bYmodemInfo.send_f(YMODEM_ACK); bYmodemInfo.send_f(YMODEM_C); bYmodemInfo.statu = YM_S_WAIT_NAME; } } return 0; } /** * \} */ /** * \} */ /** * \} */ /** * \} */ #endif /************************ Copyright (c) 2019 Bean *****END OF FILE****/