/* * 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 "shellif.h" #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 "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 "util/ntstdio.h" #include "usrcmd.h" #include "util/ntopt.h" #include "netapp/dhcp4_cli.h" #include "ntp_cli.h" #include "netcmd.h" #endif ID ws_api_mailboxid = MAIN_DATAQUEUE; ID ws_mempoolid = MPF_NET_BUF_256; extern ntstdio_t *ntstdio; char command[NTOPT_TEXT_MAXLEN]; const uint8_t mac_addr[6] = {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC}; const struct utsname host_name = { "TOPPERS/ASP3", TARGET_NAME, "3.5.0", "3.5.0", TARGET_NAME, "toppers.jp" }; int shell_uname(struct utsname *uts) { memcpy(uts, &host_name, sizeof(host_name)); return 0; } 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 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 (*PowerOn_Reset_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) { ntlibc_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}, }; cmd_table_info_t cmd_table_info = { cmdlist, sizeof(cmdlist) / sizeof(cmdlist[0]) }; 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 (ntlibc_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 (ntlibc_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) { found = 1; (*((PowerOn_Reset_t *)0x18200000))(args); } if ((found == 0) && (((const char *)args[1])[0] != '\0')) ntstdio_printf(ntstdio, "Unknown command found. %s \n", (const char *)args[1]); return result; } 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++) { ntstdio_puts(ntstdio, p->cmd); ntstdio_puts(ntstdio, "\t:"); ntstdio_puts(ntstdio, p->desc); ntstdio_puts(ntstdio, "\n"); p++; } return 0; } void shellif_into() { /* メインタスクの優先度より高くする */ chg_pri(SHELLCMD_PRIORITY, MAIN_PRIORITY + 1); } void shellif_outof() { /* shellcmdタスクの優先度に戻す */ chg_pri(SHELLCMD_PRIORITY, SHELLCMD_PRIORITY); } void shell_abort() { shellcmd_exit_code = -1; longjmp(shellcmd_exit, 1); } void shell_exit(int exitcd) { shellcmd_exit_code = exitcd; longjmp(shellcmd_exit, 1); } void shell_exit_group(int exitcd) { shellcmd_exit_code = exitcd; longjmp(shellcmd_exit, 1); } 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; } int shell_clock_getres(clockid_t clk_id, struct timespec *res) { if ((clk_id != CLOCK_REALTIME) && (clk_id != CLOCK_MONOTONIC)) return -EINVAL; memset(&res->tv_sec, 0xFF, sizeof(res->tv_sec)); res->tv_nsec = 0; return 0; } int shell_clock_gettime(clockid_t clk_id, struct timespec *tp) { SYSTIM now = 0; if ((clk_id != CLOCK_REALTIME) && (clk_id != CLOCK_MONOTONIC)) return -EINVAL; get_tim(&now); tp->tv_sec = now / 1000000; tp->tv_nsec = (now % 1000000) * 1000; return 0; } int shell_clock_settime(clockid_t clk_id, const struct timespec *tp) { if ((clk_id != CLOCK_REALTIME) && (clk_id != CLOCK_MONOTONIC)) return -EINVAL; SYSTIM time; ER ret; time = (tp->tv_sec * 1000000ll) + (tp->tv_nsec / 1000ll); ret = set_tim(time); if (ret != E_OK) { return -EPERM; } return 0; } sigset_t g_sigmask; int shell_sigprocmask(int how, const sigset_t *restrict set, sigset_t *restrict old) { if (old != NULL) memcpy(old, &g_sigmask, sizeof(sigset_t)); switch (how) { case SIG_BLOCK: for (int i = 0; i < sizeof(g_sigmask.__bits) / sizeof(g_sigmask.__bits[0]); i++) { g_sigmask.__bits[i] |= set->__bits[i]; } break; case SIG_UNBLOCK: for (int i = 0; i < sizeof(g_sigmask.__bits) / sizeof(g_sigmask.__bits[0]); i++) { g_sigmask.__bits[i] &= ~set->__bits[i]; } break; case SIG_SETMASK: memcpy(&g_sigmask, set, sizeof(sigset_t)); break; default: return -EINVAL; } return 0; } // musl-1.1.18\src\internal\ksigaction.h struct k_sigaction { void(*handler)(int); unsigned long flags; void(*restorer)(void); unsigned mask[2]; }; struct k_sigaction sigtable[7]; int shell_sigaction(int sig, const struct k_sigaction *restrict sa, struct k_sigaction *restrict old, size_t size) { struct k_sigaction *sat; switch(sig){ case SIGALRM: sat = &sigtable[0]; break; case SIGFPE: sat = &sigtable[1]; break; case SIGILL: sat = &sigtable[2]; break; case SIGSEGV: sat = &sigtable[3]; break; case SIGBUS: sat = &sigtable[4]; break; case SIGABRT: sat = &sigtable[5]; break; case SIGPIPE: sat = &sigtable[6]; break; default: return -EINVAL; } if (old != NULL) memcpy(old, sat, offsetof(struct k_sigaction, mask) + size); memcpy(sat, sa, offsetof(struct k_sigaction, mask) + size); return 0; } int shell_madvise(void *a, size_t b, int c) { return 0; } int shell_gettid() { ID tskid; ER ret; ret = get_tid(&tskid); if (ret != E_OK) return -1; return tskid; } int shell_tkill(int tid, int sig) { if ((tid == SHELLCMD_TASK) && (sig == SIGABRT)) { shell_abort(); } no_implement("tkill"); return -1; } int shell_kill(int pid, int sig) { DebugBreak(); return -1; } int shell_gettimeofday(struct timeval *tv, void *tzvp) { SYSTIM time; if (!tv) return 0; get_tim(&time); tv->tv_sec = time / 1000000; tv->tv_usec = time - (tv->tv_sec * 1000000); return 0; } int shell_nanosleep(const struct timespec *req, struct timespec *rem) { ER ret; TMO tmo; SYSTIM prev, now, diff; if ((req == NULL) || (req->tv_nsec < 0) || (req->tv_nsec >= 1000000000)) return -EINVAL; get_tim(&prev); tmo = req->tv_sec * 1000000 + req->tv_nsec / 1000; ret = tslp_tsk(tmo); if (ret == E_OK) { if (rem != NULL) { get_tim(&now); diff = now - prev; rem->tv_sec = diff / 1000000ll; rem->tv_nsec = (diff - (rem->tv_sec * 1000000ll)) * 1000ll; } return 0; } else if (ret == E_TMOUT) { if (rem != NULL) { rem->tv_sec = 0; rem->tv_nsec = 0; } return 0; } return -EFAULT; } ssize_t shell_getrandom(void *buf, size_t buflen, unsigned int flags) { SYSTIM now; int32_t i; int *output = (int *)buf; size_t sz = buflen / 4; get_tim(&now); srand(now); for (i = 0; i < sz; i++) output[i] = rand(); for (i = 4 * sz; i < buflen; i++) ((char *)buf)[i] = rand(); return buflen; } extern uint32_t __CmdBase; extern uint32_t __CmdLimit; void *shell_brk(void *addr) { if (addr == 0) { return (void *)((intptr_t)&__CmdBase + 0x40000); } if ((addr >= (intptr_t)&__CmdBase + 0x40000) && (addr < &__CmdLimit)) { return addr; } return (void *)-1; } void *shell_mmap2(void *start, size_t length, int prot, int flags, int fd, off_t pgoffset) { if (fd != -1) return -EINVAL; if ((length >= 0) && (length <= (intptr_t)&__CmdLimit - ((intptr_t)&__CmdBase + 0x40000))) { return &__CmdBase + 0x40000; } return (void *)-1; } int shell_mprotect(void *addr, size_t len, int prot) { //if ((addr >= (intptr_t)&__CmdBase + 0x40000) && ((intptr_t)addr + len < &__CmdLimit)) { return 0; //} //return -1; }