/**************************************************************************** * apps/testing/monkey/monkey_main.c * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. The * ASF licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "monkey.h" #include "monkey_utils.h" #include "monkey_log.h" /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ #define MONKEY_PREFIX "monkey" #define CONSTRAIN(x, low, high) \ ((x) < (low) ? (low) : ((x) > (high) ? (high) : (x))) #define OPTARG_TO_VALUE(value, type, base) \ do \ { \ FAR char *ptr; \ (value) = (type)strtoul(optarg, &ptr, (base)); \ if (*ptr != '\0') \ { \ MONKEY_LOG_ERROR("Parameter error: -%c %s", ch, optarg); \ show_usage(argv[0], EXIT_FAILURE); \ } \ } while (0) #define OPTARG_TO_RANGE(value_1, value_2, delimiter) \ do \ { \ int converted; \ int v1; \ int v2; \ converted = sscanf(optarg, "%d" delimiter "%d", &v1, &v2); \ if (converted == 2 && v1 >= 0 && v2 >= 0) \ { \ value_1 = v1; \ value_2 = v2; \ } \ else \ { \ MONKEY_LOG_ERROR("Error range: %s", optarg); \ show_usage(argv[0], EXIT_FAILURE); \ } \ } while (0) /* Default parameters */ #if defined(CONFIG_VIDEO_FB) # define MONKEY_SCREEN_DEV "/dev/fb0" # define MONKEY_SCREEN_GETVIDEOINFO FBIOGET_VIDEOINFO #elif defined(CONFIG_LCD) # define MONKEY_SCREEN_DEV "/dev/lcd0" # define MONKEY_SCREEN_GETVIDEOINFO LCDDEVIO_GETVIDEOINFO #endif #define MONKEY_SCREEN_HOR_RES_DEFAULT 480 #define MONKEY_SCREEN_VER_RES_DEFAULT 480 #define MONKEY_PERIOD_MIN_DEFAULT 100 #define MONKEY_PERIOD_MAX_DEFAULT 500 #define MONKEY_BUTTON_BIT_DEFAULT 0 #define MONKEY_EVENT_CLICK_WEIGHT_DEFAULT 70 #define MONKEY_EVENT_LONG_PRESS_WEIGHT_DEFAULT 10 #define MONKEY_EVENT_DRAG_WEIGHT_DEFAULT 20 #define MONKEY_EVENT_CLICK_DURATION_MIN_DEFAULT 50 #define MONKEY_EVENT_CLICK_DURATION_MAX_DEFAULT 200 #define MONKEY_EVENT_LONG_PRESS_DURATION_MIN_DEFAULT 400 #define MONKEY_EVENT_LONG_PRESS_DURATION_MAX_DEFAULT 600 #define MONKEY_EVENT_DRAG_DURATION_MIN_DEFAULT 100 #define MONKEY_EVENT_DRAG_DURATION_MAX_DEFAULT 400 #define MONKEY_EVENT_PARAM_INIT(name) \ do \ { \ param->event[MONKEY_EVENT_##name].weight = \ MONKEY_EVENT_##name##_WEIGHT_DEFAULT; \ param->event[MONKEY_EVENT_##name].duration_min = \ MONKEY_EVENT_##name##_DURATION_MIN_DEFAULT; \ param->event[MONKEY_EVENT_##name].duration_max = \ MONKEY_EVENT_##name##_DURATION_MAX_DEFAULT; \ } while (0) /**************************************************************************** * Private Type Declarations ****************************************************************************/ struct monkey_param_s { int dev_type_mask; FAR const char *file_path; int hor_res; int ver_res; int period_min; int period_max; int btn_bit; int log_level; struct monkey_event_config_s event[MONKEY_EVENT_LAST]; }; enum monkey_wait_res_e { MONKEY_WAIT_RES_AGAIN, MONKEY_WAIT_RES_PAUSE, MONKEY_WAIT_RES_STOP, MONKEY_WAIT_RES_ERROR, }; /**************************************************************************** * Private Functions ****************************************************************************/ /**************************************************************************** * Name: show_usage ****************************************************************************/ static void show_usage(FAR const char *progname, int exitcode) { printf("\nUsage: %s" " -t " " -f " " -p " " -s " " -b " " -l \n" " --weight-click " " --weight-longpress " " --weight-drag \n" " --duration-click " " --duration-longpress " " --duration-drag \n", progname); printf("\nWhere:\n"); printf(" -t Device type mask: uinput = 0x%02X;" " touch = 0x%02X; button = 0x%02X.\n", MONKEY_UINPUT_TYPE_MASK, MONKEY_DEV_TYPE_TOUCH, MONKEY_DEV_TYPE_BUTTON); printf(" -f Recorder playback file path.\n"); printf(" -p Period(ms) range: " "-\n"); printf(" -s Screen resolution: " "x\n"); printf(" -b Button bit: 0 ~ 31\n"); printf(" -l Log level: 0 ~ 3\n"); printf(" --weight-click Click event weight.\n"); printf(" --weight-longpress Long press event weight.\n"); printf(" --weight-drag Drag event weight.\n"); printf(" --duration-click Click duration(ms) range: " "-.\n"); printf(" --duration-longpress Long press duration(ms) range: " "-.\n"); printf(" --duration-drag Drag duration(ms) range: " "-.\n"); exit(exitcode); } /**************************************************************************** * Name: monkey_get_screen_resolution ****************************************************************************/ static int monkey_get_screen_resolution(FAR int *hor_res, FAR int *ver_res) { #ifdef MONKEY_SCREEN_DEV struct fb_videoinfo_s vinfo; int fd; int ret; FAR const char *dev_path = MONKEY_SCREEN_DEV; *hor_res = MONKEY_SCREEN_HOR_RES_DEFAULT; *ver_res = MONKEY_SCREEN_VER_RES_DEFAULT; fd = open(dev_path, 0); if (fd < 0) { MONKEY_LOG_ERROR("screen dev %s open failed: %d", dev_path, errno); return ERROR; } ret = ioctl(fd, MONKEY_SCREEN_GETVIDEOINFO, (unsigned long)((uintptr_t)&vinfo)); if (ret < 0) { MONKEY_LOG_ERROR("get video info failed: %d", errno); } else { *hor_res = vinfo.xres; *ver_res = vinfo.yres; } close(fd); return ret; #else *hor_res = MONKEY_SCREEN_HOR_RES_DEFAULT; *ver_res = MONKEY_SCREEN_VER_RES_DEFAULT; return OK; #endif /* MONKEY_SCREEN_DEV */ } /**************************************************************************** * Name: monkey_init ****************************************************************************/ static FAR struct monkey_s *monkey_init( FAR const struct monkey_param_s *param) { FAR struct monkey_s *monkey; struct monkey_config_s config; int i; if (!param->dev_type_mask) { show_usage(MONKEY_PREFIX, EXIT_FAILURE); } monkey = monkey_create(param->dev_type_mask); if (!monkey) { goto failed; } monkey_config_default_init(&config); config.screen.hor_res = param->hor_res; config.screen.ver_res = param->ver_res; config.period.min = param->period_min; config.period.max = param->period_max; config.btn_bit = param->btn_bit; memcpy(config.event, param->event, sizeof(config.event)); monkey_set_config(monkey, &config); monkey_log_set_level(param->log_level); MONKEY_LOG_NOTICE("Screen: %dx%d", config.screen.hor_res, config.screen.ver_res); MONKEY_LOG_NOTICE("Period: %" PRIu32 " ~ %" PRIu32 "ms", config.period.min, config.period.max); MONKEY_LOG_NOTICE("Button bit: %d", config.btn_bit); MONKEY_LOG_NOTICE("Log level: %d", monkey_log_get_level()); for (i = 0; i < MONKEY_EVENT_LAST; i++) { MONKEY_LOG_NOTICE("Event %d(%s): weight=%d" " duration %d ~ %dms", i, monkey_event_type2name(i), config.event[i].weight, config.event[i].duration_min, config.event[i].duration_max); } if (MONKEY_IS_UINPUT_TYPE(param->dev_type_mask)) { if (param->file_path) { monkey_set_mode(monkey, MONKEY_MODE_PLAYBACK); if (!monkey_set_recorder_path(monkey, param->file_path)) { goto failed; } } else { monkey_set_mode(monkey, MONKEY_MODE_RANDOM); } } else { monkey_set_mode(monkey, MONKEY_MODE_RECORD); if (!monkey_set_recorder_path(monkey, CONFIG_TESTING_MONKEY_REC_DIR_PATH)) { goto failed; } monkey_set_period(monkey, config.period.min); } return monkey; failed: if (monkey) { monkey_delete(monkey); } return NULL; } /**************************************************************************** * Name: parse_long_commandline ****************************************************************************/ static void parse_long_commandline(int argc, FAR char **argv, int ch, FAR const struct option *longopts, int longindex, FAR struct monkey_param_s *param) { int event_index; switch (longindex) { case 0: case 1: case 2: event_index = longindex; OPTARG_TO_VALUE(param->event[event_index].weight, uint8_t, 10); break; case 3: case 4: case 5: event_index = longindex - 3; OPTARG_TO_RANGE(param->event[event_index].duration_min, param->event[event_index].duration_max, "-"); break; default: MONKEY_LOG_WARN("Unknown longindex: %d", longindex); show_usage(argv[0], EXIT_FAILURE); break; } } /**************************************************************************** * Name: parse_commandline ****************************************************************************/ static void parse_commandline(int argc, FAR char **argv, FAR struct monkey_param_s *param) { int ch; int longindex = 0; FAR const char *optstring = "t:f:p:s:b:l:"; const struct option longopts[] = { {"weight-click", required_argument, NULL, 0 }, {"weight-longpress", required_argument, NULL, 0 }, {"weight-drag", required_argument, NULL, 0 }, {"duration-click", required_argument, NULL, 0 }, {"duration-longpress", required_argument, NULL, 0 }, {"duration-drag", required_argument, NULL, 0 }, {0, 0, NULL, 0 } }; memset(param, 0, sizeof(struct monkey_param_s)); monkey_get_screen_resolution(¶m->hor_res, ¶m->ver_res); param->period_min = MONKEY_PERIOD_MIN_DEFAULT; param->period_max = MONKEY_PERIOD_MAX_DEFAULT; param->btn_bit = MONKEY_BUTTON_BIT_DEFAULT; param->log_level = MONKEY_LOG_LEVEL_NOTICE; MONKEY_EVENT_PARAM_INIT(CLICK); MONKEY_EVENT_PARAM_INIT(LONG_PRESS); MONKEY_EVENT_PARAM_INIT(DRAG); while ((ch = getopt_long(argc, argv, optstring, longopts, &longindex)) != ERROR) { switch (ch) { case 0: parse_long_commandline(argc, argv, ch, longopts, longindex, param); break; case 't': OPTARG_TO_VALUE(param->dev_type_mask, int, 16); break; case 'f': param->file_path = optarg; break; case 'p': OPTARG_TO_RANGE(param->period_min, param->period_max, "-"); break; case 's': OPTARG_TO_RANGE(param->hor_res, param->ver_res, "x"); break; case 'b': OPTARG_TO_VALUE(param->btn_bit, int, 10); param->btn_bit = CONSTRAIN(param->btn_bit, 0, 31); break; case 'l': OPTARG_TO_VALUE(param->log_level, int, 10); param->log_level = CONSTRAIN(param->log_level, 0, MONKEY_LOG_LEVEL_LAST - 1); break; case '?': MONKEY_LOG_WARN("Unknown option: %c", optopt); show_usage(argv[0], EXIT_FAILURE); break; } } } /**************************************************************************** * Name: monkey_pause ****************************************************************************/ static int monkey_pause(void) { sigset_t set; sigemptyset(&set); sigaddset(&set, SIGCONT); return sigwaitinfo(&set, NULL); } /**************************************************************************** * Name: monkey_wait ****************************************************************************/ static enum monkey_wait_res_e monkey_wait(uint32_t ms) { sigset_t set; struct timespec timeout; int ret; enum monkey_wait_res_e res = MONKEY_WAIT_RES_ERROR; if (ms == 0) { return MONKEY_WAIT_RES_AGAIN; } timeout.tv_sec = ms / 1000; timeout.tv_nsec = (ms % 1000) * 1000000; sigemptyset(&set); sigaddset(&set, SIGTSTP); ret = sigtimedwait(&set, NULL, &timeout); if (ret < 0) { int errcode = errno; if (errcode == EINTR) { res = MONKEY_WAIT_RES_STOP; } else if(errcode == EAGAIN) { res = MONKEY_WAIT_RES_AGAIN; } else { MONKEY_LOG_ERROR("Unknow error: %d", errcode); } } else if (ret == SIGTSTP) { res = MONKEY_WAIT_RES_PAUSE; } return res; } /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** * Name: monkey_main * * Description: * * Input Parameters: * Standard argc and argv * * Returned Value: * Zero on success; a positive, non-zero value on failure. * ****************************************************************************/ int main(int argc, FAR char *argv[]) { struct monkey_param_s param; FAR struct monkey_s *monkey; parse_commandline(argc, argv, ¶m); monkey = monkey_init(¶m); if (!monkey) { return ERROR; } while (1) { enum monkey_wait_res_e res; int sleep_ms; sleep_ms = monkey_update(monkey); if (sleep_ms < 0) { break; } res = monkey_wait(sleep_ms); if (res == MONKEY_WAIT_RES_AGAIN) { continue; } else if (res == MONKEY_WAIT_RES_PAUSE) { MONKEY_LOG_NOTICE("pause"); if (monkey_pause() < 0) { break; } MONKEY_LOG_NOTICE("continue..."); } else { /* STOP or ERROR */ break; } } monkey_delete(monkey); return OK; }