Arrow / Mbed OS DAPLink Reset
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers vfs_user.c Source File

vfs_user.c

Go to the documentation of this file.
00001 /**
00002  * @file    vfs_user.c
00003  * @brief   Implementation of vfs_user.h
00004  *
00005  * DAPLink Interface Firmware
00006  * Copyright (c) 2009-2020, ARM Limited, All Rights Reserved
00007  * Copyright 2019, Cypress Semiconductor Corporation 
00008  * or a subsidiary of Cypress Semiconductor Corporation.
00009  * SPDX-License-Identifier: Apache-2.0
00010  *
00011  * Licensed under the Apache License, Version 2.0 (the "License"); you may
00012  * not use this file except in compliance with the License.
00013  * You may obtain a copy of the License at
00014  *
00015  * http://www.apache.org/licenses/LICENSE-2.0
00016  *
00017  * Unless required by applicable law or agreed to in writing, software
00018  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
00019  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00020  * See the License for the specific language governing permissions and
00021  * limitations under the License.
00022  */
00023 
00024 #include <stdbool.h>
00025 #include <ctype.h>
00026 #include <string.h>
00027 
00028 #include "vfs_user.h"
00029 #include "vfs_manager.h"
00030 #include "error.h"
00031 #include "util.h"
00032 #include "settings.h"
00033 #include "daplink.h"
00034 #include "version_git.h"
00035 #include "info.h"
00036 #include "gpio.h"           // for gpio_get_sw_reset
00037 #include "flash_intf.h"     // for flash_intf_target
00038 #include "cortex_m.h"
00039 #include "target_board.h"
00040 #include "flash_manager.h"
00041 
00042 //! @brief Size in bytes of the virtual disk.
00043 //!
00044 //! Must be bigger than 4x the flash size of the biggest supported
00045 //! device.  This is to accomodate for hex file programming.
00046 #define VFS_DISK_SIZE (MB(64))
00047 
00048 //! @brief Constants for magic action or config files.
00049 //!
00050 //! The "magic files" are files with a special name that if created on the USB MSC volume, will
00051 //! cause an event. There are two classes of magic files: action files and config files. The former
00052 //! causes a given action to take place, while the latter changes a persistent configuration setting
00053 //! to a predetermined value.
00054 //!
00055 //! See #s_magic_file_info for the mapping of filenames to these enums.
00056 typedef enum _magic_file {
00057     kDAPLinkModeActionFile,     //!< Switch between interface and bootloader.
00058     kTestAssertActionFile,      //!< Force an assertion for testing.
00059     kRefreshActionFile,         //!< Force a remount.
00060     kEraseActionFile,           //!< Erase the target flash.
00061     kAutoResetConfigFile,       //!< Enable reset after flash.
00062     kHardResetConfigFile,       //!< Disable reset after flash.
00063     kAutomationOnConfigFile,    //!< Enable automation.
00064     kAutomationOffConfigFile,   //!< Disable automation.
00065     kOverflowOnConfigFile,      //!< Enable UART overflow reporting.
00066     kOverflowOffConfigFile,     //!< Disable UART overflow reporting.
00067     kMSDOnConfigFile,           //!< Enable USB MSC. Uh....
00068     kMSDOffConfigFile,          //!< Disable USB MSC.
00069     kPageEraseActionFile,       //!< Enable page programming and sector erase for drag and drop.
00070     kChipEraseActionFile,       //!< Enable page programming and chip erase for drag and drop.
00071 } magic_file_t;
00072 
00073 //! @brief Mapping from filename string to magic file enum.
00074 typedef struct _magic_file_info {
00075     const char *name;   //!< Name of the magic file, must be in 8.3 format.
00076     magic_file_t which; //!< Enum for the file.
00077 } magic_file_info_t;
00078 
00079 static const char mbed_redirect_file[] =
00080     "<!doctype html>\r\n"
00081     "<!-- mbed Platform Website and Authentication Shortcut -->\r\n"
00082     "<html>\r\n"
00083     "<head>\r\n"
00084     "<meta charset=\"utf-8\">\r\n"
00085     "<title>mbed Website Shortcut</title>\r\n"
00086     "</head>\r\n"
00087     "<body>\r\n"
00088     "<script>\r\n"
00089     "window.location.replace(\"@R\");\r\n"
00090     "</script>\r\n"
00091     "</body>\r\n"
00092     "</html>\r\n";
00093 
00094 static const char error_prefix[] = "error: ";
00095 static const char error_type_prefix[] = "type: ";
00096 
00097 static const vfs_filename_t assert_file = "ASSERT  TXT";
00098 
00099 //! @brief Table of magic files and their names.
00100 static const magic_file_info_t s_magic_file_info[] = {
00101         { daplink_mode_file_name, kDAPLinkModeActionFile },
00102         { "ASSERT  ACT", kTestAssertActionFile      },
00103         { "REFRESH ACT", kRefreshActionFile         },
00104         { "ERASE   ACT", kEraseActionFile           },
00105         { "AUTO_RSTCFG", kAutoResetConfigFile       },
00106         { "HARD_RSTCFG", kHardResetConfigFile       },
00107         { "AUTO_ON CFG", kAutomationOnConfigFile    },
00108         { "AUTO_OFFCFG", kAutomationOffConfigFile   },
00109         { "OVFL_ON CFG", kOverflowOnConfigFile      },
00110         { "OVFL_OFFCFG", kOverflowOffConfigFile     },
00111         { "MSD_ON  CFG", kMSDOnConfigFile           },
00112         { "MSD_OFF CFG", kMSDOffConfigFile          },
00113         { "PAGE_ON ACT", kPageEraseActionFile       },
00114         { "PAGE_OFFACT", kChipEraseActionFile       },
00115     };
00116 
00117 static uint8_t file_buffer[VFS_SECTOR_SIZE];
00118 static char assert_buf[64 + 1];
00119 static uint16_t assert_line;
00120 static assert_source_t assert_source;
00121 static uint32_t remount_count;
00122 
00123 static uint32_t get_file_size(vfs_read_cb_t read_func);
00124 
00125 static uint32_t read_file_mbed_htm(uint32_t sector_offset, uint8_t *data, uint32_t num_sectors);
00126 static uint32_t read_file_details_txt(uint32_t sector_offset, uint8_t *data, uint32_t num_sectors);
00127 static uint32_t read_file_fail_txt(uint32_t sector_offset, uint8_t *data, uint32_t num_sectors);
00128 static uint32_t read_file_assert_txt(uint32_t sector_offset, uint8_t *data, uint32_t num_sectors);
00129 static uint32_t read_file_need_bl_txt(uint32_t sector_offset, uint8_t *data, uint32_t num_sectors);
00130 
00131 static uint32_t update_html_file(uint8_t *data, uint32_t datasize);
00132 static uint32_t update_details_txt_file(uint8_t *data, uint32_t datasize);
00133 static void erase_target(void);
00134 
00135 static uint32_t expand_info(uint8_t *buf, uint32_t bufsize);
00136 
00137 void vfs_user_build_filesystem()
00138 {
00139     uint32_t file_size;
00140     vfs_file_t file_handle;
00141     // Setup the filesystem based on target parameters
00142     vfs_init(get_daplink_drive_name(), VFS_DISK_SIZE);
00143     // MBED.HTM
00144     file_size = get_file_size(read_file_mbed_htm);
00145     vfs_create_file(get_daplink_url_name(), read_file_mbed_htm, 0, file_size);
00146     // DETAILS.TXT
00147     file_size = get_file_size(read_file_details_txt);
00148     vfs_create_file("DETAILS TXT", read_file_details_txt, 0, file_size);
00149 
00150     // FAIL.TXT
00151     if (vfs_mngr_get_transfer_status() != ERROR_SUCCESS) {
00152         file_size = get_file_size(read_file_fail_txt);
00153         vfs_create_file("FAIL    TXT", read_file_fail_txt, 0, file_size);
00154     }
00155 
00156     // ASSERT.TXT
00157     if (config_ram_get_assert(assert_buf, sizeof(assert_buf), &assert_line, &assert_source)) {
00158         file_size = get_file_size(read_file_assert_txt);
00159         file_handle = vfs_create_file(assert_file, read_file_assert_txt, 0, file_size);
00160         vfs_file_set_attr(file_handle, (vfs_file_attr_bit_t)0); // Remove read only attribute
00161     }
00162 
00163     // NEED_BL.TXT
00164     volatile uint32_t bl_start = DAPLINK_ROM_BL_START; // Silence warnings about null pointer
00165     volatile uint32_t if_start = DAPLINK_ROM_IF_START; // Silence warnings about null pointer
00166 
00167     if (daplink_is_interface() &&
00168             (DAPLINK_ROM_BL_SIZE > 0) &&
00169             (0 == memcmp((void *)bl_start, (void *)if_start, DAPLINK_MIN_WRITE_SIZE))) {
00170         // If the bootloader contains a copy of the interfaces vector table
00171         // then an error occurred when updating so warn that the bootloader is
00172         // missing.
00173         file_size = get_file_size(read_file_need_bl_txt);
00174         vfs_create_file("NEED_BL TXT", read_file_need_bl_txt, 0, file_size);
00175     }
00176 }
00177 
00178 // Default file change hook.
00179 __WEAK bool vfs_user_file_change_handler_hook(const vfs_filename_t filename, vfs_file_change_t  change,
00180         vfs_file_t file, vfs_file_t new_file_data)
00181 {
00182     return false;
00183 }
00184 
00185 // Default magic file hook.
00186 __WEAK bool vfs_user_magic_file_hook(const vfs_filename_t filename, bool *do_remount)
00187 {
00188     return false;
00189 }
00190 
00191 // Callback to handle changes to the root directory.  Should be used with vfs_set_file_change_callback
00192 void vfs_user_file_change_handler(const vfs_filename_t filename, vfs_file_change_t  change, vfs_file_t file, vfs_file_t new_file_data)
00193 {
00194     // Call file changed hook. If it returns true, then it handled the request and we have nothing
00195     // more to do.
00196     if (vfs_user_file_change_handler_hook(filename, change, file, new_file_data)) {
00197         return;
00198     }
00199 
00200     // Allow settings to be changed if automation mode is
00201     // enabled or if the user is holding the reset button
00202     bool btn_pressed = gpio_get_reset_btn();
00203 
00204     if (!btn_pressed && !config_get_automation_allowed()) {
00205         return;
00206     }
00207 
00208     if (VFS_FILE_CHANGED  == change) {
00209         // Unused
00210     }
00211 
00212     else if (VFS_FILE_CREATED  == change) {
00213         bool do_remount = true; // Almost all magic files cause a remount.
00214         int32_t which_magic_file = -1;
00215 
00216         // Let the hook examine the filename. If it returned false then look for the standard
00217         // magic files.
00218         if (!vfs_user_magic_file_hook(filename, &do_remount)) {
00219             // Compare the new file's name to our table of magic filenames.
00220             for (int32_t i = 0; i < ARRAY_SIZE(s_magic_file_info); ++i) {
00221                 if (!memcmp(filename, s_magic_file_info[i].name, sizeof(vfs_filename_t))) {
00222                     which_magic_file = i;
00223                 }
00224             }
00225 
00226             // Check if we matched a magic filename and handle it.
00227             if (which_magic_file != -1) {
00228                 switch (which_magic_file) {
00229                     case kDAPLinkModeActionFile:
00230                         if (daplink_is_interface()) {
00231                             config_ram_set_hold_in_bl(true);
00232                         } else {
00233                             // Do nothing - bootloader will go to interface by default
00234                         }
00235                         break;
00236                     case kTestAssertActionFile:
00237                         // Test asserts
00238                         util_assert(0);
00239                         do_remount = false;
00240                         break;
00241                     case kRefreshActionFile:
00242                         // Remount to update the drive
00243                         break;
00244                     case kEraseActionFile:
00245                         erase_target();
00246                         break;
00247                     case kAutoResetConfigFile:
00248                         config_set_auto_rst(true);
00249                         break;
00250                     case kHardResetConfigFile:
00251                         config_set_auto_rst(false);
00252                         break;
00253                     case kAutomationOnConfigFile:
00254                         config_set_automation_allowed(true);
00255                         break;
00256                     case kAutomationOffConfigFile:
00257                         config_set_automation_allowed(false);
00258                         break;
00259                     case kOverflowOnConfigFile:
00260                         config_set_overflow_detect(true);
00261                         break;
00262                     case kOverflowOffConfigFile:
00263                         config_set_overflow_detect(false);
00264                         break;
00265                     case kMSDOnConfigFile:
00266                         config_ram_set_disable_msd(false);
00267                         break;
00268                     case kMSDOffConfigFile:
00269                         config_ram_set_disable_msd(true);
00270                         break;
00271                     case kPageEraseActionFile:
00272                         config_ram_set_page_erase(true);
00273                         break;
00274                     case kChipEraseActionFile:
00275                         config_ram_set_page_erase(false);
00276                         break;
00277                     default:
00278                         util_assert(false);
00279                 }
00280             }
00281             else {
00282                 do_remount = false;
00283             }
00284         }
00285 
00286         // Remount if requested.
00287         if (do_remount) {
00288             vfs_mngr_fs_remount();
00289         }
00290     }
00291 
00292     else if (VFS_FILE_DELETED  == change) {
00293         if (!memcmp(filename, assert_file, sizeof(vfs_filename_t))) {
00294             // Clear assert and remount to update the drive
00295             util_assert_clear();
00296             vfs_mngr_fs_remount();
00297         }
00298     }
00299 }
00300 
00301 void vfs_user_disconnecting()
00302 {
00303     // Reset if programming was successful  //TODO - move to flash layer
00304     if (daplink_is_bootloader() && (ERROR_SUCCESS == vfs_mngr_get_transfer_status())) {
00305         SystemReset();
00306     }
00307 
00308     // If hold in bootloader has been set then reset after usb is disconnected
00309     if (daplink_is_interface() && (config_ram_get_hold_in_bl() || config_ram_get_disable_msd()==1)) {
00310         SystemReset();
00311     }
00312 
00313     remount_count++;
00314 }
00315 
00316 // Get the filesize from a filesize callback.
00317 // The file data must be null terminated for this to work correctly.
00318 static uint32_t get_file_size(vfs_read_cb_t read_func)
00319 {
00320     // Determine size of the file by faking a read
00321     return read_func(0, file_buffer, 1);
00322 }
00323 
00324 // File callback to be used with vfs_add_file to return file contents
00325 static uint32_t read_file_mbed_htm(uint32_t sector_offset, uint8_t *data, uint32_t num_sectors)
00326 {
00327     if (sector_offset != 0) {
00328         return 0;
00329     }
00330 
00331     return update_html_file(data, VFS_SECTOR_SIZE);
00332 }
00333 
00334 // File callback to be used with vfs_add_file to return file contents
00335 static uint32_t read_file_details_txt(uint32_t sector_offset, uint8_t *data, uint32_t num_sectors)
00336 {
00337 
00338     if (sector_offset != 0) {
00339         return 0;
00340     }
00341 
00342     return update_details_txt_file(data, VFS_SECTOR_SIZE);
00343 }
00344 
00345 // Text representation of each error type, starting from the rightmost bit
00346 static const char* const error_type_names[] = {
00347     "internal",
00348     "transient",
00349     "user",
00350     "target",
00351     "interface"
00352 };
00353 
00354 COMPILER_ASSERT(1 << ARRAY_SIZE(error_type_names) == ERROR_TYPE_MASK + 1);
00355 
00356 // File callback to be used with vfs_add_file to return file contents
00357 static uint32_t read_file_fail_txt(uint32_t sector_offset, uint8_t *data, uint32_t num_sectors)
00358 {
00359     uint32_t size = 0;
00360     char *buf = (char *)data;
00361     error_t status = vfs_mngr_get_transfer_status();
00362     const char *contents = error_get_string(status);
00363     error_type_t type = error_get_type(status);
00364 
00365     if (sector_offset != 0) {
00366         return 0;
00367     }
00368 
00369     size += util_write_string(buf + size, error_prefix);
00370     size += util_write_string(buf + size, contents);
00371     size += util_write_string(buf + size, "\r\n");
00372     size += util_write_string(buf + size, error_type_prefix);
00373 
00374     // Write each applicable error type, separated by commas
00375     int index = 0;
00376     bool first = true;
00377     while (type && index < ARRAY_SIZE(error_type_names)) {
00378         if (!first) {
00379             size += util_write_string(buf + size, ", ");
00380         }
00381         if (type & 1) {
00382             size += util_write_string(buf + size, error_type_names[index]);
00383             first = false;
00384         }
00385         index++;
00386         type >>= 1;
00387     }
00388 
00389     size += util_write_string(buf + size, "\r\n");
00390     return size;
00391 }
00392 
00393 // File callback to be used with vfs_add_file to return file contents
00394 static uint32_t read_file_assert_txt(uint32_t sector_offset, uint8_t *data, uint32_t num_sectors)
00395 {
00396     uint32_t pos;
00397     const char *source_str;
00398     char *buf = (char *)data;
00399     uint32_t * hexdumps = 0;
00400     uint8_t valid_hexdumps = 0;
00401     uint8_t index = 0;
00402 
00403     if (sector_offset != 0) {
00404         return 0;
00405     }
00406 
00407     pos = 0;
00408 
00409     if (ASSERT_SOURCE_BL == assert_source) {
00410         source_str = "Bootloader";
00411     } else if (ASSERT_SOURCE_APP == assert_source) {
00412         source_str = "Application";
00413     } else {
00414         source_str = 0;
00415     }
00416 
00417     pos += util_write_string(buf + pos, "Assert\r\n");
00418     pos += util_write_string(buf + pos, "File: ");
00419     pos += util_write_string(buf + pos, assert_buf);
00420     pos += util_write_string(buf + pos, "\r\n");
00421     pos += util_write_string(buf + pos, "Line: ");
00422     pos += util_write_uint32(buf + pos, assert_line);
00423     pos += util_write_string(buf + pos, "\r\n");
00424 
00425     if (source_str != 0) {
00426         pos += util_write_string(buf + pos, "Source: ");
00427         pos += util_write_string(buf + pos, source_str);
00428         pos += util_write_string(buf + pos, "\r\n");
00429     }
00430 
00431     valid_hexdumps = config_ram_get_hexdumps(&hexdumps);
00432     if ((valid_hexdumps > 0) && (hexdumps != 0)) {
00433         //print hexdumps
00434         pos += util_write_string(buf + pos, "Hexdumps\r\n");
00435         while ((index < valid_hexdumps) && ((pos + 10) < VFS_SECTOR_SIZE)) { //hexdumps + newline is always 10 characters
00436             pos += util_write_hex32(buf + pos, hexdumps[index++]);
00437             pos += util_write_string(buf + pos, "\r\n");
00438         }
00439     }
00440 
00441     return pos;
00442 }
00443 
00444 // File callback to be used with vfs_add_file to return file contents
00445 static uint32_t read_file_need_bl_txt(uint32_t sector_offset, uint8_t *data, uint32_t num_sectors)
00446 {
00447     const char *contents = "A bootloader update was started but unable to complete.\r\n"
00448                            "Reload the bootloader to fix this error message.\r\n";
00449     uint32_t size = strlen(contents);
00450 
00451     if (sector_offset != 0) {
00452         return 0;
00453     }
00454 
00455     memcpy(data, contents, size);
00456     return size;
00457 }
00458 
00459 
00460 static uint32_t update_html_file(uint8_t *data, uint32_t datasize)
00461 {
00462     char *buf = (char *)data;
00463     //Needed by expand_info strlen
00464     memset(buf, 0, datasize);
00465     memcpy(buf, mbed_redirect_file, strlen(mbed_redirect_file));
00466     //expand
00467     return expand_info(data, datasize);
00468 }
00469 
00470 static uint32_t update_details_txt_file(uint8_t *data, uint32_t datasize)
00471 {
00472     uint32_t pos=0;
00473     const char *mode_str;
00474 
00475     char *buf = (char *)data;
00476 
00477     //Needed by expand_info strlen
00478     memset(buf, 0, datasize);
00479 
00480     pos += util_write_string(buf + pos, "# DAPLink Firmware - see https://mbed.com/daplink\r\n");
00481     // Unique ID
00482     pos += util_write_string(buf + pos, "Unique ID: @U\r\n");
00483     // HIC ID
00484     pos += util_write_string(buf + pos, "HIC ID: @D\r\n");
00485     // Settings
00486     pos += util_write_string(buf + pos, "Auto Reset: ");
00487     pos += util_write_string(buf + pos, config_get_auto_rst() ? "1" : "0");
00488     pos += util_write_string(buf + pos, "\r\n");
00489     pos += util_write_string(buf + pos, "Automation allowed: ");
00490     pos += util_write_string(buf + pos, config_get_automation_allowed() ? "1" : "0");
00491     pos += util_write_string(buf + pos, "\r\n");
00492     pos += util_write_string(buf + pos, "Overflow detection: ");
00493     pos += util_write_string(buf + pos, config_get_overflow_detect() ? "1" : "0");
00494     pos += util_write_string(buf + pos, "\r\n");
00495     pos += util_write_string(buf + pos, "Page erasing: ");
00496     pos += util_write_string(buf + pos, config_ram_get_page_erase() ? "1" : "0");
00497     pos += util_write_string(buf + pos, "\r\n");
00498     // Current mode
00499     mode_str = daplink_is_bootloader() ? "Bootloader" : "Interface";
00500     pos += util_write_string(buf + pos, "Daplink Mode: ");
00501     pos += util_write_string(buf + pos, mode_str);
00502     pos += util_write_string(buf + pos, "\r\n");
00503     // Current build's version
00504     pos += util_write_string(buf + pos, mode_str);
00505     pos += util_write_string(buf + pos, " Version: @V\r\n");
00506 
00507     // Other builds version (bl or if)
00508     if (!daplink_is_bootloader() && info_get_bootloader_present()) {
00509         pos += util_write_string(buf + pos, "Bootloader Version: ");
00510         pos += util_write_uint32_zp(buf + pos, info_get_bootloader_version(), 4);
00511         pos += util_write_string(buf + pos, "\r\n");
00512     }
00513 
00514     if (!daplink_is_interface() && info_get_interface_present()) {
00515         pos += util_write_string(buf + pos, "Interface Version: ");
00516         pos += util_write_uint32_zp(buf + pos, info_get_interface_version(), 4);
00517         pos += util_write_string(buf + pos, "\r\n");
00518     }
00519 
00520     // GIT sha
00521     pos += util_write_string(buf + pos, "Git SHA: ");
00522     pos += util_write_string(buf + pos, GIT_COMMIT_SHA);
00523     pos += util_write_string(buf + pos, "\r\n");
00524     // Local modifications when making the build
00525     pos += util_write_string(buf + pos, "Local Mods: ");
00526     pos += util_write_uint32(buf + pos, GIT_LOCAL_MODS);
00527     pos += util_write_string(buf + pos, "\r\n");
00528     // Supported USB endpoints
00529     pos += util_write_string(buf + pos, "USB Interfaces: ");
00530 #ifdef MSC_ENDPOINT
00531     pos += util_write_string(buf + pos, "MSD");
00532 #endif
00533 #ifdef CDC_ENDPOINT
00534     pos += util_write_string(buf + pos, ", CDC");
00535 #endif
00536 #ifdef HID_ENDPOINT
00537     pos += util_write_string(buf + pos, ", HID");
00538 #endif
00539 #if (WEBUSB_INTERFACE)
00540     pos += util_write_string(buf + pos, ", WebUSB");
00541 #endif
00542     pos += util_write_string(buf + pos, "\r\n");
00543 
00544     // CRC of the bootloader (if there is one)
00545     if (info_get_bootloader_present()) {
00546         pos += util_write_string(buf + pos, "Bootloader CRC: 0x");
00547         pos += util_write_hex32(buf + pos, info_get_crc_bootloader());
00548         pos += util_write_string(buf + pos, "\r\n");
00549     }
00550 
00551     // CRC of the interface
00552     pos += util_write_string(buf + pos, "Interface CRC: 0x");
00553     pos += util_write_hex32(buf + pos, info_get_crc_interface());
00554     pos += util_write_string(buf + pos, "\r\n");
00555 
00556     // Number of remounts that have occurred
00557     pos += util_write_string(buf + pos, "Remount count: ");
00558     pos += util_write_uint32(buf + pos, remount_count);
00559     pos += util_write_string(buf + pos, "\r\n");
00560 
00561     //Target URL
00562     pos += util_write_string(buf + pos, "URL: @R\r\n");
00563 
00564     return expand_info(data, datasize);
00565 }
00566 
00567 // Fill buf with the contents of the mbed redirect file by
00568 // expanding the special characters in mbed_redirect_file.
00569 static uint32_t expand_info(uint8_t *buf, uint32_t bufsize)
00570 {
00571     uint8_t *orig_buf = buf;
00572     uint8_t *insert_string;
00573 
00574     do {
00575         // Look for key or the end of the string
00576         while ((*buf != '@') && (*buf != 0)) {
00577             buf++;
00578         }
00579 
00580         // If key was found then replace it
00581         if ('@' == *buf) {
00582             switch (*(buf + 1)) {
00583                 case 'm':
00584                 case 'M':   // MAC address
00585                     insert_string = (uint8_t *)info_get_mac();
00586                     break;
00587 
00588                 case 'u':
00589                 case 'U':   // UUID
00590                     insert_string = (uint8_t *)info_get_unique_id();
00591                     break;
00592 
00593                 case 'b':
00594                 case 'B':   // Board ID
00595                     insert_string = (uint8_t *)info_get_board_id();
00596                     break;
00597 
00598                 case 'h':
00599                 case 'H':   // Host ID
00600                     insert_string = (uint8_t *)info_get_host_id();
00601                     break;
00602 
00603                 case 't':
00604                 case 'T':   // Target ID
00605                     insert_string = (uint8_t *)info_get_target_id();
00606                     break;
00607 
00608                 case 'd':
00609                 case 'D':   // HIC
00610                     insert_string = (uint8_t *)info_get_hic_id();
00611                     break;
00612 
00613                 case 'v':
00614                 case 'V':   // Firmware version
00615                     insert_string = (uint8_t *)info_get_version();
00616                     break;
00617 
00618                 case 'r':
00619                 case 'R':   // URL replacement
00620                     insert_string = (uint8_t *)get_daplink_target_url();
00621                     break;
00622 
00623                 default:
00624                     insert_string = (uint8_t *)"ERROR";
00625                     break;
00626             }
00627 
00628             // Remove strip_count characters from the start of buf and then insert
00629             // insert_string at the new start of buf.
00630             uint32_t buf_len = strlen((const char *)buf);
00631             uint32_t str_len = strlen((const char *)insert_string);
00632             //buffer overflow check on insert
00633             if( (buf + str_len + buf_len - 2) < (orig_buf+bufsize)){
00634                 // push out string
00635                 memmove(buf + str_len, buf + 2, buf_len - 2);
00636                 // insert
00637                 memcpy(buf, insert_string, str_len);
00638             }else{
00639                 //stop the string expansion and leave as it is
00640                 buf += buf_len;
00641                 break;
00642             }
00643 
00644         }
00645     } while (*buf != '\0');
00646 
00647     return (buf - orig_buf);
00648 }
00649 
00650 // Initialize flash algo, erase flash, uninit algo
00651 static void erase_target(void)
00652 {
00653     flash_intf_target->init();
00654     flash_intf_target->erase_chip();
00655     flash_intf_target->uninit();
00656 }