| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| #include <sys/types.h> |
| #include <inttypes.h> |
| #include <string.h> |
| |
| #include <os/mynewt.h> |
| |
| #include <bsp/bsp.h> |
| #include <hal/hal_bsp.h> |
| #include <hal/hal_flash.h> |
| #include <hal/hal_gpio.h> |
| #include <hal/hal_watchdog.h> |
| |
| #include "flash_loader/flash_loader.h" |
| |
| /* |
| * Anything marked as 'volatile' is either expected to be read and/or written |
| * by programmer. |
| */ |
| volatile int fl_state; |
| volatile int fl_cmd; |
| volatile int fl_cmd_rc; |
| |
| uint8_t *fl_data; |
| volatile uint8_t *fl_cmd_data; |
| volatile uint32_t fl_cmd_amount; |
| volatile uint32_t fl_cmd_flash_id; |
| volatile uint32_t fl_cmd_flash_addr; |
| int fl_cmd_data_sz = MYNEWT_VAL(FLASH_LOADER_DL_SZ) / 2; |
| |
| /* |
| * Load/verify use doble buffering scheme. Programmer can write the |
| * data for next flash operation while app is executing previous command. |
| */ |
| struct { |
| uint8_t *buf; |
| uint32_t amount; |
| uint32_t flash_id; |
| uint32_t addr; |
| } fl_write; |
| |
| uint8_t fl_verify_buf[MYNEWT_VAL(FLASH_LOADER_VERIFY_BUF_SZ)]; |
| |
| static void |
| fl_rotate_databuf(void) |
| { |
| fl_write.buf = (uint8_t *)fl_cmd_data; |
| fl_write.amount = fl_cmd_amount; |
| fl_write.flash_id = fl_cmd_flash_id; |
| fl_write.addr = fl_cmd_flash_addr; |
| |
| if (fl_cmd_data == fl_data) { |
| fl_cmd_data = &fl_data[fl_cmd_data_sz]; |
| } else { |
| fl_cmd_data = fl_data; |
| } |
| fl_cmd_amount = 0; |
| } |
| |
| static int |
| fl_load_cmd(void) |
| { |
| int rc; |
| |
| if (fl_write.amount > fl_cmd_data_sz) { |
| return FL_RC_ARG_ERR; |
| } |
| rc = hal_flash_write(fl_write.flash_id, fl_write.addr, |
| fl_write.buf, fl_write.amount); |
| if (rc) { |
| return FL_RC_FLASH_ERR; |
| } |
| return FL_RC_OK; |
| } |
| |
| static int |
| fl_erase_cmd(void) |
| { |
| int rc; |
| |
| rc = hal_flash_erase(fl_cmd_flash_id, fl_cmd_flash_addr, fl_cmd_amount); |
| if (rc) { |
| return FL_RC_FLASH_ERR; |
| } |
| return FL_RC_OK; |
| } |
| |
| static int |
| fl_verify_cmd(void) |
| { |
| int rc; |
| uint32_t off; |
| int blen; |
| |
| if (fl_write.amount > fl_cmd_data_sz) { |
| return FL_RC_ARG_ERR; |
| } |
| for (off = 0; off < fl_write.amount; off += blen) { |
| blen = fl_write.amount - off; |
| if (blen > sizeof(fl_verify_buf)) { |
| blen = sizeof(fl_verify_buf); |
| } |
| rc = hal_flash_read(fl_write.flash_id, fl_write.addr + off, |
| fl_verify_buf, blen); |
| if (rc) { |
| return FL_RC_FLASH_ERR; |
| } |
| if (memcmp(fl_verify_buf, fl_write.buf + off, blen)) { |
| return FL_RC_VERIFY_ERR; |
| } |
| } |
| return FL_RC_OK; |
| } |
| |
| static int |
| fl_dump_cmd(void) |
| { |
| int rc; |
| |
| rc = hal_flash_read(fl_cmd_flash_id, fl_cmd_flash_addr, (void *)fl_cmd_data, |
| fl_cmd_amount); |
| if (rc) { |
| return FL_RC_FLASH_ERR; |
| } |
| return FL_RC_OK; |
| } |
| |
| /* |
| * Blinks led if running (and LED is defined). |
| */ |
| static void |
| blink_led(void) |
| { |
| #if LED_BLINK_PIN |
| static int init = 0; |
| static int fl_loop_cntr; |
| |
| if (!init) { |
| hal_gpio_init_out(LED_BLINK_PIN, 0); |
| init = 1; |
| } |
| if (fl_loop_cntr > MYNEWT_VAL(FLASH_LOADER_LOOP_PER_BLINK)) { |
| fl_loop_cntr = 0; |
| hal_gpio_toggle(LED_BLINK_PIN); |
| } else { |
| fl_loop_cntr++; |
| } |
| #endif |
| } |
| |
| int |
| mynewt_main(int argc, char **argv) |
| { |
| int rc; |
| |
| hal_bsp_init(); |
| flash_map_init(); |
| #if MYNEWT_VAL(WATCHDOG_INTERVAL) > 0 |
| hal_watchdog_init(MYNEWT_VAL(WATCHDOG_INTERVAL)); |
| hal_watchdog_enable(); |
| #endif |
| |
| fl_data = malloc(MYNEWT_VAL(FLASH_LOADER_DL_SZ)); |
| assert(fl_data); |
| fl_cmd_data = fl_data; |
| while (1) { |
| if (!fl_cmd) { |
| fl_state = FL_WAITING; |
| blink_led(); |
| continue; |
| } |
| fl_state = FL_EXECUTING; |
| switch (fl_cmd) { |
| case FL_CMD_PING: |
| fl_cmd = 0; |
| rc = FL_RC_OK; |
| break; |
| case FL_CMD_LOAD: |
| fl_rotate_databuf(); |
| fl_cmd = 0; |
| rc = fl_load_cmd(); |
| break; |
| case FL_CMD_ERASE: |
| fl_cmd = 0; |
| rc = fl_erase_cmd(); |
| break; |
| case FL_CMD_VERIFY: |
| fl_rotate_databuf(); |
| fl_cmd = 0; |
| rc = fl_verify_cmd(); |
| break; |
| case FL_CMD_LOAD_VERIFY: |
| fl_rotate_databuf(); |
| fl_cmd = 0; |
| rc = fl_load_cmd(); |
| if (rc == FL_RC_OK) { |
| rc = fl_verify_cmd(); |
| } |
| break; |
| case FL_CMD_DUMP: |
| fl_cmd = 0; |
| rc = fl_dump_cmd(); |
| break; |
| default: |
| fl_cmd = 0; |
| rc = FL_RC_UNKNOWN_CMD_ERR; |
| break; |
| } |
| #if MYNEWT_VAL(WATCHDOG_INTERVAL) > 0 |
| hal_watchdog_tickle(); |
| #endif |
| if (fl_cmd_rc <= FL_RC_OK) { |
| fl_cmd_rc = rc; |
| } |
| } |
| } |