/* * Usage: * * new UART("platform_specific_name") * */ static enum v7_err UART_ctor(struct v7 *v7, v7_val_t *res) { (void) res; enum v7_err rcode = V7_OK; v7_val_t this_obj = v7_get_this(v7); v7_val_t dev = v7_arg(v7, 0); struct user_data *ud; void *uart; const char *name; size_t len; if (!v7_is_string(dev)) { rcode = v7_throwf(v7, "Error", "device must be string"); goto clean; } ud = (struct user_data *) calloc(1, sizeof(struct user_data)); ud->v7 = v7; ud->want = 0; ud->cb = V7_UNDEFINED; v7_own(v7, &ud->cb); name = v7_get_string(v7, &dev, &len); uart = sj_hal_open_uart(name, (void *) ud); if (uart == NULL) { rcode = v7_throwf(v7, "Error", "cannot open uart"); goto clean; } v7_def(v7, this_obj, "_ud", ~0, _V7_DESC_HIDDEN(1), v7_mk_foreign(v7, ud)); v7_def(v7, this_obj, "_dev", ~0, _V7_DESC_HIDDEN(1), v7_mk_foreign(v7, uart)); clean: return rcode; }
void sj_init_uart(struct v7 *v7) { v7_val_t uart = V7_UNDEFINED, uart_proto = V7_UNDEFINED, uart_ctor = V7_UNDEFINED; v7_own(v7, &uart); v7_own(v7, &uart_proto); v7_own(v7, &uart_ctor); uart = v7_mk_object(v7); uart_proto = v7_mk_object(v7); uart_ctor = v7_mk_function_with_proto(v7, UART_ctor, uart_proto); v7_def(v7, uart, "dev", ~0, _V7_DESC_HIDDEN(1), uart_ctor); v7_set_method(v7, uart_proto, "read", UART_read); v7_set_method(v7, uart_proto, "write", UART_write); v7_set_method(v7, uart_proto, "recv", UART_recv); v7_set(v7, v7_get_global(v7), "UART", ~0, uart); { enum v7_err rcode = v7_exec( v7, "UART.open = function (d) { return new UART.dev(d); }", NULL); assert(rcode == V7_OK); #if defined(NDEBUG) (void) rcode; #endif } v7_disown(v7, &uart_ctor); v7_disown(v7, &uart_proto); v7_disown(v7, &uart); }
V7_PRIVATE v7_val_t mk_cfunction_obj(struct v7 *v7, v7_cfunction_t *f, int num_args) { val_t obj = mk_object(v7, v7->vals.function_prototype); struct gc_tmp_frame tf = new_tmp_frame(v7); tmp_stack_push(&tf, &obj); v7_def(v7, obj, "", 0, _V7_DESC_HIDDEN(1), v7_mk_cfunction(f)); if (num_args >= 0) { v7_def(v7, obj, "length", 6, (V7_DESC_ENUMERABLE(0) | V7_DESC_WRITABLE(0) | V7_DESC_CONFIGURABLE(0)), v7_mk_number(v7, num_args)); } tmp_frame_cleanup(&tf); return obj; }
static void set_clubby(struct v7 *v7, v7_val_t obj, struct clubby *clubby) { v7_def(v7, obj, s_clubby_prop, sizeof(s_clubby_prop), (V7_DESC_WRITABLE(0) | V7_DESC_CONFIGURABLE(0) | _V7_DESC_HIDDEN(1)), v7_mk_foreign(v7, clubby)); }
static void mqtt_ev_handler(struct mg_connection *nc, int ev, void *ev_data) { struct mg_mqtt_message *msg = (struct mg_mqtt_message *) ev_data; struct user_data *ud = (struct user_data *) nc->user_data; struct v7 *v7 = ud->v7; v7_val_t cb; (void) nc; (void) ev_data; switch (ev) { case MG_EV_CONNECT: if (*(int *) ev_data == 0) { mg_send_mqtt_handshake(nc, ud->client_id); } else { cb = v7_get(v7, ud->client, SJ_MQTT_ERROR_CB, ~0); if (!v7_is_undefined(cb)) { sj_invoke_cb0(v7, cb); } } break; case MG_EV_MQTT_CONNACK: { /* * Call connect or error cb if they were registered. */ const char *key; if (msg->connack_ret_code == MG_EV_MQTT_CONNACK_ACCEPTED) { key = SJ_MQTT_CONNECT_CB; } else { key = SJ_MQTT_ERROR_CB; } cb = v7_get(v7, ud->client, key, ~0); if (!v7_is_undefined(cb)) { sj_invoke_cb0(v7, cb); } break; } case MG_EV_MQTT_PUBLISH: cb = v7_get(v7, ud->client, SJ_MQTT_MESSAGE_CB, ~0); if (!v7_is_undefined(cb)) { v7_val_t topic = v7_mk_string(v7, msg->topic, strlen(msg->topic), 1); v7_val_t payload = v7_mk_string(v7, msg->payload.p, msg->payload.len, 1); sj_invoke_cb2(v7, cb, topic, payload); } break; case MG_EV_CLOSE: /* * Invoke close cb and then destroys all mg state. */ cb = v7_get(v7, ud->client, SJ_MQTT_CLOSE_CB, ~0); if (!v7_is_undefined(cb)) { sj_invoke_cb0(v7, cb); } v7_def(v7, ud->client, "_nc", ~0, _V7_DESC_HIDDEN(1), V7_UNDEFINED); v7_disown(v7, &ud->client); free(ud->client_id); free(ud); break; } }
/* * Make a new MQTT client. * * Arguments: * url: url where to connect to * opts: option object * * Recognized option object properties: * * - clientId: string; mqtt client id. defaults to * Math.random().toString(16).substr(2, 10) * * Example: * * var client = MQTT.connect('mqtt://test.mosquitto.org'); * * client.on('connect', function () { * client.subscribe('presence'); * client.publish('presence', 'Hello mqtt'); * }); * * client.on('message', function (topic, message) { * console.log(message); * }); * * TLS can be enabled by choosing the `mqtts://` protocol. In that * case the default port is 8883 as defined by IANA. * * The API is modeled after https://www.npmjs.com/package/mqtt. * */ enum v7_err sj_mqtt_connect(struct v7 *v7, v7_val_t *res) { enum v7_err rcode = V7_OK; const char *url; size_t len; struct mg_str host, scheme; unsigned int port; struct mg_connection *nc; struct user_data *ud; char *url_with_port = NULL; int use_ssl = 0; v7_val_t urlv = v7_arg(v7, 0), opts = v7_arg(v7, 1); v7_val_t client_id; v7_val_t proto = v7_get(v7, v7_get(v7, v7_get_global(v7), "MQTT", ~0), "proto", ~0); if (!v7_is_string(urlv)) { rcode = v7_throwf(v7, "Error", "invalid url string"); goto clean; } url = v7_get_string(v7, &urlv, &len); if (mg_parse_uri(mg_mk_str(url), &scheme, NULL, &host, &port, NULL, NULL, NULL) < 0) { rcode = v7_throwf(v7, "Error", "invalid url string"); goto clean; } if (mg_vcmp(&scheme, "mqtt") == 0) { url += sizeof("mqtt://") - 1; } else if (mg_vcmp(&scheme, "mqtts") == 0) { url += sizeof("mqtts://") - 1; use_ssl = 1; } else { rcode = v7_throwf(v7, "Error", "unsupported protocol"); goto clean; } client_id = v7_get(v7, opts, "clientId", ~0); if (v7_is_undefined(client_id)) { rcode = v7_exec(v7, "Math.random().toString(16).substr(2,8)", &client_id); if (rcode != V7_OK) { goto clean; } } if (port == 0) { if (asprintf(&url_with_port, "%.*s%s", (int) host.len, host.p, (use_ssl ? ":8883" : ":1883")) < 0) { rcode = v7_throwf(v7, "Error", "Out of memory"); goto clean; } } nc = mg_connect(&sj_mgr, url_with_port ? url_with_port : url, mqtt_ev_handler); if (nc == NULL) { rcode = v7_throwf(v7, "Error", "cannot create connection"); goto clean; } if (use_ssl) { #ifdef MG_ENABLE_SSL mg_set_ssl(nc, NULL, NULL); #else rcode = v7_throwf(v7, "Error", "SSL not enabled"); goto clean; #endif } mg_set_protocol_mqtt(nc); *res = v7_mk_object(v7); v7_set_proto(v7, *res, proto); ud = calloc(1, sizeof(*ud)); if (ud == NULL) { rcode = v7_throwf(v7, "Error", "Out of memory"); goto clean; } ud->v7 = v7; ud->client = *res; ud->client_id = strdup(v7_get_cstring(v7, &client_id)); if (ud->client_id == NULL) { free(ud); rcode = v7_throwf(v7, "Error", "Out of memory"); goto clean; } nc->user_data = ud; v7_own(v7, &ud->client); v7_def(v7, *res, "_nc", ~0, _V7_DESC_HIDDEN(1), v7_mk_foreign(v7, nc)); clean: free(url_with_port); return rcode; }