11. 运动功能

控制和同步设备的运动状态

11.1. 同步运动状态

//同步状态
//使用场景:1.App连接成功  2.app接收到开始运动命令 3.app主动发送开始运动命令
//WatchManager是WatchOpImpl的子类,须在1.3配置好sdk
WatchManager watchManager = WatchManager.getInstance();
//初始化健康功能实现
HealthOpImpl healthOp = new HealthOpImpl(watchManager);
//执行读取运动信息功能并等待结果回调
healthOp.readSportsInfo(healthOp.getConnectedDevice(), new OnOperationCallback<SportsInfo>() {
    @Override
    public void onSuccess(SportsInfo result) {
        //成功回调
        //result.getMode();//运动类型
        //result.getState(); //运动状态
        //result.getId(); //运动id
        //RcspUtil.intToTime(result.getId()); //运动开始时间
        //result.getReadRealTimeDataInterval(); //同步运动实时数据的时间间隔
        //result.getHeartRateMode();//运动的心率模式
    }

    @Override
    public void onFailed(BaseError error) {
        //失败回调
        //error - 错误信息
    }
});

11.2. 开始运动

//WatchManager是WatchOpImpl的子类,须在1.3配置好sdk
WatchManager watchManager = WatchManager.getInstance();
//初始化健康功能实现
HealthOpImpl healthOp = new HealthOpImpl(watchManager);
//注册RCSP事件监听器
watchManager.registerOnRcspEventListener(new OnRcspEventListener() {
    @Override
    public void onSportsState(BluetoothDevice device, int state) {
        //此处将会回调运动状态变化
        if (state == StateCode.SPORT_STATE_RUNNING) { //正在运动
            //同步设备状态
            healthOp.readSportsInfo(device, null);
        }
    }
});
int mode = SportsInfoStatusSyncCmd.SPORTS_TYPE_OUTDOOR & 0xff; //户外运动模式
//执行开始运动功能并等待结果回调
healthOp.startSports(healthOp.getConnectedDevice(), mode, new OnOperationCallback<Boolean>() {
    @Override
    public void onSuccess(Boolean result) {
        //成功回调
        //结果将会OnRcspEventListener#onSportsState回调
    }

    @Override
    public void onFailed(BaseError error) {
        //失败回调
        //error - 错误信息
    }
});

11.3. 暂停运动

//WatchManager是WatchOpImpl的子类,须在1.3配置好sdk
WatchManager watchManager = WatchManager.getInstance();
//初始化健康功能实现
HealthOpImpl healthOp = new HealthOpImpl(watchManager);
//注册RCSP事件监听器
watchManager.registerOnRcspEventListener(new OnRcspEventListener() {
    @Override
    public void onSportsState(BluetoothDevice device, int state) {
        //此处将会回调运动状态变化
        if (state == StateCode.SPORT_STATE_PAUSE) { //运动暂停
            //更新运动状态
        }
    }
});
//执行暂停运动功能并等待结果回调
healthOp.pauseSports(healthOp.getConnectedDevice(), new OnOperationCallback<Boolean>() {
    @Override
    public void onSuccess(Boolean result) {
        //成功回调
        //结果将会OnRcspEventListener#onSportsState回调
    }

     @Override
    public void onFailed(BaseError error) {
        //失败回调
        //error - 错误信息
    }
});

11.4. 继续运动

//WatchManager是WatchOpImpl的子类,须在1.3配置好sdk
WatchManager watchManager = WatchManager.getInstance();
//初始化健康功能实现
HealthOpImpl healthOp = new HealthOpImpl(watchManager);
//注册RCSP事件监听器
watchManager.registerOnRcspEventListener(new OnRcspEventListener() {
    @Override
    public void onSportsState(BluetoothDevice device, int state) {
        //此处将会回调运动状态变化
        if (state == StateCode.SPORT_STATE_RESUME) {//继续运动
            //同步设备状态
            //healthOp.readSportsInfo(device, null);
        }
    }
});
//执行继续运动功能并等待结果回调
healthOp.resumeSports(healthOp.getConnectedDevice(), new OnOperationCallback<Boolean>() {
    @Override
    public void onSuccess(Boolean result) {
        //成功回调
        //结果将会OnRcspEventListener#onSportsState回调
    }

    @Override
    public void onFailed(BaseError error) {
        //失败回调
        //error - 错误信息
    }
});

11.5. 停止运动

//WatchManager是WatchOpImpl的子类,须在1.3配置好sdk
WatchManager watchManager = WatchManager.getInstance();
//初始化健康功能实现
HealthOpImpl healthOp = new HealthOpImpl(watchManager);
//注册RCSP事件监听器
watchManager.registerOnRcspEventListener(new OnRcspEventListener() {
    @Override
    public void onSportsState(BluetoothDevice device, int state) {
        //此处将会回调运动状态变化
        if (state == StateCode.SPORT_STATE_NONE) { //运动结束
            //处理运动信息
            //1.获取运动信息,有两种方法
            //1) 等待onSportInfoChange回调
            //2) 获取缓存运动信息
//               SportsInfo sportsInfo = watchManager.getDeviceInfo(device).getSportsInfo();
//               sportsInfo.getEndTime(); //结束时间
//               sportsInfo.getRecoveryTime(); //运动恢复时间
//               sportsInfo.getRecordFileId(); //运动记录文件ID
//               sportsInfo.getRecordFileSize(); //运动记录文件大小
//               sportsInfo.getExerciseIntensityState(); //运动强度状态
            //2.获取运动记录文件
//               QueryFileTask.File file = new QueryFileTask.File(QueryFileTask.TYPE_SPORTS_RECORD, sportsInfo.getRecordFileId(), sportsInfo.getRecordFileSize());
//               ReadFileTask.Param param = new ReadFileTask.Param(QueryFileTask.TYPE_SPORTS_RECORD, (short) file.id, file.size, 0);
                //详细参考文件传输功能说明
        }
    }

    @Override
    public void onSportInfoChange(BluetoothDevice device, SportsInfo sportsInfo) {
        //此处将会回调改变的运动信息

    }
});
//执行停止运动功能并等待结果回调
healthOp.stopSports(healthOp.getConnectedDevice(), new OnOperationCallback<Boolean>() {
    @Override
    public void onSuccess(Boolean result) {
        //成功回调
        //结果将会OnRcspEventListener#onSportsState回调
    }

    @Override
    public void onFailed(BaseError error) {
        //失败回调
         //error - 错误信息
    }
});

11.6. 同步实时运动数据

//同步运动实时数据
//WatchManager是WatchOpImpl的子类,须在1.3配置好sdk
WatchManager watchManager = WatchManager.getInstance();
//初始化健康功能实现
HealthOpImpl healthOp = new HealthOpImpl(watchManager);
//执行读取运动实时数据功能并等待结果回调
healthOp.readRealTimeSportsData(healthOp.getConnectedDevice(), new OnOperationCallback<RealTimeSportsData>() {
    @Override
    public void onSuccess(RealTimeSportsData result) {
        if(result == null){
            onFailed(new BaseError(RcspErrorCode.ERR_RESPONSE_BAD_RESULT, "Real time data is null."));
            return;
        }
        //成功回调
//        result.getVersion();        //版本
//        result.getStep();           //运动步数
//        result.getDistance();       //运动距离, 单位:0.01 km
//        result.getDuration();       //运动时长, 单位:秒
//        result.getSpeed();          //速度,单位:km/h
//        result.getPace();           //配速,单位:s/km
//        result.getCalorie();        //热量,单位:kcal
//        result.getStepFreq();       //步频,单位:step/min
//        result.getStride();         //步幅,单位:cm
//        result.getExerciseStatus(); //运动强度状态:最大心率模式={0非运动、1热身、2燃脂、3有氧耐力、4无氧耐力、5极限}<br/>储备心率模式={0非运动、1有氧基础、2有氧进阶、3乳酸阈值、4无氧基础、5无氧进阶}
//        result.getHeartRate();      //实时心率
    }

    @Override
    public void onFailed(BaseError error) {
        //失败回调
        //error - 错误信息
    }
});

11.7. 监听设备的运动状态变化

//监听设备的运动状态变化
//WatchManager是WatchOpImpl的子类,须在1.3配置好sdk
WatchManager watchManager = WatchManager.getInstance();
//注册RCSP事件监听器
watchManager.registerOnRcspEventListener(new OnRcspEventListener() {
    @Override
    public void onSportsState(BluetoothDevice device, int state) {
        //此处回调运动状态
        switch (state) {
            case StateCode.SPORT_STATE_NONE:     //运动结束
                //参考结束运动功能处理
                break;
            case StateCode.SPORT_STATE_RUNNING:  //正在运动
                //参考开始运动功能处理
                break;
            case StateCode.SPORT_STATE_PAUSE:    //运动暂停
                break;
            case StateCode.SPORT_STATE_RESUME:   //继续运动
                break;
        }
    }

    @Override
    public void onSportInfoChange(BluetoothDevice device, SportsInfo sportsInfo) {
        //此处回调运动信息
    }
});

11.8. 读取运动记录文件

//WatchManager是WatchOpImpl的子类,须在1.3配置好sdk
WatchManager watchManager = WatchManager.getInstance();
QueryFileTask.File file; //通过运动结束命令或者查询文件列表获取到
byte type = file.type; //文件类型
short id = file.id; //文件id
int size = file.size; //要读取的内容大小
//注意:如果运动结束返回的file.id和file.size为0,则认为运动距离过短,设备没有保存运动记录
ReadFileTask.Param param = new ReadFileTask.Param(type, id, size, 0);
ReadFileTask task = new ReadFileTask(watchManager, param);
task.setListener(new SimpleTaskListener() {

    @Override
    public void onBegin() {
        //开始
    }

    @Override
    public void onError(int code, String msg) {
        //异常
    }

    @Override
    public void onFinish() {
        //读取完成
        byte [] data =  task.getReadData(); //获取文件内容
        SportRecord sportRecord = SportRecord.from(data);//解析运动数据内容
    }
});
task.start();

11.9. 运动记录文件结构

运功记录文件通过小文件传输方式获取, 注意:运动记录的文件数据是以小端格式存储

偏移

长度

属性名

备注

Byte 0

1

运动模式

运动模式:参考 运动模式

Byte 1

1

版本号

有效范围: 0~255

Byte 2

1

间隔

有效范围: 1~180 , 单位是秒

Byte 3-12

10

保留位

格式如下:
Byte0 : mask — 检查校验位(0xee: 检查位完整 0xe0: 数据被破坏)
Byte1-4 : 数据信息
- Bit0-14 : block — 数据块(代表有多少个数据格式)
- Bit15-31 : size — 文件大小
Byte5-9 : reserved — 保留位

Byte 13-n

n

数据区域

数据格式: [flag(1Byte)+len(1Byte)+data] * n
heart rate: 心率, 有效范围: 0~220
speed: 速度, 有效范围: 0~8000, 单位是0.01公里/小时
pace: 配速, 单位:秒
n : 第n公里
flag: 标志位
- 0: 开始时间包: 参考 时间结构(4Bytes)
- 1: 基础包: heart(1Byte)+step_freq(2Bytes)+speed(2Bytes)
- 2: 暂停包: 参考 时间结构(4Bytes)
- 3: 每公里配速包: pace(2Bytes)+n(1Byte)
- 0xff: 结束包: 参考 时间结构(4Bytes)

Byte(n+1)-(n+2)

2

时长

有效范围: 1-28800, 单位是秒

Byte(n+3)-(n+6)

4

保留位

保留位

Byte(n+7)-(n+8)

2

距离

有效范围: 1-65535, 单位是0.01公里

Byte(n+9)-(n+10)

2

热量

有效范围: 1-65535, 单位是千卡, Kcal

Byte(n+11)-(n+14)

4

步数

有效范围: 0-200000, 单位是步

Byte(n+15)-(n+16)

2

恢复时间

Byte(n+15): 时, 单位是1小时, 有效范围: 0~168
Byte(n+16): 分, 单位是1分钟, 有效范围: 0~60

Byte(n+17)

1

心率模式

0x00: 最大心率模式 0x01: 存储心率模式

Byte(n+18)-(n+38)

20

运动强度状态站比时长

(4Bytes为一组, 从模式1开始), 单位是秒

11.9.1. 运动模式

模式名称

模式值

非运动模式

0x00

室外跑步

0x01

室内跑步

0x02

11.9.2. 时间结构(4Bytes)

意义

位置

Bit31-26

Bit25-22

Bit21-17

Bit16-12

Bit11-6

Bit5-0

长度(bit)

6

4

5

5

6

6

备注

起始时间:2010

1~12

1 ~ 31

0 ~ 24

0 ~ 59

0 ~ 59

举例:
2021-08-02 10:10:10
2E04A28A
00 1011   1000  00010     01010    001010    001010