freemaster_client.c 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. /*
  2. * Copyright 2024 NXP
  3. * NXP Proprietary. This software is owned or controlled by NXP and may only be used strictly in
  4. * accordance with the applicable license terms. By expressly accepting such terms or by downloading, installing,
  5. * activating and/or otherwise using the software, you are agreeing that you have read, and that you agree to
  6. * comply with and are bound by, such license terms. If you do not agree to be bound by the applicable license
  7. * terms, then you may not retain, install, activate or otherwise use the software.
  8. */
  9. #include <time.h>
  10. #include <errno.h>
  11. #include <string.h>
  12. #include "freemaster_client.h"
  13. #if LV_USE_GUIDER_SIMULATOR && LV_USE_FREEMASTER
  14. #include "external_data_init.h"
  15. #define CALL_RETRY_COUNT 5
  16. #define DEFAULT_STRING "NULL"
  17. CURL *ws_connect = NULL;
  18. lv_obj_t *gg_prompt = NULL;
  19. extern pthread_mutex_t lvgl_mutex;
  20. extern pthread_mutex_t jsonrpc_mutex;
  21. static uint32_t retry_count = 0;
  22. void connect_init()
  23. {
  24. ws_connect = websocket_connect(freemaster_server);
  25. if (ws_connect == NULL)
  26. {
  27. prompt_display("websocket connect failed.");
  28. return;
  29. }
  30. return;
  31. }
  32. void freemaster_disconnect()
  33. {
  34. if (ws_connect != NULL)
  35. {
  36. websocket_close(ws_connect);
  37. ws_connect = NULL;
  38. }
  39. return;
  40. }
  41. bool equal_to_double_max(double a)
  42. {
  43. /* set the threshold of double type */
  44. const double epsilon = 1e-9;
  45. return fabs(fabs(a) - DBL_MAX) / DBL_MAX < epsilon;
  46. }
  47. // Release the memory occupied by the string array
  48. void free_string_array(char **array, int count)
  49. {
  50. for (int i = 0; i < count; i++)
  51. {
  52. free(array[i]);
  53. }
  54. free(array);
  55. }
  56. void freeMasterParse(void *param)
  57. {
  58. if (strcmp(((readVariableParm *)param)->apiName, "ReadVariable") == 0)
  59. {
  60. readVariableParm *user_parm = param;
  61. char **dataArray = read_variable(user_parm->varArray, user_parm->arrayLen);
  62. /* use timedlock to avoid dead loop when there is screen transition event*/
  63. struct timespec timeout = {0, LV_DEF_REFR_PERIOD * 1000 * 1000};
  64. int err = pthread_mutex_timedlock(&lvgl_mutex, &timeout);
  65. if (0 != err)
  66. return;
  67. /* display the extern data according to widget type. */
  68. switch (user_parm->widget_type)
  69. {
  70. case GG_LABEL:
  71. {
  72. lv_label_set_text(user_parm->parentObj, dataArray[0]);
  73. break;
  74. }
  75. case GG_CHART:
  76. {
  77. lv_chart_series_t *childObj = NULL;
  78. for (int i = 0; i < user_parm->arrayLen; i++)
  79. {
  80. childObj = (user_parm->childObjArray)[i];
  81. lv_chart_set_next_value(user_parm->parentObj, childObj, atoi(dataArray[i]));
  82. }
  83. lv_chart_refresh(user_parm->parentObj);
  84. break;
  85. }
  86. case GG_BAR:
  87. {
  88. lv_bar_set_value(user_parm->parentObj, atoi(dataArray[0]), LV_ANIM_OFF);
  89. break;
  90. }
  91. case GG_METER:
  92. {
  93. meter_needle *childObj = NULL;
  94. for (int i = 0; i < user_parm->arrayLen; i++)
  95. {
  96. childObj = (user_parm->childObjArray)[i];
  97. lv_scale_set_line_needle_value(user_parm->parentObj, childObj->needle_obj, childObj->needle_length, atoi(dataArray[i]));
  98. }
  99. break;
  100. }
  101. case GG_ARC:
  102. {
  103. lv_arc_set_value(user_parm->parentObj, atoi(dataArray[0]));
  104. break;
  105. }
  106. case GG_SLIDER:
  107. {
  108. lv_slider_set_value(user_parm->parentObj, atoi(dataArray[0]), LV_ANIM_OFF);
  109. break;
  110. }
  111. case GG_SWITCH:
  112. {
  113. if (atoi(dataArray[0]) == 0 && lv_obj_has_state(user_parm->parentObj, LV_STATE_CHECKED))
  114. {
  115. lv_obj_clear_state(user_parm->parentObj, LV_STATE_CHECKED);
  116. }
  117. if (atoi(dataArray[0]) == 1 && !lv_obj_has_state(user_parm->parentObj, LV_STATE_CHECKED))
  118. {
  119. lv_obj_add_state(user_parm->parentObj, LV_STATE_CHECKED);
  120. }
  121. break;
  122. }
  123. default:
  124. break;
  125. }
  126. free_string_array(dataArray, user_parm->arrayLen);
  127. pthread_mutex_unlock(&lvgl_mutex);
  128. }
  129. return;
  130. }
  131. void prompt_display(char *message)
  132. {
  133. if (gg_prompt == NULL || !lv_obj_is_valid(gg_prompt))
  134. {
  135. gg_prompt = lv_label_create(lv_layer_top()); /* create the prompt label on the top layer */
  136. lv_label_set_text(gg_prompt, message);
  137. lv_obj_set_pos(gg_prompt, 0, 0); /* set the prompt label position */
  138. lv_obj_set_size(gg_prompt, lv_disp_get_hor_res(NULL), 30); /* set the prompt label size */
  139. lv_label_set_long_mode(gg_prompt, LV_LABEL_LONG_SCROLL); /* set the label text long mode */
  140. lv_color_t red = lv_color_hex(0xff0027);
  141. lv_obj_set_style_border_width(gg_prompt, 1, LV_PART_MAIN|LV_STATE_DEFAULT); /* define the font color as yellow */
  142. lv_obj_set_style_text_color(gg_prompt, red, LV_PART_MAIN | LV_STATE_DEFAULT); /* set the label font color */
  143. lv_obj_set_style_radius(gg_prompt, 3, LV_PART_MAIN|LV_STATE_DEFAULT);
  144. }
  145. }
  146. json_t *callAPI(json_t* params, char *method_name)
  147. {
  148. static uint32_t id = 1;
  149. json_error_t error;
  150. json_t *json_obj = NULL;
  151. json_t *request_data = NULL;
  152. /* try to connect*/
  153. if (ws_connect == NULL)
  154. connect_init();
  155. /* still unsuccessful? */
  156. if (ws_connect == NULL)
  157. return NULL;
  158. request_data = json_object();
  159. pthread_mutex_lock(&jsonrpc_mutex);
  160. /* format the request params json string */
  161. json_object_set_new(request_data, "jsonrpc", json_string("2.0"));
  162. json_object_set_new(request_data, "id", json_integer(id));
  163. json_object_set_new(request_data, "method", json_string(method_name));
  164. json_object_set_new(request_data, "params", params);
  165. /* dynamically increase id for jsonrpc request params*/
  166. id++;
  167. if (id == UINT_MAX)
  168. {
  169. id = 1;
  170. }
  171. pthread_mutex_unlock(&jsonrpc_mutex);
  172. /* Convert JSON object to string */
  173. char *param_str = json_dumps(request_data, JSON_INDENT(4));
  174. /* get the json data from FreeMaster server JSONRPC with websocket.*/
  175. char *origin_response = websocket_request(ws_connect, param_str);
  176. if (origin_response == NULL)
  177. {
  178. fprintf(stderr, "No data returned from jsonrpc server.\n");
  179. goto err_ret;
  180. }
  181. #ifdef DEBUG
  182. fprintf(stdout, "Decoding json: %s\n", origin_response);
  183. #endif
  184. json_obj = json_loads(origin_response, 0, &error);
  185. if (json_obj == NULL)
  186. {
  187. fprintf(stderr, "Failed to decode json: %s\n", error.text);
  188. goto err_ret;
  189. }
  190. err_ret:
  191. /* Release the JSON object and its string */
  192. if(request_data)
  193. json_decref(request_data);
  194. if(origin_response)
  195. free(origin_response);
  196. if(param_str)
  197. free(param_str);
  198. return json_obj;
  199. }
  200. char **read_variable(fm_var *varArray, int arrayLen)
  201. {
  202. json_t *result_json;
  203. char **dataArray = (char **)malloc(arrayLen * sizeof(char *));
  204. if (dataArray == NULL)
  205. {
  206. return NULL; // malloc failed.
  207. }
  208. for (int i = 0; i < arrayLen; i++)
  209. {
  210. char *variable_name = varArray[i].varName;
  211. json_t *params_arr = json_array();
  212. json_array_append_new(params_arr, json_string(variable_name));
  213. result_json = callAPI(params_arr, "ReadVariable");
  214. /* Automatically release the memory occupied by the object when the reference count becomes 0 */
  215. json_decref(params_arr);
  216. if (result_json == NULL)
  217. {
  218. dataArray[i] = strdup(DEFAULT_STRING);
  219. continue;
  220. }
  221. int success = 0, retval = 0, errorCode = 0;
  222. char *id, *dataFormatted, *errorMessage = NULL;
  223. int data;
  224. json_error_t error;
  225. int res = json_unpack_ex(result_json, &error, 0, "{s:s, s:{s:b, s?F, s:{s:b, s?:s}, s?{s:i, s:s}}}",
  226. "id", &id, "result", "success", &success, "data", &data, "xtra", "retval", &retval,
  227. "formatted", &dataFormatted, "error", "code", &errorCode, "msg", &errorMessage);
  228. if (res == -1 || !success)
  229. {
  230. char * dispaly_error = errorMessage ? errorMessage : error.text;
  231. retry_count += 1;
  232. fprintf(stderr, "%s\n", dispaly_error);
  233. /* retry read the variable when the time over the CALL_RETRT_COUNT will alert the error message. */
  234. if (retry_count >= CALL_RETRY_COUNT)
  235. {
  236. prompt_display(dispaly_error);
  237. }
  238. /* call the api failed will be set the default string */
  239. dataArray[i] = strdup(DEFAULT_STRING);
  240. continue;
  241. }
  242. if (success && res != -1)
  243. {
  244. if (lv_obj_is_valid(gg_prompt))
  245. {
  246. lv_obj_del(gg_prompt);
  247. gg_prompt = NULL;
  248. retry_count = 0;
  249. }
  250. }
  251. dataArray[i] = strdup(dataFormatted);
  252. if (dataArray[i] == NULL)
  253. {
  254. // If memory allocation fails, release the allocated memory and return NULL.
  255. for (int j = 0; j < i; j++)
  256. {
  257. free(dataArray[j]);
  258. }
  259. free(dataArray);
  260. return NULL;
  261. }
  262. json_decref(result_json);
  263. }
  264. return dataArray;
  265. }
  266. void write_variable(char *varName, int value)
  267. {
  268. json_t *params_arr = json_array();
  269. json_array_append_new(params_arr, json_string(varName));
  270. json_array_append_new(params_arr, json_integer(value));
  271. callAPI(params_arr, "WriteVariable");
  272. json_decref(params_arr); /* Automatically release the memory occupied by the object when the reference count becomes 0 */
  273. return;
  274. }
  275. #endif