Example node for Yodiwo's Plegma API
Dependencies: EthernetInterface FXOS8700Q HTTPClient HTTPD MQTTS SDFileSystem YodiwoPlegma mbed-rpc mbed-rtos mbed wolfSSL
Revision 2:b7489c070d1f, committed 2015-09-04
- Comitter:
- mitsarionas
- Date:
- Fri Sep 04 08:41:34 2015 +0000
- Parent:
- 1:c5abc450140c
- Child:
- 3:11b767300d32
- Commit message:
- pairing & configuration read/write working
Changed in this revision
--- a/HTTPD.lib Tue Sep 01 12:01:50 2015 +0000 +++ b/HTTPD.lib Fri Sep 04 08:41:34 2015 +0000 @@ -1,1 +1,1 @@ -http://mbed.org/users/okini3939/code/HTTPD/#d18dff347122 +http://mbed.org/users/okini3939/code/HTTPD/#f30e7b210e53
--- a/MQTT.lib Tue Sep 01 12:01:50 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -http://mbed.org/teams/mqtt/code/MQTT/#e335fcc1a663
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MQTTS.lib Fri Sep 04 08:41:34 2015 +0000 @@ -0,0 +1,1 @@ +http://developer.mbed.org/users/wolfSSL/code/MQTTS/#d8968fcc21b8
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/config.cpp Fri Sep 04 08:41:34 2015 +0000 @@ -0,0 +1,67 @@ +#include "jsmn.h" +#include "config.h" +#include <string.h> +#include <stdio.h> + +Yodiwo_Plegma_Json_e Configuration_FromJson(char* json, size_t jsonSize, config_t *config) +{ + memset(config, 0, sizeof(config_t)); + ParseTable table[] = { + { "uuid", 4, Parse_String, NULL, (void **)&config->uuid }, + { "name", 4, Parse_String, NULL, (void **)&config->name }, + { "nodeKey", 7, Parse_String, NULL, (void **)&config->nodeKey }, + { "nodeSecret", 10, Parse_String, NULL, (void **)&config->nodeSecret }, + { "pairingServerUrl", 16, Parse_String, NULL, (void **)&config->pairingServerUrl }, + { "ypchannelServer", 15, Parse_String, NULL, (void **)&config->ypchannelServer }, + { "ypchannelServerPort", 19, Parse_Int, NULL, (void **)&config->ypchannelServerPort }, + { "webPort", 7, Parse_Int, NULL, (void **)&config->webPort }, + { "mqttBrokerHostname", 18, Parse_String, NULL, (void **)&config->mqttBrokerHostname }, + }; + return HelperJsonParseExec(json, jsonSize, table, sizeof(table) / sizeof(table[0])); +} + +int Configuration_ToJson(char* jsonStart, size_t jsonSize, config_t *config) +{ + char *json = jsonStart, *jsonEnd = json + jsonSize; + json += snprintf(json, jsonEnd - json, "{ \"uuid\" : \"%s\"", config->uuid); if (json >= jsonEnd) return -1; + json += snprintf(json, jsonEnd - json, ", \"name\" : \"%s\"", config->name); if (json >= jsonEnd) return -1; + json += snprintf(json, jsonEnd - json, ", \"nodeKey\" : \"%s\"", config->nodeKey); if (json >= jsonEnd) return -1; + json += snprintf(json, jsonEnd - json, ", \"nodeSecret\" : \"%s\"", config->nodeSecret); if (json >= jsonEnd) return -1; + json += snprintf(json, jsonEnd - json, ", \"pairingServerUrl\" : \"%s\"", config->pairingServerUrl); if (json >= jsonEnd) return -1; + json += snprintf(json, jsonEnd - json, ", \"ypchannelServer\" : \"%s\"", config->ypchannelServer); if (json >= jsonEnd) return -1; + json += snprintf(json, jsonEnd - json, ", \"ypchannelServerPort\" : %d", config->ypchannelServerPort); if (json >= jsonEnd) return -1; + json += snprintf(json, jsonEnd - json, ", \"webPort\" : %d", config->webPort); if (json >= jsonEnd) return -1; + json += snprintf(json, jsonEnd - json, ", \"mqttBrokerHostname\" : \"%s\"", config->mqttBrokerHostname); if (json >= jsonEnd) return -1; + *json = '}'; json++; + *json = '\0'; json++; + return json - jsonStart; +} + + +//TODO: proper +static char buf[1024]; + +int read_config(config_t *config, char *filename) +{ + FILE *f = fopen(filename, "r"); + if (f == NULL) { + return -1; + } + int size = fread(buf, 1, 1024, f); + buf[size] = '\0'; + fclose(f); + return Configuration_FromJson(buf, size, config); +} + +int write_config(config_t *config, char *filename) +{ + FILE *f = fopen(filename, "w"); + if (f == NULL) { + return -1; + } + int r = Configuration_ToJson(buf, 1024, config); + if (r < 0) return r; + fwrite(buf, r - 1, 1, f); + fclose(f); + return 0; +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/config.h Fri Sep 04 08:41:34 2015 +0000 @@ -0,0 +1,33 @@ +#ifndef __CONFIG_H__ +#define __CONFIG_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdint.h> +#include <stdlib.h> +#include "yodiwo_helpers.h" + +typedef struct +{ + char *uuid; + char *name; + char *nodeKey; + char *nodeSecret; + char *pairingServerUrl; + char *ypchannelServer; + int32_t ypchannelServerPort; + int32_t webPort; + char *mqttBrokerHostname; +} config_t; + + +int read_config(config_t *config, char *filename); +int write_config(config_t *config, char *filename); + +#ifdef __cplusplus +} +#endif + +#endif /* __CONFIG_H__ */ \ No newline at end of file
--- a/main.cpp Tue Sep 01 12:01:50 2015 +0000 +++ b/main.cpp Fri Sep 04 08:41:34 2015 +0000 @@ -7,10 +7,12 @@ //#include "HTTPServer.h" //#include "LocalFileSystem.h" #include "SDFileSystem.h" // SD File System functions -//#include "HTTPRequestHandler.h" + #include "FsHandler.h" #include "RpcHandler.h" #include "pairing_backend.h" +#include "pairing_http_handler.h" +#include "config.h" #define DAT0 PTE3 // MOSI #define CMD PTE1 // MISO @@ -25,7 +27,7 @@ uint32_t button_pressed; Thread *thread2; //HTTPServer server; -HTTPD *httpd; +extern HTTPD *httpd; // Instantiate a local file system handler named 'local' which will be used later to access files on the mbed. //LocalFileSystem local("local"); @@ -33,8 +35,14 @@ SDFileSystem sd(DAT0, CMD, CLK, CD, "sd"); // MOSI, MISO, SCLK, CS //Serial pc(USBTX, USBRX); // Virtual COM Port +//MQTTEthernet ipstack; +MQTTSocket ipstack; +//MQTT::Client<MQTTEthernet, Countdown> *client; -pairing_context pairing_state; + +config_t configuration; + +extern pairing_context pairing_state; void pairing_done(char *nodeKey, char *secretKey); @@ -59,79 +67,35 @@ } } -void httpd_thread(void const *arg) -{ -// HTTPD *server; -// server = HTTPD::getInstance(); -// -// server->start(8080); -} - void callback_pairing (int id); int main() { Thread thread(led_thread); // thread2 = new Thread(button_thread); - -// FILE *File = fopen("/sd/sdfile.txt", "w"); // open file -// if(File == NULL) { // check if present -// printf("No SD Card or bad format\n"); // print message -// } else { // otherwise -// printf("Ready to write\n"); // message preparing to write -// } -// fprintf(File, "FRDM-K64F"); // write data -// fclose(File); // close file on SD - eth.init(); - eth.connect(); printf("IP Address is %s\n", eth.getIPAddress()); -// MQTTEthernet ipstack = MQTTEthernet(); -// MQTT::Client<MQTTEthernet, Countdown> client = MQTT::Client<MQTTEthernet, Countdown>(ipstack); -// - -// TCPSocketConnection sock; -// sock.connect("mbed.org", 80); -// -// char http_cmd[] = "GET /media/uploads/mbed_official/hello.txt HTTP/1.0\n\n"; -// sock.send_all(http_cmd, sizeof(http_cmd)-1); -// -// char buffer[300]; -// int ret; -// while (true) { -// ret = sock.receive(buffer, sizeof(buffer)-1); -// if (ret <= 0) -// break; -// buffer[ret] = '\0'; -// printf("Received %d chars from server:\n%s\n", ret, buffer); -// } -// -// sock.close(); + int r = read_config(&configuration, "/sd/config.json"); + printf("read config returned: %d\n", r); -// HTTPFsRequestHandler::mount("/sd/", "/"); -// server.addHandler<HTTPFsRequestHandler>("/"); + printf("p: %p %p\n", configuration.nodeKey, configuration.nodeSecret); + printf("...: %d %d\n", configuration.nodeKey[0], configuration.nodeKey[1]); + if (!configuration.nodeKey) { + printf("not paired, launching HTTP server for pairing\n"); + start_pairing_http_server(ð, 80, pairing_done); + } else { -// HTTPFsRequestHandler::mount("/sd/", "/"); -// server.addHandler<HTTPRpcRequestHandler>("/"); -// -// if (!server.start(80, ð)) { -// error("Server not starting !"); -// exit(0); -// } -// - httpd = new HTTPD; -// httpd->attach("/cgi-bin/", &callback_cgi); -// httpd->attach("/ws/", &callback_ws); - httpd->attach("/pairing_functions/", &callback_pairing); - httpd->attach("/", "/sd/www/"); - httpd->start(80); + printf("found NodeKey: %s, proceeding to connection\n", configuration.nodeKey); + } + + ipstack = MQTTSocket(); +// client = new MQTT::Client<MQTTEthernet, Countdown>(ipstack); -// Thread thread3(httpd_thread); // eth.disconnect(); -// + button_pressed = 0; sw2.fall(&sw2_press); @@ -143,33 +107,18 @@ } } -void callback_pairing (int id) { - int i, n; - char buf[256]; - - if (!strcmp(httpd->getFilename(id), "start_pairing")) { - printf("starting pairing...\n"); - pairing_context_init_with_defaults(&pairing_state, pairing_done); - start_pairing(&pairing_state); - } - strcpy(buf, httpd->getFilename(id)); - strcat(buf, "\r\n"); - strcat(buf, httpd->getQueryString(id)); - strcat(buf, "\r\n"); - n = strlen(buf); - - i = httpd->receive(id, &buf[n], sizeof(buf) - n); - if (i < 0) return; - i += n; - buf[i] = 0; - - printf("CGI %d %s\r\n", id, buf); - httpd->send(id, buf, i, "Content-Type: text/plain\r\n"); -} void pairing_done(char *nodeKey, char *secretKey) { printf("pairing done!\n"); printf("NokeKey: %s\n", nodeKey); printf("SecretKey: %s\n", secretKey); + configuration.nodeKey = nodeKey; + configuration.nodeSecret = secretKey; + int r = write_config(&configuration, "/sd/config.json"); + if (r < 0) { + printf("error writing config to file\n"); + } else { + printf("successfully written new config to file\n"); + } }
--- a/pairing_backend.cpp Tue Sep 01 12:01:50 2015 +0000 +++ b/pairing_backend.cpp Fri Sep 04 08:41:34 2015 +0000 @@ -4,10 +4,17 @@ #include "rtos.h" #include "yodiwo_helpers.h" #include "jsmn.h" +#include "config.h" HTTPClient http; char recvBuff[1024*20]; int __get_tokens(pairing_context *ctx); +int __get_keys(pairing_context *ctx); + +int do_on_thread(function_with_result func, void *args, unsigned int stack_size); +void __thread_wrapper(void const *arg); + +#define PAGE_SERVER_PHASE2 "userconfirm" int pairing_context_init_with_defaults(pairing_context *ctx, onPaired_callback callback) { @@ -18,35 +25,77 @@ return 0; } +extern config_t configuration; + +int pairing_context_init_from_config(pairing_context *ctx, onPaired_callback callback) +{ + printf("server url: %s\n", configuration.pairingServerUrl); + printf("uuid: %s\n", configuration.uuid); + printf("name: %s\n", configuration.name); + ctx->postUrl = configuration.pairingServerUrl; + ctx->uuid = configuration.uuid; + ctx->name = configuration.name; + ctx->onPaired = callback; + return 0; +} + #define STACK_SIZE 24000 -void get_tokens_thread(void const *arg); -int start_pairing(pairing_context *ctx) +int pairing_get_tokens(pairing_context *ctx) { printf("getting tokens from server\n"); - Thread t(get_tokens_thread, ctx, osPriorityNormal, STACK_SIZE); + return do_on_thread((function_with_result)__get_tokens, ctx, STACK_SIZE); +} + +char* get_server_phase2_url(pairing_context *ctx, char *nodeUrlBase) +{ + int len = 200; //TODO: proper calculation + char* result = (char *)malloc(sizeof(char) * len); + if (!result) + return NULL; + sprintf(result, "%s" PAGE_SERVER_PHASE2 "?token2=%s&noderedirect=%snext", ctx->postUrl, ctx->token2, nodeUrlBase); + return result; +} + +int pairing_get_keys(pairing_context *ctx) +{ + printf("getting keys from server\n"); + return do_on_thread((function_with_result)__get_keys, ctx, STACK_SIZE); +} + +char str[512]; +char url[100]; + +struct thread_info +{ + function_with_result func; + void * args; + int result; +}; + +void __thread_wrapper(void const *arg) +{ + struct thread_info *info = (struct thread_info *)arg; + info->result = info->func(info->args); +} + +int do_on_thread(function_with_result func, void *args, unsigned int stack_size) +{ + struct thread_info info; + info.func = func; + info.args = args; + Thread t(__thread_wrapper, &info, osPriorityNormal, stack_size); while (t.get_state() != Thread::Inactive) { // printf("yielding... %d\n", t.get_state()); // Thread::yield(); // Thread::wait(1000); } - printf("thread ended?\n"); - return 0; -} - -char str[512]; -char url[100]; - -void get_tokens_thread(void const *arg) -{ - printf("in thread\n"); - __get_tokens((pairing_context *)arg); + return info.result; } int __get_tokens(pairing_context *ctx) { - strcpy(url, ctx->postUrl); strcat(url, "/gettokens"); http.dumpReqHeader(true); @@ -87,8 +136,6 @@ printf("error parsing response"); return -2; } - - } else { @@ -98,3 +145,41 @@ } + +int __get_keys(pairing_context *ctx) +{ + strcpy(url, ctx->postUrl); + strcat(url, "/getkeys"); + http.dumpReqHeader(true); + http.dumpResHeader(true); + int ret; + + //POST data + HTTPMap map; + HTTPText inText(str, 512); + map.put("uuid", ctx->uuid); + map.put("token1", ctx->token1); + printf("\nTrying to post data...\n"); + ret = http.post(url, map, &inText); + Yodiwo_Plegma_PairingServerKeysResponse_t keys; + if (!ret) + { + printf("Executed POST successfully - read %d characters\n", strlen(str)); + printf("Result: %s\n", str); + int jret = Yodiwo_Plegma_PairingServerKeysResponse_FromJson(str, strlen(str), &keys); + if (jret == Yodiwo_JsonSuccessParse) { + ctx->nodeKey = keys.nodeKey; + ctx->secretKey = keys.secretKey; + return 0; + } else { + printf("error parsing response"); + return -2; + } + } + else + { + printf("Error - ret = %d - HTTP return code = %d\n", ret, http.getHTTPResponseCode()); + } + return ret; + +}
--- a/pairing_backend.h Tue Sep 01 12:01:50 2015 +0000 +++ b/pairing_backend.h Fri Sep 04 08:41:34 2015 +0000 @@ -12,6 +12,8 @@ typedef void (*onPaired_callback)(char *nodeKey, char *secretKey); +typedef int (*function_with_result)(void *arg); + typedef struct { char *postUrl; @@ -31,13 +33,12 @@ } tokens_t; int pairing_context_init_with_defaults(pairing_context *ctx, onPaired_callback callback); - -int start_pairing(pairing_context *ctx); - +int pairing_context_init_from_config(pairing_context *ctx, onPaired_callback callback); - +int pairing_get_tokens(pairing_context *ctx); +int pairing_get_keys(pairing_context *ctx); - +char* get_server_phase2_url(pairing_context *ctx, char *nodeUrlBase); #ifdef __cplusplus }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pairing_http_handler.cpp Fri Sep 04 08:41:34 2015 +0000 @@ -0,0 +1,79 @@ +#include "EthernetInterface.h" +#include "HTTPD.h" +#include "string.h" +#include "pairing_backend.h" +#include "pairing_http_handler.h" + +HTTPD *httpd; +pairing_context pairing_state; +onPaired_callback pairing_done_cb; +EthernetInterface *interface; +void pairing_handler (int id); + +int start_pairing_http_server(EthernetInterface *eth, int port, onPaired_callback onPaired) +{ + pairing_done_cb = onPaired; + interface = eth; + httpd = new HTTPD; +// httpd->attach("/cgi-bin/", &callback_cgi); +// httpd->attach("/ws/", &callback_ws); + httpd->attach("/pairing/", &pairing_handler); + httpd->attach("/", "/sd/www/"); + return httpd->start(port); +} + +void pairing_handler (int id) +{ + int i, n; + int ret; + char buf[256]; + char backUrl[100]; + + if (!strcmp(httpd->getFilename(id), "startpairing")) { + printf("starting pairing...\n"); + pairing_context_init_from_config(&pairing_state, pairing_done_cb); + pairing_get_tokens(&pairing_state); + + int idx = 0; + i = 0; + sprintf(backUrl, "http://%s", interface->getIPAddress()); + char *uri = httpd->getUri(id); + printf("1st url part: %s\n",backUrl); + while (uri[i] != '\0') { + if (uri[i] == '/') { + idx = i; + } + i++; + } + strncat(backUrl, uri, idx + 1); + printf("more of url: %s\n", backUrl); + char *redirect = get_server_phase2_url(&pairing_state, backUrl); + printf("redirect url: %s\n", redirect); + if (redirect) { + httpd->redirect(id, 302, redirect, NULL, 0, NULL); +// free(redirect); + return; + } + + } else if (!strcmp(httpd->getFilename(id), "next")) { + ret = pairing_get_keys(&pairing_state); + pairing_done_cb(pairing_state.nodeKey, pairing_state.secretKey); + sprintf(buf, "OK\r\nnodeKey: %s\r\nsecretKey: %s\r\n", pairing_state.nodeKey, pairing_state.secretKey); + httpd->send(id, buf, strlen(buf), "Content-Type: text/plain\r\n"); + } else { + httpd->httpdError(id, 404); + } + strcpy(buf, httpd->getFilename(id)); + strcat(buf, "\r\n"); + strcat(buf, httpd->getQueryString(id)); + strcat(buf, "\r\n"); + n = strlen(buf); + + i = httpd->receive(id, &buf[n], sizeof(buf) - n); + if (i < 0) return; + i += n; + buf[i] = 0; + + printf("CGI %d %s\r\n", id, buf); +// httpd->send(id, buf, i, "Content-Type: text/plain\r\n"); +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pairing_http_handler.h Fri Sep 04 08:41:34 2015 +0000 @@ -0,0 +1,20 @@ + +#ifndef __PAIRING_HTTP_HANDLER_H__ +#define __PAIRING_HTTP_HANDLER_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "pairing_backend.h" + +int start_pairing_http_server(EthernetInterface *eth, int port, onPaired_callback onPaired); + +void pairing_handler(int id); + + +#ifdef __cplusplus +} +#endif + +#endif /* __PAIRING_HTTP_HANDLER_H__ */ \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/snippets.cpp Fri Sep 04 08:41:34 2015 +0000 @@ -0,0 +1,66 @@ + +///////////////////////////////////// FILE SYSTEM ////////////////////////////////////////// + +#include "SDFileSystem.h" // SD File System functions + +//#define DAT0 PTE3 // MOSI +//#define CMD PTE1 // MISO +//#define CLK PTE2 // SCLK +//#define CD PTE4 // CS + +//SDFileSystem sd(DAT0, CMD, CLK, CD, "sd"); // MOSI, MISO, SCLK, CS + +void file_stuff() +{ + FILE *File = fopen("/sd/sdfile.txt", "w"); // open file + if(File == NULL) { // check if present + printf("No SD Card or bad format\n"); // print message + } else { // otherwise + printf("Ready to write\n"); // message preparing to write + } + fprintf(File, "FRDM-K64F"); // write data + fclose(File); // close file on SD +} + +//////////////////////////////////////////////////////////////////////////////////////// + +///////////////////////////////////// TCP ////////////////////////////////////////// + +// TCPSocketConnection sock; +// sock.connect("mbed.org", 80); +// +// char http_cmd[] = "GET /media/uploads/mbed_official/hello.txt HTTP/1.0\n\n"; +// sock.send_all(http_cmd, sizeof(http_cmd)-1); +// +// char buffer[300]; +// int ret; +// while (true) { +// ret = sock.receive(buffer, sizeof(buffer)-1); +// if (ret <= 0) +// break; +// buffer[ret] = '\0'; +// printf("Received %d chars from server:\n%s\n", ret, buffer); +// } +// +// sock.close(); + + +///////////////////////////////////// MQTT ////////////////////////////////////////// + +// MQTTEthernet ipstack = MQTTEthernet(); +// MQTT::Client<MQTTEthernet, Countdown> client = MQTT::Client<MQTTEthernet, Countdown>(ipstack); + + + +///////////////////////////////////// other http server ////////////////////////////////////////// + +// HTTPFsRequestHandler::mount("/sd/", "/"); +// server.addHandler<HTTPFsRequestHandler>("/"); + + +// +// if (!server.start(80, ð)) { +// error("Server not starting !"); +// exit(0); +// } +// \ No newline at end of file
--- a/yodiwo.lib Tue Sep 01 12:01:50 2015 +0000 +++ b/yodiwo.lib Fri Sep 04 08:41:34 2015 +0000 @@ -1,1 +1,1 @@ -yodiwo#384a04dc912e +yodiwo#e204589f4229