/* * TOPPERS PROJECT Home Network Working Group Software * * Copyright (C) 2014-2019 Cores Co., Ltd. Japan * * 上記著作権者は,以下の(1)~(4)の条件を満たす場合に限り,本ソフトウェ * ア(本ソフトウェアを改変したものを含む.以下同じ)を使用・複製・改 * 変・再配布(以下,利用と呼ぶ)することを無償で許諾する. * (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作 * 権表示,この利用条件および下記の無保証規定が,そのままの形でソー * スコード中に含まれていること. * (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使 * 用できる形で再配布する場合には,再配布に伴うドキュメント(利用 * 者マニュアルなど)に,上記の著作権表示,この利用条件および下記 * の無保証規定を掲載すること. * (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使 * 用できない形で再配布する場合には,次のいずれかの条件を満たすこ * と. * (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著 * 作権表示,この利用条件および下記の無保証規定を掲載すること. * (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに * 報告すること. * (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損 * 害からも,上記著作権者およびTOPPERSプロジェクトを免責すること. * また,本ソフトウェアのユーザまたはエンドユーザからのいかなる理 * 由に基づく請求からも,上記著作権者およびTOPPERSプロジェクトを * 免責すること. * * 本ソフトウェアは,無保証で提供されているものである.上記著作権者お * よびTOPPERSプロジェクトは,本ソフトウェアに関して,特定の使用目的 * に対する適合性も含めて,いかなる保証も行わない.また,本ソフトウェ * アの利用により直接的または間接的に生じたいかなる損害に関しても,そ * の責任を負わない. * * @(#) $Id$ */ /* * サンプルプログラム(1)の本体 */ #include #include #include #include #include #include "syssvc/serial.h" #include "syssvc/syslog.h" #include "target_syssvc.h" #include "kernel_cfg.h" #include "main.h" #include "mbed_retarget.h" #include "fdtable.h" #ifndef NTSHELL_NO_SOCKET #include #include #include #include #include #include #include #include #include #include #include #include "ffarch.h" #include "ff.h" #include "websocket_fbs.h" #include "core/ntshell.h" #include "core/ntlibc.h" #include "usrcmd.h" #include "util/ntopt.h" #include "netapp/dhcp4_cli.h" #include "ntp_cli.h" #include "netcmd.h" #endif #include "../musl-1.1.18/include/elf.h" ID ws_api_mailboxid = MAIN_DATAQUEUE; ID ws_mempoolid = MPF_NET_BUF_256; char command[NTOPT_TEXT_MAXLEN]; const uint8_t mac_addr[6] = {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC}; enum main_state_t { main_state_start, main_state_idle, #ifndef NTSHELL_NO_SOCKET main_state_start_dhcp, #endif main_state_servey_cmd, }; struct main_obj_t { ntshell_t ntshell; int timer; enum main_state_t state; SYSTIM prev, now; task_base_t **tasks; int task_count; #ifndef NTSHELL_NO_SOCKET uint8_t link; uint8_t link_up; uint8_t up; uint8_t dhcp; uint8_t ntp; ntp_cli_state_t ntp_state; #endif bool_t exec; int event_req, event_res; }; struct main_obj_t main_obj; #ifndef NTSHELL_NO_SOCKET static void netif_link_callback(T_IFNET *ether); static void main_change_netif_link(uint8_t link_up, uint8_t up); #endif static void main_initialize(struct main_obj_t *obj); static void main_finalize(struct main_obj_t *obj); static int main_get_timer(struct main_obj_t *obj); static void main_progress(struct main_obj_t *obj, int elapse); static void main_timeout(struct main_obj_t *obj, bool_t wakeup); static int execute_command(struct main_obj_t *obj, int wait); static const Elf32_Ehdr *load_elf(const uint8_t *file); static void execute_elf(const Elf32_Ehdr *, long *args); static void read_cmdlist_from_elf(const Elf32_Ehdr *Ehdr); static int usrcmd_ntopt_callback(long *args, void *extobj); #ifndef NTSHELL_NO_SOCKET static void ntp_cli_state_changed(ntp_cli_state_t state); #endif void stdio_open(ID portid); void stdio_input(unsigned char c); bool_t dhcp_enable; int ntshell_exit; int shellcmd_exit_code; volatile int shellcmd_state; typedef void (*elf_entry_t)(long *args); jmp_buf shellcmd_exit; void main_task_init(task_base_t **tasks, int task_count) { main_obj.tasks = tasks; main_obj.task_count = task_count; } int uart_read(char *buf, int cnt, void *extobj) { struct main_obj_t *obj = (struct main_obj_t *)extobj; int result; ER ret; int timer; bool_t wakeup = false; obj->prev = obj->now; if (obj->event_req != obj->event_res) { obj->event_res = obj->event_req; wakeup = true; #ifndef NTSHELL_NO_SOCKET if (obj->dhcp) { obj->dhcp = 0; obj->state = main_state_start_dhcp; } #endif obj->timer = 0; } /* タイマー取得 */ timer = main_get_timer(obj); /* 待ち */ ret = serial_trea_dat(SIO_PORTID, buf, cnt, timer); if ((ret < 0) && (ret != E_OK) && (ret != E_TMOUT) && (ret != E_RLWAI)) { syslog(LOG_NOTICE, "tslp_tsk ret: %s %d", itron_strerror(ret), timer); ntshell_exit = 1; return -1; } if (ret != E_TMOUT) wakeup = true; result = (int)ret; ret = get_tim(&obj->now); if (ret != E_OK) { syslog(LOG_NOTICE, "get_tim ret: %s", itron_strerror(ret)); ntshell_exit = 1; return -1; } /* 時間経過 */ int elapse = obj->now - obj->prev; main_progress(obj, elapse); /* タイムアウト処理 */ main_timeout(obj, wakeup); return result; } int uart_write(const char *buf, int cnt, void *extobj) { return serial_wri_dat(SIO_PORTID, buf, cnt); } int cmd_execute(const char *text, void *extobj) { if (text != NULL) { strlcpy(command, text, sizeof(command)); } ER ret; ID tskid = 0; ret = get_tid(&tskid); if (ret != E_OK) { syslog(LOG_ERROR, "get_tid %d", ret); } return execute_command(&main_obj, tskid == MAIN_TASK); } gpio_t led_blue, led_green, led_red, sw; /* * メインタスク */ void main_task(intptr_t exinf) { struct main_obj_t *obj = (struct main_obj_t *)&main_obj; 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); obj->exec = gpio_read(&sw) == 1; gpio_write(&led_blue, 1); gpio_write(&led_green, obj->exec ? 1 : 0); gpio_write(&led_red, 0); ether_set_link_callback(main_change_netif_link); /* 初期化 */ ffarch_init(); stdio_open(SIO_PORTID); #ifndef NTSHELL_NO_SOCKET ntp_cli_set_state_changed_cb(ntp_cli_state_changed); #endif main_initialize(obj); ntshell_init(&obj->ntshell, uart_read, uart_write, cmd_execute, obj); ntshell_set_prompt(&obj->ntshell, "NTShell>"); ntshell_execute(&obj->ntshell); main_finalize(obj); } /* * 初期化 */ static void main_initialize(struct main_obj_t *obj) { ER ret; ID tskid = 0; ret = get_tid(&tskid); if (ret != E_OK) { syslog(LOG_ERROR, "get_tid %d", ret); return; } obj->timer = 100000; obj->state = main_state_start; for (int i = 0; i < obj->task_count; i++) { task_base_t *task = obj->tasks[i]; task->on_start(task, tskid); } gpio_write(&led_blue, 0); gpio_write(&led_green, 0); act_tsk(HTTPD1_TASK); act_tsk(HTTPD2_TASK); ret = get_tim(&obj->now); if (ret != E_OK) { syslog(LOG_ERROR, "get_tim"); ext_tsk(); return; } } static void main_finalize(struct main_obj_t *obj) { for (int i = 0; i < obj->task_count; i++) { task_base_t *task = obj->tasks[i]; task->on_end(task); } } /* * タイマー取得 */ static int main_get_timer(struct main_obj_t *obj) { int timer = obj->timer; for (int i = 0; i < obj->task_count; i++) { task_base_t *task = obj->tasks[i]; int timer2 = task->get_timer(task); if ((timer == -1) || ((timer2 != -1) && (timer > timer2))) timer = timer2; } return timer; } /* * 時間経過 */ static void main_progress(struct main_obj_t *obj, int elapse) { if (obj->timer != TMO_FEVR) { obj->timer -= elapse; if (obj->timer < 0) { obj->timer = 0; } } for (int i = 0; i < obj->task_count; i++) { task_base_t *task = obj->tasks[i]; task->progress(task, elapse); } } /* * タイムアウト処理 */ static void main_timeout(struct main_obj_t *obj, bool_t wakeup) { ER ret; uint32_t event = wakeup ? MAIN_EVENT_WAKEUP : 0; if (!wakeup && (obj->timer != 0)) return; switch (obj->state) { case main_state_start: #ifndef NTSHELL_NO_SOCKET ether_set_link_callback(netif_link_callback); #endif { FILINFO fno; #if FF_USE_LFN char lfn[FF_MAX_LFN + 1]; fno.lfname = lfn; fno.lfsize = FF_MAX_LFN + 1; #endif if (f_stat("1:/upload/main.mrb", &fno) != FR_OK) { obj->exec = false; } if (obj->exec) { cmd_execute("mruby -b 1:/upload/main.mrb", obj); } } obj->state = main_state_idle; obj->timer = TMO_FEVR; break; #ifndef NTSHELL_NO_SOCKET case main_state_start_dhcp: ret = dhcp4c_renew_info(); if (ret == E_OK) { obj->state = main_state_idle; obj->timer = TMO_FEVR; } else { obj->state = main_state_start_dhcp; obj->timer = 1000000; } break; #endif default: obj->state = main_state_idle; obj->timer = TMO_FEVR; break; } #ifndef NTSHELL_NO_SOCKET if (obj->link) { obj->link = 0; event |= MAIN_EVENT_NETIF_CHANGED; if (obj->link_up) event |= MAIN_EVENT_LINK_UP; if (obj->up) event |= MAIN_EVENT_UP; if (obj->link_up && obj->up) ntp_cli_execute(); main_change_netif_link(obj->link_up, obj->up); } if (obj->ntp) { obj->ntp = 0; if (obj->ntp_state != NTP_CLI_STATE_SYNC) event |= MAIN_EVENT_NTP_ASYNC; else event |= MAIN_EVENT_NTP_SYNC; } #endif for (int i = 0; i < obj->task_count; i++) { task_base_t *task = obj->tasks[i]; task->process(task, event); } } #ifndef NTSHELL_NO_SOCKET /* MACアドレスの設定時に呼ばれる */ void mbed_mac_address(char *mac) { memcpy(mac, mac_addr, 6); } void main_change_netif_link(uint8_t link_up, uint8_t up) { FLGPTN flgptn; T_RTSK rtsk; ER ret; ret = ref_tsk(SHELLCMD_TASK, &rtsk); if ((ret != E_OK) || (rtsk.tskstat == TTS_DMT)) return; FD_SET(0, (fd_set *)&flgptn); set_flg(FLG_SELECT_WAIT, flgptn); } void netif_link_callback(T_IFNET *ether) { struct main_obj_t *obj = (struct main_obj_t *)&main_obj; uint8_t link_up = (ether->flags & IF_FLAG_LINK_UP) != 0; uint8_t up = (ether->flags & IF_FLAG_UP) != 0; bool_t wake = false; if (dhcp_enable) { if (!link_up) dhcp4c_rel_info(); else if (!up) { wake = dhcp4c_renew_info() != E_OK; if (wake) { obj->dhcp = 1; } } } else { up = link_up; } if ((obj->link_up != link_up) || (obj->up != up)) { obj->link = 1; wake = true; } obj->link_up = link_up; obj->up = up; if (wake && (obj->event_req == obj->event_res)) { obj->event_req++; rel_wai(MAIN_TASK); } } void ntp_cli_state_changed(ntp_cli_state_t state) { struct main_obj_t *obj = (struct main_obj_t *)&main_obj; bool_t wake = obj->ntp_state != state; if (wake) { obj->ntp_state = state; obj->ntp = 1; if (obj->event_req == obj->event_res) { obj->event_req++; rel_wai(MAIN_TASK); } } } #endif /* * shellcmdタスク */ void shellcmd_task(intptr_t exinf) { shellcmd_state = 1; if (setjmp(shellcmd_exit) == 0) { shellcmd_exit_code = ntopt_parse(command, usrcmd_ntopt_callback, NULL); } //fflush(stdout); clean_fd(); shellcmd_state = 2; } static const cmd_table_t cmdlist[] = { {"cd", "change directory", usrcmd_cd }, {"ls", "list files", usrcmd_ls }, {"cp", "copy file", usrcmd_cp }, {"rm", "remove file", usrcmd_rm }, {"mv", "move file", usrcmd_mv }, {"mkdir", "Make directory", usrcmd_mkdir}, {"hexdump", "Hex dump", usrcmd_hexdump}, {"date", "print date and time", usrcmd_date}, #ifndef NTSHELL_NO_SOCKET {"ping", "ping", usrcmd_ping}, {"dhcpc", "DHCP Client rel/renew/info", usrcmd_dhcp4c}, {"dnsc", "DNS client", usrcmd_dnsc }, {"ntpc", "NTP client", usrcmd_ntpc }, #endif {"info", "This is a description text string for info command.", usrcmd_info}, {"exit", "Exit Natural Tiny Shell", usrcmd_exit}, {"help", "This is a description text string for help command.", usrcmd_help}, }; const cmd_table_info_t cmd_table_info = { cmdlist, sizeof(cmdlist) / sizeof(cmdlist[0]) }; cmd_table_info_t elf_cmd_table_info; static int usrcmd_ntopt_callback(long *args, void *extobj) { const cmd_table_t *p = cmd_table_info.table; int result = 0; int found = 0; if (*args == 0) return result; if (strcmp((const char *)args[1], "help") == 0) { found = 1; result = usrcmd_help(args[0], (char **)&args[1]); } else for (int i = 0; i < cmd_table_info.count; i++) { if (strcmp((const char *)args[1], p->cmd) == 0) { found = 1; result = p->func(args[0], (char **)&args[1]); break; } p++; } if ((found == 0) && setjmp(shellcmd_exit) == 0) { const Elf32_Ehdr *elf = load_elf((const uint8_t *)0x18200000); if (elf != NULL) { found = 1; execute_elf(elf, args); } } if ((found == 0) && (((const char *)args[1])[0] != '\0')) printf("Unknown command found. %s \n", (const char *)args[1]); return result; } int usrcmd_help(int argc, char **argv) { const cmd_table_t *p, *q; const Elf32_Ehdr *elf = load_elf((const uint8_t *)0x18200000); if (elf != NULL) { read_cmdlist_from_elf(elf); } else { elf_cmd_table_info.count = 0; } p = cmd_table_info.table; for (int i = 0; i < cmd_table_info.count - 3; i++, p++) { printf("%s\t:%s\n", p->cmd, p->desc); } p = elf_cmd_table_info.table; for (int i = 0; i < elf_cmd_table_info.count; i++, p++) { printf("%s\t:%s\n", p->cmd, p->desc); } p = &cmd_table_info.table[cmd_table_info.count - 3]; for (int i = cmd_table_info.count - 3; i < cmd_table_info.count; i++, p++) { printf("%s\t:%s\n", p->cmd, p->desc); } return 0; } void shellif_into() { /* メインタスクの優先度より高くする */ chg_pri(SHELLCMD_PRIORITY, MAIN_PRIORITY + 1); } void shellif_outof() { /* shellcmdタスクの優先度に戻す */ chg_pri(SHELLCMD_PRIORITY, SHELLCMD_PRIORITY); } int execute_command(struct main_obj_t *obj, int wait) { T_RTSK rtsk; ER ret; ret = ter_tsk(SHELLCMD_TASK); if ((ret != E_OK) && (ret != E_OBJ)) { syslog(LOG_ERROR, "ter_tsk => %d", ret); } if (ret == E_OK) tslp_tsk(100000); clean_fd(); shellcmd_state = 0; ret = act_tsk(SHELLCMD_TASK); if (ret != E_OK) { syslog(LOG_ERROR, "act_tsk => %d", ret); } if (wait == 0) return 0; do { obj->state = main_state_servey_cmd; obj->timer = 100000; char c; if (obj->ntshell.func_read(&c, sizeof(c), obj->ntshell.extobj) == 1) { // Ctrl+Cが押された場合 if (c == 0x03) { // コマンドタスクを終了 ret = ter_tsk(SHELLCMD_TASK); if (ret != E_OK) { syslog(LOG_ERROR, "ter_tsk => %d", ret); } shellcmd_exit_code = -1; shellcmd_state = 4; if (ret == E_OK) tslp_tsk(100000); break; } stdio_input(c); } ret = ref_tsk(SHELLCMD_TASK, &rtsk); if ((ret != E_OK) || (rtsk.tskstat == TTS_DMT)) shellcmd_state = 3; } while(shellcmd_state == 1); obj->state = main_state_idle; obj->timer = TMO_FEVR; clean_fd(); return shellcmd_exit_code; } const Elf32_Ehdr *load_elf(const uint8_t *file) { Elf32_Ehdr Ehdr; memcpy(&Ehdr, &file[0], sizeof(Elf32_Ehdr)); // Magic if ((Ehdr.e_ident[EI_MAG0] != ELFMAG0) || (Ehdr.e_ident[EI_MAG1] != ELFMAG1) || (Ehdr.e_ident[EI_MAG2] != ELFMAG2) || (Ehdr.e_ident[EI_MAG3] != ELFMAG3)) return NULL; // Class if (Ehdr.e_ident[EI_CLASS] != ELFCLASS32) return NULL; // Byte order if (Ehdr.e_ident[EI_DATA] != ELFDATA2LSB) return NULL; // ELF Version if (Ehdr.e_ident[EI_VERSION] != EV_CURRENT) return NULL; // type if (Ehdr.e_type != ET_EXEC) return NULL; // Machine if (Ehdr.e_machine != EM_ARM) return NULL; if (Ehdr.e_version != EV_CURRENT) return NULL; return (const Elf32_Ehdr *)file; } void execute_elf(const Elf32_Ehdr *Ehdr, long *args) { const uint8_t *file = (const uint8_t *)Ehdr; Elf32_Shdr StringShdr; memcpy(&StringShdr, &file[Ehdr->e_shoff + (Ehdr->e_shstrndx * Ehdr->e_shentsize)], sizeof(StringShdr)); if (Ehdr->e_shoff > 0) { Elf32_Shdr Shdr; for (int i = 0; i < Ehdr->e_shnum; i++) { memcpy(&Shdr, (Elf32_Shdr *)&file[Ehdr->e_shoff + (i * Ehdr->e_shentsize)], sizeof(Elf32_Shdr)); Shdr.sh_size -= Shdr.sh_addr; if ((Shdr.sh_flags & SHF_ALLOC) == 0) { // skip } else if (Shdr.sh_type == SHT_PROGBITS) { if ((Shdr.sh_flags & SHF_WRITE) == 0) { // inplace } else { memcpy(Shdr.sh_addr, Shdr.sh_offset, Shdr.sh_size); } } else if (Shdr.sh_type == SHT_NOBITS) { memset(Shdr.sh_addr, 0, Shdr.sh_size); } else { // skip } } } ((elf_entry_t)Ehdr->e_entry)(args); } void read_cmdlist_from_elf(const Elf32_Ehdr *Ehdr) { const uint8_t *file = (const uint8_t *)Ehdr; Elf32_Shdr StringShdr; memcpy(&StringShdr, &file[Ehdr->e_shoff + (Ehdr->e_shstrndx * Ehdr->e_shentsize)], sizeof(StringShdr)); if (Ehdr->e_shoff > 0) { Elf32_Shdr Shdr; for (int i = 0; i < Ehdr->e_shnum; i++) { memcpy(&Shdr, (Elf32_Shdr *)&file[Ehdr->e_shoff + (i * Ehdr->e_shentsize)], sizeof(Elf32_Shdr)); Shdr.sh_size -= Shdr.sh_addr; char *name; if (Shdr.sh_name > 0) { name = (char *)&file[StringShdr.sh_offset + Shdr.sh_name]; } else { name = NULL; } if ((name != NULL) && (strcmp(name, ".cmdlist") == 0)) { elf_cmd_table_info.table = (const cmd_table_t *)Shdr.sh_addr; elf_cmd_table_info.count = Shdr.sh_size / sizeof(cmd_table_t); } } } }