2019-05-06 19:55:10 -04:00
|
|
|
/*
|
|
|
|
* 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 <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <math.h>
|
|
|
|
#include "freertos/FreeRTOS.h"
|
|
|
|
#include "freertos/task.h"
|
2019-09-14 21:40:37 -04:00
|
|
|
#include "freertos/timers.h"
|
2019-05-06 19:55:10 -04:00
|
|
|
#include "freertos/event_groups.h"
|
|
|
|
#include "esp_system.h"
|
|
|
|
#include "esp_log.h"
|
2019-09-14 19:51:35 -04:00
|
|
|
#include "esp_console.h"
|
|
|
|
#include "esp_vfs_dev.h"
|
2019-05-06 19:55:10 -04:00
|
|
|
#include "nvs_flash.h"
|
|
|
|
#include "esp_http_client.h"
|
2019-09-14 19:51:35 -04:00
|
|
|
#include "driver/uart.h"
|
2019-05-07 13:01:16 -04:00
|
|
|
#include "driver/mcpwm.h"
|
|
|
|
#include "soc/mcpwm_reg.h"
|
|
|
|
#include "soc/mcpwm_struct.h"
|
2019-09-14 19:51:35 -04:00
|
|
|
#include "linenoise/linenoise.h"
|
|
|
|
#include "argtable3/argtable3.h"
|
2019-09-14 21:40:37 -04:00
|
|
|
#include "driver/gpio.h"
|
2019-05-07 13:01:16 -04:00
|
|
|
|
|
|
|
#include "esp32-wifi-manager.h"
|
2019-05-06 19:55:10 -04:00
|
|
|
|
|
|
|
#define TAG "CACO"
|
|
|
|
|
2019-09-14 21:40:37 -04:00
|
|
|
#define GPIO_INPUT_IO_0 33
|
|
|
|
#define GPIO_INPUT_PIN_SEL ((1ULL<<GPIO_INPUT_IO_0))
|
|
|
|
#define ESP_INTR_FLAG_DEFAULT 0
|
|
|
|
|
2019-05-07 13:01:16 -04:00
|
|
|
#define BASE_URL "http://192.168.0.1/"
|
|
|
|
#define CMD_BEEP "cmd=audio resplay 0 1 3\n"
|
|
|
|
|
2019-09-14 19:51:35 -04:00
|
|
|
#define CONFIG_SERVO_ENABLE (0)
|
|
|
|
#define CONFIG_SHOOT_DELAY_MS (30000)
|
2019-09-14 21:40:37 -04:00
|
|
|
#define CONFIG_TIMEOUT_SHOOT (100 / portTICK_PERIOD_MS)
|
2019-09-14 19:51:35 -04:00
|
|
|
|
2019-05-06 19:55:10 -04:00
|
|
|
static uint8_t id;
|
|
|
|
|
2019-09-14 21:40:37 -04:00
|
|
|
static EventGroupHandle_t wm_event_group;
|
|
|
|
static xQueueHandle gpio_evt_queue = NULL;
|
|
|
|
static xTimerHandle button_timer;
|
2019-05-07 13:01:16 -04:00
|
|
|
|
2019-09-14 19:51:35 -04:00
|
|
|
static struct {
|
|
|
|
struct arg_int *value; // how fast it will move in uS
|
|
|
|
struct arg_int *duration; // for how long it will move
|
|
|
|
struct arg_end *end;
|
|
|
|
} servo_args;
|
|
|
|
|
2019-05-07 13:01:16 -04:00
|
|
|
esp_err_t _http_event_handle(esp_http_client_event_t *evt) {
|
|
|
|
//ESP_LOGI(TAG, "Returning request for %s", (char*)evt->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() {
|
2019-09-14 19:51:35 -04:00
|
|
|
ESP_LOGI(TAG, "shooting");
|
|
|
|
|
2019-05-07 13:01:16 -04:00
|
|
|
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();
|
|
|
|
|
2019-09-14 19:51:35 -04:00
|
|
|
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
|
|
|
|
2019-05-07 13:01:16 -04:00
|
|
|
while(true) {
|
2019-09-14 21:40:37 -04:00
|
|
|
//shoot();
|
2019-05-07 13:01:16 -04:00
|
|
|
|
2019-09-14 19:51:35 -04:00
|
|
|
if(CONFIG_SERVO_ENABLE) {
|
|
|
|
vTaskDelay(3000 / portTICK_PERIOD_MS);
|
2019-05-07 13:01:16 -04:00
|
|
|
|
2019-09-14 19:51:35 -04:00
|
|
|
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);
|
|
|
|
}
|
2019-05-07 13:01:16 -04:00
|
|
|
|
2019-09-14 19:51:35 -04:00
|
|
|
vTaskDelay(CONFIG_SHOOT_DELAY_MS / portTICK_PERIOD_MS);
|
2019-05-07 13:01:16 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-14 19:51:35 -04:00
|
|
|
void pwm_init() {
|
2019-05-07 13:01:16 -04:00
|
|
|
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
|
2019-09-14 19:51:35 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void servo() {
|
|
|
|
ESP_LOGI(TAG, "value: %d duration: %d", servo_args.value->ival[0], servo_args.duration->ival[0]);
|
2019-05-07 13:01:16 -04:00
|
|
|
|
|
|
|
while(true) {
|
2019-09-14 19:51:35 -04:00
|
|
|
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);
|
2019-05-07 13:01:16 -04:00
|
|
|
}
|
2019-09-14 19:51:35 -04:00
|
|
|
|
|
|
|
return ESP_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void register_servo_cmd() {
|
|
|
|
servo_args.value = arg_int0("v", "value", "<int>", "move value in us");
|
|
|
|
servo_args.value->ival[0] = 1200;
|
|
|
|
|
|
|
|
servo_args.duration = arg_int0("d", "duration", "<int>", "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);
|
2019-05-07 13:01:16 -04:00
|
|
|
}
|
|
|
|
|
2019-09-14 21:40:37 -04:00
|
|
|
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)) {
|
2019-09-14 21:52:29 -04:00
|
|
|
EventBits_t ev_bits = xEventGroupGetBits(wm_event_group);
|
|
|
|
|
|
|
|
if(ev_bits & (WIFI_SCANNING|WIFI_CONNECTING)) {
|
|
|
|
ESP_LOGI(TAG, "Scan or connection in progress...");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if((ev_bits & WIFI_CONNECTED) == 0) {
|
|
|
|
ESP_LOGI(TAG, "No connectiong, connecting");
|
|
|
|
wifi_manager_scan();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2019-09-14 21:40:37 -04:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2019-05-06 19:55:10 -04:00
|
|
|
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]);
|
2019-05-07 13:01:16 -04:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-14 21:40:37 -04:00
|
|
|
wifi_manager_scan();
|
|
|
|
|
2019-09-14 19:51:35 -04:00
|
|
|
//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;
|
|
|
|
|
2019-09-14 21:40:37 -04:00
|
|
|
gpio_init();
|
|
|
|
|
2019-09-14 19:51:35 -04:00
|
|
|
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);
|
|
|
|
}
|
2019-05-06 19:55:10 -04:00
|
|
|
};
|