/* * 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$ */ /* * サンプルプログラム(1)の本体 */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define ETHER_MAX_LEN 1518 #define IF_FLAG_UP 1 #define IF_FLAG_LINK_UP 2 #define MAKE_IPV4_ADDR(a,b,c,d) htonl(((uint32_t)(a)<<24)|((uint32_t)(b)<<16)|((uint32_t)(c)<<8)|(d)) struct udp_msg { struct sockaddr_in dst; int len; uint8_t buffer[ETHER_MAX_LEN]; }; typedef struct { cmd_table_t *table; cmd_table_t *count; } cmd_table_info_t; extern int mrbc_main(int argc, char **argv); extern int mrdb_main(int argc, char **argv); extern int mruby_main(int argc, char **argv); extern int mirb_main(int argc, char **argv); extern int curl_main(int argc, char **argv); extern int tcc_main(int argc, char **argv); extern int vi_main(int argc, char **argv); extern int onitest_main(int argc, char **argv); extern int tcp_echo_main(int argc, char **argv); extern int echo_client_main(int argc, char **argv); extern int mrdb_break(void); static const cmd_table_t cmdlist[] = { {"mrbc", "mruby compiler executable", mrbc_main}, {"mrdb","mruby debugger command", mrdb_main}, {"mruby","mruby command", mruby_main}, {"mirb", "Embeddable Interactive Ruby Shell", mirb_main}, {"curl", "Command lines or scripts to transfer data", curl_main}, {"tcc", "Tiny C compiler", tcc_main}, {"vi", "Text editor", vi_main}, {"onitest", "Onigumo Test", onitest_main}, {"tcp_echo", "TCP echo server/client", tcp_echo_main}, {"help", "This is a description text string for help command.", usrcmd_help}, }; cmd_table_info_t cmd_table_info = { &cmdlist, sizeof(cmdlist) / sizeof(cmdlist[0]) }; int echonet = 1; struct timeval main_time; struct RClass *_module_target_board; int sock; int main(int argc, char **argv) { if (argc == 0) { return 0; } const cmd_table_t *p = cmd_table_info.table; for (int i = 0; i < cmd_table_info.count; i++) { if (strcmp((const char *)argv[0], p->cmd) == 0) { return p->func(argc, argv); } p++; } printf("Unknown command found.\n"); return 0; } int run_mruby_code(int argc, char **argv, const uint8_t *code, const char *cmdline) { mrb_state *mrb; struct RProc* n; struct mrb_irep *irep; mrb_value ARGV; mrbc_context *c; mrb_value v; mrb_sym zero_sym; echonet = 0; /* mrubyの初期化 */ mrb = mrb_open(); if (mrb == NULL) return -1; int ai = mrb_gc_arena_save(mrb); ARGV = mrb_ary_new_capa(mrb, argc); for (int i = 0; i < argc; i++) { mrb_ary_push(mrb, ARGV, mrb_str_new_cstr(mrb, argv[i])); } mrb_define_global_const(mrb, "ARGV", ARGV); c = mrbc_context_new(mrb); c->dump_result = TRUE; /* Set $0 */ zero_sym = mrb_intern_lit(mrb, "$0"); mrbc_filename(mrb, c, cmdline); mrb_gv_set(mrb, zero_sym, mrb_str_new_cstr(mrb, cmdline)); irep = mrb_read_irep(mrb, code); n = mrb_proc_new(mrb, irep); mrb_run(mrb, n, mrb_nil_value()); mrb_gc_arena_restore(mrb, ai); mrbc_context_free(mrb, c); if (mrb->exc) { if (!mrb_undef_p(v)) { mrb_print_error(mrb); } n = -1; } mrb_close(mrb); return 0; } int tcp_echo_main(int argc, char **argv) { extern const uint8_t echo_server_code[]; extern const uint8_t echo_client_code[]; if (argc >= 2) { if (strcmp(argv[1], "-s") == 0) { return run_mruby_code(argc - 2, &argv[2], echo_server_code, "echo_server"); } else if (strcmp(argv[1], "-c") == 0) { return run_mruby_code(argc - 2, &argv[2], echo_client_code, "echo_client"); } } printf("tcp_echo -s port\n"); printf("tcp_echo -c ipaddr port\n"); return 0; } int usrcmd_help(int argc, char **argv) { const cmd_table_t *p = cmd_table_info.table; for (int i = 0; i < cmd_table_info.count; i++) { printf(p->cmd); printf("\t:"); printf(p->desc); printf("\n"); p++; } return 0; } void sigusr1_handler(int sig) { printf("signal called\n"); } void mrb_target_board_init() { int ret; struct sockaddr_in ep; struct ip_mreq mreq; signal(SIGUSR1, sigusr1_handler); sock = socket(AF_INET, SOCK_DGRAM, 0); memset(&ep, 0, sizeof(ep)); ep.sin_family = AF_INET; ep.sin_port = htons(3610); ep.sin_addr.s_addr = INADDR_ANY; //ep.sin_addr.s_addr = MAKE_IPV4_ADDR(192,168,137,200); ret = bind(sock, &ep, sizeof(ep)); if (ret != 0) { printf("bind %d", ret); return; } mreq.imr_interface.s_addr = INADDR_ANY; mreq.imr_multiaddr.s_addr = MAKE_IPV4_ADDR(224, 0, 23, 0); ret = setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq)); if (ret != 0) { printf("setsockopt %d", ret); return; } ret = gettimeofday(&main_time, NULL); if (ret != 0) { printf("gettimeofday"); return; } } void mrb_target_board_final() { close(sock); } void mrb_target_board_break() { raise(SIGUSR1); } /* * アプリケーションタスクの登録 */ static mrb_value mrb_target_board_wait_msg(mrb_state *mrb, mrb_value self) { int tmr; struct timeval timer, *ptimer; struct timeval now, elps; int ret, ret2; struct udp_msg _msg; struct udp_msg *msg = &_msg; mrb_value arv[3]; fd_set readfds, writefds, errorfds; mrb_get_args(mrb, "i", &tmr); if (tmr < 0) ptimer = NULL; else { timer.tv_sec = tmr / 1000; timer.tv_usec = (tmr % 1000) * 1000; ptimer = &timer; } FD_ZERO(&readfds); FD_ZERO(&writefds); FD_ZERO(&errorfds); FD_SET(sock, &readfds); FD_SET(sock, &writefds); FD_SET(sock, &errorfds); /* メッセージ待ち */ memset(msg, 0, sizeof(*msg)); ret = select(sock + 1, &readfds, &writefds, &errorfds, ptimer); if (ret < 0) mrb_raise(mrb, E_RUNTIME_ERROR, "socket select error"); if (FD_ISSET(sock, &readfds)) { int fromlen = sizeof(msg->dst); msg->len = recvfrom(sock, msg->buffer, sizeof(msg->buffer), 0, &msg->dst, &fromlen); if (msg->len < 0) { printf("recvfrom %d", msg->len); return mrb_nil_value(); } } ret2 = gettimeofday(&now, NULL); if (ret2 != 0) { printf("gettimeofday"); return mrb_nil_value(); } timersub(&now, &main_time, &elps); arv[0] = mrb_fixnum_value(elps.tv_sec); main_time = now; /* タイムアウトの場合 */ if (ret == 0) { return mrb_ary_new_from_values(mrb, 1, arv); } /* 内部イベントの場合 */ if (msg->dst.sin_addr.s_addr == 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); } 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; struct sockaddr_in *ep; int ret; mrb_get_args(mrb, "SS", &rep, &rdat); if (RSTRING_LEN(rep) != sizeof(struct sockaddr_in)) { mrb_raise(mrb, E_RUNTIME_ERROR, "snd_msg"); return mrb_nil_value(); } ep = (struct sockaddr_in *)RSTRING_PTR(rep); ret = sendto(sock, RSTRING_PTR(rdat), RSTRING_LEN(rdat), 0, (struct sockaddr *)ep, sizeof(*ep)); if (ret < 0) { mrb_raise(mrb, E_RUNTIME_ERROR, "sendto"); 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; struct sockaddr_in *ep; mrb_get_args(mrb, "S", &rep); if (RSTRING_LEN(rep) < sizeof(struct sockaddr_in)) { mrb_raise(mrb, E_RUNTIME_ERROR, "is_local_addr"); return mrb_nil_value(); } ep = (struct sockaddr_in *)RSTRING_PTR(rep); return (ep->sin_addr.s_addr == 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; struct sockaddr_in *ep; mrb_get_args(mrb, "S", &rep); if (RSTRING_LEN(rep) < sizeof(struct sockaddr_in)) { mrb_raise(mrb, E_RUNTIME_ERROR, "is_multicast_addr"); return mrb_nil_value(); } ep = (struct sockaddr_in *)RSTRING_PTR(rep); return (ep->sin_addr.s_addr == 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; struct sockaddr_in *ep1, *ep2; mrb_get_args(mrb, "SS", &rep1, &rep2); if ((RSTRING_LEN(rep1) != sizeof(struct sockaddr_in)) || (RSTRING_LEN(rep2) != sizeof(struct sockaddr_in))) { mrb_raise(mrb, E_RUNTIME_ERROR, "equals_addr"); return mrb_nil_value(); } ep1 = (struct sockaddr_in *)RSTRING_PTR(rep1); ep2 = (struct sockaddr_in *)RSTRING_PTR(rep2); return (ep1->sin_addr.s_addr == ep2->sin_addr.s_addr) ? mrb_true_value() : mrb_false_value(); } /* * ローカルアドレスの取得 */ static mrb_value mrb_target_board_get_local_addr(mrb_state *mrb, mrb_value self) { struct sockaddr_in ep; mrb_value rep; memset(&ep, 0, sizeof(ep)); ep.sin_family = AF_INET; ep.sin_addr.s_addr = MAKE_IPV4_ADDR(127, 0, 0, 1); ep.sin_port = htons(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) { struct sockaddr_in ep; mrb_value rep; memset(&ep, 0, sizeof(ep)); ep.sin_family = AF_INET; ep.sin_addr.s_addr = MAKE_IPV4_ADDR(224, 0, 23, 0); ep.sin_port = htons(3610); rep = mrb_str_new(mrb, (char *)&ep, sizeof(ep)); return rep; } void mrb_mruby_others_gem_init(mrb_state* mrb) { if (!echonet) return; _module_target_board = mrb_define_module(mrb, "TargetBoard"); 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()); mrb_target_board_init(); } void mrb_mruby_others_gem_final(mrb_state* mrb) { if (!echonet) return; mrb_target_board_final(); } void _start_c(long *p); int _data, _mdata, _edata; int _bss, _ebss; void _PowerON_Reset(long *args) { memcpy(&_data, &_mdata, (size_t)&_edata - (size_t)&_data); memset(&_bss, 0, (size_t)&_ebss - (size_t)&_bss); _start_c(args); } #define FVECT_SECT __attribute__ ((section (".fvectors"))) const void *HardwareVectors[] FVECT_SECT = { _PowerON_Reset, mrdb_break, }; char stack_space[0x100000] __attribute__ ((section (".stack")));