/* * Copyright (c) 2018, Real-Thread Information Technology Ltd * All rights reserved * * This software is dual-licensed: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. For the terms of this * license, see . * * You are free to use this software under the terms of the GNU General * Public License, but WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * Alternatively, you can license this software under a commercial * license, please send mail to business@rt-thread.com for contact. * * Change Logs: * Date Author Notes * 2018-09-25 ZYH the first version */ #include "rtthread.h" #include "rdbd.h" #include "rdbd_service.h" #include "rdbd_service_manager.h" #include "rthw.h" #include #include #include #include #include #define PKGS_USING_USB_RDBD #undef DBG_ENABLE #define DBG_SECTION_NAME "RDBD Shell" #define DBG_LEVEL DBG_WARNING #define DBG_COLOR #include static int start(void * args); static int stop(void * args); static int resume(void * args); static int suspend(void * args); static struct rdbd_service_control_ops control_ops = { start, stop, resume, suspend, }; extern rt_uint32_t finsh_get_echo(void); extern void finsh_set_echo(rt_uint32_t echo); char drop_buffer[128]; static rt_err_t rt_shell_service_device_init(struct rt_device *dev) { ((void)dev); return RT_EOK; } static rt_err_t rt_shell_service_device_open(struct rt_device *dev, rt_uint16_t oflag) { dev->open_flag = oflag & 0xff; return RT_EOK; } static rt_err_t rt_shell_service_device_close(struct rt_device *dev) { ((void)dev); return RT_EOK; } static rt_size_t rt_shell_service_device_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size) { struct rdbd_service * shell_service = (struct rdbd_service *)dev->user_data; fd_set readset; int res = 0; int max_fd = shell_service->in_pipe_read_fd + 1; //if(RDBD_SERVICE_STATUS_RUNNING == shell_service->status) { FD_ZERO(&readset); FD_SET(shell_service->in_pipe_read_fd, &readset); if(finsh_get_echo()) { finsh_set_echo(0); } res = select(max_fd, &readset, RT_NULL, RT_NULL, RT_NULL); if(res > 0) { if(FD_ISSET(shell_service->in_pipe_read_fd, &readset)) { return read(shell_service->in_pipe_read_fd, buffer, size); } } } return 0; } static rt_size_t rt_shell_service_device_write(rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size) { struct rdbd_service * shell_service = (struct rdbd_service *)dev->user_data; fd_set writeset; int res = 0; int max_fd = shell_service->out_pipe_write_fd + 1; char * returnBuffer = RT_NULL; int written_size = 0; int result = size; int n_size = 0; int i; for(i = 0; i < size; i++) { if(((char *)buffer)[i] == '\n') { n_size ++; } } returnBuffer = rt_malloc(size + n_size); for(i = 0; i < size; i++) { if(((char *)buffer)[i] == '\n') { returnBuffer[written_size] = '\r'; written_size++; } returnBuffer[written_size] = ((char *)buffer)[i]; written_size++; } size = written_size; written_size = 0; while(size) { if(RDBD_SERVICE_STATUS_RUNNING == shell_service->status) { FD_ZERO(&writeset); FD_SET(shell_service->out_pipe_write_fd, &writeset); res = select(max_fd, RT_NULL, &writeset, RT_NULL, RT_NULL); if(res > 0) { if(FD_ISSET(shell_service->out_pipe_write_fd, &writeset)) { written_size = write(shell_service->out_pipe_write_fd, returnBuffer + written_size, size); if(written_size > 0) { size -= written_size; } } } } else { break; } } free(returnBuffer); return result; } #ifdef RT_USING_DEVICE_OPS const static struct rt_device_ops shell_ops = { rt_shell_service_device_init, rt_shell_service_device_open, rt_shell_service_device_close, rt_shell_service_device_read, rt_shell_service_device_write, RT_NULL }; #endif static int start(void * args) { struct rdbd_service * shell_service = (struct rdbd_service *)args; if(RT_NULL == shell_service) { LOG_E("Start up service error, args is null"); return -1; } if(shell_service->flag & RDBD_SERVICE_FLAG_RD) { shell_service->in_pipe_read_fd = open(shell_service->in_pipe_path, O_RDONLY | O_NONBLOCK, 0); if(shell_service->in_pipe_read_fd < 0) { LOG_E("Start up service %s error open in pipe failed",shell_service->name); return -1; } } if(shell_service->flag & RDBD_SERVICE_FLAG_WR) { shell_service->out_pipe_write_fd = open(shell_service->out_pipe_path, O_WRONLY | O_NONBLOCK, 0); if(shell_service->out_pipe_write_fd < 0) { LOG_E("Start up service %s error open out pipe failed",shell_service->name); goto _error; } } if(shell_service->flag & RDBD_SERVICE_FLAG_RD) { shell_service->in_pipe_write_fd = open(shell_service->in_pipe_path, O_WRONLY | O_NONBLOCK, 0); if(shell_service->in_pipe_write_fd < 0) { LOG_E("Start up transfer error open in pipe failed",shell_service->name); return -1; } } if(shell_service->flag & RDBD_SERVICE_FLAG_WR) { shell_service->out_pipe_read_fd = open(shell_service->out_pipe_path, O_RDONLY | O_NONBLOCK, 0); if(shell_service->out_pipe_read_fd < 0) { LOG_E("Start up transfer error open out pipe failed",shell_service->name); goto _error; } } return 0; _error: if(shell_service->in_pipe_read_fd >= 0) { close(shell_service->in_pipe_read_fd); shell_service->in_pipe_read_fd = -1; } if(shell_service->in_pipe_write_fd >= 0) { close(shell_service->in_pipe_write_fd); shell_service->in_pipe_write_fd = -1; } if(shell_service->out_pipe_read_fd >= 0) { close(shell_service->out_pipe_read_fd); shell_service->out_pipe_read_fd = -1; } if(shell_service->out_pipe_write_fd >= 0) { close(shell_service->out_pipe_write_fd); shell_service->out_pipe_write_fd = -1; } return -1; } static int stop(void * args) { struct rdbd_service * shell_service = (struct rdbd_service *)args; if(RT_NULL == shell_service) { LOG_E("Stop service error, args is null"); return -1; } if(shell_service->in_pipe_read_fd >= 0) { if(close(shell_service->in_pipe_read_fd) < 0) { LOG_E("Close fd %d failed", shell_service->in_pipe_read_fd); return -1; } shell_service->in_pipe_read_fd = -1; } if(shell_service->in_pipe_write_fd >= 0) { if(close(shell_service->in_pipe_write_fd) < 0) { LOG_E("Close fd %d failed", shell_service->in_pipe_write_fd); return -1; } shell_service->in_pipe_write_fd = -1; } if(shell_service->in_pipe_write_fd >= 0) { if(close(shell_service->in_pipe_write_fd) < 0) { LOG_E("Close fd %d failed", shell_service->in_pipe_write_fd); return -1; } shell_service->in_pipe_write_fd = -1; } if(shell_service->out_pipe_write_fd >= 0) { if(close(shell_service->out_pipe_write_fd) < 0) { LOG_E("Close fd %d failed", shell_service->out_pipe_write_fd); return -1; } shell_service->out_pipe_write_fd = -1; } return 0; } static int resume(void * args) { //Not need return 0; } static int suspend(void * args) { //Not need return 0; } int rdbd_shell_service_init(void) { struct rdbd_service * shell_service; rt_device_t shell_device = rt_calloc(sizeof(struct rt_thread), 1); rdbd_t usbrdbd = rdbd_find("usb"); if(RT_NULL == usbrdbd) { LOG_E("rdbd usb find error"); return -1; } shell_service = rdbd_create_service(RDBD_SERVICE_ID_SHELL, "shell", &control_ops, RT_NULL, "shellin", 128,"shellout", 128, RDBD_SERVICE_FLAG_WR|RDBD_SERVICE_FLAG_RD); if(RT_NULL == shell_service) { LOG_E("shell_service create error"); goto _error; } LOG_I("Service %s created :", shell_service->name); LOG_I("in_pipe_path %s", shell_service->in_pipe_path); LOG_I("out_pipe_path %s", shell_service->out_pipe_path); LOG_I("service_id %d", shell_service->service_id); LOG_I("status %d", shell_service->status); shell_device->type = RT_Device_Class_Char; #ifdef RT_USING_DEVICE_OPS shell_device->ops = &shell_ops; #else shell_device->init = rt_shell_service_device_init; shell_device->open = rt_shell_service_device_open; shell_device->close = rt_shell_service_device_close; shell_device->read = rt_shell_service_device_read; shell_device->write = rt_shell_service_device_write; shell_device->control = RT_NULL; #endif shell_device->user_data = shell_service; shell_service->user_data = shell_device; rt_device_register(shell_device, "rdbdsh", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX); rdbd_service_install(usbrdbd, shell_service); rt_console_set_device("rdbdsh"); // /* add non-block flag */ // ioctl(libc_stdio_get_console(), F_SETFL, (void *) (dev_old_flag | O_NONBLOCK)); /* set tcp shell device for console */ libc_stdio_set_console("rdbdsh", O_RDWR); rdbd_service_control(shell_service, RDBD_SERVICE_START, shell_service); return 0; _error: if(RT_NULL != usbrdbd) { //TO DO } return -1; } INIT_APP_EXPORT(rdbd_shell_service_init);