zephyr/drivers/bluetooth/nble/rpc_serialize.c
Louis Caron beeafae556 Bluetooth: Align the NBLE firmware version and upgrade SD
The latest NBLE firmware includes a new version
exchange mechanism that is independent from the
RPC function definition.  It also allows using
firmwares that are automatically generated by
the official builders without needing a local
build.
The upgrade of the softdevice fixes several
issues in PTS tests.  The major change in
term of API introduced by this upgrade is that
upon write requests, the offset and data of the
write request must be sent back to the softdevice.

Change-Id: Ie574047a09a4e6fdcbf775bc98d8a61f981cee0c
Signed-off-by: Louis Caron <louis.caron@intel.com>
2016-07-14 13:59:39 +00:00

433 lines
10 KiB
C

/*
* Copyright (c) 2016 Intel Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <string.h>
#include <atomic.h>
#include <bluetooth/gatt.h>
#include <bluetooth/conn.h>
#include "rpc.h"
#include "gap_internal.h"
#include "gatt_internal.h"
#include "rpc_functions_to_ble_core.h"
#if !defined(CONFIG_NBLE_DEBUG_RPC)
#undef BT_DBG
#define BT_DBG(fmt, ...)
#endif
/* Build the functions exposed */
/* Define the functions identifiers per signature */
#define FN_SIG_NONE(__fn) fn_index_##__fn,
#define FN_SIG_S(__fn, __s) FN_SIG_NONE(__fn)
#define FN_SIG_P(__fn, __type) FN_SIG_NONE(__fn)
#define FN_SIG_S_B(__fn, __s, __type, __length) FN_SIG_NONE(__fn)
#define FN_SIG_B_B_P(__fn, __type1, __length1, __type2, __length2, __type3) \
FN_SIG_NONE(__fn)
#define FN_SIG_S_P(__fn, __s, __type) FN_SIG_NONE(__fn)
#define FN_SIG_S_B_P(__fn, __s, __type, __length, __type_ptr) \
FN_SIG_NONE(__fn)
#define FN_SIG_S_B_B_P(__fn, __s, __type1, __length1, __type2, __length2, \
__type3) FN_SIG_NONE(__fn)
/* Build the list of function indexes -> this should match the array at
* deserialization
*/
enum { LIST_FN_SIG_NONE fn_none_index_max };
enum { LIST_FN_SIG_S fn_s_index_max };
enum { LIST_FN_SIG_P fn_p_index_max };
enum { LIST_FN_SIG_S_B fn_s_b_index_max };
enum { LIST_FN_SIG_B_B_P fn_b_b_p_index_max };
enum { LIST_FN_SIG_S_P fn_s_p_index_max };
enum { LIST_FN_SIG_S_B_P fn_s_b_p_index_max };
enum { LIST_FN_SIG_S_B_B_P fn_s_b_b_p_index_max };
/* Implement the functions using serialization API */
#undef FN_SIG_NONE
#undef FN_SIG_S
#undef FN_SIG_P
#undef FN_SIG_S_B
#undef FN_SIG_B_B_P
#undef FN_SIG_S_P
#undef FN_SIG_S_B_P
#undef FN_SIG_S_B_B_P
#define FN_SIG_NONE(__fn) \
void __fn(void) \
{ \
rpc_serialize_none(fn_index_##__fn); \
}
#define FN_SIG_S(__fn, __s) \
void __fn(__s p_s) \
{ \
rpc_serialize_s(fn_index_##__fn, p_s, sizeof(*p_s)); \
}
#define FN_SIG_P(__fn, __type) \
void __fn(__type p_priv) \
{ \
rpc_serialize_p(fn_index_##__fn, p_priv); \
}
#define FN_SIG_S_B(__fn, __s, __type, __length) \
void __fn(__s p_s, __type p_buf, __length length) \
{ \
rpc_serialize_s_b(fn_index_##__fn, p_s, sizeof(*p_s), \
p_buf, length); \
}
#define FN_SIG_B_B_P(__fn, __type1, __length1, __type2, __length2, \
__type3) \
void __fn(__type1 p_buf1, __length1 length1, __type2 p_buf2, \
__length2 length2, __type3 p_priv) \
{ \
rpc_serialize_b_b_p(fn_index_##__fn, p_buf1, length1, \
p_buf2, length2, p_priv); \
}
#define FN_SIG_S_P(__fn, __s, __type) \
void __fn(__s p_s, __type p_priv) \
{ \
rpc_serialize_s_p(fn_index_##__fn, p_s, sizeof(*p_s), \
p_priv); \
}
#define FN_SIG_S_B_P(__fn, __s, __type, __length, __type_ptr) \
void __fn(__s p_s, __type p_buf, __length length, \
__type_ptr p_priv) \
{ \
rpc_serialize_s_b_p(fn_index_##__fn, p_s, sizeof(*p_s), \
p_buf, length, p_priv); \
}
#define FN_SIG_S_B_B_P(__fn, __s, __type1, __length1, __type2, \
__length2, __type3) \
void __fn(__s p_s, __type1 p_buf1, __length1 length1, \
__type2 p_buf2, __length2 length2, __type3 p_priv) \
{ \
rpc_serialize_s_b_b_p(fn_index_##__fn, p_s, \
sizeof(*p_s), p_buf1, length1, \
p_buf2, length2, p_priv); \
}
/* Build the functions */
LIST_FN_SIG_NONE
LIST_FN_SIG_S
LIST_FN_SIG_P
LIST_FN_SIG_S_B
LIST_FN_SIG_B_B_P
LIST_FN_SIG_S_P
LIST_FN_SIG_S_B_P
LIST_FN_SIG_S_B_B_P
#undef FN_SIG_NONE
#undef FN_SIG_S
#undef FN_SIG_P
#undef FN_SIG_S_B
#undef FN_SIG_B_B_P
#undef FN_SIG_S_P
#undef FN_SIG_S_B_P
#undef FN_SIG_S_B_B_P
#define DJB2_HASH(__h, __v) ((((__h) << 5) + (__h)) + (__v))
#define FN_SIG_NONE(__fn) \
hash = DJB2_HASH(hash, 1);
#define FN_SIG_S(__fn, __s) \
do { \
hash = DJB2_HASH(hash, 2); \
hash = DJB2_HASH(hash, sizeof(*((__s)0))); \
} while (0);
#define FN_SIG_P(__fn, __type) \
hash = DJB2_HASH(hash, 3);
#define FN_SIG_S_B(__fn, __s, __type, __length) \
do { \
hash = DJB2_HASH(hash, 4); \
hash = DJB2_HASH(hash, sizeof(*((__s)0))); \
} while (0);
#define FN_SIG_B_B_P(__fn, __type1, __length1, __type2, __length2, \
__type3) \
do { \
hash = DJB2_HASH(hash, 5); \
hash = DJB2_HASH(hash, sizeof(*((__s)0))); \
} while (0);
#define FN_SIG_S_P(__fn, __s, __type) \
do { \
hash = DJB2_HASH(hash, 6); \
hash = DJB2_HASH(hash, sizeof(*((__s)0))); \
} while (0);
#define FN_SIG_S_B_P(__fn, __s, __type, __length, __type_ptr) \
do { \
hash = DJB2_HASH(hash, 7); \
hash = DJB2_HASH(hash, sizeof(*((__s)0))); \
} while (0);
#define FN_SIG_S_B_B_P(__fn, __s, __type1, __length1, __type2, \
__length2, __type3) \
do { \
hash = DJB2_HASH(hash, 8); \
hash = DJB2_HASH(hash, sizeof(*((__s)0))); \
} while (0);
uint32_t rpc_serialize_hash(void)
{
uint32_t hash = 5381;
LIST_FN_SIG_NONE;
LIST_FN_SIG_S;
LIST_FN_SIG_P;
LIST_FN_SIG_S_B;
LIST_FN_SIG_B_B_P;
LIST_FN_SIG_S_P;
LIST_FN_SIG_S_B_P;
LIST_FN_SIG_S_B_B_P;
return hash;
}
#define SIG_TYPE_SIZE 1
#define FN_INDEX_SIZE 1
#define POINTER_SIZE 4
static void _send(struct net_buf *buf)
{
rpc_transmit_cb(buf);
}
static uint16_t encoded_structlen(uint8_t structlen)
{
return 1 + structlen;
}
static void serialize_struct(struct net_buf *buf, const uint8_t *struct_data,
uint8_t struct_length)
{
net_buf_add_u8(buf, struct_length);
memcpy(net_buf_add(buf, struct_length), struct_data, struct_length);
}
static uint16_t encoded_buflen(const uint8_t *buf, uint16_t buflen)
{
if (!buf) {
return 1;
}
if (buflen < (1 << 7)) {
return 1 + buflen;
} else {
return 2 + buflen;
}
}
static void serialize_buf(struct net_buf *buf, const uint8_t *data,
uint16_t len)
{
uint16_t varint;
uint8_t *p;
if (!data) {
len = 0;
}
varint = len;
p = net_buf_add_u8(buf, (varint & 0x7f));
if (varint >= (1 << 7)) {
*p |= 0x80;
net_buf_add_u8(buf, (varint >> 7));
}
memcpy(net_buf_add(buf, len), data, len);
}
static void serialize_p(struct net_buf *buf, void *ptr)
{
uintptr_t val = (uintptr_t)ptr;
memcpy(net_buf_add(buf, sizeof(val)), &val, sizeof(val));
}
void rpc_serialize_none(uint8_t fn_index)
{
struct net_buf *buf;
buf = rpc_alloc_cb(SIG_TYPE_SIZE + FN_INDEX_SIZE);
net_buf_add_u8(buf, SIG_TYPE_NONE);
net_buf_add_u8(buf, fn_index);
_send(buf);
}
void rpc_serialize_s(uint8_t fn_index, const void *struct_data,
uint8_t struct_length)
{
struct net_buf *buf;
buf = rpc_alloc_cb(SIG_TYPE_SIZE + FN_INDEX_SIZE +
encoded_structlen(struct_length));
net_buf_add_u8(buf, SIG_TYPE_S);
net_buf_add_u8(buf, fn_index);
serialize_struct(buf, struct_data, struct_length);
_send(buf);
}
void rpc_serialize_p(uint8_t fn_index, void *priv)
{
struct net_buf *buf;
buf = rpc_alloc_cb(SIG_TYPE_SIZE + FN_INDEX_SIZE + POINTER_SIZE);
net_buf_add_u8(buf, SIG_TYPE_P);
net_buf_add_u8(buf, fn_index);
serialize_p(buf, priv);
_send(buf);
}
void rpc_serialize_s_b(uint8_t fn_index, const void *struct_data,
uint8_t struct_length, const void *vbuf,
uint16_t vbuf_length)
{
struct net_buf *buf;
buf = rpc_alloc_cb(SIG_TYPE_SIZE + FN_INDEX_SIZE +
encoded_structlen(struct_length) +
encoded_buflen(vbuf, vbuf_length));
net_buf_add_u8(buf, SIG_TYPE_S_B);
net_buf_add_u8(buf, fn_index);
serialize_struct(buf, struct_data, struct_length);
serialize_buf(buf, vbuf, vbuf_length);
_send(buf);
}
void rpc_serialize_b_b_p(uint8_t fn_index, const void *vbuf1,
uint16_t vbuf1_length, const void *vbuf2,
uint16_t vbuf2_length, void *priv)
{
struct net_buf *buf;
buf = rpc_alloc_cb(SIG_TYPE_SIZE + FN_INDEX_SIZE +
encoded_buflen(vbuf1, vbuf1_length) +
encoded_buflen(vbuf2, vbuf2_length) + POINTER_SIZE);
net_buf_add_u8(buf, SIG_TYPE_B_B_P);
net_buf_add_u8(buf, fn_index);
serialize_buf(buf, vbuf1, vbuf1_length);
serialize_buf(buf, vbuf2, vbuf2_length);
serialize_p(buf, priv);
_send(buf);
}
void rpc_serialize_s_p(uint8_t fn_index, const void *struct_data,
uint8_t struct_length, void *priv)
{
struct net_buf *buf;
buf = rpc_alloc_cb(SIG_TYPE_SIZE + FN_INDEX_SIZE +
encoded_structlen(struct_length) + POINTER_SIZE);
net_buf_add_u8(buf, SIG_TYPE_S_P);
net_buf_add_u8(buf, fn_index);
serialize_struct(buf, struct_data, struct_length);
serialize_p(buf, priv);
_send(buf);
}
void rpc_serialize_s_b_p(uint8_t fn_index, const void *struct_data,
uint8_t struct_length, const void *vbuf,
uint16_t vbuf_length, void *priv)
{
struct net_buf *buf;
buf = rpc_alloc_cb(SIG_TYPE_SIZE + FN_INDEX_SIZE +
encoded_structlen(struct_length) +
encoded_buflen(vbuf, vbuf_length) + POINTER_SIZE);
net_buf_add_u8(buf, SIG_TYPE_S_B_P);
net_buf_add_u8(buf, fn_index);
serialize_struct(buf, struct_data, struct_length);
serialize_buf(buf, vbuf, vbuf_length);
serialize_p(buf, priv);
_send(buf);
}
void rpc_serialize_s_b_b_p(uint8_t fn_index, const void *struct_data,
uint8_t struct_length, const void *vbuf1,
uint16_t vbuf1_length, const void *vbuf2,
uint16_t vbuf2_length, void *priv)
{
struct net_buf *buf;
buf = rpc_alloc_cb(SIG_TYPE_SIZE + FN_INDEX_SIZE +
encoded_structlen(struct_length) +
encoded_buflen(vbuf1, vbuf1_length) +
encoded_buflen(vbuf2, vbuf2_length) + POINTER_SIZE);
net_buf_add_u8(buf, SIG_TYPE_S_B_B_P);
net_buf_add_u8(buf, fn_index);
serialize_struct(buf, struct_data, struct_length);
serialize_buf(buf, vbuf1, vbuf1_length);
serialize_buf(buf, vbuf2, vbuf2_length);
serialize_p(buf, priv);
_send(buf);
}
void rpc_init(uint32_t version)
{
struct net_buf *buf;
struct {
uint32_t version;
uint32_t ser_hash;
uint32_t des_hash;
} struct_data;
struct_data.version = version;
struct_data.ser_hash = rpc_serialize_hash();
struct_data.des_hash = rpc_deserialize_hash();
buf = rpc_alloc_cb(SIG_TYPE_SIZE + FN_INDEX_SIZE +
encoded_structlen(sizeof(struct_data)));
net_buf_add_u8(buf, SIG_TYPE_CONTROL);
net_buf_add_u8(buf, 0);
serialize_struct(buf, (uint8_t *)&struct_data, sizeof(struct_data));
_send(buf);
}