/* * TOPPERS ECHONET Lite Communication Middleware * * Copyright (C) 2014-2017 Cores Co., Ltd. Japan * * 上記著作権者は,以下の(1)~(4)の条件を満たす場合に限り,本ソフトウェ * ア(本ソフトウェアを改変したものを含む.以下同じ)を使用・複製・改 * 変・再配布(以下,利用と呼ぶ)することを無償で許諾する. * (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作 * 権表示,この利用条件および下記の無保証規定が,そのままの形でソー * スコード中に含まれていること. * (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使 * 用できる形で再配布する場合には,再配布に伴うドキュメント(利用 * 者マニュアルなど)に,上記の著作権表示,この利用条件および下記 * の無保証規定を掲載すること. * (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使 * 用できない形で再配布する場合には,次のいずれかの条件を満たすこ * と. * (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著 * 作権表示,この利用条件および下記の無保証規定を掲載すること. * (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに * 報告すること. * (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損 * 害からも,上記著作権者およびTOPPERSプロジェクトを免責すること. * また,本ソフトウェアのユーザまたはエンドユーザからのいかなる理 * 由に基づく請求からも,上記著作権者およびTOPPERSプロジェクトを * 免責すること. * * 本ソフトウェアは,無保証で提供されているものである.上記著作権者お * よびTOPPERSプロジェクトは,本ソフトウェアに関して,特定の使用目的 * に対する適合性も含めて,いかなる保証も行わない.また,本ソフトウェ * アの利用により直接的または間接的に生じたいかなる損害に関しても,そ * の責任を負わない. * * @(#) $Id: main.c 270 2017-02-09 04:03:47Z coas-nagasima $ */ /* * サンプルプログラム(1)の本体 */ #include #include #include #include #include #include #include "syssvc/serial.h" #include "syssvc/syslog.h" #include "kernel_cfg.h" #include "main.h" #include "rza1.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../webserver/httpd.h" #include "../webserver/httpd-fs.h" #include "../webserver/http-strings.h" #include "../webserver/base64.h" #include "../webserver/sha1.h" #include "mruby_arduino.h" #include "gpio_api.h" #include "arduino.h" #include "ff.h" #ifndef _MSC_VER void strcpy_s(char *dst, int size, const char *src); void strcat_s(char *dst, int size, const char *src); #endif uint8_t mac_addr[6] = {0x00, 0x30, 0x13, 0x06, 0x62, 0xC0}; SYSTIM main_time; struct httpd_state *uploding; static void netif_link_callback(T_IFNET *ether); static void execute_ruby(); /* TCP 送受信ウィンドバッファ */ uint8_t tcp_swbuf1[TCP_SWBUF_SIZE]; uint8_t tcp_rwbuf1[TCP_RWBUF_SIZE]; uint8_t tcp_swbuf2[TCP_SWBUF_SIZE]; uint8_t tcp_rwbuf2[TCP_RWBUF_SIZE]; #define ISO_nl 0x0a #define ISO_space 0x20 #define ISO_bang 0x21 #define ISO_percent 0x25 #define ISO_period 0x2e #define ISO_slash 0x2f #define ISO_colon 0x3a ID ecn_api_mailboxid; ID WEBSOCKET_MBXID; struct httpd_state httpd_state[2] = { {MAIN1_TASK, TCP_CEPID1}, {MAIN2_TASK, TCP_CEPID2}, }; /* * ネットワーク層の選択 */ #ifdef SUPPORT_INET6 #define TCP_ACP_CEP(c,r,d,t) tcp6_acp_cep(c,r,d,t) #define IP2STR(s,a) ipv62str(s,a) #else /* of #ifdef SUPPORT_INET6 */ #ifdef SUPPORT_INET4 #define TCP_ACP_CEP(c,r,d,t) tcp_acp_cep(c,r,d,t) #define IP2STR(s,a) ip2str(s,a) #endif /* of #ifdef SUPPORT_INET4 */ #endif /* of #ifdef SUPPORT_INET6 */ struct httpd_state *get_httpd(ID cepid) { for (int i = 0; i < 2; i++) { if (httpd_state[i].cepid != cepid) continue; return &httpd_state[i]; } return NULL; } struct websocket *websocket_getws(ID wbsid) { for (int i = 0; i < 2; i++) { if (httpd_state[i].websocket.wbsid != wbsid) continue; return &httpd_state[i].websocket; } return NULL; } void send_file(struct httpd_state *s) { char *buf; int len, slen; while (s->file.len > 0) { slen = tcp_get_buf(s->cepid, (void **)&buf, TMO_FEVR); if (slen < 0) { syslog(LOG_ERROR, "send_file#tcp_get_buf(%s.%d) => %d", s->addr, ((T_IPV4EP *)s->dst)->portno, slen); s->state = STATE_CLOSING; break; } if (slen == 0) return; len = s->file.len; if (len > slen) len = slen; len = httpd_fs_read(&s->file, buf, len); if (len <= 0) { syslog(LOG_ERROR, "send_file#httpd_fs_read(%s.%d) => %d", s->addr, ((T_IPV4EP *)s->dst)->portno, len); break; } s->file.len -= len; s->file.pos += len; if ((slen = tcp_snd_buf(s->cepid, len)) != E_OK) { syslog(LOG_ERROR, "send_file#tcp_snd_buf(%s.%d) => %d", s->addr, ((T_IPV4EP *)s->dst)->portno, slen); s->state = STATE_CLOSING; break; } } syslog(LOG_NOTICE, "close: %s.%d %s", s->addr, ((T_IPV4EP *)s->dst)->portno, s->filename); httpd_fs_close(&s->file); s->file.len = 0; s->file.pos = 0; s->out.state = OUT_STATE_SEND_END; } void send_data(struct httpd_state *s) { char *buf; int len, slen; while (s->response_len > 0) { slen = tcp_get_buf(s->cepid, (void **)&buf, TMO_FEVR); if (slen < 0) { syslog(LOG_ERROR, "send_data#tcp_get_buf(%s.%d) => %d", s->addr, ((T_IPV4EP *)s->dst)->portno, slen); s->state = STATE_CLOSING; break; } if (slen == 0) return; len = s->response_len; if (len > slen) len = slen; memcpy(buf, &s->response_body[s->response_pos], len); s->response_len -= len; s->response_pos += len; if ((slen = tcp_snd_buf(s->cepid, len)) != E_OK) { syslog(LOG_ERROR, "send_data#tcp_snd_buf(%s.%d) => %d", s->addr, ((T_IPV4EP *)s->dst)->portno, slen); s->state = STATE_CLOSING; break; } } s->response_body = NULL; s->response_len = 0; s->response_pos = 0; s->out.state = OUT_STATE_SEND_END; } void send_headers(struct httpd_state *s, const char *statushdr) { int len; char *ptr; len = strlen(statushdr); tcp_snd_dat(s->cepid, (void *)statushdr, len, TMO_FEVR); if ((s->filename[0] == '0') && (s->file.len > 0)) { len = sizeof(http_content_encoding_gzip) - 1; tcp_snd_dat(s->cepid, (void *)http_content_encoding_gzip, len, TMO_FEVR); } if (s->file.redirect) { len = sizeof(http_location) - 1; tcp_snd_dat(s->cepid, (void *)http_location, len, TMO_FEVR); if (s->filename[0] == '1') { len = 2; tcp_snd_dat(s->cepid, "/~", len, TMO_FEVR); } len = strlen(s->filename); tcp_snd_dat(s->cepid, s->filename, len, TMO_FEVR); if (s->query != NULL) { tcp_snd_dat(s->cepid, "?", 1, TMO_FEVR); len = strlen(s->query); tcp_snd_dat(s->cepid, s->query, len, TMO_FEVR); } len = 2; tcp_snd_dat(s->cepid, "\r", len, TMO_FEVR); } ptr = strrchr(s->filename, ISO_period); if (ptr == NULL) { len = sizeof(http_content_type_binary) - 1; tcp_snd_dat(s->cepid, (void *)http_content_type_binary, len, TMO_FEVR); } else if (strncmp(http_html, ptr, sizeof(http_html) - 1) == 0 || strncmp(http_htm, ptr, sizeof(http_htm) - 1) == 0) { len = sizeof(http_content_type_html) - 1; tcp_snd_dat(s->cepid, (void *)http_content_type_html, len, TMO_FEVR); } else if (strncmp(http_css, ptr, sizeof(http_css) - 1) == 0) { len = sizeof(http_content_type_css) - 1; tcp_snd_dat(s->cepid, (void *)http_content_type_css, len, TMO_FEVR); } else if (strncmp(http_js, ptr, sizeof(http_js) - 1) == 0) { len = sizeof(http_content_type_js) - 1; tcp_snd_dat(s->cepid, (void *)http_content_type_js, len, TMO_FEVR); } else if (strncmp(http_json, ptr, sizeof(http_json) - 1) == 0) { len = sizeof(http_content_type_json) - 1; tcp_snd_dat(s->cepid, (void *)http_content_type_json, len, TMO_FEVR); } else if (strncmp(http_png, ptr, sizeof(http_png) - 1) == 0) { len = sizeof(http_content_type_png) - 1; tcp_snd_dat(s->cepid, (void *)http_content_type_png, len, TMO_FEVR); } else if (strncmp(http_gif, ptr, sizeof(http_gif) - 1) == 0) { len = sizeof(http_content_type_gif) - 1; tcp_snd_dat(s->cepid, (void *)http_content_type_gif, len, TMO_FEVR); } else if (strncmp(http_jpg, ptr, sizeof(http_jpg) - 1) == 0) { len = sizeof(http_content_type_jpg) - 1; tcp_snd_dat(s->cepid, (void *)http_content_type_jpg, len, TMO_FEVR); } else if (strncmp(http_svg, ptr, sizeof(http_svg) - 1) == 0) { len = sizeof(http_content_type_svg) - 1; tcp_snd_dat(s->cepid, (void *)http_content_type_svg, len, TMO_FEVR); } else if (strncmp(http_text, ptr, sizeof(http_text) - 1) == 0) { len = sizeof(http_content_type_text) - 1; tcp_snd_dat(s->cepid, (void *)http_content_type_text, len, TMO_FEVR); } else if (strncmp(http_eot, ptr, sizeof(http_eot) - 1) == 0) { len = sizeof(http_content_type_eot) - 1; tcp_snd_dat(s->cepid, (void *)http_content_type_eot, len, TMO_FEVR); } else if (strncmp(http_ttf, ptr, sizeof(http_ttf) - 1) == 0) { len = sizeof(http_content_type_ttf) - 1; tcp_snd_dat(s->cepid, (void *)http_content_type_ttf, len, TMO_FEVR); } else if (strncmp(http_woff, ptr, sizeof(http_woff) - 1) == 0) { len = sizeof(http_content_type_woff) - 1; tcp_snd_dat(s->cepid, (void *)http_content_type_woff, len, TMO_FEVR); } else if (strncmp(http_woff2, ptr, sizeof(http_woff2) - 1) == 0) { len = sizeof(http_content_type_woff2) - 1; tcp_snd_dat(s->cepid, (void *)http_content_type_woff2, len, TMO_FEVR); } else if (strncmp(http_ico, ptr, sizeof(http_ico) - 1) == 0) { len = sizeof(http_content_type_ico) - 1; tcp_snd_dat(s->cepid, (void *)http_content_type_ico, len, TMO_FEVR); } else { len = sizeof(http_content_type_plain) - 1; tcp_snd_dat(s->cepid, (void *)http_content_type_plain, len, TMO_FEVR); } if (s->file.len > 0) { len = sizeof(http_content_length) - 1; tcp_snd_dat(s->cepid, (void *)http_content_length, len, TMO_FEVR); sprintf(s->temp, "%d\r\n", s->file.len); tcp_snd_dat(s->cepid, (void *)s->temp, strlen(s->temp), TMO_FEVR); } if (s->message.should_keep_alive && s->reset == 0) { len = sizeof(http_connection_keep_alive) - 1; tcp_snd_dat(s->cepid, (void *)http_connection_keep_alive, len, TMO_FEVR); } else { len = sizeof(http_connection_close) - 1; tcp_snd_dat(s->cepid, (void *)http_connection_close, len, TMO_FEVR); } tcp_snd_dat(s->cepid, (void *)http_crnl, 2, TMO_FEVR); if (s->filename != NULL) { s->out.state = OUT_STATE_SEND_FILE; } else { s->out.state = OUT_STATE_SEND_DATA; } } void handle_output(struct httpd_state *s) { s->out.wait = false; switch (s->out.state) { case OUT_STATE_WAIT_REQUEST: s->out.wait = true; break; case OUT_STATE_OPEN_GET_FILE: syslog(LOG_NOTICE, "open: %s.%d %s", s->addr, ((T_IPV4EP *)s->dst)->portno, s->filename); if (!httpd_fs_open(s->filename, sizeof(s->message.request_url), &s->file)) { s->filename = NULL; s->response_body = http_content_404; s->response_pos = 0; s->response_len = sizeof(http_content_403) - 1; s->out.statushdr = http_header_404; } else { s->out.statushdr = s->file.redirect ? http_header_301 : http_header_200; } s->out.state = OUT_STATE_SEND_HEADER; break; case OUT_STATE_WAIT_POST_BODY: s->out.wait = true; break; case OUT_STATE_BODY_RECEIVED: s->out.statushdr = http_header_200; s->out.state = OUT_STATE_SEND_HEADER; break; case OUT_STATE_SEND_HEADER: send_headers(s, s->out.statushdr); break; case OUT_STATE_SEND_FILE: send_file(s); break; case OUT_STATE_SEND_DATA: send_data(s); break; case OUT_STATE_SEND_END: s->out.wait = true; if (s->message.should_keep_alive && s->reset == 0) { s->out.state = OUT_STATE_WAIT_REQUEST; } else { s->state = STATE_CLOSING; } break; } } void send_ws_headers(struct httpd_state *s, const char *statushdr) { int len; len = strlen(statushdr); tcp_snd_dat(s->cepid, (void *)statushdr, len, TMO_FEVR); len = sizeof(http_upgrade) - 1; tcp_snd_dat(s->cepid, (void *)http_upgrade, len, TMO_FEVR); len = strlen(s->message.upgrade); tcp_snd_dat(s->cepid, s->message.upgrade, len, TMO_FEVR); len = sizeof(http_crnl) - 1; tcp_snd_dat(s->cepid, (void *)http_crnl, len, TMO_FEVR); len = sizeof(http_connection) - 1; tcp_snd_dat(s->cepid, (void *)http_connection, len, TMO_FEVR); len = strlen(s->message.connection); tcp_snd_dat(s->cepid, s->message.connection, len, TMO_FEVR); len = sizeof(http_crnl) - 1; tcp_snd_dat(s->cepid, (void *)http_crnl, len, TMO_FEVR); len = sizeof(http_sec_websocket_accept) - 1; tcp_snd_dat(s->cepid, (void *)http_sec_websocket_accept, len, TMO_FEVR); len = strlen(s->message.response_key); tcp_snd_dat(s->cepid, s->message.response_key, len, TMO_FEVR); len = sizeof(http_crnl) - 1; tcp_snd_dat(s->cepid, (void *)http_crnl, len, TMO_FEVR); len = sizeof(http_sec_websocket_protocol) - 1; tcp_snd_dat(s->cepid, (void *)http_sec_websocket_protocol, len, TMO_FEVR); len = strlen(s->message.sec_websocket_protocol); tcp_snd_dat(s->cepid, s->message.sec_websocket_protocol, len, TMO_FEVR); len = sizeof(http_crnl) - 1; tcp_snd_dat(s->cepid, (void *)http_crnl, len, TMO_FEVR); len = sizeof(http_crnl) - 1; tcp_snd_dat(s->cepid, (void *)http_crnl, len, TMO_FEVR); } void send_ws_data(struct httpd_state *s) { char *buf; int slen; slen = tcp_get_buf(s->cepid, (void **)&buf, TMO_FEVR); if (slen < 0) { syslog(LOG_ERROR, "send_ws_data#tcp_get_buf(%s.%d) => %d", s->addr, ((T_IPV4EP *)s->dst)->portno, slen); return; } websocket_output(&s->websocket, buf, slen); } void handle_ws_output(struct httpd_state *s) { char shaHash[20]; SHA_CTX sha1; int len; strlncat(s->message.response_key, sizeof(s->message.response_key), s->message.sec_websocket_key, sizeof(s->message.sec_websocket_key)); len = strlncat(s->message.response_key, sizeof(s->message.response_key), http_websocket_guid, sizeof(http_websocket_guid)); memset(shaHash, 0, sizeof(shaHash)); SHA1_Init(&sha1); SHA1_Update(&sha1, (sha1_byte *)s->message.response_key, len); SHA1_Final((sha1_byte *)shaHash, &sha1); base64_encode((unsigned char *)s->message.response_key, sizeof(s->message.response_key), (unsigned char *)shaHash, sizeof(shaHash)); send_ws_headers(s, http_header_101); s->message.response_key[0] = '\0'; do { while (!websocket_newdata(&s->websocket)) slp_tsk(); send_ws_data(s); } while ((s->state == STATE_CONNECTED) && (!s->close_req)); s->state = STATE_DISCONNECTED; websocket_destroy(&s->websocket); s->close_req = 0; s->state = STATE_CLOSING; } void handle_input(struct httpd_state *s) { size_t done; int len; s->in.wait = false; switch (s->in.state) { case IN_STATE_START: http_parser_init(&s->parser, HTTP_REQUEST); s->in.state = IN_STATE_REQUEST; break; case IN_STATE_REQUEST: case IN_STATE_RESPONSE: case IN_STATE_UPLOAD: if ((len = tcp_rcv_buf(s->cepid, (void **)&s->in.data, TMO_POL)) <= 0) { if ((len == E_TMOUT) || (len == 0)) { // 3秒は待つ if (main_time - s->in.timer < 30000000) { s->in.wait = true; break; } } syslog(LOG_ERROR, "handle_input#tcp_rcv_buf#%d(%s.%d) => %d", s->in.state, s->addr, ((T_IPV4EP *)s->dst)->portno, len); uploding = NULL; s->state = STATE_CLOSING; return; } done = http_parser_execute(&s->parser, &websvr_settings, s->in.data, len); tcp_rel_buf(s->cepid, done); if (s->parser.http_errno != HPE_OK) { syslog(LOG_ERROR, "http_parser error %s.%d => %d", s->addr, ((T_IPV4EP *)s->dst)->portno, s->parser.http_errno); uploding = NULL; s->state = STATE_CLOSING; return; } s->parse_pos = done; s->parse_len = len - done; break; case IN_STATE_UPLOAD_WAIT: if (uploding != NULL) { s->in.wait = true; } else { uploding = s; s->in.state = IN_STATE_UPLOAD; } break; case IN_STATE_WEBSOCKET: if (s->parse_len <= 0) { if ((len = tcp_rcv_buf(s->cepid, (void **)&s->in.data, TMO_POL)) <= 0) { if ((len == E_TMOUT) || (len == 0)) { s->in.wait = true; break; } syslog(LOG_ERROR, "handle_input#tcp_rcv_buf#%d(%s.%d) => %d", s->in.state, s->addr, ((T_IPV4EP *)s->dst)->portno, len); s->state = STATE_CLOSING; break; } s->parse_pos = 0; s->parse_len = len; } else len = s->parse_len; done = websocket_input(&s->websocket, (void *)s->in.data, s->parse_len); tcp_rel_buf(s->cepid, done); if ((done != 0) || (s->websocket.rstate.opecode == connection_close)) { s->close_req = 1; s->state = STATE_CLOSING; break; } s->parse_pos = done; s->parse_len -= done; break; case IN_STATE_END: s->in.wait = true; break; default: s->state = STATE_CLOSING; break; } } /* * ノンブロッキングコールのコールバック関数 */ ER callback_nblk_tcp(ID cepid, FN fncd, void *p_parblk) { struct httpd_state *s = get_httpd(cepid); if (s == NULL) syslog(LOG_NOTICE, "callback_nblk_tcp(%d, %d)", fncd, cepid); else syslog(LOG_NOTICE, "callback_nblk_tcp(%d, %s.%d)", fncd, s->addr, ((T_IPV4EP *)s->dst)->portno); return E_PAR; } /* * メインタスク */ void main_task(intptr_t exinf) { ER ret, ret2; struct httpd_state *s = &httpd_state[exinf]; if (exinf == 0) { gpio_t led_blue, led_green, led_red, sw; gpio_init_out(&led_blue, LED_BLUE); gpio_init_out(&led_green, LED_GREEN); gpio_init_out(&led_red, LED_RED); gpio_init_in(&sw, USER_BUTTON0); bool_t exec = gpio_read(&sw) == 1; gpio_write(&led_blue, 1); gpio_write(&led_green, exec ? 1 : 0); gpio_write(&led_red, 0); /* 初期化 */ if (mruby_arduino_init() == 0) { gpio_write(&led_blue, 0); } else { gpio_write(&led_blue, 0); gpio_write(&led_red, 1); } gpio_write(&led_green, 0); /* TINETが起動するまで待つ */ ether_set_link_callback(netif_link_callback); act_tsk(MAIN2_TASK); if (exec) { strcpy_s(RubyFilename, sizeof(RubyFilename), "1:/upload/main.mrb"); execute_ruby(); } } for (;;) { ret2 = get_tim(&main_time); if (ret2 != E_OK) { syslog(LOG_ERROR, "get_tim"); return; } switch (s->state) { case STATE_DISCONNECTED: memset(&s->dst, 0, sizeof(s->dst)); if ((ret = TCP_ACP_CEP(s->cepid, TCP_REPID, (T_IPV4EP *)s->dst, TMO_FEVR)) != E_OK) { syslog(LOG_ERROR, "tcp_acp_cep(%d) => %d", s->cepid, ret); tslp_tsk(100000); // TODO s->state = STATE_CLOSING; break; } IP2STR(s->addr, &((T_IPV4EP *)s->dst)->ipaddr); syslog(LOG_NOTICE, "connected: %s.%d", s->addr, ((T_IPV4EP *)s->dst)->portno); memset(&s->in, 0, sizeof(s->in)); memset(&s->out, 0, sizeof(s->out)); s->in.timer = main_time; s->state = STATE_CONNECTED; break; case STATE_CONNECTED: handle_input(s); handle_output(s); break; case STATE_WEBSOCKET: handle_input(s); handle_ws_output(s); break; case STATE_CLOSING: syslog(LOG_NOTICE, "close: %s.%d", s->addr, ((T_IPV4EP *)s->dst)->portno); tcp_sht_cep(s->cepid); tcp_cls_cep(s->cepid, TMO_FEVR); if (s->reset) { s->reset = 0; s->state = STATE_RESET; } else{ s->state = STATE_DISCONNECTED; } break; case STATE_RESET: execute_ruby(); s->state = STATE_DISCONNECTED; break; } if (s->in.wait && s->out.wait) { tslp_tsk(100000); } } } struct udp_msg { T_IPV4EP dst; int len; uint8_t buffer[ETHER_MAX_LEN]; }; SYSTIM mruby_time; struct RClass *_module_target_board; extern const uint8_t main_rb_code[]; uint8_t RubyCode[16 * 1024]; /* MACアドレスの設定時に呼ばれる */ void mbed_mac_address(char *mac) { memcpy(mac, mac_addr, 6); } /* * mruby実行タスク */ void mruby_task(intptr_t exinf) { ER ret; struct RProc* n; struct mrb_irep *irep; mrb_state *mrb; syslog(LOG_NOTICE, "mruby_task"); /* mrubyの初期化 */ mrb = mrb_open(); if (mrb == NULL) abort(); ret = get_tim(&mruby_time); if (ret != E_OK) { syslog(LOG_ERROR, "get_tim => %d", ret); return; } irep = mrb_read_irep(mrb, RubyCode); n = mrb_proc_new(mrb, irep); mrb_run(mrb, n, mrb_nil_value()); mrb_close(mrb); } static void execute_ruby() { FIL fd; FRESULT res; ER ret; syslog(LOG_NOTICE, "execute_ruby"); ret = ter_tsk(MRUBY_TASK); if ((ret != E_OK) && (ret != E_OBJ)) { syslog(LOG_ERROR, "ter_tsk => %d", ret); } tslp_tsk(100000); reset_heap(); strcpy_s(ExeFilename, sizeof(ExeFilename), RubyFilename); RubyFilename[0] = '\0'; ExeFilename[sizeof(ExeFilename) - 1] = '\0'; if (ExeFilename[0] == '\0') { return; } syslog(LOG_NOTICE, "%s", ExeFilename); wai_sem(SEM_FILESYSTEM); if ((res = f_open(&fd, ExeFilename, FA_OPEN_EXISTING | FA_READ)) == FR_OK) { if (fd.fsize < sizeof(RubyCode)) { int len = fd.fsize; for (int pos = 0; pos < fd.fsize; pos += len) { if (len > 1024) len = 1024; UINT rlen; if ((res = f_read(&fd, &RubyCode[pos], len, &rlen)) != FR_OK) break; // 他に使う人のために解放 sig_sem(SEM_FILESYSTEM); wai_sem(SEM_FILESYSTEM); } } f_close(&fd); } sig_sem(SEM_FILESYSTEM); if (res == FR_OK) { ret = act_tsk(MRUBY_TASK); if (ret != E_OK) { syslog(LOG_ERROR, "act_tsk => %d", ret); } } } ER callback_nblk_udp(ID cepid, FN fncd, void *p_parblk) { static struct udp_msg msg_inst[2]; static int msg_no = 0; struct udp_msg *msg = &msg_inst[msg_no]; ER error = E_OK; switch (fncd) { case TFN_UDP_CRE_CEP: case TFN_UDP_RCV_DAT: /* ECN_CAP_PUT("[UDP ECHO SRV] callback_nblk_udp() recv: %u", *(int *)p_parblk); */ memset(msg, 0, sizeof(struct udp_msg)); if ((msg->len = udp_rcv_dat(cepid, &msg->dst, msg->buffer, sizeof(msg->buffer), 0)) < 0) { syslog(LOG_WARNING, "[UDP ECHO SRV] recv, error: %s", itron_strerror(msg->len)); return msg->len; } msg_no = (msg_no + 1) % 2; return snd_dtq(MRUBY_DATAQUEUE, (intptr_t)msg); case TFN_UDP_SND_DAT: break; default: syslog(LOG_WARNING, "[UDP ECHO SRV] fncd:0x%04X(%s)", -fncd, (fncd == TFN_UDP_CRE_CEP ? "TFN_UDP_CRE_CEP" : (fncd == TFN_UDP_RCV_DAT ? "TFN_UDP_RCV_DAT" : (fncd == TFN_UDP_SND_DAT ? "TFN_UDP_SND_DAT" : "undef")))); error = E_PAR; break; } return error; } static void netif_link_callback(T_IFNET *ether) { static struct udp_msg msg_inst[2]; static int msg_no = 0; struct udp_msg *msg = &msg_inst[msg_no]; T_RTSK rtsk; ER ret; ret = ref_tsk(MRUBY_TASK, &rtsk); if ((ret != E_OK) || (rtsk.tskstat == TTS_DMT)) return; memset(msg, 0, sizeof(struct udp_msg)); msg->len = 1; msg->buffer[0] = ether->flags; msg_no = (msg_no + 1) % 2; snd_dtq(MRUBY_DATAQUEUE, (intptr_t)msg); } /* * アプリケーションタスクの登録 */ static mrb_value mrb_target_board_wait_msg(mrb_state *mrb, mrb_value self) { TMO timer; SYSTIM now; ER ret, ret2; struct udp_msg *msg; mrb_value arv[3]; static int first = 1; mrb_get_args(mrb, "i", &timer); if (timer != TMO_FEVR) timer *= 1000; if (first) { first = 0; syslog(LOG_NOTICE, "wait_msg"); } /* メッセージ待ち */ ret = trcv_dtq(MRUBY_DATAQUEUE, (intptr_t *)&msg, timer); if ((ret != E_OK) && (ret != E_TMOUT)) { syslog(LOG_ERROR, "trcv_dtq => %d", ret); return mrb_nil_value(); } ret2 = get_tim(&now); if (ret2 != E_OK) { syslog(LOG_ERROR, "get_tim => %d", ret); return mrb_nil_value(); } arv[0] = mrb_fixnum_value((now - mruby_time) / 1000); mruby_time = now; /* タイムアウトの場合 */ if (ret == E_TMOUT) { return mrb_ary_new_from_values(mrb, 1, arv); } /* 内部イベントの場合 */ if (msg->dst.ipaddr == 0) { /* Ethernet Link up */ if (msg->buffer[0] & IF_FLAG_LINK_UP) { arv[1] = mrb_fixnum_value(1); } /* EP Link up */ else if (msg->buffer[0] & IF_FLAG_UP) { arv[1] = mrb_fixnum_value(2); } else { arv[1] = mrb_fixnum_value(0); } return mrb_ary_new_from_values(mrb, 2, arv); } /* Echonet電文受信の場合 */ else { /* 通信端点 */ arv[1] = mrb_str_new(mrb, (char *)&msg->dst, sizeof(msg->dst)); /* 受信データ */ arv[2] = mrb_str_new(mrb, (char *)msg->buffer, msg->len); return mrb_ary_new_from_values(mrb, 3, arv); } } /* * アプリケーションタスクの登録 */ static mrb_value mrb_target_board_restart(mrb_state *mrb, mrb_value self) { /* DHCP開始 */ return self; } /* * 通信レイヤーへの送信 */ static mrb_value mrb_target_board_snd_msg(mrb_state *mrb, mrb_value self) { mrb_value rep; mrb_value rdat; T_IPV4EP *ep; ER_UINT ret; mrb_get_args(mrb, "SS", &rep, &rdat); if (RSTRING_LEN(rep) != sizeof(T_IPV4EP)) { mrb_raise(mrb, E_RUNTIME_ERROR, "snd_msg"); return mrb_nil_value(); } ep = (T_IPV4EP *)RSTRING_PTR(rep); ret = udp_snd_dat(MRUBY_ECNL_UDP_CEPID, ep, RSTRING_PTR(rdat), RSTRING_LEN(rdat), TMO_FEVR); if (ret < 0) { mrb_raise(mrb, E_RUNTIME_ERROR, "snd_msg"); return mrb_nil_value(); } return mrb_nil_value(); } /* * ローカルアドレスか確認 */ static mrb_value mrb_target_board_is_local_addr(mrb_state *mrb, mrb_value self) { mrb_value rep; T_IPV4EP *ep; mrb_get_args(mrb, "S", &rep); if (RSTRING_LEN(rep) < sizeof(T_IPV4EP)) { mrb_raise(mrb, E_RUNTIME_ERROR, "is_local_addr"); return mrb_nil_value(); } ep = (T_IPV4EP *)RSTRING_PTR(rep); return (ep->ipaddr == MAKE_IPV4_ADDR(127, 0, 0, 1)) ? mrb_true_value() : mrb_false_value(); } /* * マルチキャストアドレスか確認 */ static mrb_value mrb_target_board_is_multicast_addr(mrb_state *mrb, mrb_value self) { mrb_value rep; T_IPV4EP *ep; mrb_get_args(mrb, "S", &rep); if (RSTRING_LEN(rep) < sizeof(T_IPV4EP)) { mrb_raise(mrb, E_RUNTIME_ERROR, "is_multicast_addr"); return mrb_nil_value(); } ep = (T_IPV4EP *)RSTRING_PTR(rep); return (ep->ipaddr == MAKE_IPV4_ADDR(224, 0, 23, 0)) ? mrb_true_value() : mrb_false_value(); } /* * 同一アドレスか確認 */ static mrb_value mrb_target_board_equals_addr(mrb_state *mrb, mrb_value self) { mrb_value rep1, rep2; T_IPV4EP *ep1, *ep2; mrb_get_args(mrb, "SS", &rep1, &rep2); if ((RSTRING_LEN(rep1) != sizeof(T_IPV4EP)) || (RSTRING_LEN(rep2) != sizeof(T_IPV4EP))) { mrb_raise(mrb, E_RUNTIME_ERROR, "equals_addr"); return mrb_nil_value(); } ep1 = (T_IPV4EP *)RSTRING_PTR(rep1); ep2 = (T_IPV4EP *)RSTRING_PTR(rep2); return (ep1->ipaddr == ep2->ipaddr) ? mrb_true_value() : mrb_false_value(); } /* * ローカルアドレスの取得 */ static mrb_value mrb_target_board_get_local_addr(mrb_state *mrb, mrb_value self) { T_IPV4EP ep; mrb_value rep; ep.ipaddr = MAKE_IPV4_ADDR(127, 0, 0, 1); ep.portno = 3610; rep = mrb_str_new(mrb, (char *)&ep, sizeof(ep)); return rep; } /* * マルチキャストアドレスの取得 */ static mrb_value mrb_target_board_get_multicast_addr(mrb_state *mrb, mrb_value self) { T_IPV4EP ep; mrb_value rep; ep.ipaddr = MAKE_IPV4_ADDR(224, 0, 23, 0); ep.portno = 3610; rep = mrb_str_new(mrb, (char *)&ep, sizeof(ep)); return rep; } void mrb_mruby_others_gem_init(mrb_state* mrb) { _module_target_board = mrb_define_module(mrb, "TargetBoard"); // mbed Pin Names mrb_define_const(mrb, _module_target_board, "LED1", mrb_fixnum_value(LED1)); mrb_define_const(mrb, _module_target_board, "LED2", mrb_fixnum_value(LED2)); mrb_define_const(mrb, _module_target_board, "LED3", mrb_fixnum_value(LED3)); mrb_define_const(mrb, _module_target_board, "LED4", mrb_fixnum_value(LED4)); mrb_define_const(mrb, _module_target_board, "LED_RED", mrb_fixnum_value(LED_RED)); mrb_define_const(mrb, _module_target_board, "LED_GREEN", mrb_fixnum_value(LED_GREEN)); mrb_define_const(mrb, _module_target_board, "LED_BLUE", mrb_fixnum_value(LED_BLUE)); mrb_define_const(mrb, _module_target_board, "LED_USER", mrb_fixnum_value(LED_USER)); mrb_define_const(mrb, _module_target_board, "USBTX", mrb_fixnum_value(USBTX)); mrb_define_const(mrb, _module_target_board, "USBRX", mrb_fixnum_value(USBRX)); // Arduiono Pin Names mrb_define_const(mrb, _module_target_board, "D0", mrb_fixnum_value(D0)); mrb_define_const(mrb, _module_target_board, "D1", mrb_fixnum_value(D1)); mrb_define_const(mrb, _module_target_board, "D2", mrb_fixnum_value(D2)); mrb_define_const(mrb, _module_target_board, "D3", mrb_fixnum_value(D3)); mrb_define_const(mrb, _module_target_board, "D4", mrb_fixnum_value(D4)); mrb_define_const(mrb, _module_target_board, "D5", mrb_fixnum_value(D5)); mrb_define_const(mrb, _module_target_board, "D6", mrb_fixnum_value(D6)); mrb_define_const(mrb, _module_target_board, "D7", mrb_fixnum_value(D7)); mrb_define_const(mrb, _module_target_board, "D8", mrb_fixnum_value(D8)); mrb_define_const(mrb, _module_target_board, "D9", mrb_fixnum_value(D9)); mrb_define_const(mrb, _module_target_board, "D10", mrb_fixnum_value(D10)); mrb_define_const(mrb, _module_target_board, "D11", mrb_fixnum_value(D11)); mrb_define_const(mrb, _module_target_board, "D12", mrb_fixnum_value(D12)); mrb_define_const(mrb, _module_target_board, "D13", mrb_fixnum_value(D13)); mrb_define_const(mrb, _module_target_board, "D14", mrb_fixnum_value(D14)); mrb_define_const(mrb, _module_target_board, "D15", mrb_fixnum_value(D15)); mrb_define_const(mrb, _module_target_board, "A0", mrb_fixnum_value(A0)); mrb_define_const(mrb, _module_target_board, "A1", mrb_fixnum_value(A1)); mrb_define_const(mrb, _module_target_board, "A2", mrb_fixnum_value(A2)); mrb_define_const(mrb, _module_target_board, "A3", mrb_fixnum_value(A3)); mrb_define_const(mrb, _module_target_board, "A4", mrb_fixnum_value(A4)); mrb_define_const(mrb, _module_target_board, "A5", mrb_fixnum_value(A5)); mrb_define_const(mrb, _module_target_board, "I2C_SCL", mrb_fixnum_value(I2C_SCL)); mrb_define_const(mrb, _module_target_board, "I2C_SDA", mrb_fixnum_value(I2C_SDA)); mrb_define_const(mrb, _module_target_board, "USER_BUTTON0", mrb_fixnum_value(USER_BUTTON0)); // Not connected mrb_define_const(mrb, _module_target_board, "NC", mrb_fixnum_value(NC)); mrb_define_class_method(mrb, _module_target_board, "wait_msg", mrb_target_board_wait_msg, MRB_ARGS_REQ(1)); mrb_define_class_method(mrb, _module_target_board, "restart", mrb_target_board_restart, MRB_ARGS_NONE()); mrb_define_class_method(mrb, _module_target_board, "snd_msg", mrb_target_board_snd_msg, MRB_ARGS_REQ(2)); mrb_define_class_method(mrb, _module_target_board, "is_local_addr", mrb_target_board_is_local_addr, MRB_ARGS_REQ(1)); mrb_define_class_method(mrb, _module_target_board, "is_multicast_addr", mrb_target_board_is_multicast_addr, MRB_ARGS_REQ(1)); mrb_define_class_method(mrb, _module_target_board, "equals_addr", mrb_target_board_equals_addr, MRB_ARGS_REQ(2)); mrb_define_class_method(mrb, _module_target_board, "get_local_addr", mrb_target_board_get_local_addr, MRB_ARGS_NONE()); mrb_define_class_method(mrb, _module_target_board, "get_multicast_addr", mrb_target_board_get_multicast_addr, MRB_ARGS_NONE()); } void mrb_mruby_others_gem_final(mrb_state* mrb) { }