source: EcnlProtoTool/trunk/ntshell/src/main.c@ 443

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

prototoolにelfファイルヘッダーを付けてntshellで必要な情報を読み取れるよう変更

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 16.6 KB
Line 
1/*
2 * TOPPERS PROJECT Home Network Working Group Software
3 *
4 * Copyright (C) 2014-2019 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 <kernel.h>
43#include <t_stdlib.h>
44#include <sil.h>
45#include <setjmp.h>
46#include <string.h>
47#include "syssvc/serial.h"
48#include "syssvc/syslog.h"
49#include "target_syssvc.h"
50#include "kernel_cfg.h"
51#include "main.h"
52#include "mbed_retarget.h"
53#include "fdtable.h"
54#ifndef NTSHELL_NO_SOCKET
55#include <tinet_config.h>
56#include <netinet/in.h>
57#include <netinet/in_itron.h>
58#include <tinet_nic_defs.h>
59#include <tinet_cfg.h>
60#include <netinet/in_var.h>
61#include <net/ethernet.h>
62#include <net/if6_var.h>
63#include <net/net.h>
64#include <net/if_var.h>
65#include <netinet/udp_var.h>
66#include "ffarch.h"
67#include "ff.h"
68#include "websocket_fbs.h"
69#include "core/ntshell.h"
70#include "core/ntlibc.h"
71#include "usrcmd.h"
72#include "util/ntopt.h"
73#include "netapp/dhcp4_cli.h"
74#include "ntp_cli.h"
75#include "netcmd.h"
76#endif
77#include "../musl-1.1.18/include/elf.h"
78
79ID ws_api_mailboxid = MAIN_DATAQUEUE;
80ID ws_mempoolid = MPF_NET_BUF_256;
81
82char command[NTOPT_TEXT_MAXLEN];
83
84const uint8_t mac_addr[6] = {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC};
85
86enum main_state_t {
87 main_state_start,
88 main_state_idle,
89#ifndef NTSHELL_NO_SOCKET
90 main_state_start_dhcp,
91#endif
92 main_state_servey_cmd,
93};
94
95struct main_obj_t {
96 ntshell_t ntshell;
97 int timer;
98 enum main_state_t state;
99 SYSTIM prev, now;
100 task_base_t **tasks;
101 int task_count;
102#ifndef NTSHELL_NO_SOCKET
103 uint8_t link;
104 uint8_t link_up;
105 uint8_t up;
106 uint8_t dhcp;
107 uint8_t ntp;
108 ntp_cli_state_t ntp_state;
109#endif
110 bool_t exec;
111 int event_req, event_res;
112};
113struct main_obj_t main_obj;
114
115#ifndef NTSHELL_NO_SOCKET
116static void netif_link_callback(T_IFNET *ether);
117static void main_change_netif_link(uint8_t link_up, uint8_t up);
118#endif
119static void main_initialize(struct main_obj_t *obj);
120static void main_finalize(struct main_obj_t *obj);
121static int main_get_timer(struct main_obj_t *obj);
122static void main_progress(struct main_obj_t *obj, int elapse);
123static void main_timeout(struct main_obj_t *obj, bool_t wakeup);
124static int execute_command(struct main_obj_t *obj, int wait);
125static const Elf32_Ehdr *load_elf(const uint8_t *file);
126static void execute_elf(const Elf32_Ehdr *, long *args);
127static int usrcmd_ntopt_callback(long *args, void *extobj);
128#ifndef NTSHELL_NO_SOCKET
129static void ntp_cli_state_changed(ntp_cli_state_t state);
130#endif
131
132void stdio_open(ID portid);
133void stdio_input(unsigned char c);
134
135bool_t dhcp_enable;
136int ntshell_exit;
137int shellcmd_exit_code;
138volatile int shellcmd_state;
139typedef void (*elf_entry_t)(long *args);
140jmp_buf shellcmd_exit;
141
142void main_task_init(task_base_t **tasks, int task_count)
143{
144 main_obj.tasks = tasks;
145 main_obj.task_count = task_count;
146}
147
148int uart_read(char *buf, int cnt, void *extobj)
149{
150 struct main_obj_t *obj = (struct main_obj_t *)extobj;
151 int result;
152 ER ret;
153 int timer;
154 bool_t wakeup = false;
155
156 obj->prev = obj->now;
157
158 if (obj->event_req != obj->event_res) {
159 obj->event_res = obj->event_req;
160 wakeup = true;
161#ifndef NTSHELL_NO_SOCKET
162 if (obj->dhcp) {
163 obj->dhcp = 0;
164 obj->state = main_state_start_dhcp;
165 }
166#endif
167 obj->timer = 0;
168 }
169
170 /* タイマー取得 */
171 timer = main_get_timer(obj);
172
173 /* 待ち */
174 ret = serial_trea_dat(SIO_PORTID, buf, cnt, timer);
175 if ((ret < 0) && (ret != E_OK) && (ret != E_TMOUT) && (ret != E_RLWAI)) {
176 syslog(LOG_NOTICE, "tslp_tsk ret: %s %d", itron_strerror(ret), timer);
177 ntshell_exit = 1;
178 return -1;
179 }
180 if (ret != E_TMOUT)
181 wakeup = true;
182 result = (int)ret;
183
184 ret = get_tim(&obj->now);
185 if (ret != E_OK) {
186 syslog(LOG_NOTICE, "get_tim ret: %s", itron_strerror(ret));
187 ntshell_exit = 1;
188 return -1;
189 }
190
191 /* 時間経過 */
192 int elapse = obj->now - obj->prev;
193 main_progress(obj, elapse);
194
195 /* タイムアウト処理 */
196 main_timeout(obj, wakeup);
197
198 return result;
199}
200
201int uart_write(const char *buf, int cnt, void *extobj)
202{
203 return serial_wri_dat(SIO_PORTID, buf, cnt);
204}
205
206int cmd_execute(const char *text, void *extobj)
207{
208 if (text != NULL) {
209 strlcpy(command, text, sizeof(command));
210 }
211 ER ret;
212 ID tskid = 0;
213
214 ret = get_tid(&tskid);
215 if (ret != E_OK) {
216 syslog(LOG_ERROR, "get_tid %d", ret);
217 }
218
219 return execute_command(&main_obj, tskid == MAIN_TASK);
220}
221
222gpio_t led_blue, led_green, led_red, sw;
223
224/*
225 * メインタスク
226 */
227void main_task(intptr_t exinf)
228{
229 struct main_obj_t *obj = (struct main_obj_t *)&main_obj;
230
231 gpio_init_out(&led_blue, LED_BLUE);
232 gpio_init_out(&led_green, LED_GREEN);
233 gpio_init_out(&led_red, LED_RED);
234 gpio_init_in(&sw, USER_BUTTON0);
235
236 obj->exec = gpio_read(&sw) == 1;
237
238 gpio_write(&led_blue, 1);
239 gpio_write(&led_green, obj->exec ? 1 : 0);
240 gpio_write(&led_red, 0);
241
242 ether_set_link_callback(main_change_netif_link);
243
244 /* 初期化 */
245 ffarch_init();
246
247 stdio_open(SIO_PORTID);
248
249#ifndef NTSHELL_NO_SOCKET
250 ntp_cli_set_state_changed_cb(ntp_cli_state_changed);
251#endif
252
253 main_initialize(obj);
254
255 ntshell_init(&obj->ntshell, uart_read, uart_write, cmd_execute, obj);
256 ntshell_set_prompt(&obj->ntshell, "NTShell>");
257 ntshell_execute(&obj->ntshell);
258
259 main_finalize(obj);
260}
261
262/*
263 * 初期化
264 */
265static void main_initialize(struct main_obj_t *obj)
266{
267 ER ret;
268 ID tskid = 0;
269
270 ret = get_tid(&tskid);
271 if (ret != E_OK) {
272 syslog(LOG_ERROR, "get_tid %d", ret);
273 return;
274 }
275
276 obj->timer = 100000;
277 obj->state = main_state_start;
278
279 for (int i = 0; i < obj->task_count; i++) {
280 task_base_t *task = obj->tasks[i];
281 task->on_start(task, tskid);
282 }
283
284 gpio_write(&led_blue, 0);
285 gpio_write(&led_green, 0);
286
287 act_tsk(HTTPD1_TASK);
288 act_tsk(HTTPD2_TASK);
289
290 ret = get_tim(&obj->now);
291 if (ret != E_OK) {
292 syslog(LOG_ERROR, "get_tim");
293 ext_tsk();
294 return;
295 }
296}
297
298static void main_finalize(struct main_obj_t *obj)
299{
300 for (int i = 0; i < obj->task_count; i++) {
301 task_base_t *task = obj->tasks[i];
302 task->on_end(task);
303 }
304}
305
306/*
307 * タイマー取得
308 */
309static int main_get_timer(struct main_obj_t *obj)
310{
311 int timer = obj->timer;
312
313 for (int i = 0; i < obj->task_count; i++) {
314 task_base_t *task = obj->tasks[i];
315 int timer2 = task->get_timer(task);
316 if ((timer == -1) || ((timer2 != -1) && (timer > timer2)))
317 timer = timer2;
318 }
319
320 return timer;
321}
322
323/*
324 * 時間経過
325 */
326static void main_progress(struct main_obj_t *obj, int elapse)
327{
328 if (obj->timer != TMO_FEVR) {
329 obj->timer -= elapse;
330 if (obj->timer < 0) {
331 obj->timer = 0;
332 }
333 }
334
335 for (int i = 0; i < obj->task_count; i++) {
336 task_base_t *task = obj->tasks[i];
337 task->progress(task, elapse);
338 }
339}
340
341/*
342 * タイムアウト処理
343 */
344static void main_timeout(struct main_obj_t *obj, bool_t wakeup)
345{
346 ER ret;
347 uint32_t event = wakeup ? MAIN_EVENT_WAKEUP : 0;
348
349 if (!wakeup && (obj->timer != 0))
350 return;
351
352 switch (obj->state) {
353 case main_state_start:
354#ifndef NTSHELL_NO_SOCKET
355 ether_set_link_callback(netif_link_callback);
356#endif
357 {
358 FILINFO fno;
359#if FF_USE_LFN
360 char lfn[FF_MAX_LFN + 1];
361 fno.lfname = lfn;
362 fno.lfsize = FF_MAX_LFN + 1;
363#endif
364 if (f_stat("1:/upload/main.mrb", &fno) != FR_OK) {
365 obj->exec = false;
366 }
367
368 if (obj->exec) {
369 cmd_execute("mruby -b 1:/upload/main.mrb", obj);
370 }
371 }
372 obj->state = main_state_idle;
373 obj->timer = TMO_FEVR;
374 break;
375#ifndef NTSHELL_NO_SOCKET
376 case main_state_start_dhcp:
377 ret = dhcp4c_renew_info();
378 if (ret == E_OK) {
379 obj->state = main_state_idle;
380 obj->timer = TMO_FEVR;
381 }
382 else {
383 obj->state = main_state_start_dhcp;
384 obj->timer = 1000000;
385 }
386 break;
387#endif
388 default:
389 obj->state = main_state_idle;
390 obj->timer = TMO_FEVR;
391 break;
392 }
393#ifndef NTSHELL_NO_SOCKET
394 if (obj->link) {
395 obj->link = 0;
396 event |= MAIN_EVENT_NETIF_CHANGED;
397 if (obj->link_up)
398 event |= MAIN_EVENT_LINK_UP;
399 if (obj->up)
400 event |= MAIN_EVENT_UP;
401
402 if (obj->link_up && obj->up)
403 ntp_cli_execute();
404
405 main_change_netif_link(obj->link_up, obj->up);
406 }
407 if (obj->ntp) {
408 obj->ntp = 0;
409 if (obj->ntp_state != NTP_CLI_STATE_SYNC)
410 event |= MAIN_EVENT_NTP_ASYNC;
411 else
412 event |= MAIN_EVENT_NTP_SYNC;
413 }
414#endif
415 for (int i = 0; i < obj->task_count; i++) {
416 task_base_t *task = obj->tasks[i];
417 task->process(task, event);
418 }
419}
420
421#ifndef NTSHELL_NO_SOCKET
422/* MACアドレスの設定時に呼ばれる */
423void mbed_mac_address(char *mac)
424{
425 memcpy(mac, mac_addr, 6);
426}
427
428void main_change_netif_link(uint8_t link_up, uint8_t up)
429{
430 FLGPTN flgptn;
431 T_RTSK rtsk;
432 ER ret;
433
434 ret = ref_tsk(SHELLCMD_TASK, &rtsk);
435 if ((ret != E_OK) || (rtsk.tskstat == TTS_DMT))
436 return;
437
438 FD_SET(0, (fd_set *)&flgptn);
439
440 set_flg(FLG_SELECT_WAIT, flgptn);
441}
442
443void netif_link_callback(T_IFNET *ether)
444{
445 struct main_obj_t *obj = (struct main_obj_t *)&main_obj;
446 uint8_t link_up = (ether->flags & IF_FLAG_LINK_UP) != 0;
447 uint8_t up = (ether->flags & IF_FLAG_UP) != 0;
448 bool_t wake = false;
449
450 if (dhcp_enable) {
451 if (!link_up)
452 dhcp4c_rel_info();
453 else if (!up) {
454 wake = dhcp4c_renew_info() != E_OK;
455 if (wake) {
456 obj->dhcp = 1;
457 }
458 }
459 }
460 else {
461 up = link_up;
462 }
463
464 if ((obj->link_up != link_up) || (obj->up != up)) {
465 obj->link = 1;
466 wake = true;
467 }
468
469 obj->link_up = link_up;
470 obj->up = up;
471
472 if (wake && (obj->event_req == obj->event_res)) {
473 obj->event_req++;
474 rel_wai(MAIN_TASK);
475 }
476}
477
478void ntp_cli_state_changed(ntp_cli_state_t state)
479{
480 struct main_obj_t *obj = (struct main_obj_t *)&main_obj;
481 bool_t wake = obj->ntp_state != state;
482
483 if (wake) {
484 obj->ntp_state = state;
485 obj->ntp = 1;
486
487 if (obj->event_req == obj->event_res) {
488 obj->event_req++;
489 rel_wai(MAIN_TASK);
490 }
491 }
492}
493#endif
494
495/*
496 * shellcmdタスク
497 */
498void shellcmd_task(intptr_t exinf)
499{
500 shellcmd_state = 1;
501
502 if (setjmp(shellcmd_exit) == 0) {
503 shellcmd_exit_code = ntopt_parse(command, usrcmd_ntopt_callback, NULL);
504 }
505
506 //fflush(stdout);
507 clean_fd();
508
509 shellcmd_state = 2;
510}
511
512static const cmd_table_t cmdlist[] = {
513 {"cd", "change directory", usrcmd_cd },
514 {"ls", "list files", usrcmd_ls },
515 {"cp", "copy file", usrcmd_cp },
516 {"rm", "remove file", usrcmd_rm },
517 {"mv", "move file", usrcmd_mv },
518 {"mkdir", "Make directory", usrcmd_mkdir},
519 {"hexdump", "Hex dump", usrcmd_hexdump},
520 {"date", "print date and time", usrcmd_date},
521#ifndef NTSHELL_NO_SOCKET
522 {"ping", "ping", usrcmd_ping},
523 {"dhcpc", "DHCP Client rel/renew/info", usrcmd_dhcp4c},
524 {"dnsc", "DNS client", usrcmd_dnsc },
525 {"ntpc", "NTP client", usrcmd_ntpc },
526#endif
527 {"info", "This is a description text string for info command.", usrcmd_info},
528 {"exit", "Exit Natural Tiny Shell", usrcmd_exit},
529};
530cmd_table_info_t cmd_table_info = { cmdlist, sizeof(cmdlist) / sizeof(cmdlist[0]) };
531
532static int usrcmd_ntopt_callback(long *args, void *extobj)
533{
534 const cmd_table_t *p = cmd_table_info.table;
535 int result = 0;
536 int found = 0;
537
538 if (*args == 0)
539 return result;
540
541 if (strcmp((const char *)args[1], "help") == 0) {
542 result = usrcmd_help(args[0], (char **)&args[1]);
543 }
544 else for (int i = 0; i < cmd_table_info.count; i++) {
545 if (strcmp((const char *)args[1], p->cmd) == 0) {
546 found = 1;
547 result = p->func(args[0], (char **)&args[1]);
548 break;
549 }
550 p++;
551 }
552
553 if ((found == 0) && setjmp(shellcmd_exit) == 0) {
554 const Elf32_Ehdr *elf = load_elf((const uint8_t *)0x18200000);
555 if (elf != NULL) {
556 found = 1;
557 execute_elf(elf, args);
558 }
559 }
560
561 if ((found == 0) && (((const char *)args[1])[0] != '\0'))
562 printf("Unknown command found. %s \n", (const char *)args[1]);
563
564 return result;
565}
566
567int usrcmd_help(int argc, char **argv)
568{
569 const cmd_table_t *p = cmd_table_info.table;
570 for (int i = 0; i < cmd_table_info.count; i++) {
571 printf(p->cmd);
572 printf("\t:");
573 puts(p->desc);
574 p++;
575 }
576 return 0;
577}
578
579void shellif_into()
580{
581 /* メインタスクの優先度より高くする */
582 chg_pri(SHELLCMD_PRIORITY, MAIN_PRIORITY + 1);
583}
584
585void shellif_outof()
586{
587 /* shellcmdタスクの優先度に戻す */
588 chg_pri(SHELLCMD_PRIORITY, SHELLCMD_PRIORITY);
589}
590
591int execute_command(struct main_obj_t *obj, int wait)
592{
593 T_RTSK rtsk;
594 ER ret;
595
596 ret = ter_tsk(SHELLCMD_TASK);
597 if ((ret != E_OK) && (ret != E_OBJ)) {
598 syslog(LOG_ERROR, "ter_tsk => %d", ret);
599 }
600
601 if (ret == E_OK)
602 tslp_tsk(100000);
603
604 clean_fd();
605
606 shellcmd_state = 0;
607 ret = act_tsk(SHELLCMD_TASK);
608 if (ret != E_OK) {
609 syslog(LOG_ERROR, "act_tsk => %d", ret);
610 }
611
612 if (wait == 0)
613 return 0;
614
615 do {
616 obj->state = main_state_servey_cmd;
617 obj->timer = 100000;
618
619 char c;
620 if (obj->ntshell.func_read(&c, sizeof(c), obj->ntshell.extobj) == 1) {
621 // Ctrl+Cが押された場合
622 if (c == 0x03) {
623 // コマンドタスクを終了
624 ret = ter_tsk(SHELLCMD_TASK);
625 if (ret != E_OK) {
626 syslog(LOG_ERROR, "ter_tsk => %d", ret);
627 }
628 shellcmd_exit_code = -1;
629 shellcmd_state = 4;
630 if (ret == E_OK)
631 tslp_tsk(100000);
632 break;
633 }
634
635 stdio_input(c);
636 }
637
638 ret = ref_tsk(SHELLCMD_TASK, &rtsk);
639 if ((ret != E_OK) || (rtsk.tskstat == TTS_DMT))
640 shellcmd_state = 3;
641 } while(shellcmd_state == 1);
642
643 obj->state = main_state_idle;
644 obj->timer = TMO_FEVR;
645
646 clean_fd();
647
648 return shellcmd_exit_code;
649}
650
651const Elf32_Ehdr *load_elf(const uint8_t *file)
652{
653 Elf32_Ehdr Ehdr;
654
655 memcpy(&Ehdr, &file[0], sizeof(Elf32_Ehdr));
656
657 // Magic
658 if ((Ehdr.e_ident[EI_MAG0] != ELFMAG0)
659 || (Ehdr.e_ident[EI_MAG1] != ELFMAG1)
660 || (Ehdr.e_ident[EI_MAG2] != ELFMAG2)
661 || (Ehdr.e_ident[EI_MAG3] != ELFMAG3))
662 return NULL;
663
664 // Class
665 if (Ehdr.e_ident[EI_CLASS] != ELFCLASS32)
666 return NULL;
667
668 // Byte order
669 if (Ehdr.e_ident[EI_DATA] != ELFDATA2LSB)
670 return NULL;
671
672 // ELF Version
673 if (Ehdr.e_ident[EI_VERSION] != EV_CURRENT)
674 return NULL;
675
676 // type
677 if (Ehdr.e_type != ET_EXEC)
678 return NULL;
679
680 // Machine
681 if (Ehdr.e_machine != EM_ARM)
682 return NULL;
683
684 if (Ehdr.e_version != EV_CURRENT)
685 return NULL;
686
687 return (const Elf32_Ehdr *)file;
688}
689
690void execute_elf(const Elf32_Ehdr *Ehdr, long *args)
691{
692 const uint8_t *file = (const uint8_t *)Ehdr;
693 Elf32_Shdr StringShdr;
694 memcpy(&StringShdr, &file[Ehdr->e_shoff + (Ehdr->e_shstrndx * Ehdr->e_shentsize)], sizeof(StringShdr));
695
696 if (Ehdr->e_shoff > 0) {
697 Elf32_Shdr Shdr;
698 for (int i = 0; i < Ehdr->e_shnum; i++) {
699 memcpy(&Shdr, (Elf32_Shdr *)&file[Ehdr->e_shoff + (i * Ehdr->e_shentsize)], sizeof(Elf32_Shdr));
700 Shdr.sh_size -= Shdr.sh_addr;
701
702 char *name;
703 if (Shdr.sh_name > 0) {
704 name = (char *)&file[StringShdr.sh_offset + Shdr.sh_name];
705 }
706 else {
707 name = NULL;
708 }
709
710 if ((Shdr.sh_flags & SHF_ALLOC) == 0) {
711 // skip
712 }
713 else if (Shdr.sh_type == SHT_PROGBITS) {
714 if ((Shdr.sh_flags & SHF_WRITE) == 0) {
715 // inplace
716 }
717 else {
718 memcpy(Shdr.sh_addr, Shdr.sh_offset, Shdr.sh_size);
719 }
720 }
721 else if (Shdr.sh_type == SHT_NOBITS) {
722 memset(Shdr.sh_addr, 0, Shdr.sh_size);
723 }
724 else {
725 // skip
726 }
727 }
728 }
729
730 ((elf_entry_t)Ehdr->e_entry)(args);
731}
Note: See TracBrowser for help on using the repository browser.