/* * ESPRESSIF MIT License * * Copyright (c) 2020 * * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, * it is free of charge, to any person obtaining a copy of this software and associated * documentation files (the "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the Software is furnished * to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all copies or * substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #include #include void hap_serv_mark_primary(hap_serv_t *hs) { if (hs) { ((__hap_serv_t *)hs)->primary = true; } } void hap_serv_mark_hidden(hap_serv_t *hs) { if (hs) { ((__hap_serv_t *)hs)->hidden = true; } } /** * @brief get service hidden attribute */ bool hap_serv_get_hidden(hap_serv_t *hs) { if (hs) { return ((__hap_serv_t *)hs)->hidden; } return false; } void hap_serv_set_iid(hap_serv_t *hs, int32_t iid) { if (hs) { ((__hap_serv_t *)hs)->iid = iid; } } /** * @brief get service "primary" attribute */ bool hap_serv_get_primary(hap_serv_t *hs) { if (hs) { return ((__hap_serv_t *)hs)->primary; } return false; } hap_char_t *hap_serv_get_first_char(hap_serv_t *hs) { return ((__hap_serv_t *)hs)->chars; } /** * @brief get target characteristics by it's IID */ hap_char_t *hap_serv_get_char_by_iid(hap_serv_t *hs, int32_t iid) { if (!hs) return NULL; hap_char_t *hc; for (hc = hap_serv_get_first_char(hs); hc; hc = hap_char_get_next(hc)) { if (((__hap_char_t *)hc)->iid == iid) return hc; } return NULL; } /** * @brief get target characteristics by it's UUID */ hap_char_t *hap_serv_get_char_by_uuid(hap_serv_t *hs, const char *uuid) { if (!hs | !uuid) return NULL; hap_char_t *hc; for (hc = hap_serv_get_first_char(hs); hc; hc = hap_char_get_next(hc)) { if (!strcmp(((__hap_char_t *)hc)->type_uuid, uuid)) return hc; } return NULL; } /** * @brief get characteristics UUID prefix number */ const char *hap_serv_get_uuid(hap_serv_t *hs) { return ((__hap_serv_t *)hs)->type_uuid; } /** * Default service bulk read callback, which will be registered while creating a service. * It will internally call the actual read routines */ static int hap_serv_def_bulk_read_cb(hap_read_data_t read_data[], int count, void *serv_priv, void *read_priv) { int i; if (!count) { return HAP_FAIL; } __hap_serv_t *hs = (__hap_serv_t *)hap_char_get_parent(read_data[0].hc); /* If no read routine is registered, just return success so that the cached values * will be used */ if (!hs->read_cb) { return HAP_SUCCESS; } int ret = HAP_SUCCESS; for (i = 0; i < count; i++) { if (hs->read_cb(read_data[i].hc, read_data[i].status, serv_priv, read_priv) != HAP_SUCCESS) { ret = HAP_FAIL; } } return ret; } /** * @brief HAP create a service */ hap_serv_t *hap_serv_create(const char *type_uuid) { ESP_MFI_ASSERT(type_uuid); __hap_serv_t *_hs = hap_platform_memory_calloc(1, sizeof(__hap_serv_t)); if (!_hs) { return NULL; } _hs->type_uuid = type_uuid; _hs->bulk_read = hap_serv_def_bulk_read_cb; return (hap_serv_t *)_hs; } int hap_serv_link_serv(hap_serv_t *hs, hap_serv_t *linked_serv) { if (!hs || !linked_serv) return HAP_FAIL; hap_linked_serv_t *cur = hap_platform_memory_calloc(1, sizeof(hap_linked_serv_t)); if (!cur) return HAP_FAIL; cur->hs = linked_serv; __hap_serv_t *_hs = (__hap_serv_t *)hs; hap_linked_serv_t *linked = _hs->linked_servs; if (!linked) { _hs->linked_servs = cur; return HAP_SUCCESS; } else { while(linked->next) { linked = linked->next; } linked->next = cur; return HAP_SUCCESS; } return HAP_FAIL; } /** * @brief HAP get target service IID */ uint32_t hap_serv_get_iid(hap_serv_t *hs) { if (!hs) return 0; __hap_serv_t *tmp = (__hap_serv_t *)hs; return tmp->iid; } const char *hap_serv_get_type_uuid(hap_serv_t *hs) { if (!hs) return 0; __hap_serv_t *tmp = (__hap_serv_t *)hs; return tmp->type_uuid; } /** * @brief HAP delete target service */ void hap_serv_delete(hap_serv_t *hs) { /* Returning success even if pointer is NULL, because it means * that the service is absent and as good as deleted */ if (!hs) return; __hap_serv_t *_hs = (__hap_serv_t *)hs; __hap_char_t *_hc = (__hap_char_t *)_hs->chars; while (_hc) { _hs->chars = _hc->next_char; hap_char_delete((hap_char_t *)_hc); _hc = (__hap_char_t *)_hs->chars; } if (_hs->linked_servs) { hap_linked_serv_t *cur = _hs->linked_servs; hap_linked_serv_t *next = cur->next; while (next) { hap_platform_memory_free(cur); cur = next; next = cur->next; } hap_platform_memory_free(cur); } hap_platform_memory_free(hs); } /** * @brief add a characteristics to a service */ int hap_serv_add_char(hap_serv_t *hs, hap_char_t *hc) { if (!hs || !hc) return -1; __hap_serv_t *_hs = (__hap_serv_t *)hs; __hap_char_t *_hc = (__hap_char_t *)hc; if (_hc->parent) { ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Characteristic already added"); return HAP_FAIL; } /* If the service has no characteristics, add this as the first */ if (!_hs->chars) { _hs->chars = hc; } else { /* Else loop through the characteristics to get to the last one, * and add this at the end */ __hap_char_t *temp = (__hap_char_t *)_hs->chars; while (temp->next_char) temp = (__hap_char_t *)temp->next_char; temp->next_char = hc; } if (_hs->parent) { _hc->iid = ((__hap_acc_t *)(_hs->parent))->next_iid++; } _hc->parent = hs; return 0; } void hap_serv_set_write_cb(hap_serv_t *hs, hap_serv_write_t write) { if (hs) { ((__hap_serv_t *)hs)->write_cb = write; } } void hap_serv_set_read_cb(hap_serv_t *hs, hap_serv_read_t read) { if (hs) { ((__hap_serv_t *)hs)->read_cb = read; } } void hap_serv_set_bulk_read_cb(hap_serv_t *hs, hap_serv_bulk_read_t read) { if (hs) { ((__hap_serv_t *)hs)->bulk_read = read; } } hap_serv_t *hap_serv_get_next(hap_serv_t *hs) { if (hs) { return ((__hap_serv_t *)hs)->next_serv; } else { return NULL; } } hap_acc_t *hap_serv_get_parent(hap_serv_t *hs) { if (hs) { return ((__hap_serv_t *)hs)->parent; } else { return NULL; } } void hap_serv_set_priv(hap_serv_t *hs, void *priv) { if (hs) { ((__hap_serv_t *)hs)->priv = priv; } } void *hap_serv_get_priv(hap_serv_t *hs) { if (hs) { return ((__hap_serv_t *)hs)->priv; } else { return NULL; } }