/* * Copyright 2019 Microchip Technology Inc. and its subsidiaries * * 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. */ #define _GNU_SOURCE #include #include #include #include #include "wrap-unicens.h" typedef struct async_job_ { wrap_ucs_result_cb_t result_fptr; void *result_user_ptr; } async_job_t; typedef struct parse_result_ { int done; char *str_result; } parse_result_t; static afb_api_t api_handle_ = NULL; /* Initializes UNICENS API wrapper */ extern int wrap_ucs_init(afb_api_t api_handle) { api_handle_ = api_handle; return afb_api_require_api(api_handle_, "UNICENS", 1); } /* * Subscribes to unicens2-binding events. * \return Returns 0 if successful, otherwise != 0". */ extern int wrap_ucs_subscribe_sync(void) { int err; json_object *j_response, *j_query = NULL; char *error, *info; /* Build an empty JSON object */ if((err = wrap_json_pack(&j_query, "{}"))) { AFB_API_ERROR(api_handle_, "Failed to create subscribe json object"); return err; } if((err = afb_api_call_sync(api_handle_, "UNICENS", "subscribe", j_query, &j_response, &error, &info))) { AFB_API_ERROR(api_handle_, "Fail subscribing to UNICENS events"); return err; } else { AFB_API_NOTICE(api_handle_, "Subscribed to UNICENS events, res=%s", json_object_to_json_string(j_response)); json_object_put(j_response); } return 0; } /* * Subscribes to unicens2-binding RX message events. * \return Returns 0 if successful, otherwise != 0". */ extern int wrap_ucs_subscriberx_sync(void) { int err; json_object *j_response, *j_query = NULL; char *error, *info; /* Build an empty JSON object */ if((err = wrap_json_pack(&j_query, "{}"))) { AFB_API_ERROR(api_handle_, "Failed to create subscribe RX json object"); return err; } if((err = afb_api_call_sync(api_handle_, "UNICENS", "subscriberx", j_query, &j_response, &error, &info))) { AFB_API_ERROR(api_handle_, "Fail subscribing to UNICENS RX events"); return err; } else { AFB_API_NOTICE(api_handle_, "Subscribed to UNICENS RX events, res=%s", json_object_to_json_string(j_response)); json_object_put(j_response); } return 0; } extern int wrap_ucs_interpretrx_event(const char *event, struct json_object *object, wrap_ucs_rx_message_cb_t callback) { int node_id = 0; int msg_id = 0; uint8_t *data_ptr = NULL; size_t data_sz = 0; if (strcmp(event, "UNICENS/rx-message") != 0) { return -1; // unhandled event } if (wrap_json_unpack(object, "{s:i, s:i, s?Y}", "node", &node_id, "msgid", &msg_id, "data", &data_ptr, &data_sz) != 0) { AFB_API_NOTICE(api_handle_, "Parsing rx-message failed."); return -2; } if (callback != NULL) { callback((uint16_t)node_id, (uint16_t)msg_id, (uint16_t)data_sz, data_ptr); } return 0; } extern int wrap_ucs_interpret_event(const char *event, struct json_object *object, wrap_ucs_availability_cb_t callback) { int node_id = 0; int available = false; if (strcmp(event, "UNICENS/node-availibility") != 0) { return -1; // unhandled event } if (wrap_json_unpack(object, "{s:i,s:b}", "node", &node_id, "available", &available) != 0) { AFB_API_NOTICE(api_handle_, "Parsing node-availibility failed."); return -2; } if (callback != NULL) { callback((uint16_t)node_id, (bool)available); } return 0; } /* * Write I2C command to a network node. * \param node Node address * \param ata_ptr Reference to command data * \param data_sz Size of the command data. Valid values: 1..32. * \return Returns 0 if successful, otherwise != 0". */ extern int wrap_ucs_i2cwrite_sync(uint16_t node, uint8_t *data_ptr, uint8_t data_sz) { int err; uint8_t cnt; json_object *j_response, *j_query, *j_array = NULL; char *error, *info; j_query = json_object_new_object(); j_array = json_object_new_array(); if(! j_query || ! j_array) { if (j_query) json_object_put(j_query); if (j_array) json_object_put(j_array); AFB_API_ERROR(api_handle_, "Failed to create writei2c json objects"); return -1; } for(cnt = 0U; cnt < data_sz; cnt++) json_object_array_add(j_array, json_object_new_int(data_ptr[cnt])); json_object_object_add(j_query, "node", json_object_new_int(node)); json_object_object_add(j_query, "data", j_array); if((err = afb_api_call_sync(api_handle_, "UNICENS", "writei2c", j_query, &j_response, &error, &info))) { AFB_API_ERROR(api_handle_, "Failed to call writei2c_sync"); return err; } else { AFB_API_INFO(api_handle_, "Called writei2c_sync, res=%s", json_object_to_json_string(j_response)); json_object_put(j_response); } return 0; } extern int wrap_ucs_sendmessage_sync(uint16_t src_addr, uint16_t msg_id, uint8_t *data_ptr, uint8_t data_sz) { json_object *j_query, *j_response = NULL; char *error, *info; int err = 1; int node = (int)src_addr; int msgid = (int)msg_id; size_t data_size = (size_t)data_sz; AFB_API_NOTICE(api_handle_, "--- HAL triggering send message ---"); /* skip data attribute if possible, wrap_json_unpack may fail to deal with * an empty Base64 string */ if (data_size > 0) wrap_json_pack(&j_query, "{s:i, s:i, s:Y}", "node", node, "msgid", msgid, "data", data_ptr, data_size); else wrap_json_pack(&j_query, "{s:i, s:i}", "node", node, "msgid", msgid); AFB_API_NOTICE(api_handle_, "wrap_ucs_sendmessage: jquery=%s", json_object_to_json_string(j_query)); err = afb_api_call_sync(api_handle_, "UNICENS", "sendmessage", j_query, &j_response, &error, &info); if (err != 0) { AFB_API_ERROR(api_handle_, "Failed to call wrap_ucs_sendmessage ret=%d", err); } else { AFB_API_NOTICE(api_handle_, "Called wrap_ucs_sendmessage, successful"); } if (j_response != NULL) { AFB_API_NOTICE(api_handle_, "wrap_ucs_sendmessage, response=%s", json_object_to_json_string(j_response)); json_object_put(j_response); } return err; } /* ---------------------------- ASYNCHRONOUS API ---------------------------- */ static void wrap_ucs_i2cwrite_cb(void *closure, /*int status, */struct json_object *j_result, const char *error, const char * info, afb_api_t api) { async_job_t *job_ptr; AFB_API_INFO(api_handle_, "%s: closure=%p status=?, res=%s", __func__, closure, /*status,*/ json_object_to_json_string(j_result)); if(closure) { job_ptr = (async_job_t *) closure; if(job_ptr->result_fptr) job_ptr->result_fptr(0/*(uint8_t) abs(status)*/, job_ptr->result_user_ptr); free(closure); } } /* * Write I2C command to a network node. * \param node Node address * \param data_ptr Reference to command data * \param data_sz Size of the command data. Valid values: 1..32. * \return Returns 0 if successful, otherwise != 0". */ extern int wrap_ucs_i2cwrite(uint16_t node, uint8_t *data_ptr, uint8_t data_sz, wrap_ucs_result_cb_t result_fptr, void *result_user_ptr) { uint8_t cnt; json_object *j_query, *j_array = NULL; async_job_t *job_ptr = NULL; j_query = json_object_new_object(); j_array = json_object_new_array(); if(! j_query || ! j_array) { AFB_API_ERROR(api_handle_, "Failed to create writei2c json objects"); return -1; } for(cnt = 0U; cnt < data_sz; cnt++) json_object_array_add(j_array, json_object_new_int(data_ptr[cnt])); json_object_object_add(j_query, "node", json_object_new_int(node)); json_object_object_add(j_query, "data", j_array); job_ptr = malloc(sizeof(async_job_t)); if(! job_ptr) { AFB_API_ERROR(api_handle_, "Failed to create async job object"); json_object_put(j_query); return -2; } job_ptr->result_fptr = result_fptr; job_ptr->result_user_ptr = result_user_ptr; afb_api_call(api_handle_, "UNICENS", "writei2c", j_query, wrap_ucs_i2cwrite_cb, job_ptr); return 0; }