| /* |
| * 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 "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 |
| |
| #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); |
| } |