// Copyright (c) 2020 Cesanta Software Limited // All rights reserved // // Example Websocket server. See https://mongoose.ws/tutorials/websocket-server/ #include "mongoose.h" #include "datadef.h" #define PWR_TYPE PDU_AC_I3O3 static const char *s_listen_on = "ws://localhost"; static const char *s_web_root = "."; static void send_powerc(struct mg_connection* c); static int ws_send(struct mg_connection* c, int type, void *data, int len) { pkt_hdr_t* h = (pkt_hdr_t*)malloc(sizeof(pkt_hdr_t)+len); if (!h) { return -1; } h->magic = PKT_MAGIC; h->type = type; h->nack = 3; h->dlen = len; memcpy(h->data, data, len); mg_ws_send(c, (const void*)h, sizeof(pkt_hdr_t) + len, WEBSOCKET_OP_BINARY); return 0; } // This RESTful server implements the following endpoints: // /websocket - upgrade to Websocket, and implement websocket echo server // /rest - respond with JSON string {"result": 123} // any other URI serves static files from s_web_root static void fn(struct mg_connection *c, int ev, void *ev_data) { if (ev == MG_EV_WS_OPEN) { } else if (ev == MG_EV_HTTP_MSG) { struct mg_http_message *hm = (struct mg_http_message *) ev_data; if (mg_match(hm->uri, mg_str("/ws"), NULL)) { // Upgrade to websocket. From now on, a connection is a full-duplex // Websocket connection, which will receive MG_EV_WS_MSG events. mg_ws_upgrade(c, hm, NULL); } else if (mg_match(hm->uri, mg_str("/rest"), NULL)) { // Serve REST response mg_http_reply(c, 200, "", "{\"result\": %d}\n", 123); } else { // Serve static files struct mg_http_serve_opts opts = {.root_dir = s_web_root}; mg_http_serve_dir(c, (struct mg_http_message*)ev_data, &opts); } } else if (ev == MG_EV_WS_MSG) { // Got websocket frame. Received data is wm->data. Echo it back! struct mg_ws_message *wm = (struct mg_ws_message *) ev_data; pkt_hdr_t *h= (pkt_hdr_t*)wm->data.buf; power_total_t* pt = (power_total_t*)h->data; //mg_ws_send(c, wm->data.buf, wm->data.len, WEBSOCKET_OP_TEXT); } } static float rand_float(float min, float max) { return ((float)rand()/(float)RAND_MAX) * (max - min) + min; } static void powert_rand(power_total_t *pt) { int i,cnt = 1; #if 0 pt->voltage = 1.1f; pt->current = 2.2f; pt->freq = 3.3f; pt->power = 4.4f; pt->consump = 5.5f; pt->active = 6.6f; pt->reactive = 7.7f; pt->apparent = 8.8f; #else if (pt->type >= PDU_AC_I3O3) { cnt = 3; } for (i = 0; i < cnt; i++) { pt->total[i].voltage = rand_float(1.0f, 100.0f); pt->total[i].current = rand_float(1.0f, 100.0f); pt->total[i].freq = rand_float(1.0f, 100.0f); pt->total[i].power = rand_float(1.0f, 100.0f); pt->total[i].consump = rand_float(1.0f, 100.0f); pt->total[i].active = rand_float(1.0f, 100.0f); pt->total[i].reactive = rand_float(1.0f, 100.0f); pt->total[i].apparent = rand_float(1.0f, 100.0f); } #endif } static void thrval_set(thr_val_t* tv) { tv->en = 0; tv->val = 100.0f; tv->act = 0; memset(tv->para, 0, 14); } static void thr_set(thr_t *thr) { thrval_set(&thr->v_upper); thrval_set(&thr->v_lower); thrval_set(&thr->c_upper); thrval_set(&thr->p_upper); thrval_set(&thr->w_upper); } static void alarm_set(alarm_t* a) { a->v_upper = 0; a->v_lower = 0; a->c_upper = 0; a->p_upper = 0; a->w_upper = 0; } static void powerc_rand(power_ch_t* pc, uint8_t addr, uint8_t ch, uint8_t sch) { int i,cnt = 1; pc->info.type = PWR_TYPE; pc->info.addr = addr; pc->info.ch = ch; pc->info.sch = sch; pc->info.ph_id = 0; pc->info.start_delay = 0; pc->info.stop_delay = 0; thr_set(&pc->thr); alarm_set(&pc->alarm); if (pc->info.type >= PDU_AC_I3O3) { cnt = 3; } for (i = 0; i < cnt; i++) { pc->power[i].voltage = rand_float(100.0f, 400.0f); pc->power[i].current = rand_float(1.0f, 100.0f); pc->power[i].freq = 50.0f; pc->power[i].power = rand_float(1.0f, 100.0f); pc->power[i].consump = rand_float(1.0f, 100.0f); pc->power[i].factor = rand_float(0.0f, 1.0f); pc->power[i].status = 1; pc->power[i].nwire = 0; } pc->time = 0; } static void send_powerc(struct mg_connection *c) { int i,j,ch=0; power_ch_t pc; #if 1 #define BOARD_CNT 2 #define BOARC_CH_CNT 2 //uint8_t addr[BOARD_CNT] = {2,4,6,7,8}; uint8_t addr[BOARD_CNT] = { 2,4}; #else #define BOARD_CNT 1 #define BOARC_CH_CNT 1 uint8_t addr[BOARD_CNT] = { 2 }; #endif for (i = 0; i < BOARD_CNT; i++) { for (j = 0; j < BOARC_CH_CNT; j++) { powerc_rand(&pc, addr[i], ch, j); ws_send(c, PKT_TYPE_POWER_CH , &pc, sizeof(pc)); ch++; } } } static void send_powert(struct mg_connection* c) { power_total_t pt; powert_rand(&pt); ws_send(c, PKT_TYPE_POWER_TOTAL , &pt, sizeof(pt)); } static void send_alarm(struct mg_connection* c) { alarm_data_t a; a.ch = 0; a.alarm.v_upper = 1; a.alarm.v_lower = 0; a.alarm.c_upper = 0; a.alarm.p_upper = 0; a.alarm.w_upper = 0; a.time = 0; ws_send(c, PKT_TYPE_ALARM, &a, sizeof(a)); } static void timer_fn(void* arg) { static uint32_t cnt = 0; struct mg_mgr* mgr = (struct mg_mgr*)arg; cnt++; for (struct mg_connection* c = mgr->conns; c != NULL; c = c->next) { send_powerc(c); send_powert(c); if (cnt%10==0) { send_alarm(c); } } } int main(void) { struct mg_mgr mgr; // Event manager srand((uint32_t)time(NULL)); mg_mgr_init(&mgr); // Initialise event manager printf("ws server on %s/ws\n", s_listen_on); mg_timer_add(&mgr, 1000, MG_TIMER_REPEAT, timer_fn, &mgr); mg_http_listen(&mgr, s_listen_on, fn, NULL); // Create HTTP listener for (;;) mg_mgr_poll(&mgr, 200); // Infinite event loop mg_mgr_free(&mgr); return 0; }