2.4. 消息格式

消息格式使用 Google's Protocol Buffers 来编解码。 网关端可以选择任意语言版本,手环使用的是 Nanopb 实现。

2.4.1. 数据结构定义文件

数据格式定义如下(仅有此一个文件):

syntax = "proto3";

/*
 *******************************************************************************
 * Status
 *******************************************************************************
 */

message Status {
  message Request {}
  message Response {
    // 手环的本地时间戳,如果和网关的差别过大,网关可以通过设置更新手环的时间戳。
    // 手环第一次上电时的时间戳从0开始计时
    uint32 localTimestampInSecond = 1;
    // Major.Minor.Patch+X
    uint32 softwareVersion = 2;
    uint32 hardwareVersion = 3;
    bool heartRateHasNewData = 4;
    bool accHasNewData = 5;
    bool temperatureHasNewData = 6;
    bool beaconHasNewData = 7;
  }
}

/*
 *******************************************************************************
 * Settings
 *******************************************************************************
 */

message AdvertisementSettings {
  // 以分钟为单位的最小广播时间阈值
  uint32 miniReportThresholdInMinute = 1;
}

message BeaconScanSettings {
  // BLE 扫描周期。合法范围[4,16384],单位625us。
  uint32 bleInterval = 1;
  // 每个bleInterval周期内的持续扫描时间。合法范围[4,16384],单位625us,必须小于等于bleInterval。
  uint32 bleWindow = 2;
  // 一次 BLE 扫描的持续时间。单位10ms。必须大于0。
  uint32 bleDuration = 3;
  // 多久触发一次扫描Beacon。
  uint32 intervalInSecond = 4;
  // 待扫描的Beacon名字
  string beaconName = 5;
}

message SleepCommand {
  // 睡眠或唤醒事件的时间点
  uint32 timeStampInSecond = 1;
  // 1: 睡眠事件
  // 0: 唤醒事件
  bool sleep = 2;
}

message SleepSettings {
  // 1: 添加睡眠唤醒事件
  // 0: 覆盖之前设置的睡眠唤醒事件
  bool append = 1;
  //  一系列的睡眠唤醒命令。建议一次发送不要超过10条。
  repeated SleepCommand sleepCommands = 2;
}

enum SettingErrorCode {
  SE_SUCCESS = 0;
  SE_INVALID_PARAMETER = 1;
}

enum EraseOptions{
  EO_ALL = 0;
  EO_SETTINGS = 1;
  EO_PERSONAL = 2;
  EO_REBOOT = 3;
}


message AccSettings {
  // 单位是 1/512g。 1g=9.8m/s2
  uint32 threshold = 1;
}

enum LogLevel {
  LL_INFO = 0;
  LL_WARN = 1;
  LL_DEBUG = 2;
  LL_ERROR = 3;
  LL_FATAL = 4;
}

message LogSettings {
  //默认等级是 LL_FATAL,也就是所有log都会被记录
  LogLevel level = 1;
  //默认是false,即串口不会打印log
  bool uartOutput = 2;
  //默认是true,即log会被存储到flash
  bool flashStore = 3;
}

message Settings {
  message Request {
    optional uint32 newTimestamp = 1;
    optional AdvertisementSettings advSettings = 2;
    optional BeaconScanSettings beaconScanSettings = 3;
    optional SleepSettings sleepSettings = 4;
    optional EraseOptions erase = 5;
    optional AccSettings accSettings = 6;
    optional LogSettings logSettings = 7;
  }
  message Response {
    SettingErrorCode errorCode = 1;
  }

}

/*
 *******************************************************************************
 * Report
 *******************************************************************************
 */

enum ReportType{
  RT_HEART = 0;
  RT_ACC = 1;
  RT_BEACON = 2;
  RT_TEMPERATURE = 3;
  // 如果类型是Log,那么 startTimestamp 和 endTimestamp 会被忽略。
  RT_LOG = 4;
}

// 此命令格式待定,可能会修改。
message Report {
  message Request {
    uint32 startTimestamp = 1;
    uint32 endTimestamp = 2;
    ReportType reportType = 3;
  }
  message Response {
    uint32 index = 1;
    bytes data = 2;
  }
}

/*
 *******************************************************************************
 * Factory Test
 *******************************************************************************
 */

enum FactoryTestType {
  FT_NFC = 0;
  FT_ACC = 1;
  FT_FLASH = 2;
  FT_TEMPERATURE = 3;
  FT_HEART_NO_COVER = 4;
  FT_HEART_COVER = 5;
}

message FactoryTest{
  message Request{
    FactoryTestType testType = 1;
  }
  message Response {
    bool success = 1;
  }
}

/*
 *******************************************************************************
 * Request
 *******************************************************************************
 */

// 网关发送给手环的数据格式
message CougarRequest {
  oneof message {
    Status.Request status = 1;
    Settings.Request settings = 2;
    Report.Request report = 3;
  }
}

/*
 *******************************************************************************
 * Response
 *******************************************************************************
 */

// 手环返回的数据格式
message CougarResponse {
  oneof message {
    Status.Response status = 1;
    Settings.Response settings = 2;
    Report.Response report = 3;
  }
}

2.4.2. 数据封包

数据包直接使用编码之后的Request或者Respone。

手环会自动修改MTU到最大值,而且保证一个数据包仅包含一个完整的Response。网关的Request也必须在一个MTU内发完,不可以拆包。

2.4.3. 最外层格式

最外层的数据结构有两个

  • message CougarRequest {} 网关端发送

  • message CougarResponse {} 手环端返回

2.4.4. 内层格式

对于 CougarRequestCougarResponse ,均有三种内层格式。

  • 状态格式 (Status),定义在 message Status {} 中。

  • 设置格式 (Settings),定义在 message Settings {} 中。

  • 报告格式 (Report), 定义在 message Report {} 中。