4.3.13. FindMy

4.3.13.1. findmy原理简介和概述

image1

  • 支持的板级: br25、br23、bd19、br34

  • 支持的芯片: AC636N、AC635N、AC632N、AC638N

  1. Find My 是苹果公司提供的一种寻找丢失设备的服务和协议。它可以帮助用户定位并追踪丢失的苹果设备,如 AirTag 和 AirPods 等。findmy协议依托庞大的findmy network网络,即使本身没有 GPS 模块,也能利用它周围的苹果设备(iPhone,iPad,Mac)来帮助其定位。

  2. 如图1,在findmy协议中主要可以分为以下角色:

    • 拥有者设备(Owner device):拥有者设备是用户的苹果设备,如iPhone或iPad,通过使用Find My应用程序与外设进行连接和配对。拥有者设备与用户的Apple ID关联,并成为Find My网络的拥有者设备角色。

    • Find My服务器(findmy apple server):Find My功能涉及到苹果的服务器,用于处理设备的定位和数据传输。这些服务器经过IOS设备通过网络协议接收来自支持Find My功能的设备发送的定位数据,并将其提供给用户的Find My应用程序进行显示和处理。

    • 外设(Accessory):外设是实现了Find My网络协议的设备,如AirTag或其他支持Find My功能的设备(使用烧录JL FindMy SDK的芯片的产品)。外设可以通过与拥有者设备进行BLE协议连接和配对数据交互,加入Find My网络。

4.3.13.2. 快速上手

本章节主要介绍拿到sdk后如何快速运行findmy应用功能

4.3.13.2.1. 开发环境搭建

  • 首先请确保正确的搭建了 Windows 下的第三方集成开发环境 CodeBlocks和杰理的编译工具链 jl_toolchain。

https://doc.zh-jieli.com/AC63/zh-cn/master/getting_started/environmental_install/index.html

4.3.13.2.2. 板级配置和app应用选择

先配置板级apps\spp_and_le\board\bd19\board_config.h(以AC632系列为例)。

/*
 *  板级配置选择
 */
// #define CONFIG_BOARD_AC632N_DEMO
#define CONFIG_BOARD_AC6323A_FMY
// #define CONFIG_BOARD_AC6321A_DEMO
// #define CONFIG_BOARD_AC6323A_DEMO
// #define CONFIG_BOARD_AC6328A_DEMO
// #define CONFIG_BOARD_AC6328B_DONGLE
// #define CONFIG_BOARD_AC6329B_DEMO
// #define CONFIG_BOARD_AC6329C_DEMO
// #define CONFIG_BOARD_AC6329E_DEMO
// #define CONFIG_BOARD_AC6329F_DEMO

配置app选择:apps\spp_and_le\include\app_config.h

//apps example 选择,只能选1个,要配置对应的board_config.h
#define CONFIG_APP_SPP_LE                 0 //SPP + LE or LE's client
#define CONFIG_APP_FINDMY                 1 //FINDMY
#define CONFIG_APP_MULTI                  0 //蓝牙LE多连 + spp
#define CONFIG_APP_DONGLE                 0 //usb + 蓝牙(ble 主机),PC hid设备
#define CONFIG_APP_CENTRAL                0 //ble client,中心设备
#define CONFIG_APP_LL_SYNC                0 //腾讯连连
#define CONFIG_APP_BEACON                 0 //蓝牙BLE ibeacon
#define CONFIG_APP_NONCONN_24G            0 //2.4G 非连接收发
#define CONFIG_APP_TUYA                   0 //涂鸦协议
#define CONFIG_APP_AT_COM                 0 //AT com HEX格式命令
#define CONFIG_APP_AT_CHAR_COM            0 //AT com 字符串格式命令
#define CONFIG_APP_IDLE                   0 //空闲任务
#define CONFIG_APP_CONN_24G               0 //基于BLE的2.4g,板级只需要开BLE
#define CONFIG_APP_HILINK                 0 //华为协议
#define CONFIG_APP_ELECTROCAR             0 //电车项目,注意将板级处ADKEY以及别的IO占用失能, 关闭低功耗:TCFG_LOWPOWER_LOWPOWER_SEL设置为0

4.3.13.2.3. 添加苹果授权信息

Note

由于findmy配件还需要依赖苹果服务器去做功能的运转,因此还需要向苹果申请对应的授权信息才能成功绑定入网,注意第一次烧写一定要修改以下信息,这个只是JL的示例数据无法正常使用,否则无法配对入网。

授权信息的修改文件位于:ble_fmy_fmna.c

//==================================================================================
// !!!!!重要说明事项!!!!!!
// 下列是测试findmy功能需要填入自己的token信息格式示例
// 只能被搜索,不能配对绑定连接; 如要正常使用功能需要向苹果申请自己的token信息替换写入测试

//用户申请的UID,需要修改填入
static const uint8_t fmy_serial_number[16] = "";
//用户申请的product_data,需要修改填入
static const uint8_t fmy_product_data[8] = {};//JL

//默认使用的base64的公钥key,一般不需要修改
static const char fmy_Server_Encryption_Key[] = "";
static const char fmy_Signature_Verification_Key[] = "";

//用户申请的token,base64格式或者hex格式,需要修改填入

#if UUID_TOKEN_IS_BASE64_MODE
static const char fmy_token_uuid_char[] = "";
static const char fmy_token_auth_char[] = "";

#else

static const uint8_t fmy_token_uuid_hex[16] = {

};

static const uint8_t fmy_token_auth_hex[] = {
   ....
};

#endif
  • fmy_serial_number:从apple申请的序列序列号

  • fmy_product_data:从apple申请的产品信息

  • fmy_Server_Encryption_Key:从apple申请的Encryption_Key

  • fmy_Signature_Verification_Key:从apple申请的Verification_Key

  • fmy_token_uuid_char:从mfi申请的每个产品授权的uuid

  • fmy_token_auth_char:从mfi申请的每个产品授权的token

4.3.13.2.4. 添加杰理授权使用

目前JL FindMy SDK对fmna.a库进行授权的方式进行生产样机个数进行收费,有关授权算法的使用介绍如下:

https://doc.zh-jieli.com/Tools/zh-cn/mass_prod_tools/multi_auth/index.html

并且参考以下步骤完成对授权数据的烧录:

https://doc.zh-jieli.com/Tools/zh-cn/mass_prod_tools/multi_auth/prod-user.html#authroization-id

操作步骤提示如下(以AC632系列为例):

  • 获取授权Lic: 请在下单采购632N具体芯片型号时,备注“findmy多算法授权”,并联系珠海杰理客服。

  • 修改授权文件名称,并放在cpu的下载目录(cpu\bd19\tools\download\data_trans)才能编译生成带算法授权功能的fw文件。其中tkn文件的名字应与isd_config.ini的配置信息一致 file_authrunFindmyAC632N.tkn,生成完fw文件后使用烧写器进行算法授权信息的烧录

  • 运行的芯片第一次需要经过1拖2或者1拖8烧写器(lastest version)烧写授权码;如果你未完成这一步直接烧写固件,如果fw程序运行出现异常复位或者添加调试信息后出现ASSERT-FAILD: 0 fmna forbidden cfg!!!,说明芯片还没被授权,需要通过烧写器写入授权数据。

// ini文件的最后一段配置
[FW_ADDITIONAL]
FILE_LIST=(file=file_authrunFindmyAC632N.tkn:type=0xec)

Note

正确烧写杰理授权数据后,此时之后的固件烧写不会影响杰理的授权数据(除非你擦除了所有的flash数据,非必要不要擦除所有flash数据)。

4.3.13.2.5. 烧录固件

Note

如果杰理授权数据已经烧录到芯片里面,并且你也正确的修改了sdk的苹果授权信息,那么现在把findmy固件写入,打开codeblocks工程,apps\spp_and_le\board\bd19\AC632N_spp_and_le.cbp,点击编译烧录,编译烧录教程参考:

https://doc.zh-jieli.com/Tools/zh-cn/dev_tools/build_download/build_with_codeblocks.html

4.3.13.2.6. 测试使用

Note

烧录完上电后,findm配件不默认打开广播,可以查看fmy_ble_key_event_handler函数逻辑, 单击触发ADKEY0事件打开广播,此时可以打开IOS终端查找应用->物品->添加其他应用->搜索到设备->命名绑定连接

  if (event_type == KEY_EVENT_CLICK) {
        switch (key_value) {
        case TCFG_ADKEY_VALUE0:
            log_info(">>>test to enable start pairing adv");
#if FMY_MAC_CHANGE_LOCK
            fmy_pairing_reset_address();
#endif
            fmy_pairing_restart_adv();
     }

Important

如果成功连接绑定连接并且可以控制播声,那么恭喜你!已经完成了JL Findmy SDK的上手使用,可以依靠后续章节去开发属于你的findmy应用

4.3.13.3. 代码架构介绍

4.3.13.3.1. FindMy SDK框图介绍

image2

Note

上图为JL FINDMY SDK的框图架构,依托杰理的平台和fmna协议库,用户工程师不需要关注fmna中findmy状态机的转换运作原理,也不需要关注findmy协议是如何和IOS进行加密交握手完成配对,只需要简单的在我们上层留出的接口和杰理SDK原有的功能去适配自己产品上层的交互逻辑和外设即可。

4.3.13.3.2. 应用层代码文件介绍

image3

fmy功能接口应用层文件架构介绍见上图

4.3.13.4. findmy状态介绍

4.3.13.4.1. 状态介绍

findmy通过状态机的控制会在不同行为场景中转化为不同的状态,常见的状态如下:

  1. 等待配对状态(pair mode):产品还未与苹果设备(例如iPhone或者iPad)配对时,或者产品从Find My应用中移除配对时,此状态会发送等待配对的蓝牙广播。为了尽可能快的被苹果设备发现,此状态会高速广播,功耗比较大。

  2. 配对连接状态(pairing):产品与苹果设备连接完成配对过程,此状态产品与苹果设备交换大量的数据,功耗也比较大,因为此状态出现非常低频, 所以此状态对产品续航影响小。

  3. 高速连接并寻找状态(产品响铃)(high connected):完成配对的产品,可以在Find My应用中点击 “播放声音”按钮,可以使产品响铃,来找到产品,因为此状态出现低频, 所以此状态对产品续航影响小。

  4. 低速连接状态(low connected):如果已配对产品与苹果设备重连时,会处于高速连接过程(高速可以理解为产品与苹果设备的数据交互高速很高),如果没有“播放声音”操作,30秒后就会进入低速连接状态。此状态下功耗比较低。如果产品与苹果设备不断开,此状态会一直保持着。

  5. 慢速广播状态(待机状态)(separated):如果已配对产品与苹果设备远离,产品与苹果设备蓝牙断开了,此时产品就会发送慢速蓝牙广播,等待下一次重连被寻找,如果用户不尝试“播放声音”功能,产品会一直处于此状态。

4.3.13.4.2. findmy状态回调函数

  • JL FindMy SDK中在外部设置定义了回调函数供用户捕捉对应的状态以便用户自定义外设行为(例如配对完成后或者解绑有特殊的铃声)。

ble_fmy_fmna.c

/*
 * @brief findmy state callback,状态类别参考FMNA_SM_State_t枚举体
 */
static uint16_t fmy_state_callback(FMNA_SM_State_t fmy_state, const char *state_string)
{
    log_info("fmy state change->fmy_state:%s", state_string);
    switch (fmy_state) {
    case FMNA_SM_FMNA_PAIR_COMPLETE:
        log_info(">>>findmy pair success!!");
        break;
    case FMNA_SM_UNPAIR:
        log_info(">>>findmy unpair success!!");
        break;
    default:
        break;
    }
    return 0;
}

fmna_api.h

typedef enum {
    FMNA_SM_BOOT = 0,
    FMNA_SM_PAIR,
    FMNA_SM_SEPARATED,
    FMNA_SM_NEARBY,
    FMNA_SM_CONNECTING,
    FMNA_SM_FMNA_PAIR,
    FMNA_SM_FMNA_PAIR_COMPLETE,
    FMNA_SM_CONNECTED,
    FMNA_SM_DISCONNECTING,
    FMNA_SM_NOCHANGE,
    FMNA_SM_UNPAIR
} FMNA_SM_State_t;

4.3.13.5. apple license和产品信息配置

4.3.13.5.1. 产品信息配置

ble_fmy.c

static const char FMY_ManufacturerName[64] = "Zhuhai Jieli Technology Co.,Ltd.";
static const char FMY_ModelName[64] = "JLtag";
static const uint8_t FMY_AccessoryCategory[8] = {FMY_CATEGORY_Finder, 0, 0, 0, 0, 0, 0, 0};
  • FMY_ManufacturerName:公司名称

  • FMY_ModelName:配件名字

  • FMY_AccessoryCategory:产品类型

ble_fmy_cfg.h

  • TOKEN_ID_PRODUCTION_MODE:选择debug模式还是production

  • FMY_FW_VERSION_MAJOR_NUMBER:固件主要版本

  • FMY_FW_VERSION_MINOR_NUMBER:固件次要版本

  • FMY_FW_VERSION_REVISION_NUMBER:固件修订版本号

固件版本需遵循以下规则

The firmware revision string shall use the x[.y[.z]] format where :
• <x> is the major version number, required.
• <y> is the minor version number, required if it is non zero or if <z> is present.
• <z> is the revision version number, required if non zero.

4.3.13.5.2. apple license信息配置和说明

ble_fmy_cfg.h
#define  UUID_TOKEN_IS_BASE64_MODE                    1 //0--hex,   1--base64

static const uint8_t fmy_serial_number[16] = "";
static const uint8_t fmy_product_data[8] = {};
static const char fmy_Server_Encryption_Key[] = "";
static const char fmy_Signature_Verification_Key[] = "";


static const char fmy_token_uuid_char[] = "";
static const char fmy_token_auth_char[] = "";
  • TOKEN_ID_PRODUCTION_MODE:产品模式选择(debug和production)

  • UUID_TOKEN_IS_BASE64_MODE:UUID和TOKEN数据格式(hex:以十六进制填入,base64:以base64数据格式填入)

  • fmy_serial_number:从apple申请的序列序列号

  • fmy_product_data:从apple申请的产品信息

  • fmy_Server_Encryption_Key:从apple申请的Encryption_Key

  • fmy_Signature_Verification_Key:从apple申请的Verification_Key

  • fmy_token_uuid_char:从mfi申请的每个产品授权的uuid

  • fmy_token_auth_char:从mfi申请的每个产品授权的token

有关apple findmy开发资格申请可参考以下链接:

https://www.apple.com/newsroom/2021/04/apples-find-my-network-now-offers-new-third-party-finding-experiences/

授权信息写入函数如下:

ble_fmy_fmna.c

/*************************************************************************************************/
 /*!
 *  \brief      配置用户认证信息
 *
 *  \param      [in]
 *
 *  \return
 *
 *  \note  token信息写入,慎重修改!!!!!!
 */
 /*************************************************************************************************/
static int fmy_set_user_infomation(void)
{
    ret_code_t ret = FMY_SUCCESS;
    fmna_input_cfg_t input_cfg;

    fmna_user_cfg_set_patch(fmy_user_config_path);
    fmna_set_product_data(fmy_product_data);
    fmna_set_crypto_enc_key_config(fmy_Server_Encryption_Key, fmy_Signature_Verification_Key);

    //!!!配置区写入有效的token,为空时默认写入一次,使用后token会被手机更新
    //注意不要重复写入,以免token被手机更新后,丢失失效
    uint8_t *data_ram = zalloc(16 + 1024);

    if (data_ram) {
        fmna_user_cfg_set_patch(fmy_user_config_path);
        ret = fmna_user_cfg_open();
        if (ret != FMY_SUCCESS) {
            log_info("open user_cfg fail,%d", ret);
            goto w_end_free;
        }

        if (fmna_user_cfg_is_exist()) {
            //用户可确定保存的token是否有效,如果无效可修改流程,写入新的token替换
            //注意不要重复写入,以免token被手机更新后,丢失失效
            fmy_read_last_user_config();
            fmna_user_cfg_close();
            log_info("exist user_cfg info");
            goto w_end_free;
        }

        //配置区有效,并且为空才写入
        input_cfg.serial_number = fmy_serial_number;
        input_cfg.uuid = data_ram;
        input_cfg.token = &data_ram[16];

#if UUID_TOKEN_IS_BASE64_MODE
        int len = uuid_str_to_hex(fmy_token_uuid_char, input_cfg.uuid);
        if (len != 16) {
            log_info("err uuid char");
            ret = FMY_ERROR_INVALID_DATA;
        } else {
            len = fmna_Base64Decode(fmy_token_auth_char, input_cfg.token, 1024);
            if (len == 0) {
                log_info("err token char");
                ret = FMY_ERROR_INVALID_DATA;
            }
        }
#else
        memcpy(input_cfg.uuid, fmy_token_uuid_hex, 16);
        memcpy(input_cfg.token, fmy_token_auth_hex, sizeof(fmy_token_auth_hex));

#endif

        if (ret == FMY_SUCCESS) {
            ret = fmna_user_cfg_write(&input_cfg);
            fmna_user_cfg_close();
        }

w_end_free:
        free(data_ram);
    } else {
        ret = FMY_ERROR_NO_MEM;
    }

    if (ret == FMY_SUCCESS) {
        log_info("set user_cfg succ");
    } else {
        log_info("set user_cfg fail,%d", ret);
    }

    return ret;
}
if (fmna_user_cfg_is_exist()) {
            //用户可确定保存的token是否有效,如果无效可修改流程,写入新的token替换
            //注意不要重复写入,以免token被手机更新后,丢失失效
            fmy_read_last_user_config();
            fmna_user_cfg_close();
            log_info("exist user_cfg info");
            goto w_end_free;
        }

Note

参考上述流程,如果当前授权数据不正确,可以注释掉这部分逻辑重新烧录新的apple授权数据,但上电更新后,需要重新打开这段代码再烧一次回来避免每次上电后又覆盖之前的apple授权数据信息。 其中fmy_token_uuid_char和fmy_token_auth_char都将写入在flash自定义区域,并且在每次配对绑定时会进行轮转,不可随意擦除此区域数据,否则之后将无法成功绑定,起始地址和大小如下(以512k AC63x平台为例),可在isd_config.ini见。

isd_config.ini

[RESERVED_EXPAND_CONFIG]
FINDMY_ADR=0x7D000;
FINDMY_LEN=0x2000;
FINDMY_OPT=1;

4.3.13.5.3. fmy功能特性设置

fmna_api.h

//Accessory capability
#define FMY_CAPABILITY_SUPPORTS_PLAY_SOUND            BIT(0) //Supports play sound
#define FMY_CAPABILITY_SUPPORTS_MOTION_DETECTOR_UT    BIT(1) //Supports motion detector UT
#define FMY_CAPABILITY_SUPPORTS_SN_LOOKUP_BY_NFC      BIT(2) //Supports serial number lookup by NFC
#define FMY_CAPABILITY_SUPPORTS_SN_LOOKUP_BY_BLE      BIT(3) //Supports serial number lookup by BLE
#define FMY_CAPABILITY_SUPPORTS_FW_UPDATE_SERVICE     BIT(4) //Supports firmware update service
ble_fmy.c
//set capability
static const uint8_t FMY_AccessoryCapabilities[4] = {
    (FMY_CAPABILITY_SUPPORTS_PLAY_SOUND

#if FMY_OTA_SUPPORT_CONFIG
    | FMY_CAPABILITY_SUPPORTS_FW_UPDATE_SERVICE
#endif

#if TCFG_GSENSOR_ENABLE
    | FMY_CAPABILITY_SUPPORTS_MOTION_DETECTOR_UT
#endif

    | FMY_CAPABILITY_SUPPORTS_SN_LOOKUP_BY_BLE),
    0x00, 0x00, 0x00
};

Note

AccessoryCapabilities描述了findmy配件支持的各种功能,默认打开play sound和serial_number_look_up功能,motion_detection和uarp用户可根据产品特性选择打开对应的宏控制,如何控制可见下表:

Characteristic name

Data type

Size(octets)

Description

Accessory capability

Uint32

4

Bit 0 : Supports play sound Bit 1 :Supports motion detector UT Bit 2 : Supports serial number lookup by NFC Bit 3 : Supports serial number lookup by BLE Bit 4: Supports firmware update service

  • 例如我要打开playSound, Supports serial number lookup by BLE, motion detector,firmware update service 功能,则可以将这个数组的第一个字节的前五个bit设置对应的二进制值即可:10101,由于findmy产品定位是防丢器,其中motion detection和play sound是否需要取决于产品的体积,当符合以下所有标准则需要这两项功能:

  • The accessory is ≤ 30 cm in at least one dimension.

  • The accessory is ≤ 18 cm X 13 cm in two of its dimensions.

  • The accessory is ≤ 250 cm3 in three dimensional space.

4.3.13.6. play sound功能

4.3.13.6.1. play sound功能介绍

Note

play sound功能是fmna官方定义的近距离查找功能,SDK中默认打开,当IOS终端靠近findmy设备并且点击findmy app 的播放声音的按键则可以通过ble连接gatt控制触发这种行为,SDK中默认的方案使用GPIO驱动蜂鸣器(有源或无源)来实现响声。

4.3.13.6.2. play sound配置

board_ac6323a_fmy_cfg.h

//*********************************************************************************//
//                                 fmy                                        //
//*********************************************************************************//
#define  SOUND_GPIO_PORT                    IO_PORTA_00
#define  SOUND_PASSIVE_BUZZER               ENABLE_THIS_MOUDLE                      // 是否采用无源蜂鸣器-PWM推声

#if SOUND_PASSIVE_BUZZER
#define DEV_SOUND_PWM_CH                    pwm_ch0                                 //选择PWM输出通道
#endif

其中:

  • SOUND_GPIO_PORT为蜂鸣器驱动GPIO口

  • SOUND_PASSIVE_BUZZER为是否采用无源蜂鸣器发声(用pwm波推声),DISABLE则采用有源蜂鸣器驱动,只是简单的GPIO翻转来驱动发声

4.3.13.6.3. play sound 驱动函数

ble_fmy_fmna.c

#if SOUND_PASSIVE_BUZZER
// 无源蜂鸣器需要交流信号去驱动,用pwm来推信号
struct pwm_platform_data p_buzzer_pwm_data;
static void fmy_sound_passive_buzzer_init(u32 gpio, pwm_ch_num_type pwm_ch)
{
    p_buzzer_pwm_data.pwm_aligned_mode = pwm_edge_aligned;         //边沿对齐
    p_buzzer_pwm_data.frequency = 5000;                            // 5KHz

    p_buzzer_pwm_data.pwm_ch_num = pwm_ch;                        //通道选择
    p_buzzer_pwm_data.duty = 5000;                                 //占空比50%
    // 指定PWM(AC635)硬件管脚的芯片需要注意高低引脚的选择
    p_buzzer_pwm_data.h_pin = -1;                                //没有则填 -1。h_pin_output_ch_num无效,可不配置
    p_buzzer_pwm_data.l_pin = gpio;                               //硬件引脚,l_pin_output_ch_num无效,可不配置
    p_buzzer_pwm_data.complementary_en = 0;                        //两个引脚的波形, 1: 互补, 0: 同步;
    mcpwm_init(&p_buzzer_pwm_data);
}

static void fmy_sound_passive_onoff(pwm_ch_num_type pwm_ch, bool on_off)
{
    // 开关低功耗,pwm模块会在低功耗时被关闭
    fmy_state_idle_set_active(on_off);
    // 开、关pwm输出
    PORT_IO_INIT(SOUND_GPIO_PORT, !on_off)
    mcpwm_ch_open_or_close(pwm_ch, on_off);

}
#endif

static void fmy_sound_timer_control(void)
{
    DEV_SOUND_STATE(__fydata->sound_onoff);
    __fydata->sound_onoff = !__fydata->sound_onoff;
}

Note

用户可以自行修改这部分声音外设逻辑来达到自己的发声效果

4.3.13.7. Motion Detection功能

4.3.13.7.1. Motion Detection功能介绍

Note

由于findmy产品定位为防丢器协议,因此为了如何防止findmy设备被用于恶意跟踪,findmy协议设计了Motion Detection功能,当别人的设备混入您的随身物品时,并跟踪超过一段时间(设备远离拥有者设备时将会处于待机分离状态),此时设备将会开启加速度传感器gsensor检测设备是否移动,当移动时,将会发出响声提醒此时你正在被findmy设备跟踪。JL FINDMY SDK中默认集成了三种加速度传感器来采集加速度数据来完成这个功能。

4.3.13.7.2. gsensor外设配置

Note

默认采用软件IIC的方式驱动加速度传感器来获取加速度数据,可以根据产品外围设计选择io口和gsensor驱动类型,也可以参照原有代码架构自行添加加速度传感器型号并调试功能。

board_ac6323a_fmy_cfg.h

//*********************************************************************************//
//                                 IIC配置                                        //
//*********************************************************************************//
/*软件IIC设置*/
#define TCFG_SW_I2C0_CLK_PORT               IO_PORTB_06                             //软件IIC  CLK脚选择
#define TCFG_SW_I2C0_DAT_PORT               IO_PORTB_07                             //软件IIC  DAT脚选择
#define TCFG_SW_I2C0_DELAY_CNT              50                                      //IIC延时参数,影响通讯时钟频率

//*********************************************************************************//
//                                  g-sensor配置                                   //
//*********************************************************************************//
#define TCFG_GSENSOR_ENABLE                       1     //gSensor使能
// 选择findmy产品使用的加速度传感器,需有且只选一款
#define TCFG_SC7A20_EN                            1
#define TCFG_SC7A20_E_EN                          0
#define TCFG_MSA310_EN                            0

#define GSENSOR_POWER_IO                          IO_PORTA_07 // gsensor是否采用IO口供电,如不采用IO口供电,需注释此宏定义

#define TCFG_GSENOR_USER_IIC_TYPE                 0     //0:软件IIC  1:硬件IIC 目前只适配软件IIC

4.3.13.7.3. gsensor调试功能

以下步骤为为测试gsensor初始化和工作是否正常

打开gsensor相关文件打印

Motion_api.h

- #define GSENSOR_PRINTF_ENABLE             0//contrl debug printf
+ #define GSENSOR_PRINTF_ENABLE             1//contrl debug printf

app_config.h

//debug for test sensor is moving
- #define FMY_DEBUG_TEST_MOTION_DETETION     0
+ #define FMY_DEBUG_TEST_MOTION_DETETION     1

按键测试(短按两下adkey1每10s采集一次gsensor数据进行运动检测,而后再短按两下adkey1关闭gsensor数据采集)。

ble_fmy_fmna.c

    if (event_type == KEY_EVENT_DOUBLE_CLICK) {
        switch (key_value) {
        case TCFG_ADKEY_VALUE0:
#if FMY_DEBUG_TEST_MOTION_DETETION
            if (motion_test_flag) {
                sensor_init();
                motion_test_id = sys_timer_add(NULL, fmy_test_get_send_sensor_data, 10000);
            } else {
                sys_timer_del(motion_test_id);
                motion_test_id = 0;
                sensor_deinit();
            }
            motion_test_flag = !motion_test_flag;
#endif

            break;
        }
    }

Note

如果传感器初始化和采集数据正常,可以尝试移动旋转传感器观察打印信息看是否检测到移动,如未观测到,则需要检测传感器是否工作正常。

4.3.13.8. UARP功能

4.3.13.8.1. UARP简介

Note

UARP协议是apple 私有的固件升级协议,JL FINDMY SDK已经接入了UARP固件升级功能,用户只需要打开配置即可。

4.3.13.8.2. 使用介绍

board_ac6323a_fmy_global_build_cfg.h

- #define CONFIG_DOUBLE_BANK_ENABLE               0       //单双备份选择(若打开了改宏,FLASH结构变为双备份结构,适用于接入第三方协议的OTA, PS: JL-OTA同样支持双备份升级, 需要根据实际FLASH大小同时配置CONFIG_FLASH_SIZE)
- #define CONFIG_APP_OTA_ENABLE                   0       //是否支持RCSP升级(JL-OTA)
- #define CONFIG_DB_UPDATE_DATA_GENERATE_EN       0       //是否生成db_data.bin(用于第三方协议接入使用)
+#define CONFIG_DOUBLE_BANK_ENABLE                1       //单双备份选择(若打开了改宏,FLASH结构变为双备份结构,适用于接入第三方协议的OTA, PS: JL-OTA同样支持双备份升级, 需要根据实际FLASH大小同时配置CONFIG_FLASH_SIZE)
+#define CONFIG_APP_OTA_ENABLE                    1       //是否支持RCSP升级(JL-OTA)
+ #define CONFIG_DB_UPDATE_DATA_GENERATE_EN       1       //是否生成db_data.bin(用于第三方协议接入使用)

这三个宏也对应打开FMY_AccessoryCapabilitiesFMY_CAPABILITY_SUPPORTS_FW_UPDATE_SERVICE的特性

ble_fmy_ota.h

#define FMY_OTA_SUPPORT_CONFIG  (CONFIG_DOUBLE_BANK_ENABLE && CONFIG_APP_OTA_ENABLE && CONFIG_DB_UPDATE_DATA_GENERATE_EN)

ble_fmy.c

//set capability
static const uint8_t FMY_AccessoryCapabilities[4] = {
.....
#if FMY_OTA_SUPPORT_CONFIG
    | FMY_CAPABILITY_SUPPORTS_FW_UPDATE_SERVICE
#endif
.....
};

Note

值得注意的是,打开UARP功能后,编译烧录时可能会提示flash不足的问题,可以尝试关闭一些打印开关后重新调试。(选择512k的flash)

//flash size vaule definition
#define FLASH_SIZE_256K							0x40000
#define FLASH_SIZE_512K							0x80000
#define FLASH_SIZE_1M							0x100000
#define FLASH_SIZE_2M							0x200000
#define FLASH_SIZE_4M							0x400000

#define CONFIG_FLASH_SIZE                       FLASH_SIZE_512K    //配置FLASH大小

//存放token信息
#define CONFIG_FINDMY_INFO_ENABLE      		    1		//配置是否支持FINDMY存储
#if CONFIG_FINDMY_INFO_ENABLE
#if(CONFIG_FLASH_SIZE == FLASH_SIZE_1M)
//INI里面有个规则是VM一定会放到最前面
#define CONFIG_VM_ADDR                          0xFA000 //8K
#define CONFIG_BTIF_ADDR	                    0xFC000 //4k
#define CONFIG_BTIF_LEN		                    0x1000
#define CONFIG_BTIF_OPT		                    1
#define CONFIG_FINDMY_INFO_ADDR	                0xFD000 //config user space
#define CONFIG_FINDMY_INFO_LEN	                0x2000  //need 8K
#define CONFIG_FINDMY_INFO_OPT	                1

#else
#define CONFIG_VM_ADDR                          0x7A000 //8K
#define CONFIG_BTIF_ADDR	                    0x7C000 //4k
#define CONFIG_BTIF_LEN		                    0x1000
#define CONFIG_BTIF_OPT		                    1
#define CONFIG_FINDMY_INFO_ADDR	                0x7D000 //config user space
#define CONFIG_FINDMY_INFO_LEN	                0x2000  //need 8K
#define CONFIG_FINDMY_INFO_OPT	                1

#endif
#endif

app_config.h

#ifdef CONFIG_RELEASE_ENABLE
#define LIB_DEBUG    0
#else
- #define LIB_DEBUG    1
+ #define LIB_DEBUG    0
#endif

log_config.c

const char log_tag_const_v_GATT_COMM AT(.LOG_TAG_CONST) = 0;
const char log_tag_const_i_GATT_COMM AT(.LOG_TAG_CONST) = 0;
const char log_tag_const_d_GATT_COMM AT(.LOG_TAG_CONST) = 0;
const char log_tag_const_w_GATT_COMM AT(.LOG_TAG_CONST) = 0;
const char log_tag_const_e_GATT_COMM AT(.LOG_TAG_CONST) = 1;

const char log_tag_const_v_GATT_SERVER AT(.LOG_TAG_CONST) = 0;
const char log_tag_const_i_GATT_SERVER AT(.LOG_TAG_CONST) = 0;
const char log_tag_const_d_GATT_SERVER AT(.LOG_TAG_CONST) = 0;
const char log_tag_const_w_GATT_SERVER AT(.LOG_TAG_CONST) = 0;
const char log_tag_const_e_GATT_SERVER AT(.LOG_TAG_CONST) = 1;

const char log_tag_const_v_GATT_CLIENT AT(.LOG_TAG_CONST) = 0;
const char log_tag_const_i_GATT_CLIENT AT(.LOG_TAG_CONST) = 0;
const char log_tag_const_d_GATT_CLIENT AT(.LOG_TAG_CONST) = 0;
const char log_tag_const_w_GATT_CLIENT AT(.LOG_TAG_CONST) = 0;
const char log_tag_const_e_GATT_CLIENT AT(.LOG_TAG_CONST) = 0;

4.3.13.8.3. UARP功能使用测试

  • 首先按照快速上手的章节成功完成了findmy的绑定配置并且配置了UARP功能,打印显示UARP功能已开启,完成绑定连接后可以看到固件的版本号

image-20240425141254784

IMG_0046(20240425-135542)

  • 在sdk工程修改ble_fmy_cfg.h文件将默认版本号修改(需要领先于当前版本号)

//===============================================================
//firmware version config
#define  FMY_FW_VERSION_MAJOR_NUMBER                  1
#define  FMY_FW_VERSION_MINOR_NUMBER                  0
#define  FMY_FW_VERSION_REVISION_NUMBER               10
  • 重新编译工程,可以在fw-AC63_BT_SDK-master\cpu\bd19\tools\download\data_trans看到新生成的db_update_data.bin文件,可以使用改文件进行UARP文件的打包

image-20240425142011267

  • 使用U盘将该文件传输到MAC电脑,使用mac电脑上的mfigr2工具生成uarp文件

  • 依次输入下面两条命令,生成完UARPMFiMetaDataTable2文件后修改UARPMFiMetaDataTable2的信息

  • ./mfigr2 superbinary generate mfiMetaData=UARPMFiMetaDataTable2.plist
    ./mfigr2 superbinary generate mfiPlist=MyUARPSuperBinary.plist    
    
    • SuperBinary Firmware Version(对应SDK中的固件版本1.0.10)

    • Payload Filepath(从u盘拷贝过来的杰理bin文件)

    • Payload Version ((对应SDK中的固件版本1.0.10))

verson_change

  • 输入下面命令生成.uarp升级文件,文件名字要对应db_update_bin_v1010.bin

./mfigr2 superbinary compose metaDataFilepath=UARPMFiMetaDataTable2.plist payloadsFilepath=db_update_bin_v1010.bin plistFilepath=MyUARPSuperBinary.plist superBinaryFilepath=test-23-v144.uarp   

uarp_file

Note

在mac电脑生成完UARP文件后将其使用隔空投送发送到iphone上,就使用FMCA软件进行firmware update的测试操作,点击升级即可(偶尔会未有升级可用按键,可以尝试重启手机,重新选择uarp文件,再回到查找app),此时可以看到打印在不断的刷屏打印ota数据说明正在升级中,升级完成后会自动重启!

image-20240425155343409

image-20240425155358456

image-20240425152708384

4.3.13.9. 按键调试

  • 用户可以添加button行为来调试产品的一些按键特性

配置io_key或者ad_key:board_ac6323a_fmy_cfg.h

//*********************************************************************************//
//                                 iokey 配置                                      //
//*********************************************************************************//
#define TCFG_IOKEY_ENABLE                                    DISABLE_THIS_MOUDLE //是否使能IO按键

#define TCFG_IOKEY_POWER_CONNECT_WAY         ONE_PORT_TO_LOW    //按键一端接低电平一端接IO

#define TCFG_IOKEY_POWER_ONE_PORT                    IO_PORTB_01        //IO按键端口

#define TCFG_IOKEY_PREV_CONNECT_WAY                  ONE_PORT_TO_LOW  //按键一端接低电平一端接IO
#define TCFG_IOKEY_PREV_ONE_PORT                     IO_PORTB_00

#define TCFG_IOKEY_NEXT_CONNECT_WAY          ONE_PORT_TO_LOW  //按键一端接低电平一端接IO
#define TCFG_IOKEY_NEXT_ONE_PORT                     IO_PORTB_02

//*********************************************************************************//
//                                 adkey 配置                                      //
//*********************************************************************************//
#define TCFG_ADKEY_ENABLE                   ENABLE_THIS_MOUDLE //是否使能AD按键
#define TCFG_ADKEY_PORT                     IO_PORTA_09 //AD按键端口(需要注意选择的IO口是否支持AD功能)
/*AD通道选择,需要和AD按键的端口相对应:
    AD_CH_PA1    AD_CH_PA3    AD_CH_PA4    AD_CH_PA5
    AD_CH_PA9    AD_CH_PA1    AD_CH_PB1    AD_CH_PB4
    AD_CH_PB6    AD_CH_PB7    AD_CH_DP     AD_CH_DM
    AD_CH_PB2
*/

按键行为控制:ble_fmy_fmna.c

void fmy_ble_key_event_handler(u8 event_type, u8 key_value)
{
    log_info("%s: event= %d,key= %d", __FUNCTION__, event_type, key_value);

    if (event_type == KEY_EVENT_DOUBLE_CLICK) {
        switch (key_value) {
        case TCFG_ADKEY_VALUE0:
#if FMY_DEBUG_TEST_MOTION_DETETION
            if (motion_test_flag) {
                sensor_init();
                motion_test_id = sys_timer_add(NULL, fmy_test_get_send_sensor_data, 10000);
            } else {
                sys_timer_del(motion_test_id);
                motion_test_id = 0;
                sensor_deinit();
            }
            motion_test_flag = !motion_test_flag;
#endif

            break;
        }
    }

    if (event_type == KEY_EVENT_CLICK) {
        switch (key_value) {
        case TCFG_ADKEY_VALUE0:
            log_info(">>>test to enable start pairing adv");
            fmy_pairing_reset_address();
            fmy_pairing_restart_adv();
            break;

        case TCFG_ADKEY_VALUE1:
        case TCFG_ADKEY_VALUE7:
            log_info(">>>test to low battery");
            fmy_test_switch_battery_level(BAT_STATE_CRITICALLY_LOW);
            break;

        case TCFG_ADKEY_VALUE2:
        case TCFG_ADKEY_VALUE8:
            log_info(">>>test to enable serialnumber_lookup read");
            fmna_paired_serialnumber_lookup_enable(1);
            break;

        default:
            break;
        }
    }

    if (event_type == KEY_EVENT_LONG) {
        switch (key_value) {
        case TCFG_ADKEY_VALUE0:
            log_info(">>>test to reset accessory");
            __fy_vm->reset_config = 1;
            fmy_vm_deal(__fy_vm, 1);
            fmna_plaform_reset_config();
            fmy_systerm_reset(30);

            break;

        case TCFG_ADKEY_VALUE1:
        case TCFG_ADKEY_VALUE7:
            log_info(">>>test to full battery");
            fmy_test_switch_battery_level(BAT_STATE_FULL);
            break;

        case TCFG_ADKEY_VALUE2:
        case TCFG_ADKEY_VALUE8:
            log_info(">>>test to disable serialnumber_lookup read");
            fmna_paired_serialnumber_lookup_enable(0);
            break;

        default:
            break;
        }
    }

    if (event_type == KEY_EVENT_CLICK || event_type == KEY_EVENT_LONG) {
#ifdef LED_KEY_GAPIO_PORT
        PORT_IO_OUPUT(LED_KEY_GAPIO_PORT, PORT_VALUE_HIGH);
        sys_timeout_add(0, fmy_led_timeout_handle, 500);
#endif
    }

}

4.3.13.10. findmy电池相关功能

在配对时,IOS主机将会读取配件的产品信息,其中包括此时产品的电量,用户根据产品电池特性来设置电池类型。

fmna_api.h
/*
0 = Powered
1 = Non-rechargeable battery
2 = Rechargeable battery
*/
typedef enum {
    FMNA_BAT_POWERED = 0,
    FMNA_BAT_NON_RECHARGEABLE,
    FMNA_BAT_RECHARGEABLE,
} FMNA_battery_level_t;

使用杰理平台的电量检测来获取产品的电量数据

fmna_api.h

typedef enum {
    BAT_STATE_FULL = 0,
    BAT_STATE_MEDIUM,
    BAT_STATE_LOW,
    BAT_STATE_CRITICALLY_LOW,//5.1.4,stop advertising
} fmna_bat_state_level_t;

ble_fmy.c

static void fmy_update_battery_level(void)
{

#if TCFG_SYS_LVD_EN
    uint8_t  bat_level = get_cur_battery_level();//0~9
    log_info("read vbat:%d\n", bat_level);

    if (bat_level > 8) {
        __fydata->battery_level = BAT_STATE_FULL;
    } else if (bat_level < 2) {
        __fydata->battery_level = BAT_STATE_CRITICALLY_LOW;
    } else if (bat_level < 4) {
        __fydata->battery_level = BAT_STATE_LOW;
    } else {
        __fydata->battery_level = BAT_STATE_MEDIUM;
    }
#else
    __fydata->battery_level = BAT_STATE_FULL;
#endif

    log_info("%s,bat_lev= %d", __FUNCTION__, __fydata->battery_level);
}

4.3.13.11. 常用api介绍

已封装以下控制行为函数,可根据产品特性功能使用

  • 模拟设置配件电量

void fmy_test_switch_battery_level(u8 bat_val);

bat_val – 电池状态值可参考以下结构体

typedef enum {
    BAT_STATE_FULL = 0,
    BAT_STATE_MEDIUM,
    BAT_STATE_LOW,
    BAT_STATE_CRITICALLY_LOW,//5.1.4,stop advertising
} fmna_bat_state_level_t;
  • 获得电池电量状态

static int fmy_get_battery_level(void);
  • 打开/关闭serial number_lookup read

void fmna_paired_serialnumber_lookup_enable(uint8_t enable)

enable:true/false打开或关闭

  • 恢复出厂设置并重启

void fmna_plaform_reset_config(void)
static void fmy_systerm_reset(u32 delay_ticks);
  • 进入软关机

void fmy_power_event_to_user(u8 event);

想要进入软关机可调用:fmy_power_event_to_user(POWER_EVENT_POWER_SOFTOFF);

  • 更换mac地址重新打开广播

static void fmy_pairing_reset_address(void);
static void fmy_pairing_restart_adv(void)

4.3.13.12. 常见问题汇总

  • codeblocks提示tkn文件不存在

image4

Warning

没有把tkn文件放到指定路径,需要向杰理申请tkn授权文件

  • 绑定时显示无法继续

image5

Note

没有使用正确的apple授权信息,或者存储信息错误,需要重新擦写授权信息