nxp/nfc3d/cloud_websocket.c

See examples/nxp/nfc3d

/*
* ZentriOS SDK LICENSE AGREEMENT | Zentri.com, 2015.
*
* Use of source code and/or libraries contained in the ZentriOS SDK is
* subject to the Zentri Operating System SDK license agreement and
* applicable open source license agreements.
*
*/
#include "common.h"
uint32_t cloud_post_ctr = 10; // Drives state machine that shows info on the LCD about cloud posts
static uint32_t websocket_handle;
/*************************************************************************************************/
zos_result_t cloud_init(void)
{
websocket_handle = ZOS_INVALID_HANDLE;
cloud_connect_event_handler(NULL);
return ZOS_SUCCESS;
}
/*************************************************************************************************/
void cloud_post_update(void)
{
zn_event_trigger(periodic_post_event_handler, NULL);
}
/*************************************************************************************************/
static void cloud_connect_event_handler(void *arg)
{
zos_result_t result;
char url_str[128];
char uuid_str[48];
const zos_websocket_config_t config =
{
.buffer_size = 1024,
.host = url_str,
.certs.ca = "zentri.cloud.cer",
.gpio = ZOS_GPIO_INVALID,
.frame_type = WEBSOCKET_TEXT_FRAME
};
websocket_handle = ZOS_INVALID_HANDLE;
zn_event_unregister(cloud_connect_event_handler, NULL);
ZOS_LOG("- Initializing cloud services");
sprintf(url_str, CLOUD_WS_URL, zn_settings_get_print_str("system.uuid", uuid_str, sizeof(uuid_str)));
{
uint32_t join_result;
zn_settings_get_uint32("wlan.join.result", &join_result);
ZOS_LOG("Failed to join local network: wlan.join.result: %u, err code: %u", join_result, result);
}
else if(ZOS_FAILED(result, zn_websocket_connect_with_config(&config, &websocket_handle)))
{
ZOS_LOG("Failed to open websocket connection");
}
else
{
zn_websocket_register_client_event_handlers(websocket_handle, websocket_disconnect_handler, websocket_rx_handler);
zn_event_register_periodic(periodic_post_event_handler, NULL, CLOUD_POST_PERIOD, EVENT_FLAGS1(REQUIRE_WLAN));
}
if(result != ZOS_SUCCESS)
{
local_set_lcd_wifi_text();
local_set_lcd_internet_msg(ZOS_FALSE);
ZOS_LOG("Trying again in %u seconds", CLOUD_CONNECT_RETRY_PERIOD/1000);
zn_event_register_timed(cloud_connect_event_handler, NULL, CLOUD_CONNECT_RETRY_PERIOD, 0);
}
else
{
local_set_lcd_touchnfc_msg();
local_set_lcd_internet_msg(ZOS_TRUE);
ZOS_LOG("Connected to cloud");
ZOS_LOG("[Success]");
}
}
/*************************************************************************************************/
static void network_event_handler(uint32_t is_up)
{
if(!is_up)
{
ZOS_LOG("WLAN network down!");
attempt_reconnect(NULL);
}
}
/*************************************************************************************************/
static void websocket_disconnect_handler(uint32_t handle)
{
ZOS_LOG("Websocket disconnected");
attempt_reconnect(NULL);
}
/*************************************************************************************************/
static void attempt_reconnect(void *dummy)
{
zn_websocket_disconnect(websocket_handle);
zn_event_unregister(periodic_post_event_handler, NULL);
zn_event_issue(cloud_connect_event_handler, NULL, 0);
}
/*************************************************************************************************/
static void websocket_rx_handler(uint32_t handle)
{
zos_result_t result;
char buffer[512];
json_parse_context_t *context = NULL;
{
.buffer_len = sizeof(buffer),
.buffer = buffer,
.reader = json_parse_reader
};
if(ZOS_FAILED(result, json_parse_context_init(&context, &config)))
{
}
else if(ZOS_FAILED(result, json_parse_chunked(context, NULL)))
{
}
else
{
const json_tok_t *tok = json_context_get_value(context, "lcd_msg", NULL);
if(tok != NULL)
{
local_set_lcd_msg(JSON_STR(tok));
}
else
{
result = ZOS_ERROR;
ZOS_LOG("Failed to parse json");
}
}
}
/*************************************************************************************************/
static zos_result_t json_parse_reader(void *user, void *data, uint32_t max_length, uint32_t *bytes_read)
{
uint32_t available;
*bytes_read = 0;
loop:
if(result == ZOS_SUCCESS &&
!ZOS_FAILED(result, zn_websocket_poll(websocket_handle, &available)))
{
if(available > 0)
{
{
.payload_length = max_length
};
result = zn_websocket_client_read_frame(websocket_handle, &frame, ZOS_NO_WAIT);
memcpy(data, frame.payload, frame.payload_length);
*bytes_read = frame.payload_length;
goto loop;
}
}
return result;
}
/*************************************************************************************************/
static void periodic_post_event_handler(void *arg)
{
zos_result_t result;
if(ZOS_FAILED(result, write_setting("system.uuid", "{\"uuid\":\"%s\",")))
{
}
else if(ZOS_FAILED(result, write_setting("softap.ssid", "\"ssid\":\"%s\",")))
{
}
else if(ZOS_FAILED(result, write_setting("softap.passkey", "\"password\":\"%s\",")))
{
}
else if(ZOS_FAILED(result, write_setting("softap.static.ip", "\"ip\":\"%s\",")))
{
}
else if(ZOS_FAILED(result, write_setting("softap.dns_server.url", "\"dns\":\"%s\",")))
{
}
else if(ZOS_FAILED(result, write_setting("time.uptime", "\"uptime\":%s,")))
{
}
else if(ZOS_FAILED(result, write_setting("time.rtc utc", "\"time\":\"%s\",")))
{
}
else if(ZOS_FAILED(result, write_tag_read_count()))
{
}
else if(ZOS_FAILED(result, write_lcd_msg()))
{
}
else if(ZOS_FAILED(result, write_ap_clients()))
{
}
if(result != ZOS_SUCCESS && result != ZOS_TIMEOUT)
{
ZOS_LOG("Cloud post failed: %d", result);
attempt_reconnect(NULL);
}
else
{
if(cloud_post_ctr < 3)
{ // First show that device info is being sent to the cloud
local_set_lcd_sending_msg();
cloud_post_ctr++;
}
else if(cloud_post_ctr < 5)
{ // Now tell the user to look at their phone to get the info
local_set_lcd_seephone_msg();
cloud_post_ctr++;
}
else
{ // Finally go back to telling the user to tap their phone on the NFC tag
local_set_lcd_touchnfc_msg();
}
local_set_lcd_internet_msg(ZOS_TRUE);
}
}
/*************************************************************************************************/
static zos_result_t write_setting(const char *setting, const char *fmt_str)
{
char buffer[128];
char tmp[128];
const int len = sprintf(buffer, fmt_str, zn_settings_get_print_str(setting, tmp, sizeof(tmp)));
return zn_websocket_write(websocket_handle, buffer, len, ZOS_TRUE);
}
/*************************************************************************************************/
static zos_result_t write_tag_read_count(void)
{
char buffer[128];
const int len = sprintf(buffer, "\"tag_reads\":%u,", (unsigned int)nfc3d_context.tag_read_count);
nfc3d_context.tag_read_count = 0;
return zn_websocket_write(websocket_handle, buffer, len, ZOS_TRUE);
}
/*************************************************************************************************/
static zos_result_t write_lcd_msg(void)
{
char buffer[128];
const int len = sprintf(buffer, "\"lcd_msg\":\"%s\",", nfc3d_context.lcd_msg);
return zn_websocket_write(websocket_handle, buffer, len, ZOS_TRUE);
}
/*************************************************************************************************/
static zos_result_t write_ap_clients(void)
{
char buffer[128];
zos_result_t result;
const int len = sprintf(buffer, "\"app_clients\":[");
if(!ZOS_FAILED(result, zn_websocket_write(websocket_handle, buffer, len, ZOS_TRUE)))
{
uint32_t i = 0;
zn_network_softap_client_list(client_list, NULL);
for(const zos_softap_client_t *cli = client_list; cli < &client_list[ZOS_MAX_SOFTAP_CLIENTS]; ++cli)
{
if(cli->connected)
{
char tmp[20];
const int len1 = sprintf(buffer, "%s{\"ip\":\"%s\",",
(i++ > 0) ? "," : "", ip_to_str(cli->ip_address, tmp));
if(ZOS_FAILED(result, zn_websocket_write(websocket_handle, buffer, len1, ZOS_TRUE)))
{
break;
}
const int len2 = sprintf(buffer, "\"mac\":\"%s\"}", mac_to_str(&cli->mac_address, tmp));
if(ZOS_FAILED(result, zn_websocket_write(websocket_handle, buffer, len2, ZOS_TRUE)))
{
break;
}
}
}
if(result == ZOS_SUCCESS)
{
result = zn_websocket_write(websocket_handle, "]}", 2, ZOS_FALSE);
}
}
return result;
}