Skip to content

Commit 91de7f7

Browse files
authored
Generic thingset handler (#11)
Adds general URI parser, ThingSet query building and serial discovery function
1 parent ca9451a commit 91de7f7

File tree

7 files changed

+530
-120
lines changed

7 files changed

+530
-120
lines changed

main/main.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "lwip/dns.h"
3030

3131
#include "ts_serial.h"
32+
#include "ts_client.h"
3233
#include "can.h"
3334
#include "emoncms.h"
3435
#include "wifi.h"
@@ -58,13 +59,15 @@ void app_main(void)
5859
#if CONFIG_THINGSET_CAN
5960
can_setup();
6061
xTaskCreatePinnedToCore(can_receive_task, "CAN_rx", 4096,
61-
NULL, RX_TASK_PRIO, NULL, tskNO_AFFINITY);
62+
NULL, RX_TASK_PRIO, NULL, 1);
6263
#endif
6364

6465
#if CONFIG_THINGSET_SERIAL
6566
ts_serial_setup();
67+
6668
xTaskCreatePinnedToCore(ts_serial_rx_task, "ts_serial_rx", 4096,
67-
NULL, RX_TASK_PRIO, NULL, tskNO_AFFINITY);
69+
NULL, RX_TASK_PRIO, NULL, 1);
70+
ts_scan_devices();
6871
#endif
6972

7073
if (strlen(CONFIG_WIFI_SSID) > 0) {

main/provisioning.c

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -61,21 +61,6 @@ static void event_handler(void* arg, esp_event_base_t event_base,
6161
break;
6262
}
6363
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
64-
/*Set the hostname for the default TCP/IP station interface
65-
esp_err_t err;
66-
char *HOSTNAME = CONFIG_DEVICE_HOSTNAME;
67-
const char *name;
68-
if ((err = tcpip_adapter_set_hostname(TCPIP_ADAPTER_IF_STA, HOSTNAME))
69-
!= ESP_OK) {
70-
ESP_LOGE(TAG, "Err: %s", esp_err_to_name(err));
71-
} else {
72-
if ((err = tcpip_adapter_get_hostname(TCPIP_ADAPTER_IF_STA, &name)) != ESP_OK) {
73-
ESP_LOGE(TAG, "Err Get Hostname: %s\n", esp_err_to_name(err));
74-
} else {
75-
ESP_LOGE(TAG, "Hostname: %s\n", (name == NULL ? "<None>" : name));
76-
}
77-
}*/
78-
7964
esp_wifi_connect();
8065
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
8166
ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;

main/ts_client.c

Lines changed: 214 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -5,67 +5,249 @@
55
*/
66

77
#include "ts_client.h"
8+
#include "ts_serial.h"
89

910
#include <stdio.h>
1011
#include <stdlib.h>
1112

1213
#include "esp_http_server.h"
1314
#include "esp_err.h"
1415
#include "esp_log.h"
16+
#include "cJSON.h"
1517

1618
static const char *TAG = "ts_client";
19+
static TSDevice *devices[10];
1720

18-
char *ts_resp_data(char *resp)
21+
22+
void ts_scan_devices()
1923
{
20-
if (resp[0] == ':') {
21-
char *pos = strstr(resp, ". ");
22-
if (pos != NULL) {
23-
return pos + 2;
24+
//scan serial connection
25+
devices[0] = (TSDevice *) heap_caps_malloc(sizeof(TSDevice), MALLOC_CAP_8BIT);
26+
if (ts_serial_scan_device_info(devices[0]) != 0) {
27+
free(devices[0]);
28+
devices[0] = NULL;
29+
};
30+
31+
//TODO scan CAN connection
32+
}
33+
34+
char *ts_get_device_list()
35+
{
36+
cJSON *obj = cJSON_CreateObject();
37+
int i = 0;
38+
while (devices[i] != NULL) {
39+
cJSON *id = cJSON_CreateString(devices[i]->ts_device_id);
40+
cJSON_AddItemToObject(obj, devices[i]->ts_name, id);
41+
i++;
42+
}
43+
char *names_string = NULL;
44+
if (i > 0) {
45+
names_string = cJSON_Print(obj);
46+
cJSON_Delete(obj);
47+
} else {
48+
// hackky solution so that free() can always be called on names_string
49+
const char msg[] = "No devices Connected";
50+
names_string = (char *) malloc(sizeof(msg)+1);
51+
strncpy(names_string, msg, sizeof(msg)+1);
52+
}
53+
return names_string;
54+
}
55+
56+
TSDevice *ts_get_device(char *device_id)
57+
{
58+
int i = 0;
59+
while (devices[i] != NULL) {
60+
if (strcmp(devices[i]->ts_device_id, device_id) == 0) {
61+
return devices[i];
2462
}
63+
i++;
2564
}
2665
return NULL;
2766
}
2867

29-
int ts_resp_status(char *resp)
68+
// wrapper for strlen() to check for NULL
69+
static int strlen_null(char *r)
3070
{
31-
unsigned int status_code = 0;
32-
int ret = sscanf(resp, ":%X ", &status_code);
33-
if (ret > 0) {
34-
return status_code;
71+
if (r != NULL) {
72+
return(strlen(r));
73+
} else {
74+
return 0;
3575
}
36-
else {
37-
return -1;
76+
}
77+
78+
char *exec_or_create(char *node)
79+
{
80+
if (strstr(node, "auth") != NULL || strstr(node, "exec") != NULL) {
81+
return "!";
82+
} else {
83+
return "+";
3884
}
3985
}
4086

41-
int ts_req_hdr_from_http(char *buf, size_t buf_size, int method, const char *uri)
87+
void ts_parse_uri(const char *uri, TSUriElems *params)
4288
{
43-
ESP_LOGI(TAG, "URI: %s, method: %d", uri, method);
89+
if (uri == NULL || uri[0] == '\0') {
90+
ESP_LOGE(TAG, "Got invalid uri");
91+
return;
92+
}
93+
params->ts_list_subnodes = uri[strlen(uri)] == '/' ? 0 : 1;
4494

45-
switch (method) {
46-
case HTTP_GET:
47-
buf[0] = '?';
95+
// copy uri so we can safely modify
96+
char *temp_uri = (char *) heap_caps_malloc((strlen(uri)+1), MALLOC_CAP_8BIT);
97+
if (temp_uri == NULL) {
98+
ESP_LOGE(TAG, "Unable to allocate memory for temp_uri");
99+
return;
100+
}
101+
strcpy(temp_uri, uri);
102+
// extract device ID
103+
int i = 0;
104+
while (temp_uri[i] != '\0' && temp_uri[i] != '/') {
105+
i++;
106+
}
107+
// replace '/' so we have two null-terminated strings
108+
temp_uri[i] = '\0';
109+
params->ts_device_id = temp_uri;
110+
// this points either to '\0' aka NULL or the rest of the string
111+
params->ts_target_node = temp_uri + i + 1;
112+
ESP_LOGD(TAG, "Device_id: %s", params->ts_device_id);
113+
ESP_LOGD(TAG, "Target Node: %s", params->ts_target_node);
114+
ESP_LOGD(TAG, "List the sub nodes: %s", params->ts_list_subnodes == 1 ? "yes" : "no");
115+
}
116+
117+
char *ts_build_query(uint8_t ts_method, TSUriElems *params)
118+
{
119+
// calculate size to allocate buffer
120+
int nbytes = 3; // method + termination + zero termination
121+
if (*(params->ts_target_node) == '\0' && params->ts_list_subnodes == 1) {
122+
nbytes++; // '/' at the end of query
123+
}
124+
nbytes += strlen_null(params->ts_target_node);
125+
if (params->ts_payload != NULL) {
126+
// additional whitespace between uri and array/json
127+
nbytes += strlen_null(params->ts_payload) +1;
128+
}
129+
char *ts_query = (char *) heap_caps_malloc(nbytes, MALLOC_CAP_8BIT);
130+
131+
if (ts_query == NULL) {
132+
ESP_LOGE(TAG, "Unable to allocate memory for ts_query");
133+
return NULL;
134+
}
135+
int pos = 0;
136+
switch (ts_method){
137+
case TS_GET:
138+
ts_query[pos] = '?';
48139
break;
49-
case HTTP_POST:
50-
buf[0] = '!';
140+
case TS_POST:
141+
ts_query[pos] = *(exec_or_create(params->ts_target_node));
51142
break;
52-
case HTTP_PATCH:
53-
buf[0] = '=';
143+
case TS_PATCH:
144+
ts_query[pos] = '=';
145+
break;
146+
case TS_DELETE:
147+
ts_query[pos] = '-';
54148
break;
55149
default:
56-
buf[0] = '\0'; // empty string
150+
ts_query[pos] = '\0';
151+
return ts_query; // nothing else to do here
152+
}
153+
pos++;
154+
// corner case for getting device categories
155+
if (*(params->ts_target_node) == '\0' && params->ts_list_subnodes == 1) {
156+
ts_query[pos] = '/';
157+
pos++;
158+
} else {
159+
strncpy(ts_query + pos, params->ts_target_node, strlen_null(params->ts_target_node));
160+
pos += strlen_null(params->ts_target_node);
161+
}
162+
if (params->ts_payload != NULL) {
163+
ts_query[pos] = ' ';
164+
pos++;
165+
strncpy(ts_query + pos, params->ts_payload, strlen_null(params->ts_payload));
166+
pos += strlen_null(params->ts_payload);
57167
}
168+
//terminate query properly
169+
ts_query[pos] = '\n';
170+
pos++;
171+
ts_query[pos] = '\0';
172+
ESP_LOGD(TAG, "Build query String: %s !", ts_query);
173+
return ts_query;
174+
}
58175

59-
int pos_function = strlen("/ts/serial/");
60-
int len_function = strlen(uri) - pos_function;
61-
if (len_function > 0) {
62-
int ret = snprintf(buf + 1, buf_size - 2, "%s", uri + pos_function);
63-
if (ret > 0) {
64-
return ret + 1;
65-
}
66-
else {
67-
buf[1] = '\0'; // terminate properly
176+
TSResponse *ts_execute(const char *uri, char *content, int http_method)
177+
{
178+
uint8_t ts_method;
179+
switch (http_method) {
180+
case HTTP_DELETE:
181+
ts_method = TS_DELETE;
182+
break;
183+
case HTTP_GET:
184+
ts_method = TS_GET;
185+
break;
186+
case HTTP_POST:
187+
ts_method = TS_POST;
188+
break;
189+
case HTTP_PATCH:
190+
ts_method = TS_PATCH;
191+
break;
192+
default:
193+
ts_method = TS_GET;
194+
break;
195+
}
196+
TSUriElems params;
197+
params.ts_payload = content;
198+
ts_parse_uri(uri, &params);
199+
TSDevice *device = ts_get_device(params.ts_device_id);
200+
if (device == NULL) {
201+
ESP_LOGD(TAG, "No Device, freeing query string and device id");
202+
heap_caps_free(params.ts_device_id);
203+
return NULL;
204+
}
205+
char *ts_query_string = ts_build_query(ts_method, &params);
206+
207+
TSResponse *res = (TSResponse *) heap_caps_malloc(sizeof(TSResponse), MALLOC_CAP_8BIT);
208+
if (res == NULL) {
209+
ESP_LOGE(TAG, "Unable to allocate memory for ts response");
210+
heap_caps_free(ts_query_string);
211+
heap_caps_free(params.ts_device_id);
212+
return NULL;
213+
}
214+
215+
res->block = device->send(ts_query_string, device->CAN_Address);
216+
if (res->block == NULL) {
217+
ESP_LOGD(TAG, "No Response, freeing query string and device id");
218+
heap_caps_free(ts_query_string);
219+
heap_caps_free(params.ts_device_id);
220+
heap_caps_free(res);
221+
return NULL;
222+
}
223+
res->ts_status_code = ts_resp_status(res->block);
224+
res->data = ts_resp_data(res->block);
225+
226+
heap_caps_free(ts_query_string);
227+
heap_caps_free(params.ts_device_id);
228+
229+
return res;
230+
}
231+
232+
char *ts_resp_data(char *resp)
233+
{
234+
if (resp[0] == ':') {
235+
char *pos = strstr(resp, ". ");
236+
if (pos != NULL) {
237+
return pos + 2;
68238
}
69239
}
70-
return 0;
240+
return NULL;
241+
}
242+
243+
int ts_resp_status(char *resp)
244+
{
245+
unsigned int status_code = 0;
246+
int ret = sscanf(resp, ":%X ", &status_code);
247+
if (ret > 0) {
248+
return status_code;
249+
}
250+
else {
251+
return -1;
252+
}
71253
}

0 commit comments

Comments
 (0)