| #include <stdlib.h> |
| #include <string.h> |
| #include "aapiGattServer.h" |
| #include "gatt-builtin.h" |
| #include "aapiGatt.h" |
| #include "gatt.h" |
| #include "log.h" |
| #include "bt.h" |
| #include "mt.h" |
| |
| |
| /* this grouping is not part of the GATT spec and its semantics are thus unclear. */ |
| |
| struct aapiGattServerService { |
| int gattSvc; |
| uint8_t inst; |
| }; |
| |
| struct aapiGattServer { |
| struct aapiGattServer *next; |
| struct aapiGattServer *prev; |
| bt_uuid_t andrUuid; |
| int refNum; |
| uint32_t numServices; |
| struct aapiGattServerService *services; |
| }; |
| |
| |
| |
| |
| |
| |
| /* our state */ |
| static btgatt_server_callbacks_t mCbks; |
| |
| static pthread_mutex_t mAapiGattSrvLock = PTHREAD_MUTEX_INITIALIZER; |
| static struct aapiGattServer *mServers; |
| static bool mInited = false; |
| |
| |
| |
| /* |
| * FUNCTION: aapiGattServerFindStructByRef |
| * USE: Find a aapiGattServer struct by reference number |
| * PARAMS: ref - the reference |
| * RETURN: the aapiGattServer struct or NULL if not found |
| * NOTES: call with mAapiGattSrvLock held |
| */ |
| static struct aapiGattServer* aapiGattServerFindStructByRef(int ref) |
| { |
| struct aapiGattServer *ret = mServers; |
| |
| while (ret && ret->refNum != ref) |
| ret = ret->next; |
| |
| return ret; |
| } |
| |
| /* |
| * FUNCTION: aapiGattServerFindStructByUuid |
| * USE: Find a aapiGattServer struct by android-style uuid |
| * PARAMS: andrUuid - the uuid |
| * RETURN: the aapiGattServer struct or NULL if not found |
| * NOTES: call with mAapiGattSrvLock held |
| */ |
| static struct aapiGattServer* aapiGattServerFindStructByUuid(const bt_uuid_t *andrUuid) |
| { |
| struct aapiGattServer *ret = mServers; |
| |
| while (ret && memcmp(&ret->andrUuid, andrUuid, sizeof(ret->andrUuid))) |
| ret = ret->next; |
| |
| return ret; |
| } |
| |
| /* |
| * FUNCTION: aapiGattServerContainsServiceWithUuid |
| * USE: See if a aapiGattServer contains a service with a given UUID |
| * PARAMS: srv - the aapiGattServer |
| * uuid - the uuid in question |
| * instIdP - if non-null, instance Id will be stored here |
| * RETURN: true if found, false else |
| * NOTES: call with mAapiGattSrvLock held |
| */ |
| static bool aapiGattServerContainsServiceWithUuid(const struct aapiGattServer *srv, const struct uuid *uuid, uint8_t *instIdP) |
| { |
| struct uuid localUuid; |
| uint32_t i; |
| |
| for (i = 0; i < srv->numServices; i++) { |
| if (gattServiceGetUuid(srv->services[i].gattSvc, &localUuid)) |
| loge("Failed to get uuid. This is not possible\n"); |
| else if (uuidCmp(&localUuid, uuid)) { |
| if (instIdP) |
| *instIdP = srv->services[i].inst; |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| /* |
| * FUNCTION: aapiGattServerRegisterServer |
| * USE: Registers a GATT server application with the stack |
| * PARAMS: uuid - the uuid |
| * RETURN: status |
| * NOTES: also calls callback with result if successful result here |
| */ |
| static bt_status_t aapiGattServerRegisterServer(bt_uuid_t *andrUuid) |
| { |
| bt_status_t ret = BT_STATUS_FAIL; |
| int ref = 0; |
| |
| pthread_mutex_lock(&mAapiGattSrvLock); |
| if (aapiGattServerFindStructByUuid(andrUuid)) |
| loge("Refusing to create identical GATT server\n"); |
| else { |
| struct aapiGattServer *srv = (struct aapiGattServer*)calloc(1, sizeof(struct aapiGattServer)); |
| if (!srv) { |
| loge("Failed to allocate GATT server\n"); |
| ret = BT_STATUS_NOMEM; |
| } else { |
| |
| /* grab a free reference number */ |
| srv->refNum = mServers ? (mServers->refNum + 1) : 1; |
| while (aapiGattServerFindStructByRef(srv->refNum)) |
| srv->refNum++; |
| |
| /* link it in */ |
| srv->next = mServers; |
| if (mServers) |
| mServers->prev = srv; |
| mServers = srv; |
| |
| /* save uuid */ |
| memcpy(&srv->andrUuid, andrUuid, sizeof(srv->andrUuid)); |
| |
| /* prepare to announce success */ |
| ret = BT_STATUS_SUCCESS; |
| ref = srv->refNum; |
| } |
| } |
| pthread_mutex_unlock(&mAapiGattSrvLock); |
| |
| mCbks.register_server_cb(ret, ref, andrUuid); |
| return ret; |
| } |
| |
| /* |
| * FUNCTION: aapiGattServerUnregisterServer |
| * USE: Unregister a server application from the stack |
| * PARAMS: server_if - the server's reference number |
| * RETURN: status |
| * NOTES: also calls callback with result if successful result here |
| */ |
| static bt_status_t aapiGattServerUnregisterServer(int server_if) |
| { |
| bt_status_t ret = BT_STATUS_FAIL; |
| struct aapiGattServer *srv; |
| |
| pthread_mutex_lock(&mAapiGattSrvLock); |
| srv = aapiGattServerFindStructByRef(server_if); |
| if (!srv) |
| logw("Server not found while attempting to unregister\n"); |
| else { |
| uint32_t i; |
| |
| if (srv->next) |
| srv->next->prev = srv->prev; |
| if (srv->prev) |
| srv->prev->next = srv->next; |
| else |
| mServers = srv->next; |
| |
| for (i = 0; i < srv->numServices; i++) { |
| if (gattServiceIsRunning(srv->services[i].gattSvc)) { |
| logw("Unregistering server with running services!\n"); |
| gattServiceStop(srv->services[i].gattSvc); |
| } |
| gattServiceDestroy(srv->services[i].gattSvc); |
| } |
| if (srv->services) |
| free(srv->services); |
| free(srv); |
| ret = BT_STATUS_SUCCESS; |
| } |
| pthread_mutex_unlock(&mAapiGattSrvLock); |
| |
| return ret; |
| } |
| |
| /* |
| * FUNCTION: aapiGattServerConnect |
| * USE: Create a connection to a remote peripheral |
| * PARAMS: server_if - the server's reference number |
| * bd_addr - remote address |
| * is_direct - XXX: TODO: WTF?? |
| * transport - (BT_TRANSPORT_*) |
| * RETURN: status |
| * NOTES: also calls callback with result if successful result here |
| */ |
| static bt_status_t aapiGattServerConnect(int server_if, const bt_bdaddr_t *bd_addr, bool is_direct, int transport) |
| { |
| //TODO |
| |
| return BT_STATUS_FAIL; |
| } |
| |
| /* |
| * FUNCTION: aapiGattServerDisconnect |
| * USE: Disconnect an established connection or cancel a pending one |
| * PARAMS: server_if - the server's reference number |
| * bd_addr - remote address |
| * conn_id - connection reference number |
| * RETURN: status |
| * NOTES: also calls callback with result if successful result here |
| */ |
| static bt_status_t aapiGattServerDisconnect(int server_if, const bt_bdaddr_t *bd_addr, int conn_id) |
| { |
| //TODO |
| |
| return BT_STATUS_FAIL; |
| } |
| |
| /* |
| * FUNCTION: aapiGattServerReadF |
| * USE: GATT's callback for reading |
| * PARAMS: svc - service ref |
| * who - connection to whom this pertains to |
| * cid - ATT's connection ID |
| * transId - ATT's transaction ID |
| * handle - the handle that this pertains to |
| * byteOfst - the offset into the characteristic for the read (in bytes) |
| * reason - reason for the write (ATT_READ_FOR_*) |
| * wantedLen - the length to write |
| * RETURN: NONE |
| * NOTES: call gattSrvCbkReply() with results. returning false will send ATT_ERROR_UNLIKELY_ERROR to the client |
| */ |
| static bool aapiGattServerReadF(int svc, l2c_handle_t who, int cid, int transId, uint16_t handle, uint16_t byteOfst, uint8_t reason, uint16_t len) |
| { |
| struct bt_addr peer; |
| bt_bdaddr_t andrPeerAddr; |
| |
| if (!l2cApiGetBtAddr(who, &peer)) { |
| loge("Failed to get peer addr for read cbk\n"); |
| return false; |
| } |
| |
| memcpy(andrPeerAddr.address, peer.addr, sizeof(andrPeerAddr.address)); |
| mCbks.request_read_cb(cid, transId, &andrPeerAddr, handle, byteOfst, reason == ATT_READ_FOR_READ_BLOB); |
| |
| return true; |
| } |
| |
| /* |
| * FUNCTION: aapiGattServerWriteF |
| * USE: GATT's callback for writing |
| * PARAMS: svc - service ref |
| * who - connection to whom this pertains to |
| * cid - ATT's connection ID |
| * transId - ATT's transaction ID |
| * handle - the handle that this pertains to |
| * byteOfst - the offset into the characteristic for the write (in bytes) |
| * reason - reason for the write (ATT_WRITE_FOR_*) |
| * len - the length to write |
| * data - the data to write |
| * RETURN: NONE |
| * NOTES: call gattSrvCbkReply() with results. returning false will send ATT_ERROR_UNLIKELY_ERROR to the client |
| */ |
| static bool aapiGattServerWriteF(int svc, l2c_handle_t who, int cid, int transId, uint16_t handle, uint16_t byteOfst, uint8_t reason, uint16_t len, const void *data) |
| { |
| struct bt_addr peer; |
| bt_bdaddr_t andrPeerAddr; |
| |
| if (!l2cApiGetBtAddr(who, &peer)) { |
| loge("Failed to get peer addr for write cbk\n"); |
| return false; |
| } |
| |
| mCbks.request_write_cb(cid, transId, &andrPeerAddr, handle, byteOfst, len, true, reason == ATT_WRITE_FOR_PREPARE, (uint8_t*)data); |
| return true; |
| } |
| |
| /* |
| * FUNCTION: aapiGattServerIndF |
| * USE: GATT's callback for indication/notification progress |
| * PARAMS: svc - service ref |
| * who - connection to whom this pertains to |
| * cid - ATT's connection ID |
| * handle - the handle that this pertains to |
| * evt - what happened (GATT_SRV_EVT_*) |
| * ref - value originally passed to gattServiceSendInd() |
| * RETURN: NONE |
| * NOTES: |
| */ |
| static void aapiGattServerIndF(int svc, l2c_handle_t who, int cid, uint16_t handle, uint8_t evt, uint64_t ref) |
| { |
| /* XXX: tell java somehow? Current api has no way it seems */ |
| } |
| |
| /* |
| * FUNCTION: aapiGattServerAddService |
| * USE: Create a new service |
| * PARAMS: server_if - the server's reference number |
| * srvc_id - service identifying information |
| * num_handles - how many handles to allocate |
| * RETURN: status |
| * NOTES: also calls callback with result if successful result here |
| */ |
| static bt_status_t aapiGattServerAddService(int server_if, btgatt_srvc_id_t *srvc_id, int num_handles) |
| { |
| bt_status_t ret = BT_STATUS_FAIL; |
| struct aapiGattServer *srv; |
| uint16_t handle = 0; |
| |
| pthread_mutex_lock(&mAapiGattSrvLock); |
| srv = aapiGattServerFindStructByRef(server_if); |
| if (!srv) |
| logw("Server not found while attempting to add service\n"); |
| else { |
| struct aapiGattServerService *svcs; |
| struct uuid uuid; |
| int svc; |
| |
| svcs = realloc(srv->services, sizeof(struct aapiGattServerService[srv->numServices + 1])); |
| if (!svcs) |
| logw("Failed to make space for the service\n"); |
| else { |
| srv->services = svcs; |
| |
| aapiGattUuidFromAndroidUuid(&uuid, &srvc_id->id.uuid); |
| svc = gattServiceCreate(&uuid, srvc_id->is_primary, num_handles, aapiGattServerReadF, aapiGattServerWriteF, aapiGattServerIndF); |
| if (!svc) |
| logw("Failed to create GATT service\n"); |
| else { |
| srv->services[srv->numServices].gattSvc = svc; |
| srv->services[srv->numServices].inst = srvc_id->id.inst_id; |
| srv->numServices++; |
| handle = gattServiceGetHandleBaseBySvc(svc); |
| ret = BT_STATUS_SUCCESS; |
| } |
| } |
| } |
| pthread_mutex_unlock(&mAapiGattSrvLock); |
| |
| mCbks.service_added_cb(ret, server_if, srvc_id, handle); |
| return ret; |
| } |
| |
| /* |
| * FUNCTION: aapiGattServerFindService |
| * USE: Find a server and a service given their externally-visible reference numbers |
| * PARAMS: server_if - the server's reference number |
| * service_handle - the handle of the service |
| * srvP - if not NULL, we store the struct aapiGattServer* there |
| * svc - if not NULL, we store the service reference number there |
| * svcIdxInTableP - if not NULL, we store service's index in the server's "services" table |
| * firstOnly - if set handle is service_handle, else it is any handle in the range |
| * RETURN: true if all were found |
| * NOTES: call with mAapiGattSrvLock held |
| */ |
| static bool aapiGattServerFindService(int server_if, int handle, struct aapiGattServer **srvP, int *svcP, uint32_t *svcIdxInTableP, bool firstOnly) |
| { |
| struct aapiGattServer *srv; |
| uint32_t i; |
| int svc; |
| |
| srv = aapiGattServerFindStructByRef(server_if); |
| if (!srv) |
| return false; |
| |
| svc = gattServiceFindByHandle(handle, firstOnly); |
| if (svc < 0) |
| return false; |
| |
| /* verify proper belonging */ |
| for (i = 0; i < srv->numServices; i++) |
| if (srv->services[i].gattSvc == svc) |
| break; |
| |
| if (i == srv->numServices) { |
| logw("Found service not aprt of found server!\n"); |
| return false; |
| } |
| |
| if (srvP) |
| *srvP = srv; |
| |
| if (svcP) |
| *svcP = svc; |
| |
| if (svcIdxInTableP) |
| *svcIdxInTableP = i; |
| |
| return true; |
| } |
| |
| /* |
| * FUNCTION: aapiGattServerAddIncludedService |
| * USE: Assign an included service to it's parent service |
| * PARAMS: server_if - the server's reference number |
| * service_handle - the handle of the current service |
| * included_handle - the handle of the included service |
| * RETURN: status |
| * NOTES: also calls callback with result if successful result here |
| */ |
| static bt_status_t aapiGattServerAddIncludedService(int server_if, int service_handle, int included_handle) |
| { |
| bt_status_t ret = BT_STATUS_FAIL; |
| struct aapiGattServer *srv; |
| uint16_t handle = 0; |
| int svc; |
| |
| pthread_mutex_lock(&mAapiGattSrvLock); |
| if (!aapiGattServerFindService(server_if, service_handle, &srv, &svc, NULL, true)) |
| logw("Server/Service not found while attempting to add included service\n"); |
| else { |
| struct uuid uuid; |
| int includedSvc; |
| |
| if (!aapiGattServerFindService(server_if, included_handle, NULL, &includedSvc, NULL, true) || !gattServiceGetUuid(includedSvc, &uuid)) |
| logw("Failed to find or get UUID of included service\n"); |
| else { |
| |
| handle = gattServiceAddIncludedService(svc, &uuid); |
| if (handle) |
| ret = BT_STATUS_SUCCESS; |
| } |
| } |
| pthread_mutex_unlock(&mAapiGattSrvLock); |
| |
| mCbks.included_service_added_cb(ret, server_if, service_handle, handle); |
| return ret; |
| } |
| |
| /* |
| * FUNCTION: aapiGattServerAddCharacteristic |
| * USE: Add a characteristic to a service |
| * PARAMS: server_if - the server's reference number |
| * service_handle - the handle of the current service |
| * andrUuid - the characteristic's UUID in android format |
| * properties - characteristic's properties (in gatt terms) |
| * permissions - characteristic's permissions in android terms |
| * RETURN: status |
| * NOTES: also calls callback with result if successful result here |
| */ |
| static bt_status_t aapiGattServerAddCharacteristic(int server_if, int service_handle, bt_uuid_t *andrUuid, int properties, int permissions) |
| { |
| bt_status_t ret = BT_STATUS_FAIL; |
| struct aapiGattServer *srv; |
| uint16_t handle = 0; |
| int svc; |
| |
| pthread_mutex_lock(&mAapiGattSrvLock); |
| if (!aapiGattServerFindService(server_if, service_handle, &srv, &svc, NULL, true)) |
| logw("Server/Service not found while attempting to add characteristic\n"); |
| else { |
| struct uuid uuid; |
| |
| aapiGattUuidFromAndroidUuid(&uuid, andrUuid); |
| handle = gattServiceAddChar(svc, &uuid, properties, permissions); |
| if (handle) |
| ret = BT_STATUS_SUCCESS; |
| } |
| pthread_mutex_unlock(&mAapiGattSrvLock); |
| |
| mCbks.characteristic_added_cb(ret, server_if, andrUuid, service_handle, handle); |
| return ret; |
| } |
| |
| /* |
| * FUNCTION: aapiGattServerAddDescriptor |
| * USE: Add a descriptor to a given service |
| * PARAMS: server_if - the server's reference number |
| * service_handle - the handle of the current service |
| * andrUuid - the descriptor's UUID in android format |
| * permissions - characteristic's permissions in android terms |
| * RETURN: status |
| * NOTES: also calls callback with result if successful result here |
| */ |
| static bt_status_t aapiGattServerAddDescriptor(int server_if, int service_handle, bt_uuid_t *andrUuid, int permissions) |
| { |
| bt_status_t ret = BT_STATUS_FAIL; |
| struct aapiGattServer *srv; |
| uint16_t handle = 0; |
| int svc; |
| |
| pthread_mutex_lock(&mAapiGattSrvLock); |
| if (!aapiGattServerFindService(server_if, service_handle, &srv, &svc, NULL, true)) |
| logw("Server/Service not found while attempting to add descriptor\n"); |
| else { |
| struct uuid uuid; |
| |
| aapiGattUuidFromAndroidUuid(&uuid, andrUuid); |
| handle = gattServiceAddCharDescr(svc, &uuid, permissions); |
| if (handle) |
| ret = BT_STATUS_SUCCESS; |
| } |
| pthread_mutex_unlock(&mAapiGattSrvLock); |
| |
| mCbks.descriptor_added_cb(ret, server_if, andrUuid, service_handle, handle); |
| return ret; |
| } |
| |
| /* |
| * FUNCTION: aapiGattServerStartService |
| * USE: Starts a local service |
| * PARAMS: server_if - the server's reference number |
| * service_handle - the handle of the current service |
| * transport - which transport to use |
| * RETURN: status |
| * NOTES: also calls callback with result if successful result here |
| */ |
| static bt_status_t aapiGattServerStartService(int server_if, int service_handle, int transport) |
| { |
| bt_status_t ret = BT_STATUS_FAIL; |
| struct aapiGattServer *srv; |
| int svc; |
| |
| pthread_mutex_lock(&mAapiGattSrvLock); |
| if (!aapiGattServerFindService(server_if, service_handle, &srv, &svc, NULL, true)) |
| logw("Server/Service not found while attempting to start service\n"); |
| else { |
| bool useLE = transport == GATT_TRANSPORT_LE || transport == GATT_TRANSPORT_LE_BR_EDR; |
| bool useEDR = transport == GATT_TRANSPORT_BR_EDR || transport == GATT_TRANSPORT_LE_BR_EDR; |
| |
| if (!useLE && !useEDR) |
| logw("Cannot bring up service given no transports\n"); |
| else { |
| |
| if (gattServiceStart(svc, useLE, useEDR)) |
| ret = BT_STATUS_SUCCESS; |
| } |
| } |
| pthread_mutex_unlock(&mAapiGattSrvLock); |
| |
| mCbks.service_started_cb(ret, server_if, service_handle); |
| return ret; |
| } |
| |
| /* |
| * FUNCTION: aapiGattServerStopService |
| * USE: Stops a local service |
| * PARAMS: server_if - the server's reference number |
| * service_handle - the handle of the current service |
| * RETURN: status |
| * NOTES: also calls callback with result if successful result here |
| */ |
| static bt_status_t aapiGattServerStopService(int server_if, int service_handle) |
| { |
| bt_status_t ret = BT_STATUS_FAIL; |
| struct aapiGattServer *srv; |
| int svc; |
| |
| pthread_mutex_lock(&mAapiGattSrvLock); |
| if (!aapiGattServerFindService(server_if, service_handle, &srv, &svc, NULL, true)) |
| logw("Server/Service not found while attempting to stop service\n"); |
| else { |
| if (gattServiceStop(svc)) |
| ret = BT_STATUS_SUCCESS; |
| } |
| pthread_mutex_unlock(&mAapiGattSrvLock); |
| |
| mCbks.service_stopped_cb(ret, server_if, service_handle); |
| return ret; |
| } |
| |
| /* |
| * FUNCTION: aapiGattServerDeleteService |
| * USE: Delete a local service |
| * PARAMS: server_if - the server's reference number |
| * service_handle - the handle of the current service |
| * RETURN: status |
| * NOTES: also calls callback with result if successful result here |
| */ |
| static bt_status_t aapiGattServerDeleteService(int server_if, int service_handle) |
| { |
| bt_status_t ret = BT_STATUS_FAIL; |
| struct aapiGattServer *srv; |
| uint32_t idx; |
| int svc; |
| |
| pthread_mutex_lock(&mAapiGattSrvLock); |
| if (!aapiGattServerFindService(server_if, service_handle, &srv, &svc, &idx, true)) |
| logw("Server/Service not found while attempting to delete service\n"); |
| else { |
| memmove(srv->services + idx, srv->services + srv->numServices - 1, sizeof(struct aapiGattServerService)); |
| srv->numServices--; |
| if (gattServiceDestroy(svc)) |
| ret = BT_STATUS_SUCCESS; |
| } |
| pthread_mutex_unlock(&mAapiGattSrvLock); |
| |
| mCbks.service_deleted_cb(ret, server_if, service_handle); |
| return ret; |
| } |
| |
| /* |
| * FUNCTION: aapiGattServerSendIndication |
| * USE: Send value indication to a remote device |
| * PARAMS: server_if - the server's reference number |
| * attribute_handle - the handle of the pertinent attribute |
| * conn_id - the connection reference number |
| * len - the length of the data |
| * confirm - need confirmation? |
| * p_value - the value |
| * RETURN: status |
| * NOTES: also calls callback with result if successful result here |
| */ |
| static bt_status_t aapiGattServerSendIndication(int server_if, int attribute_handle, int conn_id, int len, int confirm, char *p_value) |
| { |
| bt_status_t ret = BT_STATUS_FAIL; |
| struct aapiGattServer *srv; |
| int svc; |
| |
| pthread_mutex_lock(&mAapiGattSrvLock); |
| if (!aapiGattServerFindService(server_if, attribute_handle, &srv, &svc, NULL, false)) |
| logw("Server/service not found while attempting to send indication\n"); |
| else { |
| if (gattServiceSendInd(svc, conn_id, attribute_handle, p_value, len, !!confirm, 0)) |
| ret = BT_STATUS_SUCCESS; |
| } |
| pthread_mutex_unlock(&mAapiGattSrvLock); |
| |
| /* XXX: callback here? */ |
| return ret; |
| } |
| |
| /* |
| * FUNCTION: aapiGattServerSendResponse |
| * USE: Send a response to a read/write operation |
| * PARAMS: conn_id - the connection reference number |
| * trans_id - transaction reference number |
| * status - the status to send |
| * response - the response to send |
| * RETURN: status |
| * NOTES: also calls callback with result if successful result here |
| */ |
| static bt_status_t aapiGattServerSendResponse(int conn_id, int trans_id, int status, btgatt_response_t *response) |
| { |
| gattSrvCbkReply(conn_id, trans_id, response->handle, status, response->attr_value.value, response->attr_value.len); |
| |
| return BT_STATUS_SUCCESS; |
| } |
| |
| /* |
| * FUNCTION: aapiGattServerGetProfileIface |
| * USE: Called to get profile pointer to the GATT server profile |
| * PARAMS: NONE |
| * RETURN: pointer to profile struct |
| * NOTES: |
| */ |
| void *aapiGattServerGetProfileIface(void) |
| { |
| static const btgatt_server_interface_t iface = { |
| .register_server = aapiGattServerRegisterServer, |
| .unregister_server = aapiGattServerUnregisterServer, |
| .connect = aapiGattServerConnect, |
| .disconnect = aapiGattServerDisconnect, |
| .add_service = aapiGattServerAddService, |
| .add_included_service = aapiGattServerAddIncludedService, |
| .add_characteristic = aapiGattServerAddCharacteristic, |
| .add_descriptor = aapiGattServerAddDescriptor, |
| .start_service = aapiGattServerStartService, |
| .stop_service = aapiGattServerStopService, |
| .delete_service = aapiGattServerDeleteService, |
| .send_indication = aapiGattServerSendIndication, |
| .send_response = aapiGattServerSendResponse, |
| }; |
| |
| return (void*)&iface; |
| } |
| |
| /* |
| * FUNCTION: aapiGattServerInit |
| * USE: Init the GATT server profile |
| * PARAMS: cbks - callbacks back into java |
| * RETURN: status |
| * NOTES: |
| */ |
| bt_status_t aapiGattServerInit(const btgatt_server_callbacks_t *cbks) |
| { |
| bt_status_t ret; |
| |
| |
| memcpy(&mCbks, cbks, sizeof(mCbks)); |
| |
| pthread_mutex_lock(&mAapiGattSrvLock); |
| if (!mInited) { |
| if (!attInit()) { |
| loge("ATT init failed\n"); |
| } else if (!gattProfileInit()) { |
| attDeinit(); |
| loge("GATT init failed\n"); |
| } else if (!gattBuiltinInit()) { |
| gattProfileDeinit(); |
| attDeinit(); |
| loge("GATT.GAP init failed\n"); |
| } else |
| mInited = true; |
| } |
| ret = mInited ? BT_STATUS_SUCCESS : BT_STATUS_FAIL; |
| pthread_mutex_unlock(&mAapiGattSrvLock); |
| |
| return ret; |
| } |
| |
| /* |
| * FUNCTION: aapiGattServerDeinit |
| * USE: Deinit the GATT server profile |
| * PARAMS: NONE |
| * RETURN: NONE |
| * NOTES: |
| */ |
| void aapiGattServerDeinit(void) |
| { |
| pthread_mutex_lock(&mAapiGattSrvLock); |
| if (mInited) { |
| mInited = false; |
| gattBuiltinDeinit(); |
| gattProfileDeinit(); |
| attDeinit(); |
| } |
| pthread_mutex_unlock(&mAapiGattSrvLock); |
| } |
| |
| |