silicon EFR32BG22 应用内进行OTA

通过Simplicity Studio新建的蓝牙工程默认是带有appLoader的,appLoader的一个缺点就是只能实现单区跟新,而且原厂没有开放appLoader的代码,有的时候可能没办满足用户的需求。比如在更新的时候需要led处于快闪的模式,appLoader就没办法做到。

appLoader的更新流程参考: https://blog.youkuaiyun.com/chengbaojin/article/details/113369125

下面说一下如何实现在用户的程序中实现OTA。

本文使用的环境

  • sdk: gecko_sdk_3.1
  • IDE: Simplicity Studio 5.0

一 flash存储情况

在这里插入图片描述
做空中升级之前是需要先烧录一个BootLoader。做双区更新一般情况下flash需要512KB及以上的大小。本文使用的是这个工程bootloader-storage-internal-single-512k

BootLoader的工程需要设置Slot 0也就是app bank2的起始地址,app bank2也就是新固件的存放地址。这里的起始地址是278528(0x4 4000)。如下图所示:
在这里插入图片描述

根据工程的autogen\linkerfile.ld文件可知,用户的应用程序存放的起始地址是0x6000,也就是说留给BootLoader的空间为24KB。

在这里插入图片描述

二 在工程中新建一个OTA服务

新建的工程默认有一个OTA服务,这个服务只有一个Control characteristic,而且在gatt_configuration.btconf文件中不可修改。这个服务不是我们所需要的,需要删除并自己新建一个OTA服务。
在这里插入图片描述

可以在下图的位置删除这个服务:在这里插入图片描述
然后自己手动添加服务,如下图:
在这里插入图片描述
这里的Data characteristic需要选择user如下图:
在这里插入图片描述
在这里插入图片描述

三 升级流程

  • 通过Control characteristic进入升级模式,通过data characteristic接收新固件
  • 设置标志,并重启
    bootloader_setImageToBootload(0);
    bootloader_rebootAndInstall();
  1. 初始化BootLoader

当接收到sl_bt_evt_system_boot_id事件之后调用bootloader_init进行初始化

 /* bootloader init must be called before calling other bootloader_xxx API calls */
 bootloader_init();

 /* read slot information from bootloader */
 if(get_slot_info() == BOOTLOADER_OK)
 {
   /* the download area is erased here (if needed), prior to any connections are opened */
   erase_slot_if_needed();
 }
  1. 向Control characteristic写0,进入升级模式
//实测发现向Control characteristic写0生成的是这个事件
case sl_bt_evt_gatt_server_attribute_value_id:{
      uint32_t connection = evt->data.evt_gatt_server_attribute_value.connection;
      uint32_t characteristic = evt->data.evt_gatt_server_attribute_value.attribute;
      LOGD("characteristic == %d\r\n",characteristic);
      if(characteristic == gattdb_ota_control)
      {
        switch(evt->data.evt_gatt_server_attribute_value.value.data[0])
        {
        case 0://Erase and use slot 0
          // NOTE: download are is NOT erased here, because the long blocking delay would result in supervision timeout
          //bootloader_eraseStorageSlot(0);
          LOGD("control 0\r\n");
          ota_image_position=0;
          ota_in_progress=1;
          sl_bt_gatt_server_send_user_write_response(connection,characteristic,0);
          break;
        case 3://END OTA process
          //wait for connection close and then reboot
          ota_in_progress=0;
          ota_image_finished=1;
          LOGD("upload finished. received file size %u bytes\r\n", ota_image_position);
          sl_bt_gatt_server_send_user_write_response(connection,characteristic,0);
          break;
        default:
          break;
        }
      }
    }
      break;
  1. 向Data characteristic写新的固件

bootloader_writeStorage的起始地址就是BootLoader中设置的slot 0的地址。bootloader_writeStorage其实是在BootLoader中实现的,这里只是一个地址的引用。

 case sl_bt_evt_gatt_server_user_write_request_id:
    {
      uint32_t connection = evt->data.evt_gatt_server_user_write_request.connection;
      uint32_t characteristic = evt->data.evt_gatt_server_user_write_request.characteristic;

      LOGD("characteristic == %d\r\n",characteristic);
      if(characteristic == gattdb_ota_control)
      {
        switch(evt->data.evt_gatt_server_user_write_request.value.data[0])
        {
        case 0://Erase and use slot 0
          // NOTE: download are is NOT erased here, because the long blocking delay would result in supervision timeout
          //bootloader_eraseStorageSlot(0);
          LOGD("control 0\r\n");
          ota_image_position=0;
          ota_in_progress=1;
          break;
        case 3://END OTA process
          //wait for connection close and then reboot
          ota_in_progress=0;
          ota_image_finished=1;
          LOGD("upload finished. received file size %u bytes\r\n", ota_image_position);
          break;
        default:
          break;
        }
      } else if(characteristic == gattdb_ota_data)
      {
        if(ota_in_progress)
        {
            LOGD("wirite data\r\n");
          bootloader_writeStorage(0,//use slot 0
              ota_image_position,
            evt->data.evt_gatt_server_user_write_request.value.data,
            evt->data.evt_gatt_server_user_write_request.value.len);
          ota_image_position+=evt->data.evt_gatt_server_user_write_request.value.len;
        }
      }
      //gecko_cmd_gatt_server_send_user_write_response(connection,characteristic,0);
      sl_bt_gatt_server_send_user_write_response(connection,characteristic,0);
    }
      break;
  1. 升级完成之后断开连接
case sl_bt_evt_connection_closed_id:{
      // Restart advertising after client has disconnected.
      pFunction Jump_To_Application;
      uint32_t JumpAddress;

      if (ota_image_finished) {
        LOGD("Installing new image\r\n");

        bootloader_setImageToBootload(0);
     	//设置安装新固件的标志位,复位之后会进入BootLoader,BootLoader负责将bank2中的内容搬运到bank1中
        bootloader_rebootAndInstall();
      
      } else{
      sc = sl_bt_advertiser_start(
        advertising_set_handle,
        advertiser_general_discoverable,
        advertiser_connectable_scannable);
      sl_app_assert(sc == SL_STATUS_OK,
                    "[E: 0x%04x] Failed to start advertising\n",
                    (int)sc);
      }
    }
      break;

四 手机端验证

  1. 手动向Control characteristic写0
    在这里插入图片描述
  2. 选择一个.gbl文件

.gbl文件的制作方法参看:https://blog.youkuaiyun.com/chengbaojin/article/details/113369125
在这里插入图片描述
在这里插入图片描述
3. 等待升级完成
在这里插入图片描述

参考文档:

### 解决Content Security Policy (CSP) img-src 'self' data: base64 错误 当遇到 `img-src` CSP 指令违反策略的问题时,通常是由于网页尝试加载不符合指定来源的图像资源引起的。以下是可能的原因以及解决方案: #### 原因分析 1. **CSP 策略定义不足** 当前 CSP 中设置了 `img-src 'self'`,这意味着只有来自同一源(即当前域名)的图片才能被加载。如果页面中有通过 `data:` 或者其他外部 URL 加载的图片,则会被阻止[^1]。 2. **Base64 图像嵌入问题** 使用 Base64 编码的内联图像是一种常见的优化手段,但如果未显式允许 `data:` 协议,在 CSP 下这些图像将无法正常显示。 3. **动态生成的内容冲突** 动态注入 HTML 内容可能导致意外行为,尤其是当内容中包含不受信任的数据时,这可能会触发 CSP 警告或错误。 --- #### 解决方案 ##### 方法一:扩展 `img-src` 定义范围 修改 `<meta>` 标签中的 CSP 策略以支持更多类型的图像来源。例如: ```html <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'; img-src 'self' data:;"> ``` 上述配置表示除了允许同源的图片外,还允许基于 Base64 的编码图像加载。 ##### 方法二:调整服务器端响应头 如果 CSP 是由 HTTP 头部设置而非 `<meta>` 标签控制,则需更新 Web 服务器配置文件。对于 Nginx 和 Apache 分别有以下示例: - **Nginx** ```nginx add_header Content-Security-Policy "default-src 'self'; script-src 'self'; img-src 'self' data;"; ``` - **Apache** ```apache Header set Content-Security-Policy "default-src 'self'; script-src 'self'; img-src 'self' data;" ``` 以上更改确保浏览器能够识别并接受 Base64 数据作为合法的图像来源[^1]。 ##### 方法三:移除违规代码片段 检查前端代码是否存在非法调用第三方资源的情况。比如某些框架库自动插入了跨域请求或者使用了未经许可的协议加载媒体资产。清理掉不必要的部分有助于减少潜在风险。 ##### 方法四:启用报告机制捕获异常事件 为了更好地监控实际运行状况,建议开启 CSP Reports 功能收集反馈日志以便后续改进措施制定。 ```html <meta http-equiv="Content-Security-Policy" content="... report-uri /csp-report-endpoint"> ``` 此操作会把每次发生的违禁访问记录提交至指定 URI 地址供管理员审查处理。 --- ### 示例代码展示 下面给出一段简单的 PHP 页面演示如何正确应用增强后的 CSP 设置防止类似问题再次发生。 ```php <?php header('Content-Security-Policy: default-src \'self\'; script-src \'self\'; img-src \'self\' data:'); ?> <!DOCTYPE html> <html lang="en"> <head> <title>CSP Example</title> </head> <body> <!-- 合法本地图片 --> <img src="/images/example.jpg"> <!-- 合法base64编码图片 --> <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA..." alt="Embedded Image"> <h1>Secure Page Loaded Successfully!</h1> </body> </html> ``` ---
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值