AndroidのBLEラジコンプロポアプリ「BLEPropo」と接続し、RCサーボとDCモータを制御するプログラムです。 BLE Nanoで動作を確認しています。 BLEPropo → https://github.com/lipoyang/BLEPropo

Dependencies:   BLE_API mbed

BLEを使ったAndroid用ラジコンプロポアプリ「BLEPropo」に対応するBLE Nano用ファームウェアです。
BLEPropoは、GitHubにて公開中。
https://github.com/lipoyang/BLEPropo
/media/uploads/lipoyang/blepropo_ui.png
ラジコンは、mbed HRM1017とRCサーボやDCモータを組み合わせて作ります。
/media/uploads/lipoyang/ministeer3.jpg
回路図
/media/uploads/lipoyang/ministeer3.pdf

Committer:
lipoyang
Date:
Sat Mar 14 12:02:48 2015 +0000
Revision:
5:7f89fca19a9e
-convert nRF51822 library to a folder

Who changed what in which revision?

UserRevisionLine numberNew contents of line
lipoyang 5:7f89fca19a9e 1 /* Copyright (c) 2012 Nordic Semiconductor. All Rights Reserved.
lipoyang 5:7f89fca19a9e 2 *
lipoyang 5:7f89fca19a9e 3 * The information contained herein is property of Nordic Semiconductor ASA.
lipoyang 5:7f89fca19a9e 4 * Terms and conditions of usage are described in detail in NORDIC
lipoyang 5:7f89fca19a9e 5 * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
lipoyang 5:7f89fca19a9e 6 *
lipoyang 5:7f89fca19a9e 7 * Licensees are granted free, non-transferable use of the information. NO
lipoyang 5:7f89fca19a9e 8 * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
lipoyang 5:7f89fca19a9e 9 * the file.
lipoyang 5:7f89fca19a9e 10 *
lipoyang 5:7f89fca19a9e 11 */
lipoyang 5:7f89fca19a9e 12
lipoyang 5:7f89fca19a9e 13 #include "ble_advdata.h"
lipoyang 5:7f89fca19a9e 14 #include "nordic_common.h"
lipoyang 5:7f89fca19a9e 15 #include "nrf_error.h"
lipoyang 5:7f89fca19a9e 16 #include "ble_gap.h"
lipoyang 5:7f89fca19a9e 17 #include "ble_srv_common.h"
lipoyang 5:7f89fca19a9e 18 #include "app_util.h"
lipoyang 5:7f89fca19a9e 19
lipoyang 5:7f89fca19a9e 20
lipoyang 5:7f89fca19a9e 21 // Offset from where advertisement data other than flags information can start.
lipoyang 5:7f89fca19a9e 22 #define ADV_FLAG_OFFSET 2
lipoyang 5:7f89fca19a9e 23
lipoyang 5:7f89fca19a9e 24 // Offset for Advertising Data.
lipoyang 5:7f89fca19a9e 25 // Offset is 2 as each Advertising Data contain 1 octet of Adveritising Data Type and
lipoyang 5:7f89fca19a9e 26 // one octet Advertising Data Length.
lipoyang 5:7f89fca19a9e 27 #define ADV_DATA_OFFSET 2
lipoyang 5:7f89fca19a9e 28
lipoyang 5:7f89fca19a9e 29 // NOTE: For now, Security Manager TK Value and Security Manager Out of Band Flags (OOB) are omitted
lipoyang 5:7f89fca19a9e 30 // from the advertising data.
lipoyang 5:7f89fca19a9e 31
lipoyang 5:7f89fca19a9e 32
lipoyang 5:7f89fca19a9e 33 static uint32_t name_encode(const ble_advdata_t * p_advdata,
lipoyang 5:7f89fca19a9e 34 uint8_t * p_encoded_data,
lipoyang 5:7f89fca19a9e 35 uint8_t * p_len)
lipoyang 5:7f89fca19a9e 36 {
lipoyang 5:7f89fca19a9e 37 uint32_t err_code;
lipoyang 5:7f89fca19a9e 38 uint16_t rem_adv_data_len;
lipoyang 5:7f89fca19a9e 39 uint16_t actual_length;
lipoyang 5:7f89fca19a9e 40 uint8_t adv_data_format;
lipoyang 5:7f89fca19a9e 41 uint8_t adv_offset;
lipoyang 5:7f89fca19a9e 42
lipoyang 5:7f89fca19a9e 43 adv_offset = *p_len;
lipoyang 5:7f89fca19a9e 44
lipoyang 5:7f89fca19a9e 45
lipoyang 5:7f89fca19a9e 46 // Check for buffer overflow.
lipoyang 5:7f89fca19a9e 47 if ((adv_offset + ADV_DATA_OFFSET > BLE_GAP_ADV_MAX_SIZE) ||
lipoyang 5:7f89fca19a9e 48 ((p_advdata->short_name_len + ADV_DATA_OFFSET) > BLE_GAP_ADV_MAX_SIZE))
lipoyang 5:7f89fca19a9e 49 {
lipoyang 5:7f89fca19a9e 50 return NRF_ERROR_DATA_SIZE;
lipoyang 5:7f89fca19a9e 51 }
lipoyang 5:7f89fca19a9e 52 actual_length = rem_adv_data_len = (BLE_GAP_ADV_MAX_SIZE - adv_offset - ADV_FLAG_OFFSET);
lipoyang 5:7f89fca19a9e 53
lipoyang 5:7f89fca19a9e 54 // Get GAP device name and length
lipoyang 5:7f89fca19a9e 55 err_code = sd_ble_gap_device_name_get(&p_encoded_data[adv_offset + ADV_DATA_OFFSET],
lipoyang 5:7f89fca19a9e 56 &actual_length);
lipoyang 5:7f89fca19a9e 57 if (err_code != NRF_SUCCESS)
lipoyang 5:7f89fca19a9e 58 {
lipoyang 5:7f89fca19a9e 59 return err_code;
lipoyang 5:7f89fca19a9e 60 }
lipoyang 5:7f89fca19a9e 61
lipoyang 5:7f89fca19a9e 62 // Check if device internd to use short name and it can fit available data size.
lipoyang 5:7f89fca19a9e 63 if ((p_advdata->name_type == BLE_ADVDATA_FULL_NAME) && (actual_length <= rem_adv_data_len))
lipoyang 5:7f89fca19a9e 64 {
lipoyang 5:7f89fca19a9e 65 // Complete device name can fit, setting Complete Name in Adv Data.
lipoyang 5:7f89fca19a9e 66 adv_data_format = BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME;
lipoyang 5:7f89fca19a9e 67 rem_adv_data_len = actual_length;
lipoyang 5:7f89fca19a9e 68 }
lipoyang 5:7f89fca19a9e 69 else
lipoyang 5:7f89fca19a9e 70 {
lipoyang 5:7f89fca19a9e 71 // Else short name needs to be used. Or application has requested use of short name.
lipoyang 5:7f89fca19a9e 72 adv_data_format = BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME;
lipoyang 5:7f89fca19a9e 73
lipoyang 5:7f89fca19a9e 74 // If application has set a preference on the short name size, it needs to be considered,
lipoyang 5:7f89fca19a9e 75 // else fit what can be fit.
lipoyang 5:7f89fca19a9e 76 if ((p_advdata->short_name_len != 0) && (p_advdata->short_name_len <= rem_adv_data_len))
lipoyang 5:7f89fca19a9e 77 {
lipoyang 5:7f89fca19a9e 78 // Short name fits available size.
lipoyang 5:7f89fca19a9e 79 rem_adv_data_len = p_advdata->short_name_len;
lipoyang 5:7f89fca19a9e 80 }
lipoyang 5:7f89fca19a9e 81 // Else whatever can fit the data buffer will be packed.
lipoyang 5:7f89fca19a9e 82 else
lipoyang 5:7f89fca19a9e 83 {
lipoyang 5:7f89fca19a9e 84 rem_adv_data_len = actual_length;
lipoyang 5:7f89fca19a9e 85 }
lipoyang 5:7f89fca19a9e 86 }
lipoyang 5:7f89fca19a9e 87
lipoyang 5:7f89fca19a9e 88 // Complete name field in encoded data.
lipoyang 5:7f89fca19a9e 89 p_encoded_data[adv_offset++] = rem_adv_data_len + 1;
lipoyang 5:7f89fca19a9e 90 p_encoded_data[adv_offset++] = adv_data_format;
lipoyang 5:7f89fca19a9e 91 (*p_len) += (rem_adv_data_len + ADV_DATA_OFFSET);
lipoyang 5:7f89fca19a9e 92
lipoyang 5:7f89fca19a9e 93 return NRF_SUCCESS;
lipoyang 5:7f89fca19a9e 94 }
lipoyang 5:7f89fca19a9e 95
lipoyang 5:7f89fca19a9e 96
lipoyang 5:7f89fca19a9e 97 static uint32_t appearance_encode(uint8_t * p_encoded_data, uint8_t * p_len)
lipoyang 5:7f89fca19a9e 98 {
lipoyang 5:7f89fca19a9e 99 uint32_t err_code;
lipoyang 5:7f89fca19a9e 100 uint16_t appearance;
lipoyang 5:7f89fca19a9e 101
lipoyang 5:7f89fca19a9e 102 // Check for buffer overflow.
lipoyang 5:7f89fca19a9e 103 if ((*p_len) + 4 > BLE_GAP_ADV_MAX_SIZE)
lipoyang 5:7f89fca19a9e 104 {
lipoyang 5:7f89fca19a9e 105 return NRF_ERROR_DATA_SIZE;
lipoyang 5:7f89fca19a9e 106 }
lipoyang 5:7f89fca19a9e 107
lipoyang 5:7f89fca19a9e 108 // Get GAP appearance field.
lipoyang 5:7f89fca19a9e 109 err_code = sd_ble_gap_appearance_get(&appearance);
lipoyang 5:7f89fca19a9e 110 if (err_code != NRF_SUCCESS)
lipoyang 5:7f89fca19a9e 111 {
lipoyang 5:7f89fca19a9e 112 return err_code;
lipoyang 5:7f89fca19a9e 113 }
lipoyang 5:7f89fca19a9e 114
lipoyang 5:7f89fca19a9e 115 // Encode Length, AD Type and Appearance.
lipoyang 5:7f89fca19a9e 116 p_encoded_data[(*p_len)++] = 3;
lipoyang 5:7f89fca19a9e 117 p_encoded_data[(*p_len)++] = BLE_GAP_AD_TYPE_APPEARANCE;
lipoyang 5:7f89fca19a9e 118
lipoyang 5:7f89fca19a9e 119 (*p_len) += uint16_encode(appearance, &p_encoded_data[*p_len]);
lipoyang 5:7f89fca19a9e 120
lipoyang 5:7f89fca19a9e 121 return NRF_SUCCESS;
lipoyang 5:7f89fca19a9e 122 }
lipoyang 5:7f89fca19a9e 123
lipoyang 5:7f89fca19a9e 124
lipoyang 5:7f89fca19a9e 125 static uint32_t uint8_array_encode(const uint8_array_t * p_uint8_array,
lipoyang 5:7f89fca19a9e 126 uint8_t adv_type,
lipoyang 5:7f89fca19a9e 127 uint8_t * p_encoded_data,
lipoyang 5:7f89fca19a9e 128 uint8_t * p_len)
lipoyang 5:7f89fca19a9e 129 {
lipoyang 5:7f89fca19a9e 130 // Check parameter consistency.
lipoyang 5:7f89fca19a9e 131 if (p_uint8_array->p_data == NULL)
lipoyang 5:7f89fca19a9e 132 {
lipoyang 5:7f89fca19a9e 133 return NRF_ERROR_INVALID_PARAM;
lipoyang 5:7f89fca19a9e 134 }
lipoyang 5:7f89fca19a9e 135
lipoyang 5:7f89fca19a9e 136 // Check for buffer overflow.
lipoyang 5:7f89fca19a9e 137 if ((*p_len) + ADV_DATA_OFFSET + p_uint8_array->size > BLE_GAP_ADV_MAX_SIZE)
lipoyang 5:7f89fca19a9e 138 {
lipoyang 5:7f89fca19a9e 139 return NRF_ERROR_DATA_SIZE;
lipoyang 5:7f89fca19a9e 140 }
lipoyang 5:7f89fca19a9e 141
lipoyang 5:7f89fca19a9e 142 // Encode Length and AD Type.
lipoyang 5:7f89fca19a9e 143 p_encoded_data[(*p_len)++] = 1 + p_uint8_array->size;
lipoyang 5:7f89fca19a9e 144 p_encoded_data[(*p_len)++] = adv_type;
lipoyang 5:7f89fca19a9e 145
lipoyang 5:7f89fca19a9e 146 // Encode array.
lipoyang 5:7f89fca19a9e 147 memcpy(&p_encoded_data[*p_len], p_uint8_array->p_data, p_uint8_array->size);
lipoyang 5:7f89fca19a9e 148 (*p_len) += p_uint8_array->size;
lipoyang 5:7f89fca19a9e 149
lipoyang 5:7f89fca19a9e 150 return NRF_SUCCESS;
lipoyang 5:7f89fca19a9e 151 }
lipoyang 5:7f89fca19a9e 152
lipoyang 5:7f89fca19a9e 153
lipoyang 5:7f89fca19a9e 154 static uint32_t tx_power_level_encode(int8_t tx_power_level,
lipoyang 5:7f89fca19a9e 155 uint8_t * p_encoded_data,
lipoyang 5:7f89fca19a9e 156 uint8_t * p_len)
lipoyang 5:7f89fca19a9e 157 {
lipoyang 5:7f89fca19a9e 158 // Check for buffer overflow.
lipoyang 5:7f89fca19a9e 159 if ((*p_len) + 3 > BLE_GAP_ADV_MAX_SIZE)
lipoyang 5:7f89fca19a9e 160 {
lipoyang 5:7f89fca19a9e 161 return NRF_ERROR_DATA_SIZE;
lipoyang 5:7f89fca19a9e 162 }
lipoyang 5:7f89fca19a9e 163
lipoyang 5:7f89fca19a9e 164 // Encode TX Power Level.
lipoyang 5:7f89fca19a9e 165 p_encoded_data[(*p_len)++] = 2;
lipoyang 5:7f89fca19a9e 166 p_encoded_data[(*p_len)++] = BLE_GAP_AD_TYPE_TX_POWER_LEVEL;
lipoyang 5:7f89fca19a9e 167 p_encoded_data[(*p_len)++] = (uint8_t)tx_power_level;
lipoyang 5:7f89fca19a9e 168
lipoyang 5:7f89fca19a9e 169 return NRF_SUCCESS;
lipoyang 5:7f89fca19a9e 170 }
lipoyang 5:7f89fca19a9e 171
lipoyang 5:7f89fca19a9e 172
lipoyang 5:7f89fca19a9e 173 static uint32_t uuid_list_sized_encode(const ble_advdata_uuid_list_t * p_uuid_list,
lipoyang 5:7f89fca19a9e 174 uint8_t adv_type,
lipoyang 5:7f89fca19a9e 175 uint8_t uuid_size,
lipoyang 5:7f89fca19a9e 176 uint8_t * p_encoded_data,
lipoyang 5:7f89fca19a9e 177 uint8_t * p_len)
lipoyang 5:7f89fca19a9e 178 {
lipoyang 5:7f89fca19a9e 179 int i;
lipoyang 5:7f89fca19a9e 180 bool is_heading_written = false;
lipoyang 5:7f89fca19a9e 181 uint8_t start_pos = *p_len;
lipoyang 5:7f89fca19a9e 182
lipoyang 5:7f89fca19a9e 183 for (i = 0; i < p_uuid_list->uuid_cnt; i++)
lipoyang 5:7f89fca19a9e 184 {
lipoyang 5:7f89fca19a9e 185 uint32_t err_code;
lipoyang 5:7f89fca19a9e 186 uint8_t encoded_size;
lipoyang 5:7f89fca19a9e 187 ble_uuid_t uuid = p_uuid_list->p_uuids[i];
lipoyang 5:7f89fca19a9e 188
lipoyang 5:7f89fca19a9e 189 // Find encoded uuid size.
lipoyang 5:7f89fca19a9e 190 err_code = sd_ble_uuid_encode(&uuid, &encoded_size, NULL);
lipoyang 5:7f89fca19a9e 191 if (err_code != NRF_SUCCESS)
lipoyang 5:7f89fca19a9e 192 {
lipoyang 5:7f89fca19a9e 193 return err_code;
lipoyang 5:7f89fca19a9e 194 }
lipoyang 5:7f89fca19a9e 195
lipoyang 5:7f89fca19a9e 196 // Check size.
lipoyang 5:7f89fca19a9e 197 if (encoded_size == uuid_size)
lipoyang 5:7f89fca19a9e 198 {
lipoyang 5:7f89fca19a9e 199 uint8_t heading_bytes = (is_heading_written) ? 0 : 2;
lipoyang 5:7f89fca19a9e 200
lipoyang 5:7f89fca19a9e 201 // Check for buffer overflow
lipoyang 5:7f89fca19a9e 202 if (*p_len + encoded_size + heading_bytes > BLE_GAP_ADV_MAX_SIZE)
lipoyang 5:7f89fca19a9e 203 {
lipoyang 5:7f89fca19a9e 204 return NRF_ERROR_DATA_SIZE;
lipoyang 5:7f89fca19a9e 205 }
lipoyang 5:7f89fca19a9e 206
lipoyang 5:7f89fca19a9e 207 if (!is_heading_written)
lipoyang 5:7f89fca19a9e 208 {
lipoyang 5:7f89fca19a9e 209 // Write AD structure heading.
lipoyang 5:7f89fca19a9e 210 (*p_len)++;
lipoyang 5:7f89fca19a9e 211 p_encoded_data[(*p_len)++] = adv_type;
lipoyang 5:7f89fca19a9e 212 is_heading_written = true;
lipoyang 5:7f89fca19a9e 213 }
lipoyang 5:7f89fca19a9e 214
lipoyang 5:7f89fca19a9e 215 // Write UUID.
lipoyang 5:7f89fca19a9e 216 err_code = sd_ble_uuid_encode(&uuid, &encoded_size, &p_encoded_data[*p_len]);
lipoyang 5:7f89fca19a9e 217 if (err_code != NRF_SUCCESS)
lipoyang 5:7f89fca19a9e 218 {
lipoyang 5:7f89fca19a9e 219 return err_code;
lipoyang 5:7f89fca19a9e 220 }
lipoyang 5:7f89fca19a9e 221 (*p_len) += encoded_size;
lipoyang 5:7f89fca19a9e 222 }
lipoyang 5:7f89fca19a9e 223 }
lipoyang 5:7f89fca19a9e 224
lipoyang 5:7f89fca19a9e 225 if (is_heading_written)
lipoyang 5:7f89fca19a9e 226 {
lipoyang 5:7f89fca19a9e 227 // Write length.
lipoyang 5:7f89fca19a9e 228 p_encoded_data[start_pos] = (*p_len) - (start_pos + 1);
lipoyang 5:7f89fca19a9e 229 }
lipoyang 5:7f89fca19a9e 230
lipoyang 5:7f89fca19a9e 231 return NRF_SUCCESS;
lipoyang 5:7f89fca19a9e 232 }
lipoyang 5:7f89fca19a9e 233
lipoyang 5:7f89fca19a9e 234
lipoyang 5:7f89fca19a9e 235 static uint32_t uuid_list_encode(const ble_advdata_uuid_list_t * p_uuid_list,
lipoyang 5:7f89fca19a9e 236 uint8_t adv_type_16,
lipoyang 5:7f89fca19a9e 237 uint8_t adv_type_128,
lipoyang 5:7f89fca19a9e 238 uint8_t * p_encoded_data,
lipoyang 5:7f89fca19a9e 239 uint8_t * p_len)
lipoyang 5:7f89fca19a9e 240 {
lipoyang 5:7f89fca19a9e 241 uint32_t err_code;
lipoyang 5:7f89fca19a9e 242
lipoyang 5:7f89fca19a9e 243 // Encode 16 bit UUIDs.
lipoyang 5:7f89fca19a9e 244 err_code = uuid_list_sized_encode(p_uuid_list,
lipoyang 5:7f89fca19a9e 245 adv_type_16,
lipoyang 5:7f89fca19a9e 246 sizeof(uint16_le_t),
lipoyang 5:7f89fca19a9e 247 p_encoded_data,
lipoyang 5:7f89fca19a9e 248 p_len);
lipoyang 5:7f89fca19a9e 249 if (err_code != NRF_SUCCESS)
lipoyang 5:7f89fca19a9e 250 {
lipoyang 5:7f89fca19a9e 251 return err_code;
lipoyang 5:7f89fca19a9e 252 }
lipoyang 5:7f89fca19a9e 253
lipoyang 5:7f89fca19a9e 254 // Encode 128 bit UUIDs.
lipoyang 5:7f89fca19a9e 255 err_code = uuid_list_sized_encode(p_uuid_list,
lipoyang 5:7f89fca19a9e 256 adv_type_128,
lipoyang 5:7f89fca19a9e 257 sizeof(ble_uuid128_t),
lipoyang 5:7f89fca19a9e 258 p_encoded_data,
lipoyang 5:7f89fca19a9e 259 p_len);
lipoyang 5:7f89fca19a9e 260 if (err_code != NRF_SUCCESS)
lipoyang 5:7f89fca19a9e 261 {
lipoyang 5:7f89fca19a9e 262 return err_code;
lipoyang 5:7f89fca19a9e 263 }
lipoyang 5:7f89fca19a9e 264
lipoyang 5:7f89fca19a9e 265 return NRF_SUCCESS;
lipoyang 5:7f89fca19a9e 266 }
lipoyang 5:7f89fca19a9e 267
lipoyang 5:7f89fca19a9e 268
lipoyang 5:7f89fca19a9e 269 static uint32_t conn_int_check(const ble_advdata_conn_int_t *p_conn_int)
lipoyang 5:7f89fca19a9e 270 {
lipoyang 5:7f89fca19a9e 271 // Check Minimum Connection Interval.
lipoyang 5:7f89fca19a9e 272 if ((p_conn_int->min_conn_interval < 0x0006) ||
lipoyang 5:7f89fca19a9e 273 (
lipoyang 5:7f89fca19a9e 274 (p_conn_int->min_conn_interval > 0x0c80) &&
lipoyang 5:7f89fca19a9e 275 (p_conn_int->min_conn_interval != 0xffff)
lipoyang 5:7f89fca19a9e 276 )
lipoyang 5:7f89fca19a9e 277 )
lipoyang 5:7f89fca19a9e 278 {
lipoyang 5:7f89fca19a9e 279 return NRF_ERROR_INVALID_PARAM;
lipoyang 5:7f89fca19a9e 280 }
lipoyang 5:7f89fca19a9e 281
lipoyang 5:7f89fca19a9e 282 // Check Maximum Connection Interval.
lipoyang 5:7f89fca19a9e 283 if ((p_conn_int->max_conn_interval < 0x0006) ||
lipoyang 5:7f89fca19a9e 284 (
lipoyang 5:7f89fca19a9e 285 (p_conn_int->max_conn_interval > 0x0c80) &&
lipoyang 5:7f89fca19a9e 286 (p_conn_int->max_conn_interval != 0xffff)
lipoyang 5:7f89fca19a9e 287 )
lipoyang 5:7f89fca19a9e 288 )
lipoyang 5:7f89fca19a9e 289 {
lipoyang 5:7f89fca19a9e 290 return NRF_ERROR_INVALID_PARAM;
lipoyang 5:7f89fca19a9e 291 }
lipoyang 5:7f89fca19a9e 292
lipoyang 5:7f89fca19a9e 293 // Make sure Minimum Connection Interval is not bigger than Maximum Connection Interval.
lipoyang 5:7f89fca19a9e 294 if ((p_conn_int->min_conn_interval != 0xffff) &&
lipoyang 5:7f89fca19a9e 295 (p_conn_int->max_conn_interval != 0xffff) &&
lipoyang 5:7f89fca19a9e 296 (p_conn_int->min_conn_interval > p_conn_int->max_conn_interval)
lipoyang 5:7f89fca19a9e 297 )
lipoyang 5:7f89fca19a9e 298 {
lipoyang 5:7f89fca19a9e 299 return NRF_ERROR_INVALID_PARAM;
lipoyang 5:7f89fca19a9e 300 }
lipoyang 5:7f89fca19a9e 301
lipoyang 5:7f89fca19a9e 302 return NRF_SUCCESS;
lipoyang 5:7f89fca19a9e 303 }
lipoyang 5:7f89fca19a9e 304
lipoyang 5:7f89fca19a9e 305
lipoyang 5:7f89fca19a9e 306 static uint32_t conn_int_encode(const ble_advdata_conn_int_t * p_conn_int,
lipoyang 5:7f89fca19a9e 307 uint8_t * p_encoded_data,
lipoyang 5:7f89fca19a9e 308 uint8_t * p_len)
lipoyang 5:7f89fca19a9e 309 {
lipoyang 5:7f89fca19a9e 310 uint32_t err_code;
lipoyang 5:7f89fca19a9e 311
lipoyang 5:7f89fca19a9e 312 // Check for buffer overflow.
lipoyang 5:7f89fca19a9e 313 if ((*p_len) + ADV_DATA_OFFSET + 2 * sizeof(uint16_le_t) > BLE_GAP_ADV_MAX_SIZE)
lipoyang 5:7f89fca19a9e 314 {
lipoyang 5:7f89fca19a9e 315 return NRF_ERROR_DATA_SIZE;
lipoyang 5:7f89fca19a9e 316 }
lipoyang 5:7f89fca19a9e 317
lipoyang 5:7f89fca19a9e 318 // Check parameters.
lipoyang 5:7f89fca19a9e 319 err_code = conn_int_check(p_conn_int);
lipoyang 5:7f89fca19a9e 320 if (err_code != NRF_SUCCESS)
lipoyang 5:7f89fca19a9e 321 {
lipoyang 5:7f89fca19a9e 322 return err_code;
lipoyang 5:7f89fca19a9e 323 }
lipoyang 5:7f89fca19a9e 324
lipoyang 5:7f89fca19a9e 325 // Encode Length and AD Type.
lipoyang 5:7f89fca19a9e 326 p_encoded_data[(*p_len)++] = 1 + 2 * sizeof(uint16_le_t);
lipoyang 5:7f89fca19a9e 327 p_encoded_data[(*p_len)++] = BLE_GAP_AD_TYPE_SLAVE_CONNECTION_INTERVAL_RANGE;
lipoyang 5:7f89fca19a9e 328
lipoyang 5:7f89fca19a9e 329 // Encode Minimum and Maximum Connection Intervals.
lipoyang 5:7f89fca19a9e 330 (*p_len) += uint16_encode(p_conn_int->min_conn_interval, &p_encoded_data[*p_len]);
lipoyang 5:7f89fca19a9e 331 (*p_len) += uint16_encode(p_conn_int->max_conn_interval, &p_encoded_data[*p_len]);
lipoyang 5:7f89fca19a9e 332
lipoyang 5:7f89fca19a9e 333 return NRF_SUCCESS;
lipoyang 5:7f89fca19a9e 334 }
lipoyang 5:7f89fca19a9e 335
lipoyang 5:7f89fca19a9e 336
lipoyang 5:7f89fca19a9e 337 static uint32_t manuf_specific_data_encode(const ble_advdata_manuf_data_t * p_manuf_sp_data,
lipoyang 5:7f89fca19a9e 338 uint8_t * p_encoded_data,
lipoyang 5:7f89fca19a9e 339 uint8_t * p_len)
lipoyang 5:7f89fca19a9e 340 {
lipoyang 5:7f89fca19a9e 341 uint8_t data_size = sizeof(uint16_le_t) + p_manuf_sp_data->data.size;
lipoyang 5:7f89fca19a9e 342
lipoyang 5:7f89fca19a9e 343 // Check for buffer overflow.
lipoyang 5:7f89fca19a9e 344 if ((*p_len) + ADV_DATA_OFFSET + data_size > BLE_GAP_ADV_MAX_SIZE)
lipoyang 5:7f89fca19a9e 345 {
lipoyang 5:7f89fca19a9e 346 return NRF_ERROR_DATA_SIZE;
lipoyang 5:7f89fca19a9e 347 }
lipoyang 5:7f89fca19a9e 348
lipoyang 5:7f89fca19a9e 349 // Encode Length and AD Type.
lipoyang 5:7f89fca19a9e 350 p_encoded_data[(*p_len)++] = 1 + data_size;
lipoyang 5:7f89fca19a9e 351 p_encoded_data[(*p_len)++] = BLE_GAP_AD_TYPE_MANUFACTURER_SPECIFIC_DATA;
lipoyang 5:7f89fca19a9e 352
lipoyang 5:7f89fca19a9e 353 // Encode Company Identifier.
lipoyang 5:7f89fca19a9e 354 (*p_len) += uint16_encode(p_manuf_sp_data->company_identifier, &p_encoded_data[*p_len]);
lipoyang 5:7f89fca19a9e 355
lipoyang 5:7f89fca19a9e 356 // Encode additional manufacturer specific data.
lipoyang 5:7f89fca19a9e 357 if (p_manuf_sp_data->data.size > 0)
lipoyang 5:7f89fca19a9e 358 {
lipoyang 5:7f89fca19a9e 359 if (p_manuf_sp_data->data.p_data == NULL)
lipoyang 5:7f89fca19a9e 360 {
lipoyang 5:7f89fca19a9e 361 return NRF_ERROR_INVALID_PARAM;
lipoyang 5:7f89fca19a9e 362 }
lipoyang 5:7f89fca19a9e 363 memcpy(&p_encoded_data[*p_len], p_manuf_sp_data->data.p_data, p_manuf_sp_data->data.size);
lipoyang 5:7f89fca19a9e 364 (*p_len) += p_manuf_sp_data->data.size;
lipoyang 5:7f89fca19a9e 365 }
lipoyang 5:7f89fca19a9e 366
lipoyang 5:7f89fca19a9e 367 return NRF_SUCCESS;
lipoyang 5:7f89fca19a9e 368 }
lipoyang 5:7f89fca19a9e 369
lipoyang 5:7f89fca19a9e 370
lipoyang 5:7f89fca19a9e 371 static uint32_t service_data_encode(const ble_advdata_t * p_advdata,
lipoyang 5:7f89fca19a9e 372 uint8_t * p_encoded_data,
lipoyang 5:7f89fca19a9e 373 uint8_t * p_len)
lipoyang 5:7f89fca19a9e 374 {
lipoyang 5:7f89fca19a9e 375 uint8_t i;
lipoyang 5:7f89fca19a9e 376
lipoyang 5:7f89fca19a9e 377 // Check parameter consistency.
lipoyang 5:7f89fca19a9e 378 if (p_advdata->p_service_data_array == NULL)
lipoyang 5:7f89fca19a9e 379 {
lipoyang 5:7f89fca19a9e 380 return NRF_ERROR_INVALID_PARAM;
lipoyang 5:7f89fca19a9e 381 }
lipoyang 5:7f89fca19a9e 382
lipoyang 5:7f89fca19a9e 383 for (i = 0; i < p_advdata->service_data_count; i++)
lipoyang 5:7f89fca19a9e 384 {
lipoyang 5:7f89fca19a9e 385 ble_advdata_service_data_t * p_service_data;
lipoyang 5:7f89fca19a9e 386 uint8_t data_size;
lipoyang 5:7f89fca19a9e 387
lipoyang 5:7f89fca19a9e 388 p_service_data = &p_advdata->p_service_data_array[i];
lipoyang 5:7f89fca19a9e 389 data_size = sizeof(uint16_le_t) + p_service_data->data.size;
lipoyang 5:7f89fca19a9e 390
lipoyang 5:7f89fca19a9e 391 // Encode Length and AD Type.
lipoyang 5:7f89fca19a9e 392 p_encoded_data[(*p_len)++] = 1 + data_size;
lipoyang 5:7f89fca19a9e 393 p_encoded_data[(*p_len)++] = BLE_GAP_AD_TYPE_SERVICE_DATA;
lipoyang 5:7f89fca19a9e 394
lipoyang 5:7f89fca19a9e 395 // Encode service UUID.
lipoyang 5:7f89fca19a9e 396 (*p_len) += uint16_encode(p_service_data->service_uuid, &p_encoded_data[*p_len]);
lipoyang 5:7f89fca19a9e 397
lipoyang 5:7f89fca19a9e 398 // Encode additional service data.
lipoyang 5:7f89fca19a9e 399 if (p_service_data->data.size > 0)
lipoyang 5:7f89fca19a9e 400 {
lipoyang 5:7f89fca19a9e 401 if (p_service_data->data.p_data == NULL)
lipoyang 5:7f89fca19a9e 402 {
lipoyang 5:7f89fca19a9e 403 return NRF_ERROR_INVALID_PARAM;
lipoyang 5:7f89fca19a9e 404 }
lipoyang 5:7f89fca19a9e 405 memcpy(&p_encoded_data[*p_len], p_service_data->data.p_data, p_service_data->data.size);
lipoyang 5:7f89fca19a9e 406 (*p_len) += p_service_data->data.size;
lipoyang 5:7f89fca19a9e 407 }
lipoyang 5:7f89fca19a9e 408 }
lipoyang 5:7f89fca19a9e 409
lipoyang 5:7f89fca19a9e 410 return NRF_SUCCESS;
lipoyang 5:7f89fca19a9e 411 }
lipoyang 5:7f89fca19a9e 412
lipoyang 5:7f89fca19a9e 413
lipoyang 5:7f89fca19a9e 414 static uint32_t adv_data_encode(const ble_advdata_t * p_advdata,
lipoyang 5:7f89fca19a9e 415 uint8_t * p_encoded_data,
lipoyang 5:7f89fca19a9e 416 uint8_t * p_len)
lipoyang 5:7f89fca19a9e 417 {
lipoyang 5:7f89fca19a9e 418 uint32_t err_code = NRF_SUCCESS;
lipoyang 5:7f89fca19a9e 419
lipoyang 5:7f89fca19a9e 420 *p_len = 0;
lipoyang 5:7f89fca19a9e 421
lipoyang 5:7f89fca19a9e 422 // Encode name.
lipoyang 5:7f89fca19a9e 423 if (p_advdata->name_type != BLE_ADVDATA_NO_NAME)
lipoyang 5:7f89fca19a9e 424 {
lipoyang 5:7f89fca19a9e 425 err_code = name_encode(p_advdata, p_encoded_data, p_len);
lipoyang 5:7f89fca19a9e 426 if (err_code != NRF_SUCCESS)
lipoyang 5:7f89fca19a9e 427 {
lipoyang 5:7f89fca19a9e 428 return err_code;
lipoyang 5:7f89fca19a9e 429 }
lipoyang 5:7f89fca19a9e 430 }
lipoyang 5:7f89fca19a9e 431
lipoyang 5:7f89fca19a9e 432 // Encode appearance.
lipoyang 5:7f89fca19a9e 433 if (p_advdata->include_appearance)
lipoyang 5:7f89fca19a9e 434 {
lipoyang 5:7f89fca19a9e 435 err_code = appearance_encode(p_encoded_data, p_len);
lipoyang 5:7f89fca19a9e 436 if (err_code != NRF_SUCCESS)
lipoyang 5:7f89fca19a9e 437 {
lipoyang 5:7f89fca19a9e 438 return err_code;
lipoyang 5:7f89fca19a9e 439 }
lipoyang 5:7f89fca19a9e 440 }
lipoyang 5:7f89fca19a9e 441
lipoyang 5:7f89fca19a9e 442 // Encode flags.
lipoyang 5:7f89fca19a9e 443 if (p_advdata->flags.size > 0)
lipoyang 5:7f89fca19a9e 444 {
lipoyang 5:7f89fca19a9e 445 err_code = uint8_array_encode(&p_advdata->flags,
lipoyang 5:7f89fca19a9e 446 BLE_GAP_AD_TYPE_FLAGS,
lipoyang 5:7f89fca19a9e 447 p_encoded_data,
lipoyang 5:7f89fca19a9e 448 p_len);
lipoyang 5:7f89fca19a9e 449 if (err_code != NRF_SUCCESS)
lipoyang 5:7f89fca19a9e 450 {
lipoyang 5:7f89fca19a9e 451 return err_code;
lipoyang 5:7f89fca19a9e 452 }
lipoyang 5:7f89fca19a9e 453 }
lipoyang 5:7f89fca19a9e 454
lipoyang 5:7f89fca19a9e 455 // Encode TX power level.
lipoyang 5:7f89fca19a9e 456 if (p_advdata->p_tx_power_level != NULL)
lipoyang 5:7f89fca19a9e 457 {
lipoyang 5:7f89fca19a9e 458 err_code = tx_power_level_encode(*p_advdata->p_tx_power_level, p_encoded_data, p_len);
lipoyang 5:7f89fca19a9e 459 if (err_code != NRF_SUCCESS)
lipoyang 5:7f89fca19a9e 460 {
lipoyang 5:7f89fca19a9e 461 return err_code;
lipoyang 5:7f89fca19a9e 462 }
lipoyang 5:7f89fca19a9e 463 }
lipoyang 5:7f89fca19a9e 464
lipoyang 5:7f89fca19a9e 465 // Encode 'more available' uuid list.
lipoyang 5:7f89fca19a9e 466 if (p_advdata->uuids_more_available.uuid_cnt > 0)
lipoyang 5:7f89fca19a9e 467 {
lipoyang 5:7f89fca19a9e 468 err_code = uuid_list_encode(&p_advdata->uuids_more_available,
lipoyang 5:7f89fca19a9e 469 BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_MORE_AVAILABLE,
lipoyang 5:7f89fca19a9e 470 BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_MORE_AVAILABLE,
lipoyang 5:7f89fca19a9e 471 p_encoded_data,
lipoyang 5:7f89fca19a9e 472 p_len);
lipoyang 5:7f89fca19a9e 473 if (err_code != NRF_SUCCESS)
lipoyang 5:7f89fca19a9e 474 {
lipoyang 5:7f89fca19a9e 475 return err_code;
lipoyang 5:7f89fca19a9e 476 }
lipoyang 5:7f89fca19a9e 477 }
lipoyang 5:7f89fca19a9e 478
lipoyang 5:7f89fca19a9e 479 // Encode 'complete' uuid list.
lipoyang 5:7f89fca19a9e 480 if (p_advdata->uuids_complete.uuid_cnt > 0)
lipoyang 5:7f89fca19a9e 481 {
lipoyang 5:7f89fca19a9e 482 err_code = uuid_list_encode(&p_advdata->uuids_complete,
lipoyang 5:7f89fca19a9e 483 BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_COMPLETE,
lipoyang 5:7f89fca19a9e 484 BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_COMPLETE,
lipoyang 5:7f89fca19a9e 485 p_encoded_data,
lipoyang 5:7f89fca19a9e 486 p_len);
lipoyang 5:7f89fca19a9e 487 if (err_code != NRF_SUCCESS)
lipoyang 5:7f89fca19a9e 488 {
lipoyang 5:7f89fca19a9e 489 return err_code;
lipoyang 5:7f89fca19a9e 490 }
lipoyang 5:7f89fca19a9e 491 }
lipoyang 5:7f89fca19a9e 492
lipoyang 5:7f89fca19a9e 493 // Encode 'solicited service' uuid list.
lipoyang 5:7f89fca19a9e 494 if (p_advdata->uuids_solicited.uuid_cnt > 0)
lipoyang 5:7f89fca19a9e 495 {
lipoyang 5:7f89fca19a9e 496 err_code = uuid_list_encode(&p_advdata->uuids_solicited,
lipoyang 5:7f89fca19a9e 497 BLE_GAP_AD_TYPE_SOLICITED_SERVICE_UUIDS_16BIT,
lipoyang 5:7f89fca19a9e 498 BLE_GAP_AD_TYPE_SOLICITED_SERVICE_UUIDS_128BIT,
lipoyang 5:7f89fca19a9e 499 p_encoded_data,
lipoyang 5:7f89fca19a9e 500 p_len);
lipoyang 5:7f89fca19a9e 501 if (err_code != NRF_SUCCESS)
lipoyang 5:7f89fca19a9e 502 {
lipoyang 5:7f89fca19a9e 503 return err_code;
lipoyang 5:7f89fca19a9e 504 }
lipoyang 5:7f89fca19a9e 505 }
lipoyang 5:7f89fca19a9e 506
lipoyang 5:7f89fca19a9e 507 // Encode Slave Connection Interval Range.
lipoyang 5:7f89fca19a9e 508 if (p_advdata->p_slave_conn_int != NULL)
lipoyang 5:7f89fca19a9e 509 {
lipoyang 5:7f89fca19a9e 510 err_code = conn_int_encode(p_advdata->p_slave_conn_int, p_encoded_data, p_len);
lipoyang 5:7f89fca19a9e 511 if (err_code != NRF_SUCCESS)
lipoyang 5:7f89fca19a9e 512 {
lipoyang 5:7f89fca19a9e 513 return err_code;
lipoyang 5:7f89fca19a9e 514 }
lipoyang 5:7f89fca19a9e 515 }
lipoyang 5:7f89fca19a9e 516
lipoyang 5:7f89fca19a9e 517 // Encode Manufacturer Specific Data.
lipoyang 5:7f89fca19a9e 518 if (p_advdata->p_manuf_specific_data != NULL)
lipoyang 5:7f89fca19a9e 519 {
lipoyang 5:7f89fca19a9e 520 err_code = manuf_specific_data_encode(p_advdata->p_manuf_specific_data,
lipoyang 5:7f89fca19a9e 521 p_encoded_data,
lipoyang 5:7f89fca19a9e 522 p_len);
lipoyang 5:7f89fca19a9e 523 if (err_code != NRF_SUCCESS)
lipoyang 5:7f89fca19a9e 524 {
lipoyang 5:7f89fca19a9e 525 return err_code;
lipoyang 5:7f89fca19a9e 526 }
lipoyang 5:7f89fca19a9e 527 }
lipoyang 5:7f89fca19a9e 528
lipoyang 5:7f89fca19a9e 529 // Encode Service Data.
lipoyang 5:7f89fca19a9e 530 if (p_advdata->service_data_count > 0)
lipoyang 5:7f89fca19a9e 531 {
lipoyang 5:7f89fca19a9e 532 err_code = service_data_encode(p_advdata, p_encoded_data, p_len);
lipoyang 5:7f89fca19a9e 533 if (err_code != NRF_SUCCESS)
lipoyang 5:7f89fca19a9e 534 {
lipoyang 5:7f89fca19a9e 535 return err_code;
lipoyang 5:7f89fca19a9e 536 }
lipoyang 5:7f89fca19a9e 537 }
lipoyang 5:7f89fca19a9e 538
lipoyang 5:7f89fca19a9e 539 return err_code;
lipoyang 5:7f89fca19a9e 540 }
lipoyang 5:7f89fca19a9e 541
lipoyang 5:7f89fca19a9e 542
lipoyang 5:7f89fca19a9e 543 static uint32_t advdata_check(const ble_advdata_t * p_advdata)
lipoyang 5:7f89fca19a9e 544 {
lipoyang 5:7f89fca19a9e 545 // Flags must be included in advertising data, and the BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED flag must be set.
lipoyang 5:7f89fca19a9e 546 if ((p_advdata->flags.size == 0) ||
lipoyang 5:7f89fca19a9e 547 (p_advdata->flags.p_data == NULL) ||
lipoyang 5:7f89fca19a9e 548 ((p_advdata->flags.p_data[0] & BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED) == 0)
lipoyang 5:7f89fca19a9e 549 )
lipoyang 5:7f89fca19a9e 550 {
lipoyang 5:7f89fca19a9e 551 return NRF_ERROR_INVALID_PARAM;
lipoyang 5:7f89fca19a9e 552 }
lipoyang 5:7f89fca19a9e 553
lipoyang 5:7f89fca19a9e 554 return NRF_SUCCESS;
lipoyang 5:7f89fca19a9e 555 }
lipoyang 5:7f89fca19a9e 556
lipoyang 5:7f89fca19a9e 557
lipoyang 5:7f89fca19a9e 558 static uint32_t srdata_check(const ble_advdata_t * p_srdata)
lipoyang 5:7f89fca19a9e 559 {
lipoyang 5:7f89fca19a9e 560 // Flags shall not be included in the scan response data.
lipoyang 5:7f89fca19a9e 561 if (p_srdata->flags.size > 0)
lipoyang 5:7f89fca19a9e 562 {
lipoyang 5:7f89fca19a9e 563 return NRF_ERROR_INVALID_PARAM;
lipoyang 5:7f89fca19a9e 564 }
lipoyang 5:7f89fca19a9e 565
lipoyang 5:7f89fca19a9e 566 return NRF_SUCCESS;
lipoyang 5:7f89fca19a9e 567 }
lipoyang 5:7f89fca19a9e 568
lipoyang 5:7f89fca19a9e 569
lipoyang 5:7f89fca19a9e 570 uint32_t ble_advdata_set(const ble_advdata_t * p_advdata, const ble_advdata_t * p_srdata)
lipoyang 5:7f89fca19a9e 571 {
lipoyang 5:7f89fca19a9e 572 uint32_t err_code;
lipoyang 5:7f89fca19a9e 573 uint8_t len_advdata = 0;
lipoyang 5:7f89fca19a9e 574 uint8_t len_srdata = 0;
lipoyang 5:7f89fca19a9e 575 uint8_t encoded_advdata[BLE_GAP_ADV_MAX_SIZE];
lipoyang 5:7f89fca19a9e 576 uint8_t encoded_srdata[BLE_GAP_ADV_MAX_SIZE];
lipoyang 5:7f89fca19a9e 577 uint8_t * p_encoded_advdata;
lipoyang 5:7f89fca19a9e 578 uint8_t * p_encoded_srdata;
lipoyang 5:7f89fca19a9e 579
lipoyang 5:7f89fca19a9e 580 // Encode advertising data (if supplied).
lipoyang 5:7f89fca19a9e 581 if (p_advdata != NULL)
lipoyang 5:7f89fca19a9e 582 {
lipoyang 5:7f89fca19a9e 583 err_code = advdata_check(p_advdata);
lipoyang 5:7f89fca19a9e 584 if (err_code != NRF_SUCCESS)
lipoyang 5:7f89fca19a9e 585 {
lipoyang 5:7f89fca19a9e 586 return err_code;
lipoyang 5:7f89fca19a9e 587 }
lipoyang 5:7f89fca19a9e 588
lipoyang 5:7f89fca19a9e 589 err_code = adv_data_encode(p_advdata, encoded_advdata, &len_advdata);
lipoyang 5:7f89fca19a9e 590 if (err_code != NRF_SUCCESS)
lipoyang 5:7f89fca19a9e 591 {
lipoyang 5:7f89fca19a9e 592 return err_code;
lipoyang 5:7f89fca19a9e 593 }
lipoyang 5:7f89fca19a9e 594 p_encoded_advdata = encoded_advdata;
lipoyang 5:7f89fca19a9e 595 }
lipoyang 5:7f89fca19a9e 596 else
lipoyang 5:7f89fca19a9e 597 {
lipoyang 5:7f89fca19a9e 598 p_encoded_advdata = NULL;
lipoyang 5:7f89fca19a9e 599 }
lipoyang 5:7f89fca19a9e 600
lipoyang 5:7f89fca19a9e 601 // Encode scan response data (if supplied).
lipoyang 5:7f89fca19a9e 602 if (p_srdata != NULL)
lipoyang 5:7f89fca19a9e 603 {
lipoyang 5:7f89fca19a9e 604 err_code = srdata_check(p_srdata);
lipoyang 5:7f89fca19a9e 605 if (err_code != NRF_SUCCESS)
lipoyang 5:7f89fca19a9e 606 {
lipoyang 5:7f89fca19a9e 607 return err_code;
lipoyang 5:7f89fca19a9e 608 }
lipoyang 5:7f89fca19a9e 609
lipoyang 5:7f89fca19a9e 610 err_code = adv_data_encode(p_srdata, encoded_srdata, &len_srdata);
lipoyang 5:7f89fca19a9e 611 if (err_code != NRF_SUCCESS)
lipoyang 5:7f89fca19a9e 612 {
lipoyang 5:7f89fca19a9e 613 return err_code;
lipoyang 5:7f89fca19a9e 614 }
lipoyang 5:7f89fca19a9e 615 p_encoded_srdata = encoded_srdata;
lipoyang 5:7f89fca19a9e 616 }
lipoyang 5:7f89fca19a9e 617 else
lipoyang 5:7f89fca19a9e 618 {
lipoyang 5:7f89fca19a9e 619 p_encoded_srdata = NULL;
lipoyang 5:7f89fca19a9e 620 }
lipoyang 5:7f89fca19a9e 621
lipoyang 5:7f89fca19a9e 622 // Pass encoded advertising data and/or scan response data to the stack.
lipoyang 5:7f89fca19a9e 623 return sd_ble_gap_adv_data_set(p_encoded_advdata, len_advdata, p_encoded_srdata, len_srdata);
lipoyang 5:7f89fca19a9e 624 }