Files
test_rtt_413/iap/iap.c

478 lines
9.9 KiB
C
Raw Normal View History

#include "rtthread.h"
#include "ipc/completion.h"
#include "ymodem.h"
#include "fal.h"
#define IAP_FLASH_SEC "app"
struct rt_completion _wait;
#define IS_AF(c) ((c >= 'A') && (c <= 'F'))
#define IS_af(c) ((c >= 'a') && (c <= 'f'))
#define IS_09(c) ((c >= '0') && (c <= '9'))
#define ISVALIDHEX(c) IS_AF(c) || IS_af(c) || IS_09(c)
#define ISVALIDDEC(c) IS_09(c)
#define CONVERTDEC(c) (c - '0')
#define CONVERTHEX_alpha(c) (IS_AF(c) ? (c - 'A'+10) : (c - 'a'+10))
#define CONVERTHEX(c) (IS_09(c) ? (c - '0') : CONVERTHEX_alpha(c))
/**
* @brief Convert a string to an integer
* @param inputstr: The string to be converted
* @param intnum: The intger value
* @retval 1: Correct
* 0: Error
*/
rt_inline rt_uint32_t Str2Int(uint8_t *inputstr, int32_t *intnum)
{
rt_uint32_t i = 0, res = 0;
rt_uint32_t val = 0;
if (inputstr[0] == '0' && (inputstr[1] == 'x' || inputstr[1] == 'X'))
{
if (inputstr[2] == '\0')
{
return 0;
}
for (i = 2; i < 11; i++)
{
if (inputstr[i] == '\0')
{
*intnum = val;
/* return 1; */
res = 1;
break;
}
if (ISVALIDHEX(inputstr[i]))
{
val = (val << 4) + CONVERTHEX(inputstr[i]);
}
else
{
/* return 0, Invalid input */
res = 0;
break;
}
}
/* over 8 digit hex --invalid */
if (i >= 11)
{
res = 0;
}
}
else /* max 10-digit decimal input */
{
for (i = 0;i < 11;i++)
{
if (inputstr[i] == '\0')
{
*intnum = val;
/* return 1 */
res = 1;
break;
}
else if ((inputstr[i] == 'k' || inputstr[i] == 'K') && (i > 0))
{
val = val << 10;
*intnum = val;
res = 1;
break;
}
else if ((inputstr[i] == 'm' || inputstr[i] == 'M') && (i > 0))
{
val = val << 20;
*intnum = val;
res = 1;
break;
}
else if (ISVALIDDEC(inputstr[i]))
{
val = val * 10 + CONVERTDEC(inputstr[i]);
}
else
{
/* return 0, Invalid input */
res = 0;
break;
}
}
/* Over 10 digit decimal --invalid */
if (i >= 11)
{
res = 0;
}
}
return res;
}
rt_err_t port_rx_ind(rt_device_t dev, rt_size_t size)
{
rt_completion_done(&_wait);
return RT_EOK;
}
#define RT_BUF_SIZE (1024)
struct custom_ctx {
struct rym_ctx parent;
int32_t file_size;
int32_t w_index;
const struct fal_partition *flash;
rt_uint8_t ck_buffer[RT_BUF_SIZE];
};
static enum rym_code _rym_recv_begin(
struct rym_ctx *ctx,
rt_uint8_t *buf,
rt_size_t len)
{
// return RYM_ERR_ACK;
// return RYM_CODE_CAN;
struct custom_ctx *cctx = (struct custom_ctx *) ctx;
RT_ASSERT(cctx);
rt_uint8_t tmp_size[16] = {0};
while (*buf != 0)
{
buf ++;
}
buf ++;
rt_bool_t end = RT_FALSE;
for (rt_uint8_t i = 0; i < 16; i++)
{
if (*buf == 0)
{
tmp_size[i] = 0;
end = RT_TRUE;
break;
}
tmp_size[i] = *buf++;
}
if (!end)
{
return RYM_CODE_CAN;
}
if (!Str2Int(tmp_size, &cctx->file_size))
{
return RYM_CODE_CAN;
}
if (cctx->file_size >= cctx->flash->len)
{
return RYM_CODE_CAN;
}
if (fal_partition_erase(cctx->flash, 0, cctx->file_size) < 0)
{
return RYM_CODE_CAN;
}
cctx->w_index = 0;
return RYM_CODE_ACK;
}
static enum rym_code _rym_recv_data(
struct rym_ctx *ctx,
rt_uint8_t *buf,
rt_size_t len)
{
struct custom_ctx *cctx = (struct custom_ctx *) ctx;
RT_ASSERT(cctx);
RT_ASSERT(len <= RT_BUF_SIZE);
if (cctx->w_index >= cctx->file_size)
{
return RYM_CODE_ACK;
}
if (cctx->w_index + len > cctx->file_size)
{
len = cctx->file_size - cctx->w_index;
}
if (fal_partition_write(cctx->flash, cctx->w_index, buf, len) <= 0)
{
return RYM_CODE_CAN;
}
if (fal_partition_read(cctx->flash, cctx->w_index, cctx->ck_buffer, len) <= 0)
{
return RYM_CODE_CAN;
}
for (int i = 0; i < len; i++)
{
if (cctx->ck_buffer[i] != buf[i])
return RYM_CODE_CAN;
}
cctx->w_index += len;
return RYM_CODE_ACK;
}
static enum rym_code _rym_recv_end(
struct rym_ctx *ctx,
rt_uint8_t *buf,
rt_size_t len)
{
return RYM_CODE_ACK;
}
enum iap_v5_cmd
{
IAP_V5_CMD_ONE_REPLY = 1,
IAP_V5_CMD_C_REPLY,
IAP_V5_CMD_UPDATE_SUCCEED,
IAP_V5_CMD_UPDATE_FAILED,
IAP_V5_CMD_BIN_OVERSIZE,
IAP_V5_CMD_CHECK_FAILED,
IAP_V5_CMD_USER_CANCEL,
IAP_V5_CMD_RECEIVE_FAILED,
IAP_V5_CMD_POWER_ON_AGAIN,
};
/**
* @brief
*
* 0xB5,0x5B,{cmd},0xBB, 0x00
*/
#define IAP_V5_CMD_SIZE (5)
static const rt_uint8_t *_pack_cmd(enum iap_v5_cmd cmd)
{
static rt_uint8_t _cmd_line[IAP_V5_CMD_SIZE]
= { 0xB5, 0x5B, 0x00, 0xBB, 0x00 };
_cmd_line[2] = cmd;
return _cmd_line;
}
#define _response_cmd(console_dev, cmd) \
rt_device_write(console_dev, 0, _pack_cmd(cmd), IAP_V5_CMD_SIZE)
static void jump_to_app(void);
extern const uint32_t IapAppAddr;
#define PORTS_NUM (10) // uart1 - uart10
static rt_device_t _read_ports(rt_device_t ports[], rt_uint8_t *pch)
{
for (int i = 0; i < PORTS_NUM; i++)
{
while (1)
{
if (rt_device_read(ports[i], 0, pch, 1) != 1)
{
break;
}
if (*pch == '1' || *pch == 'q')
{
return ports[i];
}
}
}
return RT_NULL;
}
static void _print_ports(rt_device_t ports[], const char *fmt, ...)
{
va_list args;
char line_buf[128] = { 0 };
rt_size_t real;
va_start(args, fmt);
real = rt_vsnprintf(line_buf, sizeof(line_buf), fmt, args);
va_end(args);
for (int i = 0; i < PORTS_NUM; i++)
{
rt_device_write(ports[i], 0, line_buf, real);
}
}
int iap_main_entry(void)
{
if (IapAppAddr)
{
return 0;
}
rt_err_t err = RT_EOK;
struct custom_ctx *ctx = RT_NULL;
rt_device_t console = rt_console_get_device();
RT_ASSERT(console);
rt_device_t ports[10] = {0};
char name[RT_NAME_MAX] = {0};
rt_completion_init(&_wait);
rt_bool_t _wait_mode = RT_FALSE;
rt_bool_t _continue_run = RT_FALSE;
for (int i = 0; i < 10; i++)
{
rt_snprintf(name, RT_NAME_MAX, "uart%d", i+1);
ports[i] = rt_device_find(name);
RT_ASSERT(ports[i]);
rt_device_set_rx_indicate(ports[i], port_rx_ind);
rt_device_open(ports[i], RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX);
}
rt_device_t get_port = RT_NULL;
rt_uint8_t wait_cnt = 3;
rt_uint8_t ch;
_print_ports(ports, "iap loop ...");
while (wait_cnt > 0)
{
get_port = _read_ports(ports, &ch);
if (get_port != RT_NULL)
{
if (ch == 'q')
{
_continue_run = RT_TRUE;
break;
}
if (ch == '1')
{
_wait_mode = RT_TRUE;
_response_cmd(get_port, IAP_V5_CMD_ONE_REPLY);
break;
}
}
else
{
wait_cnt--;
}
rt_completion_wait(&_wait, rt_tick_from_millisecond(100));
}
if (get_port == RT_NULL)
{
get_port = console;
}
for (int i = 0; i < PORTS_NUM; i++)
{
if (ports[i] == get_port)
{
continue;
}
rt_device_set_rx_indicate(ports[i], RT_NULL);
rt_device_close(ports[i]);
}
if (get_port != console)
{
rt_console_set_device(get_port->parent.name);
}
if (_continue_run)
{
rt_device_close(get_port);
return 0;
}
if (!_wait_mode)
{
rt_device_close(get_port);
err = RT_EOK;
goto _exit;
}
rt_device_set_rx_indicate(get_port, port_rx_ind);
rt_thread_mdelay(200);
_response_cmd(get_port, IAP_V5_CMD_C_REPLY);
ctx = rt_calloc(1, sizeof(*ctx));
if (!ctx)
{
err = RT_ENOMEM;
rt_kprintf("rt_malloc failed\n");
goto _exit;
}
ctx->flash = fal_partition_find(IAP_FLASH_SEC);
if (ctx->flash == RT_NULL)
{
err = RT_ENOSYS;
rt_kprintf("fal_partition_find %s failed: %d\n", IAP_FLASH_SEC, rt_get_errno());
rt_free(ctx);
goto _exit;
}
err = rym_recv_on_device(&ctx->parent, get_port, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX,
_rym_recv_begin, _rym_recv_data, _rym_recv_end, 1000);
rt_free(ctx);
rt_thread_mdelay(200);
if (err == RT_EOK)
{
rt_device_close(get_port);
_response_cmd(get_port, IAP_V5_CMD_UPDATE_SUCCEED);
return 0;
}
_exit:
rt_device_close(get_port);
if (err == RT_EOK)
{
rt_kprintf("jump to app ...\n");
jump_to_app();
return 0;
}
_response_cmd(get_port, IAP_V5_CMD_UPDATE_FAILED);
_response_cmd(get_port, IAP_V5_CMD_POWER_ON_AGAIN);
return 0;
}
#include <stm32f4xx.h>
#include <stdint.h>
#define FLASH_RUN_BASEADDR 0x08020000
//定义函数指针用于跳转到APP
typedef void (*pFunction)(void);
static pFunction JumpToApplication;
static uint32_t JumpAddress;
static void jump_to_app(void)
{
SysTick->CTRL = 0; //关键代码
HAL_DeInit(); //可选
HAL_NVIC_DisableIRQ(SysTick_IRQn); //可选
HAL_NVIC_ClearPendingIRQ(SysTick_IRQn); //可选
/* Jump to user application */
__disable_irq();
JumpAddress = *(__IO uint32_t*) (FLASH_RUN_BASEADDR + 4);
JumpToApplication = (pFunction) JumpAddress;
/* Initialize user application's Stack Pointer */
__set_MSP(*(__IO uint32_t*) FLASH_RUN_BASEADDR);
JumpToApplication();
}
MSH_CMD_EXPORT(jump_to_app, jump_to_app);