// 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); free(h); return 0; } 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 = 1; a->v_lower = 0; a->c_upper = 0; a->p_upper = 0; a->w_upper = 0; } 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 (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); } } 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; } typedef struct { uint8_t chs; power_ch_t pch[CH_MAX]; }powerc_data_t; static powerc_data_t powerc_data = {.chs=0}; static void send_powerc(struct mg_connection* c) { int i, j, ch = 0; #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 }; powerc_data_t* pc = &powerc_data; pc->chs = BOARD_CNT * BOARC_CH_CNT; for (i = 0; i < BOARD_CNT; i++) { for (j = 0; j < BOARC_CH_CNT; j++) { powerc_rand(&pc->pch[ch], addr[i], ch, j); ch++; } } ws_send(c, PKT_TYPE_POWER_CH, pc->pch, sizeof(power_ch_t)*pc->chs); } 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 int ws_handle(pkt_hdr_t* hdr, struct mg_connection* c) { int r = 0; if (!c->is_websocket) { printf("___ not a websocket\n"); return -1; } if (hdr->magic != PKT_MAGIC) { printf("___ magic: 0x%x is wrong!, correct is: 0x%x\n", hdr->magic, PKT_MAGIC); return -1; } printf("_____ ws handle, type:%d, subtype:%d, flag:%d\n", hdr->type, hdr->subtype, hdr->flag); switch (hdr->type) { case PKT_TYPE_PARAS: { //setup } break; case PKT_TYPE_POWER_CH: { printf("_____ send_powerc\n"); send_powerc(c); } break; case PKT_TYPE_POWER_TOTAL: { printf("_____ send_powert\n"); send_powert(c); } break; case PKT_TYPE_CH_ALL: { } break; } 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 *hdr= (pkt_hdr_t*)wm->data.buf; ws_handle(hdr, c); //mg_ws_send(c, wm->data.buf, wm->data.len, WEBSOCKET_OP_TEXT); } } static void timer_fn(void* arg) { static uint32_t cnt = 0; struct mg_mgr* mgr = (struct mg_mgr*)arg; struct mg_connection* c; cnt++; if (cnt%10==0) { for (c = mgr->conns; c != NULL; c = c->next) { 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; }