esp32-ricoh-gr2/main/main.c
2019-09-16 22:15:10 -07:00

468 lines
12 KiB
C

/*
* 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"
#include "freertos/timers.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_log.h"
#include "esp_console.h"
#include "esp_sleep.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 "driver/spi_master.h"
#include "esp32-wifi-manager.h"
#define TAG "CACO"
#define GPIO_INPUT_IO_0 33
#define GPIO_INPUT_PIN_SEL ((1ULL<<GPIO_INPUT_IO_0))
#define ESP_INTR_FLAG_DEFAULT 0
#define BASE_URL "http://192.168.0.1/"
#define CMD_BEEP "cmd=audio resplay 0 1 3\n"
#define CONFIG_SERVO_ENABLE (0)
#define CONFIG_SHOOT_DELAY_MS (30000)
#define CONFIG_TIMEOUT_SHOOT (100 / portTICK_PERIOD_MS)
#define CONFIG_SLEEP_TIMEOUT (60000 / portTICK_PERIOD_MS)
#define RTC_WAKE_IO RTC_GPIO8
#define RTC_WAKE_PIN GPIO_INPUT_IO_0
#define PIN_NUM_MOSI 22
#define PIN_NUM_CLK 23
#define LED_COUNT (1)
#define SPI_BUF (LED_COUNT + 2)
static uint8_t id;
static EventGroupHandle_t wm_event_group;
static xTimerHandle button_timer;
static xTimerHandle sleep_timer;
static spi_device_handle_t spi;
xQueueHandle gpio_evt_queue = NULL;
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;
enum led_states {
POR,
CONNECTING,
CONNECTED,
SHOOTING
};
enum led_states led_state;
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 enter_sleep() {
ESP_LOGI(TAG, "Enter deep sleep");
static spi_transaction_t trans[SPI_BUF];
int i;
for (i = 0; i < SPI_BUF; i++) {
memset(&trans[i], 0, sizeof(spi_transaction_t));
trans[i].length=8*4;
trans[i].flags = SPI_TRANS_USE_TXDATA;
}
trans[1].tx_data[0] = (0b11100000 | 0);
trans[1].tx_data[1] = 0;
trans[1].tx_data[2] = 0;
trans[1].tx_data[3] = 0;
memset(&trans[SPI_BUF - 1].tx_data, 0xFF, 4);
for(i = 0; i < SPI_BUF; i++) {
spi_device_queue_trans(spi, &trans[i], portMAX_DELAY);
}
esp_sleep_enable_ext0_wakeup(RTC_WAKE_PIN, 0);
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
//rtc_gpio_isolate(GPIO_INPUT_IO_0);
esp_deep_sleep_start();
}
void reset_sleep_timer() {
xTimerReset(sleep_timer, portMAX_DELAY);
xTimerStart(sleep_timer, portMAX_DELAY);
}
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 led_loop() {
uint8_t v = 0;
while(true) {
if(xQueueReceive(wm_event_queue, &v, portMAX_DELAY)) {
EventBits_t ev_bits = xEventGroupGetBits(wm_event_group);
ESP_LOGI(TAG, "got event: %d", ev_bits);
static spi_transaction_t trans[SPI_BUF];
int i;
for (i = 0; i < SPI_BUF; i++) {
memset(&trans[i], 0, sizeof(spi_transaction_t));
trans[i].length=8*4;
trans[i].flags = SPI_TRANS_USE_TXDATA;
}
trans[1].tx_data[0] = (0b11100000 | 1);
if(ev_bits & WIFI_CONNECTED) {
trans[1].tx_data[1] = 0;
trans[1].tx_data[2] = 127;
trans[1].tx_data[3] = 0;
} else if(ev_bits & WIFI_SCANNING) {
trans[1].tx_data[1] = 0;
trans[1].tx_data[2] = 55;
trans[1].tx_data[3] = 127;
} else if(ev_bits & WIFI_CONNECTING) {
trans[1].tx_data[1] = 127;
trans[1].tx_data[2] = 127;
trans[1].tx_data[3] = 0;
} else if(ev_bits & WIFI_IDLE) {
trans[1].tx_data[1] = 0;
trans[1].tx_data[2] = 0;
trans[1].tx_data[3] = 127;
}
memset(&trans[SPI_BUF - 1].tx_data, 0xFF, 4);
for(i = 0; i < SPI_BUF; i++) {
spi_device_queue_trans(spi, &trans[i], portMAX_DELAY);
}
}
}
}
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", "<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 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);
// don't act on state level twice
if(level == state) continue;
// track level for duplicate
state = level;
EventBits_t ev_bits = xEventGroupGetBits(wm_event_group);
ESP_LOGI(TAG, "gpio_loop: %d", ev_bits);
if(level == 0 && (ev_bits & WIFI_CONNECTED) == 0) {
ESP_LOGI(TAG, "No connectiong, connecting");
wifi_manager_scan();
continue;
}
printf("GPIO[%d] intr, val: %d\n", io_num, level);
reset_sleep_timer();
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);
sleep_timer = xTimerCreate("sleep_timer", CONFIG_SLEEP_TIMEOUT, pdFALSE, (void*)NULL, enter_sleep);
reset_sleep_timer();
xTaskCreate(gpio_loop, "gpio_loop", 2048, NULL, 10, NULL);
}
void spi_init() {
esp_err_t ret;
spi_bus_config_t buscfg={
.mosi_io_num=PIN_NUM_MOSI,
.sclk_io_num=PIN_NUM_CLK,
.quadwp_io_num=-1,
.quadhd_io_num=-1,
.max_transfer_sz=120*320*2+8
};
spi_device_interface_config_t devcfg={
.clock_speed_hz=10*1000*1000, //Clock out at 10 MHz
.mode=0, //SPI mode 0
.queue_size=7, //We want to be able to queue 7 transactions at a time
//.pre_cb=lcd_spi_pre_transfer_callback, //Specify pre-transfer callback to handle D/C line
};
//Initialize the SPI bus
ret=spi_bus_initialize(HSPI_HOST, &buscfg, 1);
ESP_ERROR_CHECK(ret);
//Attach the LCD to the SPI bus
ret=spi_bus_add_device(HSPI_HOST, &devcfg, &spi);
ESP_ERROR_CHECK(ret);
static spi_transaction_t trans[SPI_BUF];
int i;
for (i = 0; i < SPI_BUF; i++) {
memset(&trans[i], 0, sizeof(spi_transaction_t));
trans[i].length=8*4;
trans[i].flags = SPI_TRANS_USE_TXDATA;
}
trans[1].tx_data[0] = (0b11100000 | 1);
trans[1].tx_data[1] = 127;
trans[1].tx_data[2] = 127;
trans[1].tx_data[3] = 127;
memset(&trans[SPI_BUF - 1].tx_data, 0xFF, 4);
for(i = 0; i < SPI_BUF; i++) {
ret = spi_device_queue_trans(spi, &trans[i], portMAX_DELAY);
assert(ret==ESP_OK);
}
}
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);
}
}
gpio_init();
spi_init();
xTaskCreate(&led_loop, "led_loop", 4096, NULL, 6, NULL);
wifi_manager_scan();
};