/* * Copyright 2019 by Morgan Allen * * This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International * https://creativecommons.org/licenses/by-nc/4.0/ */ #include #include #include #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/timers.h" #include "freertos/event_groups.h" #include "esp_system.h" #include "esp_log.h" #include "esp_console.h" #include "esp_vfs_dev.h" #include "nvs_flash.h" #include "esp_http_client.h" #include "driver/uart.h" #include "driver/mcpwm.h" #include "soc/mcpwm_reg.h" #include "soc/mcpwm_struct.h" #include "linenoise/linenoise.h" #include "argtable3/argtable3.h" #include "driver/gpio.h" #include "esp32-wifi-manager.h" #define TAG "CACO" #define GPIO_INPUT_IO_0 33 #define GPIO_INPUT_PIN_SEL ((1ULL<user_data); switch(evt->event_id) { case HTTP_EVENT_ERROR: ESP_LOGI(TAG, "HTTP_EVENT_ERROR"); break; case HTTP_EVENT_ON_CONNECTED: ESP_LOGI(TAG, "HTTP_EVENT_ON_CONNECTED"); break; case HTTP_EVENT_HEADER_SENT: ESP_LOGI(TAG, "HTTP_EVENT_HEADER_SENT"); break; case HTTP_EVENT_ON_HEADER: ESP_LOGI(TAG, "HTTP_EVENT_ON_HEADER"); printf("%.*s", evt->data_len, (char*)evt->data); break; case HTTP_EVENT_ON_DATA: ESP_LOGI(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len); if (!esp_http_client_is_chunked_response(evt->client)) { printf("%.*s", evt->data_len, (char*)evt->data); } break; case HTTP_EVENT_ON_FINISH: ESP_LOGI(TAG, "HTTP_EVENT_ON_FINISH"); break; case HTTP_EVENT_DISCONNECTED: ESP_LOGI(TAG, "HTTP_EVENT_DISCONNECTED"); break; } return ESP_OK; } void ping() { esp_http_client_config_t config = { .url = "http://192.168.0.1/_gr", .method = HTTP_METHOD_POST, }; esp_http_client_handle_t client = esp_http_client_init(&config); esp_http_client_set_post_field(client, CMD_BEEP, strlen(CMD_BEEP)); esp_err_t err = esp_http_client_perform(client); if (err == ESP_OK) { ESP_LOGI(TAG, "Status = %d, content_length = %d", esp_http_client_get_status_code(client), esp_http_client_get_content_length(client)); } } void shoot() { ESP_LOGI(TAG, "shooting"); esp_http_client_config_t config = { .url = "http://192.168.0.1/v1/camera/shoot", .method = HTTP_METHOD_POST, }; esp_http_client_handle_t client = esp_http_client_init(&config); esp_http_client_set_post_field(client, CMD_BEEP, strlen(CMD_BEEP)); esp_err_t err = esp_http_client_perform(client); if (err == ESP_OK) { ESP_LOGI(TAG, "Status = %d, content_length = %d", esp_http_client_get_status_code(client), esp_http_client_get_content_length(client)); } } void request(char *path) { char *url = malloc(strlen(BASE_URL) + strlen(path) + 1); strcpy(url, BASE_URL); strcat(url, path); ESP_LOGI(TAG, "Making request to %s", url); esp_http_client_config_t config = { .url = url, .event_handler = _http_event_handle }; esp_http_client_handle_t client = esp_http_client_init(&config); esp_err_t err = esp_http_client_perform(client); if (err == ESP_OK) { ESP_LOGI(TAG, "Status = %d, content_length = %d", esp_http_client_get_status_code(client), esp_http_client_get_content_length(client)); } } void loop() { xEventGroupWaitBits(wm_event_group, WIFI_CONNECTED, false, true, portMAX_DELAY); ping(); vTaskDelay(1000 / portTICK_PERIOD_MS); while(true) { //shoot(); if(CONFIG_SERVO_ENABLE) { vTaskDelay(3000 / portTICK_PERIOD_MS); mcpwm_set_duty_in_us(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_A, 1200); vTaskDelay(200 / portTICK_PERIOD_MS); mcpwm_set_duty_in_us(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_A, 1500); } vTaskDelay(CONFIG_SHOOT_DELAY_MS / portTICK_PERIOD_MS); } } void pwm_init() { mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0A, 21); mcpwm_config_t pwm_config; pwm_config.frequency = 50; //frequency = 50Hz, i.e. for every servo motor time period should be 20ms pwm_config.cmpr_a = 0; //duty cycle of PWMxA = 0 pwm_config.cmpr_b = 0; //duty cycle of PWMxb = 0 pwm_config.counter_mode = MCPWM_UP_COUNTER; pwm_config.duty_mode = MCPWM_DUTY_MODE_0; mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_0, &pwm_config); //Configure PWM0A & PWM0B with above settings } void servo() { ESP_LOGI(TAG, "value: %d duration: %d", servo_args.value->ival[0], servo_args.duration->ival[0]); while(true) { mcpwm_set_duty_in_us(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_A, servo_args.value->ival[0]); vTaskDelay(servo_args.duration->ival[0] / portTICK_PERIOD_MS); mcpwm_set_duty_in_us(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_A, 1500); vTaskDelay(5000 / portTICK_PERIOD_MS); } } bool running = false; static int servo_start(int argc, char **argv) { int nerrors = arg_parse(argc, argv, (void**) &servo_args); if (nerrors != 0) { arg_print_errors(stderr, servo_args.end, argv[0]); return 1; } if(!running) { running = true; xTaskCreate(&servo, "servo", 4096, NULL, 6, NULL); } return ESP_OK; } void register_servo_cmd() { servo_args.value = arg_int0("v", "value", "", "move value in us"); servo_args.value->ival[0] = 1200; servo_args.duration = arg_int0("d", "duration", "", "duration in ms"); servo_args.end = arg_end(2); const esp_console_cmd_t start_cmd = { .command = "start", .help = "Starts the servo", .hint = NULL, .func = &servo_start, .argtable = &servo_args }; ESP_ERROR_CHECK( esp_console_cmd_register(&start_cmd) ); } static void initialize_console() { /* Disable buffering on stdin and stdout */ setvbuf(stdin, NULL, _IONBF, 0); setvbuf(stdout, NULL, _IONBF, 0); /* Minicom, screen, idf_monitor send CR when ENTER key is pressed */ esp_vfs_dev_uart_set_rx_line_endings(ESP_LINE_ENDINGS_CR); /* Move the caret to the beginning of the next line on '\n' */ esp_vfs_dev_uart_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF); /* Configure UART. Note that REF_TICK is used so that the baud rate remains * correct while APB frequency is changing in light sleep mode. */ const uart_config_t uart_config = { .baud_rate = CONFIG_CONSOLE_UART_BAUDRATE, .data_bits = UART_DATA_8_BITS, .parity = UART_PARITY_DISABLE, .stop_bits = UART_STOP_BITS_1, .use_ref_tick = true }; ESP_ERROR_CHECK( uart_param_config(CONFIG_CONSOLE_UART_NUM, &uart_config) ); /* Install UART driver for interrupt-driven reads and writes */ ESP_ERROR_CHECK( uart_driver_install(CONFIG_CONSOLE_UART_NUM, 256, 0, 0, NULL, 0) ); /* Tell VFS to use UART driver */ esp_vfs_dev_uart_use_driver(CONFIG_CONSOLE_UART_NUM); /* Initialize the console */ esp_console_config_t console_config = { .max_cmdline_args = 8, .max_cmdline_length = 256, .hint_color = atoi(LOG_COLOR_CYAN) }; ESP_ERROR_CHECK( esp_console_init(&console_config) ); /* Configure linenoise line completion library */ /* Enable multiline editing. If not set, long commands will scroll within * single line. */ linenoiseSetMultiLine(1); /* Tell linenoise where to get command completions and hints */ linenoiseSetCompletionCallback(&esp_console_get_completion); linenoiseSetHintsCallback((linenoiseHintsCallback*) &esp_console_get_hint); /* Set command history size */ linenoiseHistorySetMaxLen(100); } static void IRAM_ATTR gpio_isr_handler(void* arg) { uint32_t gpio_num = (uint32_t) arg; xQueueSendFromISR(gpio_evt_queue, &gpio_num, NULL); } void gpio_loop() { int8_t state = -1; uint32_t io_num; for(;;) { if(xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY)) { uint8_t level = gpio_get_level(io_num); printf("GPIO[%d] intr, val: %d\n", io_num, level); // don't act on state level twice if(level == state) continue; // track level for duplicate state = level; if(level == 0) { xTimerChangePeriod(button_timer, CONFIG_TIMEOUT_SHOOT, portMAX_DELAY); xTimerStart(button_timer, portMAX_DELAY); } else { xTimerStop(button_timer, portMAX_DELAY); } } } } void handle_button_timer() { shoot(); } void gpio_init() { gpio_config_t io_conf; io_conf.intr_type = GPIO_PIN_INTR_ANYEDGE; io_conf.mode = GPIO_MODE_INPUT; io_conf.pin_bit_mask = GPIO_INPUT_PIN_SEL; io_conf.pull_down_en = 0; io_conf.pull_up_en = 1; gpio_config(&io_conf); gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT); gpio_isr_handler_add(GPIO_INPUT_IO_0, gpio_isr_handler, (void*) GPIO_INPUT_IO_0); //create a queue to handle gpio event from isr gpio_evt_queue = xQueueCreate(10, sizeof(uint32_t)); //start gpio task button_timer = xTimerCreate("gpio_timer", 1000, pdFALSE, (void*)NULL, handle_button_timer); xTaskCreate(gpio_loop, "gpio_loop", 2048, NULL, 10, NULL); } void app_main() { esp_err_t ret; // Initialize NVS. ret = nvs_flash_init(); if (ret == ESP_ERR_NVS_NO_FREE_PAGES) { ESP_LOGI(TAG, "Erasing flash memory"); ESP_ERROR_CHECK(nvs_flash_erase()); ret = nvs_flash_init(); } ESP_ERROR_CHECK( ret ); uint8_t *mac; mac = (uint8_t *)malloc(6); esp_efuse_mac_get_default(mac); id = mac[5]; ESP_LOGI(TAG, "MAC: %X:%X:%X:%X:%X:%X\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); wm_event_group = wifi_manager_start(); wifi_manager_reset_store(); if(wifi_manager_ap_count() == 0) { ESP_LOGI(TAG, "Adding new AP"); if(strlen(CONFIG_WIFI_MANAGER_TEST_AP) > 0) { wifi_manager_add_ap(CONFIG_WIFI_MANAGER_TEST_AP, CONFIG_WIFI_MANAGER_TEST_PWD); } } wifi_manager_scan(); //initialize_console(); //esp_console_register_help_command(); //register_servo_cmd(); pwm_init(); xTaskCreate(&loop, "loop", 4096, NULL, 6, NULL); const char* prompt = LOG_COLOR_I "grii> " LOG_RESET_COLOR; gpio_init(); return; while(true) { char* line = linenoise(prompt); if (line == NULL) { /* Ignore empty lines */ continue; } linenoiseHistoryAdd(line); int ret; esp_err_t err = esp_console_run(line, &ret); if (err == ESP_ERR_NOT_FOUND) { printf("Unrecognized command\n"); } else if (err == ESP_ERR_INVALID_ARG) { // command was empty } else if (err == ESP_OK && ret != ESP_OK) { printf("Command returned non-zero error code: 0x%x (%s)\n", ret, esp_err_to_name(err)); } else if (err != ESP_OK) { printf("Internal error: %s\n", esp_err_to_name(err)); } /* linenoise allocates line buffer on the heap, so need to free it */ linenoiseFree(line); } };