/*
* Copyright (C) 2017, Microchip Technology Inc. and its subsidiaries.
* Author Tobias Jahnke
*
* 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
#define AFB_BINDING_VERSION 2
#include <string.h>
#include <json-c/json.h>
#include <afb/afb-binding.h>
#include "wrap_unicens.h"
#include "wrap-json.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;
/* Subscribes to unicens2-binding events.
* \return Returns 0 if successful, otherwise != 0".
*/
extern int wrap_ucs_subscribe_sync() {
json_object *j_response, *j_query = NULL;
int err;
/* Build an empty JSON object */
err = wrap_json_pack(&j_query, "{}");
if (err) {
AFB_ERROR("Failed to create subscribe json object");
goto OnErrorExit;
}
err = afb_service_call_sync("UNICENS", "subscribe", j_query, &j_response);
if (err) {
AFB_ERROR("Fail subscribing to UNICENS events");
goto OnErrorExit;
}
else {
AFB_NOTICE("Subscribed to UNICENS events, res=%s", json_object_to_json_string(j_response));
json_object_put(j_response);
}
json_object_put(j_query);
j_query = NULL;
OnErrorExit:
if (j_query)
json_object_put(j_query);
return err;
}
/* Checks if name ends with a given letter. */
static int wrap_ucs_string_ends_with(const char *name, char letter) {
int result = 0;
size_t len = strlen(name);
if (len > 0) {
if (name[len] == letter) {
result = 1;
}
}
return result;
}
/* Callback for iteration through found files. Marks search as "done" as
* soon as the search pattern "kit.xml" matches.
* \param closure User reference. Points to parse_result_t.
* \param j_obj Points to json object within array.
*/
static void wrap_ucs_find_xml_cb(void *closure, struct json_object *j_obj) {
const char *dir, *name;
parse_result_t *result;
if (!closure)
return;
result = (parse_result_t *)closure;
if (result->done)
return;
wrap_json_unpack(j_obj, "{s:s, s:s}", "dirpath", &dir, "basename", &name);
AFB_DEBUG("Found file: %s", name);
if(strstr(name, "kit.xml") != NULL) {
size_t sz = strlen(dir)+strlen(name)+10;
char * full_path = malloc(sz);
strncpy(full_path, dir, sz);
if (!wrap_ucs_string_ends_with(dir, '/'))
strncat(full_path, "/", sz);
strncat(full_path, name, sz);
AFB_DEBUG("Found XML file: %s", full_path);
result->done = 1;
result->str_result = full_path;
}
}
/* Retrieves XML configuration path to initialize unicens2-binding.
* \param config_path Directory containing XML configuration file(s).
* \param file_found Points to found file_path or NULL if not found.
* Memory must be released by calling free().
* \return Returns 0 if successful, otherwise != 0".
*/
extern int wrap_ucs_getconfig_sync(const char *config_path, char **file_found) {
int err = 0;
json_object *j_response, *j_query, *j_paths = NULL;
parse_result_t result = {.done = 0, .str_result = NULL};
*file_found = NULL;
/* Build JSON object to retrieve UNICENS configuration */
if ((config_path == NULL) || (strcmp(config_path, "") == 0))
err = wrap_json_pack(&j_query, "{}");
else
err = wrap_json_pack(&j_query, "{s:s}", "cfgpath", config_path);
if (err) {
AFB_ERROR("Failed to create listconfig json object");
goto OnErrorExit;
}
err = afb_service_call_sync("UNICENS", "listconfig", j_query, &j_response);
if (err) {
AFB_ERROR("Failed to call listconfig");
goto OnErrorExit;
}
else {
AFB_DEBUG("UNICENS listconfig result, res=%s", json_object_to_json_string(j_response));
if (json_object_object_get_ex(j_response, "response", &j_paths)) {
AFB_DEBUG("UNICENS listconfig result, paths=%s", json_object_to_json_string(j_paths));
wrap_json_optarray_for_all(j_paths, &wrap_ucs_find_xml_cb, &result);
if (result.done) {
*file_found = strdup(result.str_result);
free(result.str_result);
result.str_result = NULL;
}
else {
AFB_NOTICE("wrap_ucs_getconfig_sync, search pattern does not match for paths=%s", json_object_to_json_string(j_paths));
err = -1;
}
}
json_object_put(j_response);
}
json_object_put(j_query);
j_query = NULL;
OnErrorExit:
if (j_query)
json_object_put(j_query);
return err;
}
/* Initializes the unicens2-binding.
* \param file_name Path to XML configuration file or \c NULL for
* first found file in default path.
* \return Returns 0 if successful, otherwise != 0".
*/
extern int wrap_ucs_initialize_sync(const char *file_name) {
json_object *j_response, *j_query = NULL;
int err;
/* Build JSON object to initialize UNICENS */
if (file_name != NULL)
err = wrap_json_pack(&j_query, "{s:s}", "filename", file_name);
else
err = wrap_json_pack(&j_query, "{}");
if (err) {
AFB_ERROR("Failed to create initialize json object");
goto OnErrorExit;
}
err = afb_service_call_sync("UNICENS", "initialise", j_query, &j_response);
if (err) {
AFB_ERROR("Failed to initialize UNICENS");
goto OnErrorExit;
}
else {
AFB_NOTICE("Initialized UNICENS, res=%s", json_object_to_json_string(j_response));
json_object_put(j_response);
}
json_object_put(j_query);
j_query = NULL;
OnErrorExit:
if (j_query)
json_object_put(j_query);
return err;
}
/* 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_sync(uint16_t node, uint8_t *data_ptr, uint8_t data_sz) {
json_object *j_response, *j_query, *j_array = NULL;
int err;
uint8_t cnt;
j_query = json_object_new_object();
j_array = json_object_new_array();
if (!j_query || !j_array) {
err = -1;
AFB_ERROR("Failed to create writei2c json objects");
goto OnErrorExit;
}
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);
err = afb_service_call_sync("UNICENS", "writei2c", j_query, &j_response);
if (err) {
AFB_ERROR("Failed to call writei2c_sync");
goto OnErrorExit;
}
else {
AFB_INFO("Called writei2c_sync, res=%s", json_object_to_json_string(j_response));
json_object_put(j_response);
}
json_object_put(j_query);
j_query = NULL;
OnErrorExit:
if (j_query)
json_object_put(j_query);
return err;
}
/* ------------------ ASYNCHRONOUS API ---------------------------------------*/
static void wrap_ucs_i2cwrite_cb(void *closure, int status, struct json_object *j_result) {
AFB_INFO("wrap_ucs_i2cwrite_cb: closure=%p status=%d, res=%s", closure, status, json_object_to_json_string(j_result));
if (closure) {
async_job_t *job_ptr = (async_job_t *)closure;
if (job_ptr->result_fptr)
job_ptr->result_fptr((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) {
json_object *j_query, *j_array = NULL;
async_job_t *job_ptr = NULL;
int err;
uint8_t cnt;
j_query = json_object_new_object();
j_array = json_object_new_array();
if (!j_query || !j_array) {
err = -1;
AFB_ERROR("Failed to create writei2c json objects");
goto OnErrorExit;
}
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) {
err = -1;
AFB_ERROR("Failed to create async job object");
goto OnErrorExit;
}
job_ptr->result_fptr = result_fptr;
job_ptr->result_user_ptr = result_user_ptr;
afb_service_call("UNICENS", "writei2c", j_query, wrap_ucs_i2cwrite_cb, job_ptr);
err = 0;
j_query = NULL;
OnErrorExit:
if (j_query)
json_object_put(j_query);
return err;
}