source: EcnlProtoTool/trunk/prototool/src/main.c@ 321

Last change on this file since 321 was 321, checked in by coas-nagasima, 7 years ago

文字コードを設定

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 15.1 KB
Line 
1/*
2 * TOPPERS ECHONET Lite Communication Middleware
3 *
4 * Copyright (C) 2014-2017 Cores Co., Ltd. Japan
5 *
6 * 上記著作権者は,以下の(1)~(4)の条件を満たす場合に限り,本ソフトウェ
7 * ア(本ソフトウェアを改変したものを含む.以下同じ)を使用・複製・改
8 * 変・再配布(以下,利用と呼ぶ)することを無償で許諾する.
9 * (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
10 * 権表示,この利用条件および下記の無保証規定が,そのままの形でソー
11 * スコード中に含まれていること.
12 * (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
13 * 用できる形で再配布する場合には,再配布に伴うドキュメント(利用
14 * 者マニュアルなど)に,上記の著作権表示,この利用条件および下記
15 * の無保証規定を掲載すること.
16 * (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
17 * 用できない形で再配布する場合には,次のいずれかの条件を満たすこ
18 * と.
19 * (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著
20 * 作権表示,この利用条件および下記の無保証規定を掲載すること.
21 * (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに
22 * 報告すること.
23 * (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
24 * 害からも,上記著作権者およびTOPPERSプロジェクトを免責すること.
25 * また,本ソフトウェアのユーザまたはエンドユーザからのいかなる理
26 * 由に基づく請求からも,上記著作権者およびTOPPERSプロジェクトを
27 * 免責すること.
28 *
29 * 本ソフトウェアは,無保証で提供されているものである.上記著作権者お
30 * よびTOPPERSプロジェクトは,本ソフトウェアに関して,特定の使用目的
31 * に対する適合性も含めて,いかなる保証も行わない.また,本ソフトウェ
32 * アの利用により直接的または間接的に生じたいかなる損害に関しても,そ
33 * の責任を負わない.
34 *
35 * @(#) $Id$
36 */
37
38 /*
39 * サンプルプログラム(1)の本体
40 */
41
42#include <sys/types.h>
43#include <sys/socket.h>
44#include <sys/un.h>
45#include <netinet/in.h>
46#include <netinet/tcp.h>
47#include <arpa/inet.h>
48#include <fcntl.h>
49#include <netdb.h>
50#include <unistd.h>
51#include <setjmp.h>
52#include <signal.h>
53#include <time.h>
54#include <sys/time.h>
55#include <sys/unistd.h>
56#include <errno.h>
57
58#include <string.h>
59#include <mruby.h>
60#include <mruby/compile.h>
61#include <mruby/proc.h>
62#include <mruby/array.h>
63#include <mruby/data.h>
64#include <mruby/class.h>
65#include <mruby/dump.h>
66#include <mruby/string.h>
67#include <usrcmd.h>
68
69#define ETHER_MAX_LEN 1518
70#define IF_FLAG_UP 1
71#define IF_FLAG_LINK_UP 2
72#define MAKE_IPV4_ADDR(a,b,c,d) htonl(((uint32_t)(a)<<24)|((uint32_t)(b)<<16)|((uint32_t)(c)<<8)|(d))
73
74struct udp_msg
75{
76 struct sockaddr_in dst;
77 int len;
78 uint8_t buffer[ETHER_MAX_LEN];
79};
80
81typedef struct
82{
83 cmd_table_t *table;
84 cmd_table_t *count;
85} cmd_table_info_t;
86
87extern int mrbc_main(int argc, char **argv);
88extern int mrdb_main(int argc, char **argv);
89extern int mruby_main(int argc, char **argv);
90extern int mirb_main(int argc, char **argv);
91extern int tcc_main(int argc, char **argv);
92extern int vi_main(int argc, char **argv);
93extern int onitest_main(int argc, char **argv);
94extern int tcp_echo_main(int argc, char **argv);
95extern int echo_client_main(int argc, char **argv);
96extern int mrdb_break(void);
97
98static const cmd_table_t cmdlist[] = {
99 {"mrbc", "mruby compiler executable", mrbc_main},
100 {"mrdb","mruby debugger command", mrdb_main},
101 {"mruby","mruby command", mruby_main},
102 {"mirb", "Embeddable Interactive Ruby Shell", mirb_main},
103 {"tcc", "Tiny C compiler", tcc_main},
104 {"vi", "Text editor", vi_main},
105 {"cd", "change directory", usrcmd_cd },
106 {"ls", "list files", usrcmd_ls },
107 {"cp", "copy file", usrcmd_cp },
108 {"rm", "remove file", usrcmd_rm },
109 {"mv", "move file", usrcmd_mv },
110 {"mkdir", "Make directory", usrcmd_mkdir},
111 {"hexdump", "Hex dump", usrcmd_hexdump},
112 {"onitest", "Onigumo Test", onitest_main},
113 {"tcp_echo", "TCP echo server/client", tcp_echo_main},
114 {"help", "This is a description text string for help command.", usrcmd_help},
115 {"info", "This is a description text string for info command.", usrcmd_info},
116 {"exit", "Exit Natural Tyny Shell", usrcmd_exit},
117};
118cmd_table_info_t cmd_table_info = { &cmdlist, sizeof(cmdlist) / sizeof(cmdlist[0]) };
119
120int echonet = 1;
121struct timeval main_time;
122struct RClass *_module_target_board;
123int sock;
124
125int main(int argc, char **argv)
126{
127 if (argc == 0) {
128 return 0;
129 }
130 const cmd_table_t *p = cmd_table_info.table;
131 for (int i = 0; i < cmd_table_info.count; i++) {
132 if (strcmp((const char *)argv[0], p->cmd) == 0) {
133 return p->func(argc, argv);
134 }
135 p++;
136 }
137 printf("Unknown command found.\n");
138 return 0;
139}
140
141int run_mruby_code(int argc, char **argv, const uint8_t *code, const char *cmdline)
142{
143 mrb_state *mrb;
144 struct RProc* n;
145 struct mrb_irep *irep;
146 mrb_value ARGV;
147 mrbc_context *c;
148 mrb_value v;
149 mrb_sym zero_sym;
150
151 echonet = 0;
152
153 /* mrubyの初期化 */
154 mrb = mrb_open();
155 if (mrb == NULL)
156 return -1;
157
158 int ai = mrb_gc_arena_save(mrb);
159 ARGV = mrb_ary_new_capa(mrb, argc);
160 for (int i = 0; i < argc; i++) {
161 mrb_ary_push(mrb, ARGV, mrb_str_new_cstr(mrb, argv[i]));
162 }
163 mrb_define_global_const(mrb, "ARGV", ARGV);
164
165 c = mrbc_context_new(mrb);
166 c->dump_result = TRUE;
167
168 /* Set $0 */
169 zero_sym = mrb_intern_lit(mrb, "$0");
170 mrbc_filename(mrb, c, cmdline);
171 mrb_gv_set(mrb, zero_sym, mrb_str_new_cstr(mrb, cmdline));
172
173 irep = mrb_read_irep(mrb, code);
174 n = mrb_proc_new(mrb, irep);
175 mrb_run(mrb, n, mrb_nil_value());
176
177 mrb_gc_arena_restore(mrb, ai);
178 mrbc_context_free(mrb, c);
179 if (mrb->exc) {
180 if (!mrb_undef_p(v)) {
181 mrb_print_error(mrb);
182 }
183 n = -1;
184 }
185
186 mrb_close(mrb);
187 return 0;
188}
189
190int tcp_echo_main(int argc, char **argv)
191{
192 extern const uint8_t echo_server_code[];
193 extern const uint8_t echo_client_code[];
194
195 if (argc >= 2) {
196 if (strcmp(argv[1], "-s") == 0) {
197 return run_mruby_code(argc - 2, &argv[2], echo_server_code, "echo_server");
198 }
199 else if (strcmp(argv[1], "-c") == 0) {
200 return run_mruby_code(argc - 2, &argv[2], echo_client_code, "echo_client");
201 }
202 }
203
204 printf("tcp_echo -s port\n");
205 printf("tcp_echo -c ipaddr port\n");
206
207 return 0;
208}
209
210int usrcmd_help(int argc, char **argv)
211{
212 const cmd_table_t *p = cmd_table_info.table;
213 for (int i = 0; i < cmd_table_info.count; i++) {
214 printf(p->cmd);
215 printf("\t:");
216 printf(p->desc);
217 printf("\n");
218 p++;
219 }
220 return 0;
221}
222
223void sigusr1_handler(int sig)
224{
225 printf("signal called\n");
226}
227
228void mrb_target_board_init()
229{
230 int ret;
231 struct sockaddr_in ep;
232 struct ip_mreq mreq;
233
234 signal(SIGUSR1, sigusr1_handler);
235
236 sock = socket(AF_INET, SOCK_DGRAM, 0);
237
238 memset(&ep, 0, sizeof(ep));
239 ep.sin_family = AF_INET;
240 ep.sin_port = htons(3610);
241 ep.sin_addr.s_addr = INADDR_ANY;
242 //ep.sin_addr.s_addr = MAKE_IPV4_ADDR(192,168,137,200);
243
244 ret = bind(sock, &ep, sizeof(ep));
245 if (ret != 0) {
246 printf("bind %d", ret);
247 return;
248 }
249
250 mreq.imr_interface.s_addr = INADDR_ANY;
251 mreq.imr_multiaddr.s_addr = MAKE_IPV4_ADDR(224, 0, 23, 0);
252
253 ret = setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq));
254 if (ret != 0) {
255 printf("setsockopt %d", ret);
256 return;
257 }
258
259 ret = gettimeofday(&main_time, NULL);
260 if (ret != 0) {
261 printf("gettimeofday");
262 return;
263 }
264}
265
266void mrb_target_board_final()
267{
268 close(sock);
269}
270
271void mrb_target_board_break()
272{
273 raise(SIGUSR1);
274}
275
276/*
277 * アプリケーションタスクの登録
278 */
279static mrb_value mrb_target_board_wait_msg(mrb_state *mrb, mrb_value self)
280{
281 int tmr;
282 struct timeval timer, *ptimer;
283 struct timeval now, elps;
284 int ret, ret2;
285 struct udp_msg _msg;
286 struct udp_msg *msg = &_msg;
287 mrb_value arv[3];
288 fd_set readfds, writefds, errorfds;
289
290 mrb_get_args(mrb, "i", &tmr);
291
292 if (tmr < 0)
293 ptimer = NULL;
294 else {
295 timer.tv_sec = tmr / 1000;
296 timer.tv_usec = (tmr % 1000) * 1000;
297 ptimer = &timer;
298 }
299
300 FD_ZERO(&readfds);
301 FD_ZERO(&writefds);
302 FD_ZERO(&errorfds);
303 FD_SET(sock, &readfds);
304 FD_SET(sock, &writefds);
305 FD_SET(sock, &errorfds);
306
307 /* メッセージ待ち */
308 memset(msg, 0, sizeof(*msg));
309 ret = select(sock + 1, &readfds, &writefds, &errorfds, ptimer);
310 if (ret < 0)
311 mrb_raise(mrb, E_RUNTIME_ERROR, "socket select error");
312 if (FD_ISSET(sock, &readfds)) {
313 int fromlen = sizeof(msg->dst);
314 msg->len = recvfrom(sock, msg->buffer, sizeof(msg->buffer), 0, &msg->dst, &fromlen);
315 if (msg->len < 0) {
316 printf("recvfrom %d", msg->len);
317 return mrb_nil_value();
318 }
319 }
320
321 ret2 = gettimeofday(&now, NULL);
322 if (ret2 != 0) {
323 printf("gettimeofday");
324 return mrb_nil_value();
325 }
326
327 timersub(&now, &main_time, &elps);
328 arv[0] = mrb_fixnum_value(elps.tv_sec);
329 main_time = now;
330
331 /* タイムアウトの場合 */
332 if (ret == 0) {
333 return mrb_ary_new_from_values(mrb, 1, arv);
334 }
335
336 /* 内部イベントの場合 */
337 if (msg->dst.sin_addr.s_addr == 0) {
338 /* Ethernet Link up */
339 if (msg->buffer[0] & IF_FLAG_LINK_UP) {
340 arv[1] = mrb_fixnum_value(1);
341 }
342 /* EP Link up */
343 else if (msg->buffer[0] & IF_FLAG_UP) {
344 arv[1] = mrb_fixnum_value(2);
345 }
346
347 return mrb_ary_new_from_values(mrb, 2, arv);
348 }
349 /* Echonet電文受信の場合 */
350 else {
351 /* 通信端点 */
352 arv[1] = mrb_str_new(mrb, (char *)&msg->dst, sizeof(msg->dst));
353
354 /* 受信データ */
355 arv[2] = mrb_str_new(mrb, (char *)msg->buffer, msg->len);
356
357 return mrb_ary_new_from_values(mrb, 3, arv);
358 }
359}
360
361/*
362 * アプリケーションタスクの登録
363 */
364static mrb_value mrb_target_board_restart(mrb_state *mrb, mrb_value self)
365{
366 /* DHCP開始 */
367
368 return self;
369}
370
371/*
372 * 通信レイヤーへの送信
373 */
374static mrb_value mrb_target_board_snd_msg(mrb_state *mrb, mrb_value self)
375{
376 mrb_value rep;
377 mrb_value rdat;
378 struct sockaddr_in *ep;
379 int ret;
380
381 mrb_get_args(mrb, "SS", &rep, &rdat);
382
383 if (RSTRING_LEN(rep) != sizeof(struct sockaddr_in)) {
384 mrb_raise(mrb, E_RUNTIME_ERROR, "snd_msg");
385 return mrb_nil_value();
386 }
387
388 ep = (struct sockaddr_in *)RSTRING_PTR(rep);
389
390 ret = sendto(sock, RSTRING_PTR(rdat), RSTRING_LEN(rdat), 0, (struct sockaddr *)ep, sizeof(*ep));
391 if (ret < 0) {
392 mrb_raise(mrb, E_RUNTIME_ERROR, "sendto");
393 return mrb_nil_value();
394 }
395
396 return mrb_nil_value();
397}
398
399/*
400 * ローカルアドレスか確認
401 */
402static mrb_value mrb_target_board_is_local_addr(mrb_state *mrb, mrb_value self)
403{
404 mrb_value rep;
405 struct sockaddr_in *ep;
406
407 mrb_get_args(mrb, "S", &rep);
408
409 if (RSTRING_LEN(rep) < sizeof(struct sockaddr_in)) {
410 mrb_raise(mrb, E_RUNTIME_ERROR, "is_local_addr");
411 return mrb_nil_value();
412 }
413
414 ep = (struct sockaddr_in *)RSTRING_PTR(rep);
415
416 return (ep->sin_addr.s_addr == MAKE_IPV4_ADDR(127, 0, 0, 1)) ? mrb_true_value() : mrb_false_value();
417}
418
419/*
420 * マルチキャストアドレスか確認
421 */
422static mrb_value mrb_target_board_is_multicast_addr(mrb_state *mrb, mrb_value self)
423{
424 mrb_value rep;
425 struct sockaddr_in *ep;
426
427 mrb_get_args(mrb, "S", &rep);
428
429 if (RSTRING_LEN(rep) < sizeof(struct sockaddr_in)) {
430 mrb_raise(mrb, E_RUNTIME_ERROR, "is_multicast_addr");
431 return mrb_nil_value();
432 }
433
434 ep = (struct sockaddr_in *)RSTRING_PTR(rep);
435
436 return (ep->sin_addr.s_addr == MAKE_IPV4_ADDR(224, 0, 23, 0)) ? mrb_true_value() : mrb_false_value();
437}
438
439/*
440 * 同一アドレスか確認
441 */
442static mrb_value mrb_target_board_equals_addr(mrb_state *mrb, mrb_value self)
443{
444 mrb_value rep1, rep2;
445 struct sockaddr_in *ep1, *ep2;
446
447 mrb_get_args(mrb, "SS", &rep1, &rep2);
448
449 if ((RSTRING_LEN(rep1) != sizeof(struct sockaddr_in)) || (RSTRING_LEN(rep2) != sizeof(struct sockaddr_in))) {
450 mrb_raise(mrb, E_RUNTIME_ERROR, "equals_addr");
451 return mrb_nil_value();
452 }
453
454 ep1 = (struct sockaddr_in *)RSTRING_PTR(rep1);
455 ep2 = (struct sockaddr_in *)RSTRING_PTR(rep2);
456
457 return (ep1->sin_addr.s_addr == ep2->sin_addr.s_addr) ? mrb_true_value() : mrb_false_value();
458}
459
460/*
461 * ローカルアドレスの取得
462 */
463static mrb_value mrb_target_board_get_local_addr(mrb_state *mrb, mrb_value self)
464{
465 struct sockaddr_in ep;
466 mrb_value rep;
467
468 memset(&ep, 0, sizeof(ep));
469 ep.sin_family = AF_INET;
470 ep.sin_addr.s_addr = MAKE_IPV4_ADDR(127, 0, 0, 1);
471 ep.sin_port = htons(3610);
472
473 rep = mrb_str_new(mrb, (char *)&ep, sizeof(ep));
474
475 return rep;
476}
477
478/*
479 * マルチキャストアドレスの取得
480 */
481static mrb_value mrb_target_board_get_multicast_addr(mrb_state *mrb, mrb_value self)
482{
483 struct sockaddr_in ep;
484 mrb_value rep;
485
486 memset(&ep, 0, sizeof(ep));
487 ep.sin_family = AF_INET;
488 ep.sin_addr.s_addr = MAKE_IPV4_ADDR(224, 0, 23, 0);
489 ep.sin_port = htons(3610);
490
491 rep = mrb_str_new(mrb, (char *)&ep, sizeof(ep));
492
493 return rep;
494}
495
496void mrb_mruby_others_gem_init(mrb_state* mrb)
497{
498 if (!echonet)
499 return;
500
501 _module_target_board = mrb_define_module(mrb, "TargetBoard");
502
503 mrb_define_class_method(mrb, _module_target_board, "wait_msg", mrb_target_board_wait_msg, MRB_ARGS_REQ(1));
504 mrb_define_class_method(mrb, _module_target_board, "restart", mrb_target_board_restart, MRB_ARGS_NONE());
505 mrb_define_class_method(mrb, _module_target_board, "snd_msg", mrb_target_board_snd_msg, MRB_ARGS_REQ(2));
506 mrb_define_class_method(mrb, _module_target_board, "is_local_addr", mrb_target_board_is_local_addr, MRB_ARGS_REQ(1));
507 mrb_define_class_method(mrb, _module_target_board, "is_multicast_addr", mrb_target_board_is_multicast_addr, MRB_ARGS_REQ(1));
508 mrb_define_class_method(mrb, _module_target_board, "equals_addr", mrb_target_board_equals_addr, MRB_ARGS_REQ(2));
509 mrb_define_class_method(mrb, _module_target_board, "get_local_addr", mrb_target_board_get_local_addr, MRB_ARGS_NONE());
510 mrb_define_class_method(mrb, _module_target_board, "get_multicast_addr", mrb_target_board_get_multicast_addr, MRB_ARGS_NONE());
511
512 mrb_target_board_init();
513}
514
515void mrb_mruby_others_gem_final(mrb_state* mrb)
516{
517 if (!echonet)
518 return;
519
520 mrb_target_board_final();
521}
522
523// Provide implementation of _sbrk (low-level dynamic memory allocation
524// routine) for GCC_ARM which compares new heap pointer with MSP instead of
525// SP. This make it compatible with RTX RTOS thread stacks.
526
527// Linker defined symbol used by _sbrk to indicate where heap should start.
528int _end;
529uint32_t _stack;
530
531// Turn off the errno macro and use actual global variable instead.
532#undef errno
533int errno;
534
535static unsigned char* heap = (unsigned char*)&_end;
536
537// Dynamic memory allocation related syscall.
538caddr_t _sbrk(int incr) {
539 unsigned char* prev_heap = heap;
540 unsigned char* new_heap = heap + incr;
541
542 if (new_heap >= (unsigned char*)&_stack) { /* _stack is end of heap section */
543 errno = ENOMEM;
544 return (caddr_t)-1;
545 }
546
547 heap = new_heap;
548 return (caddr_t) prev_heap;
549}
550
551char *optarg;
552int _data, _mdata, _edata;
553int _bss, _ebss;
554
555int _PowerON_Reset(int argc, char **argv)
556{
557 memcpy(&_data, &_mdata, (size_t)&_edata - (size_t)&_data);
558 memset(&_bss, 0, (size_t)&_ebss - (size_t)&_bss);
559
560 optarg = *argv;
561 return main(argc, argv);
562}
563
564#define FVECT_SECT __attribute__ ((section (".fvectors")))
565const void *HardwareVectors[] FVECT_SECT = {
566 _PowerON_Reset,
567 mrdb_break,
568};
569
570char stack_space[0x100000] __attribute__ ((section (".stack")));
Note: See TracBrowser for help on using the repository browser.