587 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			587 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| 
								 | 
							
								/****************************************************************************
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Copyright(c) 2019 by Aerospace C.Power (Chongqing) Microelectronics. ALL RIGHTS RESERVED.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								This Information is proprietary to Aerospace C.Power (Chongqing) Microelectronics and MAY NOT
							 | 
						||
| 
								 | 
							
								be copied by any method or incorporated into another program without
							 | 
						||
| 
								 | 
							
								the express written consent of Aerospace C.Power. This Information or any portion
							 | 
						||
| 
								 | 
							
								thereof remains the property of Aerospace C.Power. The Information contained herein
							 | 
						||
| 
								 | 
							
								is believed to be accurate and Aerospace C.Power assumes no responsibility or
							 | 
						||
| 
								 | 
							
								liability for its use in any way and conveys no license or title under
							 | 
						||
| 
								 | 
							
								any patent or copyright and makes no representation or warranty that this
							 | 
						||
| 
								 | 
							
								Information is free from patent or copyright infringement.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								****************************************************************************/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include "vc_upgrade_driver.h"
							 | 
						||
| 
								 | 
							
								#include "iot_errno_api.h"
							 | 
						||
| 
								 | 
							
								#include "os_utils_api.h"
							 | 
						||
| 
								 | 
							
								#include "os_mem_api.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* define stm32 reply data */
							 | 
						||
| 
								 | 
							
								#define STM32_ACK         0x79
							 | 
						||
| 
								 | 
							
								#define STM32_NACK        0x1F
							 | 
						||
| 
								 | 
							
								#define STM32_BUSY        0x76
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* define the instructions supported by stm32 */
							 | 
						||
| 
								 | 
							
								/* init cmd */
							 | 
						||
| 
								 | 
							
								#define STM32_CMD_INIT    0x7F
							 | 
						||
| 
								 | 
							
								/* get the version and command supported */
							 | 
						||
| 
								 | 
							
								#define STM32_CMD_GET     0x00
							 | 
						||
| 
								 | 
							
								/* get version and read protection status */
							 | 
						||
| 
								 | 
							
								#define STM32_CMD_GVR     0x01
							 | 
						||
| 
								 | 
							
								/* get ID */
							 | 
						||
| 
								 | 
							
								#define STM32_CMD_GID     0x02
							 | 
						||
| 
								 | 
							
								/* read memory */
							 | 
						||
| 
								 | 
							
								#define STM32_CMD_RM      0x11
							 | 
						||
| 
								 | 
							
								/* go */
							 | 
						||
| 
								 | 
							
								#define STM32_CMD_GO      0x21
							 | 
						||
| 
								 | 
							
								/* write memory */
							 | 
						||
| 
								 | 
							
								#define STM32_CMD_WM      0x31
							 | 
						||
| 
								 | 
							
								/* no-stretch write memory */
							 | 
						||
| 
								 | 
							
								#define STM32_CMD_WM_NS   0x32
							 | 
						||
| 
								 | 
							
								/* erase */
							 | 
						||
| 
								 | 
							
								#define STM32_CMD_ER      0x43
							 | 
						||
| 
								 | 
							
								/* extended erase */
							 | 
						||
| 
								 | 
							
								#define STM32_CMD_EE      0x44
							 | 
						||
| 
								 | 
							
								/* extended erase no-stretch */
							 | 
						||
| 
								 | 
							
								#define STM32_CMD_EE_NS   0x45
							 | 
						||
| 
								 | 
							
								/* write protect */
							 | 
						||
| 
								 | 
							
								#define STM32_CMD_WP      0x63
							 | 
						||
| 
								 | 
							
								/* write protect no-stretch */
							 | 
						||
| 
								 | 
							
								#define STM32_CMD_WP_NS   0x64
							 | 
						||
| 
								 | 
							
								/* write unprotect */
							 | 
						||
| 
								 | 
							
								#define STM32_CMD_UW      0x73
							 | 
						||
| 
								 | 
							
								/* write unprotect no-stretch */
							 | 
						||
| 
								 | 
							
								#define STM32_CMD_UW_NS   0x74
							 | 
						||
| 
								 | 
							
								/* readout protect */
							 | 
						||
| 
								 | 
							
								#define STM32_CMD_RP      0x82
							 | 
						||
| 
								 | 
							
								/* readout protect no-stretch */
							 | 
						||
| 
								 | 
							
								#define STM32_CMD_RP_NS   0x83
							 | 
						||
| 
								 | 
							
								/* readout unprotect */
							 | 
						||
| 
								 | 
							
								#define STM32_CMD_UR      0x92
							 | 
						||
| 
								 | 
							
								/* readout unprotect no-stretch */
							 | 
						||
| 
								 | 
							
								#define STM32_CMD_UR_NS   0x93
							 | 
						||
| 
								 | 
							
								/* compute CRC */
							 | 
						||
| 
								 | 
							
								#define STM32_CMD_CRC     0xA1
							 | 
						||
| 
								 | 
							
								/* not a valid command */
							 | 
						||
| 
								 | 
							
								#define STM32_CMD_ERR     0xFF
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								extern const stm32_dev_t devices[];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								int is_addr_in_ram(const stm32_t *stm, uint32_t addr)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    return addr >= stm->dev->ram_start && addr < stm->dev->ram_end;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								int is_addr_in_flash(const stm32_t *stm, uint32_t addr)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    return addr >= stm->dev->fl_start && addr < stm->dev->fl_end;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								int is_addr_in_opt_bytes(const stm32_t *stm, uint32_t addr)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    /* option bytes upper range is inclusive in our device table */
							 | 
						||
| 
								 | 
							
								    return addr >= stm->dev->opt_start && addr <= stm->dev->opt_end;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								int is_addr_in_sysmem(const stm32_t *stm, uint32_t addr)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    return addr >= stm->dev->mem_start && addr < stm->dev->mem_end;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* returns the page that contains address "addr" */
							 | 
						||
| 
								 | 
							
								int flash_addr_to_page_floor(const stm32_t *stm, uint32_t addr)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    int page;
							 | 
						||
| 
								 | 
							
								    uint32_t *psize;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (!is_addr_in_flash(stm, addr))
							 | 
						||
| 
								 | 
							
								        return 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    page = 0;
							 | 
						||
| 
								 | 
							
								    addr -= stm->dev->fl_start;
							 | 
						||
| 
								 | 
							
								    psize = stm->dev->fl_ps;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    while (addr >= psize[0]) {
							 | 
						||
| 
								 | 
							
								        addr -= psize[0];
							 | 
						||
| 
								 | 
							
								        page++;
							 | 
						||
| 
								 | 
							
								        if (psize[1])
							 | 
						||
| 
								 | 
							
								            psize++;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return page;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* returns the first page whose start addr is >= "addr" */
							 | 
						||
| 
								 | 
							
								int flash_addr_to_page_ceil(const stm32_t *stm, uint32_t addr)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    int page;
							 | 
						||
| 
								 | 
							
								    uint32_t *psize;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (!(addr >= stm->dev->fl_start && addr <= stm->dev->fl_end))
							 | 
						||
| 
								 | 
							
								        return 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    page = 0;
							 | 
						||
| 
								 | 
							
								    addr -= stm->dev->fl_start;
							 | 
						||
| 
								 | 
							
								    psize = stm->dev->fl_ps;
							 | 
						||
| 
								 | 
							
								    while (addr >= psize[0]) {
							 | 
						||
| 
								 | 
							
								        addr -= psize[0];
							 | 
						||
| 
								 | 
							
								        page++;
							 | 
						||
| 
								 | 
							
								        if (psize[1])
							 | 
						||
| 
								 | 
							
								            psize++;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return addr ? page + 1 : page;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* returns the lower address of flash page "page" */
							 | 
						||
| 
								 | 
							
								uint32_t flash_page_to_addr(const stm32_t *stm, int page)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    int i;
							 | 
						||
| 
								 | 
							
								    uint32_t addr, *psize;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    addr = stm->dev->fl_start;
							 | 
						||
| 
								 | 
							
								    psize = stm->dev->fl_ps;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    for (i = 0; i < page; i++) {
							 | 
						||
| 
								 | 
							
								        addr += psize[0];
							 | 
						||
| 
								 | 
							
								        if (psize[1])
							 | 
						||
| 
								 | 
							
								            psize++;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return addr;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								extern uint32_t os_delay(uint32_t millisec);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static stm32_err_t stm32_get_ack_timeout(const stm32_t *stm,
							 | 
						||
| 
								 | 
							
								    uint32_t timeout)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    port_interface_t *port = stm->port;
							 | 
						||
| 
								 | 
							
								    uint8_t byte;
							 | 
						||
| 
								 | 
							
								    uint32_t p_err;
							 | 
						||
| 
								 | 
							
								    uint32_t t0, t1;
							 | 
						||
| 
								 | 
							
								    t0 = os_boot_time32();   //ms
							 | 
						||
| 
								 | 
							
								    do {
							 | 
						||
| 
								 | 
							
								        p_err = port->read(&byte, 1);
							 | 
						||
| 
								 | 
							
								        if (p_err == ERR_TIMEOVER && timeout) {
							 | 
						||
| 
								 | 
							
								            t1 = os_boot_time32();
							 | 
						||
| 
								 | 
							
								            if (t1 < t0 + timeout * 1000)
							 | 
						||
| 
								 | 
							
								                continue;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (p_err != ERR_OK) {
							 | 
						||
| 
								 | 
							
								            stm32_dbg_printf("Failed to read ACK byte\n");
							 | 
						||
| 
								 | 
							
								            return STM32_ERR_UNKNOWN;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (byte == STM32_ACK)
							 | 
						||
| 
								 | 
							
								            return STM32_ERR_OK;
							 | 
						||
| 
								 | 
							
								        if (byte == STM32_NACK)
							 | 
						||
| 
								 | 
							
								            return STM32_ERR_NACK;
							 | 
						||
| 
								 | 
							
								        if (byte != STM32_BUSY) {
							 | 
						||
| 
								 | 
							
								            stm32_dbg_printf("Got byte 0x%02x instead of ACK\n",
							 | 
						||
| 
								 | 
							
								                byte);
							 | 
						||
| 
								 | 
							
								            return STM32_ERR_UNKNOWN;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    } while (1);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								stm32_err_t stm32_get_ack(const stm32_t *stm)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    return stm32_get_ack_timeout(stm, 0);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static stm32_err_t stm32_send_command_timeout(const stm32_t *stm,
							 | 
						||
| 
								 | 
							
								    const uint8_t cmd, uint32_t timeout)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    port_interface_t *port = stm->port;
							 | 
						||
| 
								 | 
							
								    uint32_t p_err;
							 | 
						||
| 
								 | 
							
								    uint8_t buf[2];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    buf[0] = cmd;
							 | 
						||
| 
								 | 
							
								    buf[1] = cmd^0xFF;
							 | 
						||
| 
								 | 
							
								    p_err = port->write(buf, 2);
							 | 
						||
| 
								 | 
							
								    if (p_err != ERR_OK) {
							 | 
						||
| 
								 | 
							
								        stm32_dbg_printf("Failed to send command\n");
							 | 
						||
| 
								 | 
							
								        return STM32_ERR_UNKNOWN;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return STM32_ERR_OK;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static stm32_err_t stm32_send_command(const stm32_t *stm, const uint8_t cmd)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    return stm32_send_command_timeout(stm, cmd, 0);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								stm32_err_t stm32_send_init_cmd(const stm32_t *stm)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    port_interface_t *port = stm->port;
							 | 
						||
| 
								 | 
							
								    uint32_t result = ERR_FAIL;
							 | 
						||
| 
								 | 
							
								    uint8_t cmd = STM32_CMD_INIT;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    result = port->write(&cmd, 1);
							 | 
						||
| 
								 | 
							
								    if (result != ERR_OK) {
							 | 
						||
| 
								 | 
							
								        stm32_dbg_printf("Failed to send init to device\n");
							 | 
						||
| 
								 | 
							
								        return STM32_ERR_UNKNOWN;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return STM32_ERR_OK;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								stm32_err_t stm32_send_init_handle(const stm32_t *stm)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    port_interface_t *port = stm->port;
							 | 
						||
| 
								 | 
							
								    uint32_t result = ERR_FAIL;
							 | 
						||
| 
								 | 
							
								    uint8_t byte = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    result = port->read(&byte, 1);
							 | 
						||
| 
								 | 
							
								    if (result == ERR_OK && byte == STM32_ACK)
							 | 
						||
| 
								 | 
							
								        return STM32_ERR_OK;
							 | 
						||
| 
								 | 
							
								    if (result == ERR_OK && byte == STM32_NACK) {
							 | 
						||
| 
								 | 
							
								        /* We could get error later, but let's continue, for now. */
							 | 
						||
| 
								 | 
							
								        stm32_dbg_printf("Warning: the interface was not closed properly.\n");
							 | 
						||
| 
								 | 
							
								        return STM32_ERR_OK;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    if (result != ERR_TIMEOVER) {
							 | 
						||
| 
								 | 
							
								        stm32_dbg_printf("Failed to init device.\n");
							 | 
						||
| 
								 | 
							
								        return STM32_ERR_UNKNOWN;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return STM32_ERR_OK;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								stm32_err_t stm32_send_get_version_cmd(const stm32_t *stm)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    return stm32_send_command(stm, STM32_CMD_GVR);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								stm32_err_t stm32_send_get_version_handle(stm32_t *stm)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    /* From AN, only UART bootloader returns 5 bytes */
							 | 
						||
| 
								 | 
							
								    port_interface_t *port = stm->port;
							 | 
						||
| 
								 | 
							
								    uint8_t len = 5;
							 | 
						||
| 
								 | 
							
								    uint8_t buf[5 + 1] = {0};
							 | 
						||
| 
								 | 
							
								    if (port->read(buf, len) != ERR_OK)
							 | 
						||
| 
								 | 
							
								        return STM32_ERR_UNKNOWN;
							 | 
						||
| 
								 | 
							
								    if (buf[0] != STM32_ACK) {
							 | 
						||
| 
								 | 
							
								        return STM32_ERR_UNKNOWN;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    stm->version = buf[1];
							 | 
						||
| 
								 | 
							
								    stm->option1 = buf[2];
							 | 
						||
| 
								 | 
							
								    stm->option2 = buf[3];
							 | 
						||
| 
								 | 
							
								    if (buf[4] != STM32_ACK) {
							 | 
						||
| 
								 | 
							
								        return STM32_ERR_UNKNOWN;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return STM32_ERR_OK;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								stm32_err_t stm32_send_get_cmd(const stm32_t *stm)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    return stm32_send_command(stm, STM32_CMD_GET);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* find newer command by higher code */
							 | 
						||
| 
								 | 
							
								#define newer(prev, a) (((prev) == STM32_CMD_ERR) \
							 | 
						||
| 
								 | 
							
								            ? (a) \
							 | 
						||
| 
								 | 
							
								            : (((prev) > (a)) ? (prev) : (a)))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								stm32_err_t stm32_send_get_handle(stm32_t *stm)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    /* From AN, only UART bootloader returns 15 bytes */
							 | 
						||
| 
								 | 
							
								    port_interface_t *port = stm->port;
							 | 
						||
| 
								 | 
							
								    uint8_t len = 15;
							 | 
						||
| 
								 | 
							
								    uint8_t buf[15 + 1] = {0};
							 | 
						||
| 
								 | 
							
								    uint8_t val = 0, i = 0, new_cmds = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (port->read(buf, len) != ERR_OK)
							 | 
						||
| 
								 | 
							
								        return STM32_ERR_UNKNOWN;
							 | 
						||
| 
								 | 
							
								    if (buf[0] != STM32_ACK) {
							 | 
						||
| 
								 | 
							
								        return STM32_ERR_UNKNOWN;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    len = buf[1] + 1;
							 | 
						||
| 
								 | 
							
								    stm->bl_version = buf[2];
							 | 
						||
| 
								 | 
							
								    for (i = 1; i < len; i++) {
							 | 
						||
| 
								 | 
							
								        val = buf[i + 2];
							 | 
						||
| 
								 | 
							
								        switch (val) {
							 | 
						||
| 
								 | 
							
								        case STM32_CMD_GET:
							 | 
						||
| 
								 | 
							
								            stm->cmd->get = val; break;
							 | 
						||
| 
								 | 
							
								        case STM32_CMD_GVR:
							 | 
						||
| 
								 | 
							
								            stm->cmd->gvr = val; break;
							 | 
						||
| 
								 | 
							
								        case STM32_CMD_GID:
							 | 
						||
| 
								 | 
							
								            stm->cmd->gid = val; break;
							 | 
						||
| 
								 | 
							
								        case STM32_CMD_RM:
							 | 
						||
| 
								 | 
							
								            stm->cmd->rm = val; break;
							 | 
						||
| 
								 | 
							
								        case STM32_CMD_GO:
							 | 
						||
| 
								 | 
							
								            stm->cmd->go = val; break;
							 | 
						||
| 
								 | 
							
								        case STM32_CMD_WM:
							 | 
						||
| 
								 | 
							
								        case STM32_CMD_WM_NS:
							 | 
						||
| 
								 | 
							
								            stm->cmd->wm = newer(stm->cmd->wm, val);
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								        case STM32_CMD_ER:
							 | 
						||
| 
								 | 
							
								        case STM32_CMD_EE:
							 | 
						||
| 
								 | 
							
								        case STM32_CMD_EE_NS:
							 | 
						||
| 
								 | 
							
								            stm->cmd->er = newer(stm->cmd->er, val);
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								        case STM32_CMD_WP:
							 | 
						||
| 
								 | 
							
								        case STM32_CMD_WP_NS:
							 | 
						||
| 
								 | 
							
								            stm->cmd->wp = newer(stm->cmd->wp, val);
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								        case STM32_CMD_UW:
							 | 
						||
| 
								 | 
							
								        case STM32_CMD_UW_NS:
							 | 
						||
| 
								 | 
							
								            stm->cmd->uw = newer(stm->cmd->uw, val);
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								        case STM32_CMD_RP:
							 | 
						||
| 
								 | 
							
								        case STM32_CMD_RP_NS:
							 | 
						||
| 
								 | 
							
								            stm->cmd->rp = newer(stm->cmd->rp, val);
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								        case STM32_CMD_UR:
							 | 
						||
| 
								 | 
							
								        case STM32_CMD_UR_NS:
							 | 
						||
| 
								 | 
							
								            stm->cmd->ur = newer(stm->cmd->ur, val);
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								        case STM32_CMD_CRC:
							 | 
						||
| 
								 | 
							
								            stm->cmd->crc = newer(stm->cmd->crc, val);
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								        default:
							 | 
						||
| 
								 | 
							
								            if (new_cmds++ == 0)
							 | 
						||
| 
								 | 
							
								                stm32_dbg_printf("GET returns unknown commands (0x%2x", val);
							 | 
						||
| 
								 | 
							
								            else
							 | 
						||
| 
								 | 
							
								                stm32_dbg_printf(", 0x%2x", val);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    if (new_cmds)
							 | 
						||
| 
								 | 
							
								        stm32_dbg_printf(")\n");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (buf[14] != STM32_ACK) {
							 | 
						||
| 
								 | 
							
								        return STM32_ERR_UNKNOWN;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    if (stm->cmd->get == STM32_CMD_ERR
							 | 
						||
| 
								 | 
							
								        || stm->cmd->gvr == STM32_CMD_ERR
							 | 
						||
| 
								 | 
							
								        || stm->cmd->gid == STM32_CMD_ERR) {
							 | 
						||
| 
								 | 
							
								        stm32_dbg_printf("Error: bootloader did not returned correct"
							 | 
						||
| 
								 | 
							
								            " information from GET command\n");
							 | 
						||
| 
								 | 
							
								        return STM32_ERR_UNKNOWN;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return STM32_ERR_OK;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								stm32_err_t stm32_send_get_id_cmd(const stm32_t *stm)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    return stm32_send_command(stm, stm->cmd->gid);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								stm32_err_t stm32_send_get_id_handle(stm32_t *stm)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    /* From AN, only UART bootloader returns 5 bytes */
							 | 
						||
| 
								 | 
							
								    port_interface_t *port = stm->port;
							 | 
						||
| 
								 | 
							
								    uint8_t len = 5;
							 | 
						||
| 
								 | 
							
								    uint8_t buf[5 + 1] = {0};
							 | 
						||
| 
								 | 
							
								    uint8_t i = 0;
							 | 
						||
| 
								 | 
							
								    if (port->read(buf, len) != ERR_OK)
							 | 
						||
| 
								 | 
							
								        return STM32_ERR_UNKNOWN;
							 | 
						||
| 
								 | 
							
								    if (buf[0] != STM32_ACK) {
							 | 
						||
| 
								 | 
							
								        return STM32_ERR_UNKNOWN;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    len = buf[1] + 1;
							 | 
						||
| 
								 | 
							
								    if (len < 2) {
							 | 
						||
| 
								 | 
							
								        stm32_dbg_printf("Only %d bytes sent in the PID, "
							 | 
						||
| 
								 | 
							
								            "unknown/unsupported device\n", len);
							 | 
						||
| 
								 | 
							
								        return STM32_ERR_UNKNOWN;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    stm->pid = (buf[2] << 8) | buf[3];
							 | 
						||
| 
								 | 
							
								    if (len > 2) {
							 | 
						||
| 
								 | 
							
								        stm32_dbg_printf("This bootloader returns %d extra bytes in PID:", len);
							 | 
						||
| 
								 | 
							
								        for (i = 1; i <= len ; i++)
							 | 
						||
| 
								 | 
							
								            stm32_dbg_printf(" %02x", buf[i]);
							 | 
						||
| 
								 | 
							
								        stm32_dbg_printf("\n");
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (buf[4] != STM32_ACK) {
							 | 
						||
| 
								 | 
							
								        return STM32_ERR_UNKNOWN;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    stm->dev = devices;
							 | 
						||
| 
								 | 
							
								    while (stm->dev->id != 0x00 && stm->dev->id != stm->pid)
							 | 
						||
| 
								 | 
							
								        ++stm->dev;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (!stm->dev->id) {
							 | 
						||
| 
								 | 
							
								        stm32_dbg_printf("Unknown/unsupported device (Device ID: 0x%03x)\n",
							 | 
						||
| 
								 | 
							
								            stm->pid);
							 | 
						||
| 
								 | 
							
								        return STM32_ERR_UNKNOWN;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    stm->is_connect = 1;
							 | 
						||
| 
								 | 
							
								    return STM32_ERR_OK;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								stm32_err_t stm32_send_erase_cmd(const stm32_t *stm)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    return stm32_send_command(stm, stm->cmd->er);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								stm32_err_t stm32_send_erase_page_info(const stm32_t *stm, uint32_t spage,
							 | 
						||
| 
								 | 
							
								    uint32_t pages)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    port_interface_t *port = stm->port;
							 | 
						||
| 
								 | 
							
								    uint32_t p_err;
							 | 
						||
| 
								 | 
							
								    uint32_t pg_num;
							 | 
						||
| 
								 | 
							
								    uint8_t pg_byte;
							 | 
						||
| 
								 | 
							
								    uint8_t cs = 0;
							 | 
						||
| 
								 | 
							
								    uint8_t *buf;
							 | 
						||
| 
								 | 
							
								    int i = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /* regular erase (0x43) */
							 | 
						||
| 
								 | 
							
								    if (stm->cmd->er == STM32_CMD_ER) {
							 | 
						||
| 
								 | 
							
								        buf = os_mem_malloc(IOT_STM32_MODULE_ID,1 + pages + 1);
							 | 
						||
| 
								 | 
							
								        if (!buf)
							 | 
						||
| 
								 | 
							
								            return STM32_ERR_UNKNOWN;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        buf[i++] = pages - 1;
							 | 
						||
| 
								 | 
							
								        cs ^= (pages-1);
							 | 
						||
| 
								 | 
							
								        for (pg_num = spage; pg_num < (pages + spage); pg_num++) {
							 | 
						||
| 
								 | 
							
								            buf[i++] = pg_num;
							 | 
						||
| 
								 | 
							
								            cs ^= pg_num;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        buf[i++] = cs;
							 | 
						||
| 
								 | 
							
								        p_err = port->write(buf, i);
							 | 
						||
| 
								 | 
							
								        os_mem_free(buf);
							 | 
						||
| 
								 | 
							
								        if (p_err != ERR_OK) {
							 | 
						||
| 
								 | 
							
								            stm32_dbg_printf("Erase failed.\n");
							 | 
						||
| 
								 | 
							
								            return STM32_ERR_UNKNOWN;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return STM32_ERR_OK;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /* extended erase */
							 | 
						||
| 
								 | 
							
								    buf = os_mem_malloc(IOT_STM32_MODULE_ID, (2 + 2 * pages + 1));
							 | 
						||
| 
								 | 
							
								    if (!buf)
							 | 
						||
| 
								 | 
							
								        return STM32_ERR_UNKNOWN;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /* Number of pages to be erased - 1, two bytes, MSB first */
							 | 
						||
| 
								 | 
							
								    pg_byte = (pages - 1) >> 8;
							 | 
						||
| 
								 | 
							
								    buf[i++] = pg_byte;
							 | 
						||
| 
								 | 
							
								    cs ^= pg_byte;
							 | 
						||
| 
								 | 
							
								    pg_byte = (pages - 1) & 0xFF;
							 | 
						||
| 
								 | 
							
								    buf[i++] = pg_byte;
							 | 
						||
| 
								 | 
							
								    cs ^= pg_byte;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    for (pg_num = spage; pg_num < spage + pages; pg_num++) {
							 | 
						||
| 
								 | 
							
								        pg_byte = pg_num >> 8;
							 | 
						||
| 
								 | 
							
								        cs ^= pg_byte;
							 | 
						||
| 
								 | 
							
								        buf[i++] = pg_byte;
							 | 
						||
| 
								 | 
							
								        pg_byte = pg_num & 0xFF;
							 | 
						||
| 
								 | 
							
								        cs ^= pg_byte;
							 | 
						||
| 
								 | 
							
								        buf[i++] = pg_byte;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    buf[i++] = cs;
							 | 
						||
| 
								 | 
							
								    p_err = port->write(buf, i);
							 | 
						||
| 
								 | 
							
								    os_mem_free(buf);
							 | 
						||
| 
								 | 
							
								    if (p_err != ERR_OK) {
							 | 
						||
| 
								 | 
							
								        stm32_dbg_printf("Page-by-page erase error.\n");
							 | 
						||
| 
								 | 
							
								        return STM32_ERR_UNKNOWN;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return STM32_ERR_OK;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								stm32_err_t stm32_send_write_cmd(const stm32_t *stm)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    if (stm->cmd->wm == STM32_CMD_ERR) {
							 | 
						||
| 
								 | 
							
								        stm32_dbg_printf("Error: WRITE command not implemented in bootloader.\n");
							 | 
						||
| 
								 | 
							
								        return STM32_ERR_NO_CMD;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /* send the address and checksum */
							 | 
						||
| 
								 | 
							
								    if (stm32_send_command(stm, stm->cmd->wm) != STM32_ERR_OK) {
							 | 
						||
| 
								 | 
							
								        return STM32_ERR_UNKNOWN;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return STM32_ERR_OK;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								stm32_err_t stm32_send_write_addr(const stm32_t *stm, uint32_t address)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    uint8_t buf[5] = {0};
							 | 
						||
| 
								 | 
							
								    buf[0] = address >> 24;
							 | 
						||
| 
								 | 
							
								    buf[1] = (address >> 16) & 0xFF;
							 | 
						||
| 
								 | 
							
								    buf[2] = (address >> 8) & 0xFF;
							 | 
						||
| 
								 | 
							
								    buf[3] = address & 0xFF;
							 | 
						||
| 
								 | 
							
								    buf[4] = buf[0] ^ buf[1] ^ buf[2] ^ buf[3];
							 | 
						||
| 
								 | 
							
								    if (stm->port->write(buf, 5) != ERR_OK) {
							 | 
						||
| 
								 | 
							
								        return STM32_ERR_UNKNOWN;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return STM32_ERR_OK;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								stm32_err_t stm32_send_write_data(const stm32_t *stm,
							 | 
						||
| 
								 | 
							
								    const uint8_t data[], unsigned int len)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    port_interface_t *port = stm->port;
							 | 
						||
| 
								 | 
							
								    uint8_t cs, buf[256 + 2];
							 | 
						||
| 
								 | 
							
								    unsigned int i, aligned_len;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    aligned_len = (len + 3) & ~3;
							 | 
						||
| 
								 | 
							
								    cs = aligned_len - 1;
							 | 
						||
| 
								 | 
							
								    buf[0] = aligned_len - 1;
							 | 
						||
| 
								 | 
							
								    for (i = 0; i < len; i++) {
							 | 
						||
| 
								 | 
							
								        cs ^= data[i];
							 | 
						||
| 
								 | 
							
								        buf[i + 1] = data[i];
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    /* padding data */
							 | 
						||
| 
								 | 
							
								    for (i = len; i < aligned_len; i++) {
							 | 
						||
| 
								 | 
							
								        cs ^= 0xFF;
							 | 
						||
| 
								 | 
							
								        buf[i + 1] = 0xFF;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    buf[aligned_len + 1] = cs;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (port->write(buf, aligned_len + 2) != ERR_OK) {
							 | 
						||
| 
								 | 
							
								        return STM32_ERR_UNKNOWN;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return STM32_ERR_OK;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								stm32_err_t stm32_send_read_cmd(const stm32_t *stm)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    if (stm->cmd->rm == STM32_CMD_ERR) {
							 | 
						||
| 
								 | 
							
								        stm32_dbg_printf("Error: READ command not implemented in bootloader.\n");
							 | 
						||
| 
								 | 
							
								        return STM32_ERR_NO_CMD;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /* send the address and checksum */
							 | 
						||
| 
								 | 
							
								    if (stm32_send_command(stm, stm->cmd->rm) != STM32_ERR_OK) {
							 | 
						||
| 
								 | 
							
								        return STM32_ERR_UNKNOWN;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return STM32_ERR_OK;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								stm32_err_t stm32_send_read_addr(const stm32_t *stm, uint32_t address)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    uint8_t buf[5] = {0};
							 | 
						||
| 
								 | 
							
								    buf[0] = address >> 24;
							 | 
						||
| 
								 | 
							
								    buf[1] = (address >> 16) & 0xFF;
							 | 
						||
| 
								 | 
							
								    buf[2] = (address >> 8) & 0xFF;
							 | 
						||
| 
								 | 
							
								    buf[3] = address & 0xFF;
							 | 
						||
| 
								 | 
							
								    buf[4] = buf[0] ^ buf[1] ^ buf[2] ^ buf[3];
							 | 
						||
| 
								 | 
							
								    if (stm->port->write(buf, 5) != ERR_OK) {
							 | 
						||
| 
								 | 
							
								        return STM32_ERR_UNKNOWN;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return STM32_ERR_OK;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								stm32_err_t stm32_send_read_length(const stm32_t *stm, uint32_t len)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    if (stm32_send_command(stm, len - 1) != STM32_ERR_OK)
							 | 
						||
| 
								 | 
							
								        return STM32_ERR_UNKNOWN;
							 | 
						||
| 
								 | 
							
								    return STM32_ERR_OK;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								stm32_err_t stm32_send_read_rdata(const stm32_t *stm,
							 | 
						||
| 
								 | 
							
								    uint8_t data[], uint32_t len)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    port_interface_t *port = stm->port;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (port->read(data, len) != ERR_OK)
							 | 
						||
| 
								 | 
							
								        return STM32_ERR_UNKNOWN;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return STM32_ERR_OK;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 |