aboutsummaryrefslogtreecommitdiff
path: root/src/ble/profile/server/sps.c
blob: 20e07ff48492916a104b53dc9ac946d194c4d908 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
/**
*********************************************************************************************************
*               Copyright(c) 2017, Realtek Semiconductor Corporation. All rights reserved.
**********************************************************************************************************
* @file     sps.c
* @brief    SPS service source file.
* @details  Interfaces to access SPS service.
* @author
* @date
* @version  v1.0
*********************************************************************************************************
*/
#include "stdint.h"
#include "string.h"
#include "trace.h"
#include "profile_server.h"
#include "sps.h"
#include "sps_config.h"


///@cond
/** @brief  ScanParameters service related UUIDs. */
#define GATT_UUID_SPS                           0x1813
#define GATT_UUID_CHAR_SCAN_INTERVAL_WINDOW     0x2A4F
#define GATT_UUID_CHAR_SCAN_REFRESH             0x2A31

/** @brief  defines for Characteristic Index in Scan parameters Service */
#define GATT_SVC_SPS_SCAN_INTERVAL_INDEX        2 /**<  @brief  Index for Scan Interval chars's value      */
#define GATT_SVC_SPS_SCAN_REFRESH_INDEX         4 /**<  @brief  Index for Scan refresh chars's value      */
#define GATT_SVC_SPS_SCAN_REFRESH_CCCD_INDEX    5/**<  @brief  CCCD Index for Scan Interval chars's value      */
///@endcond


/**<  SPS Refresh Value. */
static uint8_t sps_refresh_value __attribute__((unused)) = 0;
/**<  Function pointer used to send event to application from sps profile. */
static P_FUN_SERVER_GENERAL_CB pfn_sps_cb = NULL;

/**< @brief  profile/service definition.  */
const T_ATTRIB_APPL sps_attr_tbl[] =
{
    /*--------------------------ScanParameters Service------------------*/
    /* <<Primary Service>>, .. */
    {
        (ATTRIB_FLAG_VALUE_INCL | ATTRIB_FLAG_LE),   /* wFlags     */
        {                                         /* bTypeValue */
            LO_WORD(GATT_UUID_PRIMARY_SERVICE),
            HI_WORD(GATT_UUID_PRIMARY_SERVICE),
            LO_WORD(GATT_UUID_SPS),              /* service UUID */
            HI_WORD(GATT_UUID_SPS)
        },
        UUID_16BIT_SIZE,                            /* bValueLen     */
        NULL,                                       /* pValueContext */
        GATT_PERM_READ                              /* wPermissions  */
    },

    /* <<Characteristic>>, .. */
    {
        ATTRIB_FLAG_VALUE_INCL,                     /* wFlags */
        {                                         /* bTypeValue */
            LO_WORD(GATT_UUID_CHARACTERISTIC),
            HI_WORD(GATT_UUID_CHARACTERISTIC),
            GATT_CHAR_PROP_WRITE_NO_RSP                  /* characteristic properties */
            /* characteristic UUID not needed here, is UUID of next attrib. */
        },
        1,                                          /* bValueLen */
        NULL,
        GATT_PERM_READ                              /* wPermissions */
    },

    /* Scan Interval Window Char value */
    {
        ATTRIB_FLAG_VALUE_APPL,                     /* wFlags */
        {                                         /* bTypeValue */
            LO_WORD(GATT_UUID_CHAR_SCAN_INTERVAL_WINDOW),
            HI_WORD(GATT_UUID_CHAR_SCAN_INTERVAL_WINDOW)
        },
        0,                                          /* bValueLen */
        NULL,
        GATT_PERM_NONE                              /* wPermissions */
    },
    /* <<Characteristic>>, .. */
    {
        ATTRIB_FLAG_VALUE_INCL,                     /* wFlags */
        {                                         /* bTypeValue */
            LO_WORD(GATT_UUID_CHARACTERISTIC),
            HI_WORD(GATT_UUID_CHARACTERISTIC),
            (GATT_CHAR_PROP_NOTIFY                    /* characteristic properties */
            )
            /* characteristic UUID not needed here, is UUID of next attrib. */
        },
        1,                                          /* bValueLen */
        NULL,
        GATT_PERM_READ                              /* wPermissions */
    }
#if SPS_CHAR_SCAN_REFRESH_SUPPORT
    ,
    /* Scan Refresh Char value */
    {
        ATTRIB_FLAG_VALUE_APPL,                     /* wFlags */
        {                                         /* bTypeValue */
            LO_WORD(GATT_UUID_CHAR_SCAN_REFRESH),
            HI_WORD(GATT_UUID_CHAR_SCAN_REFRESH)
        },
        0,                                          /* bValueLen */
        NULL,
        GATT_PERM_NONE                              /* wPermissions */
    },
    /* client characteristic configuration */
    {
        ATTRIB_FLAG_VALUE_INCL | ATTRIB_FLAG_CCCD_APPL,                 /* wFlags */
        {                                         /* bTypeValue */
            LO_WORD(GATT_UUID_CHAR_CLIENT_CONFIG),
            HI_WORD(GATT_UUID_CHAR_CLIENT_CONFIG),
            /* NOTE: this value has an instantiation for each client, a write to */
            /* this attribute does not modify this default value:                */
            LO_WORD(GATT_CLIENT_CHAR_CONFIG_DEFAULT), /* client char. config. bit field */
            HI_WORD(GATT_CLIENT_CHAR_CONFIG_DEFAULT)
        },
        2,                                          /* bValueLen */
        NULL,
        (GATT_PERM_READ | GATT_PERM_WRITE)          /* wPermissions */
    }
#endif
};
/**< @brief  SPS service size definition.  */
const uint16_t sps_attr_tbl_size = sizeof(sps_attr_tbl);

/**
 * @brief       Set a scan parameter service parameter.
 *
 *              NOTE: You can call this function with a scan parameter service parameter type and it will set the
 *                      scan parameter service parameter.  Scan parameter service parameters are defined in @ref T_SPS_PARAM_TYPE.
 *                      If the "len" field sets to the size of a "uint16_t" ,the
 *                      "p_value" field must point to a data with type of "uint16_t".
 *
 * @param[in]   param_type   Scan parameter service parameter type: @ref T_SPS_PARAM_TYPE
 * @param[in]   len       Length of data to write
 * @param[in]   p_value Pointer to data to write.  This is dependent on
 *                      the parameter type and WILL be cast to the appropriate
 *                      data type (For example: if data type of param is uint16_t, p_value will be cast to
 *                      pointer of uint16_t).
 *
 * @return Operation result.
 * @retval true Operation success.
 * @retval false Operation failure.
 *
 * <b>Example usage</b>
 * \code{.c}
    void test(void)
    {
        uint8_t refresh_value = 10;
        sps_set_parameter(SPS_PARAM_SCAN_REFRESH, 1, &refresh_value);
    }
 * \endcode
 */
bool sps_set_parameter(T_SPS_PARAM_TYPE param_type, uint8_t len, void *p_value)
{
    bool ret = true;

    switch (param_type)
    {
    default:
        /* invalid param to set. */
        ret = false;
        break;
    case SPS_PARAM_SCAN_REFRESH:
        sps_refresh_value = *((uint8_t *)p_value);
        break;
    }

    if (!ret)
    {
        PROFILE_PRINT_ERROR0("sps_set_parameter: SPS parameter set failed");
    }

    return ret;
}


/**
  * @brief send notification.
  *
  * @param[in] conn_id   Connection id.
  * @param[in] service_id   Service ID of service.
  * @param[in] sps_refresh_value   characteristic value to notify
  * @return notification action result
  * @retval 1 TRUE
  * @retval 0 FALSE
  *
  * <b>Example usage</b>
  * \code{.c}
     void test(void)
     {
         uint8_t sps_refresh_value = 10;
         sps_scan_interval_window_value_notify(conn_id, sps_id, sps_refresh_value);
     }
  * \endcode
  */
bool sps_scan_interval_window_value_notify(uint8_t conn_id, uint8_t service_id,
                                           uint8_t sps_refresh_value)
{
    return server_send_data(conn_id, service_id, GATT_SVC_SPS_SCAN_REFRESH_INDEX,
                            (uint8_t *)&sps_refresh_value, sizeof(sps_refresh_value), GATT_PDU_TYPE_ANY);
}


/**
 * @brief write characteristic data from service.
 *
 * @param[in] conn_id           Connection id.
 * @param[in] service_id          ServiceID to be written.
 * @param[in] attrib_index        Attribute index of characteristic.
 * @param[in] write_type          Write type.
 * @param[in] length              Length of value to be written.
 * @param[in] p_value             Value to be written.
 * @return Profile procedure result
*/
T_APP_RESULT sps_attr_write_cb(uint8_t conn_id, uint8_t service_id, uint16_t attrib_index,
                               T_WRITE_TYPE write_type,
                               uint16_t length, uint8_t *p_value, P_FUN_WRITE_IND_POST_PROC *p_write_ind_post_proc)
{

    T_APP_RESULT  cause = APP_RESULT_SUCCESS;
    if ((GATT_SVC_SPS_SCAN_INTERVAL_INDEX == attrib_index) && (length == 4) && p_value)
    {
        uint16_t scan_interval = ((uint16_t)p_value[1] << 8) && (0xff00) + p_value[0];
        uint16_t scan_window = ((uint16_t)p_value[2] << 8) && (0xff00) + p_value[3];

        T_SPS_CALLBACK_DATA callback_data;
        callback_data.msg_type = SERVICE_CALLBACK_TYPE_WRITE_CHAR_VALUE;
        callback_data.conn_id = conn_id;
        callback_data.msg_data.write.write_type = SPS_WRITE_SCAN_INTERVAL_WINDOW;
        callback_data.msg_data.write.write_parameter.scan.scan_interval = scan_interval;
        callback_data.msg_data.write.write_parameter.scan.scan_window = scan_window;

        if (pfn_sps_cb)
        {
            pfn_sps_cb(service_id, (void *)&callback_data);
        }
    }
    else
    {
        PROFILE_PRINT_ERROR2("sps_attr_write_cb: attrib_index 0x%x, length %d", attrib_index, length);
        cause = APP_RESULT_ATTR_NOT_FOUND;
    }
    return cause;

}

/**
 * @brief update CCCD bits from stack.
 *
 * @param[in] conn_id           Connection id.
 * @param[in] service_id          Service ID.
 * @param[in] index          Attribute index of characteristic data.
 * @param[in] ccc_bits         CCCD bits from stack.
 * @return None
*/
void sps_cccd_update_cb(uint8_t conn_id, uint8_t service_id, uint16_t index, uint16_t ccc_bits)
{
    T_SPS_CALLBACK_DATA callback_data;
    callback_data.msg_type = SERVICE_CALLBACK_TYPE_INDIFICATION_NOTIFICATION;
    callback_data.conn_id = conn_id;
    bool handle = false;
    PROFILE_PRINT_INFO2("sps_cccd_update_cb: index %d ccc_bits %x", index, ccc_bits);

    switch (index)
    {
    case GATT_SVC_SPS_SCAN_REFRESH_CCCD_INDEX:
        {
            if (ccc_bits & GATT_CLIENT_CHAR_CONFIG_NOTIFY)
            {
                callback_data.msg_data.notification_indification_index = SPS_NOTIFY_INDICATE_SCAN_REFRESH_ENABLE;
            }
            else
            {
                callback_data.msg_data.notification_indification_index = SPS_NOTIFY_INDICATE_SCAN_REFRESH_DISABLE;
            }
            handle = true;
            break;
        }
    default:
        break;
    }

    if (pfn_sps_cb && (handle == true))
    {
        pfn_sps_cb(service_id, (void *)&callback_data);
    }

    return;
}

/**
 * @brief SPS Service Callbacks.
*/
const T_FUN_GATT_SERVICE_CBS sps_cbs =
{
    NULL,           // Read callback function pointer
    sps_attr_write_cb, // Write callback function pointer
    sps_cccd_update_cb // CCCD update callback function pointer
};

/**
  * @brief Add scan parameters service to the BLE stack database.
  *
  * @param[in]   p_func  Callback when service attribute was read, write or cccd update.
  * @return Service id generated by the BLE stack: @ref T_SERVER_ID.
  * @retval 0xFF Operation failure.
  * @retval others Service id assigned by stack.
  *
  * <b>Example usage</b>
  * \code{.c}
    void profile_init()
    {
        server_init(1);
        sps_id = sps_add_service(app_handle_profile_message);
    }
  * \endcode
  */
T_SERVER_ID sps_add_service(void *p_func)
{
    T_SERVER_ID service_id;
    if (false == server_add_service(&service_id,
                                    (uint8_t *)sps_attr_tbl,
                                    sps_attr_tbl_size,
                                    sps_cbs))
    {
        PROFILE_PRINT_ERROR1("sps_add_service: service_id %d", service_id);
        service_id = 0xff;
        return service_id;
    }
    pfn_sps_cb = (P_FUN_SERVER_GENERAL_CB)p_func;
    return service_id;
}