Add config, buzzer, evalSwitch, switch to c++

Add config.cpp/hpp
    - macros for all input and output pins
    - gloabl evaluated switch objects
    - buzzer object
    - display config
    - encoder config

Move main.c to main.cpp and adjust code to be c++ compatible

add custom library evaluated switch (copied from armchair project)
add buzzer object (copied from armchair project)

add control.cpp/hpp with control task (no function yet)
This commit is contained in:
jonny_ji7 2022-08-17 10:22:53 +02:00
parent e7ffb6348a
commit a3f3cb340c
11 changed files with 590 additions and 49 deletions

@ -0,0 +1,4 @@
idf_component_register(
SRCS "gpio_evaluateSwitch.cpp"
INCLUDE_DIRS "."
)

@ -0,0 +1,171 @@
#include "gpio_evaluateSwitch.hpp"
static const char *TAG = "evaluateSwitch";
gpio_evaluatedSwitch::gpio_evaluatedSwitch( //minimal (use default values)
gpio_num_t gpio_num_declare
){
gpio_num = gpio_num_declare;
pullup = true;
inverted = false;
init();
};
gpio_evaluatedSwitch::gpio_evaluatedSwitch( //optional parameters given
gpio_num_t gpio_num_declare,
bool pullup_declare,
bool inverted_declare
){
gpio_num = gpio_num_declare;
pullup = pullup_declare;
inverted = inverted_declare;
init();
};
void gpio_evaluatedSwitch::init(){
ESP_LOGI(TAG, "initializing gpio pin %d", (int)gpio_num);
//define gpio pin as input
gpio_pad_select_gpio(gpio_num);
gpio_set_direction(gpio_num, GPIO_MODE_INPUT);
if (pullup == true){ //enable pullup if desired (default)
gpio_pad_select_gpio(gpio_num);
gpio_set_pull_mode(gpio_num, GPIO_PULLUP_ONLY);
}else{
gpio_set_pull_mode(gpio_num, GPIO_FLOATING);
gpio_pad_select_gpio(gpio_num);
}
//TODO add pulldown option
//gpio_set_pull_mode(gpio_num, GPIO_PULLDOWN_ONLY);
};
void gpio_evaluatedSwitch::handle(){ //Statemachine for debouncing and edge detection
if (inverted == true){
//=========================================================
//=========== Statemachine for inverted switch ============
//=================== (switch to VCC) =====================
//=========================================================
switch (p_state){
default:
p_state = switchState::FALSE;
break;
case switchState::FALSE: //input confirmed high (released)
fallingEdge = false; //reset edge event
if (gpio_get_level(gpio_num) == 1){ //pin high (on)
p_state = switchState::HIGH;
timestampHigh = esp_log_timestamp(); //save timestamp switched from low to high
} else {
msReleased = esp_log_timestamp() - timestampLow; //update duration released
}
break;
case switchState::HIGH: //input recently switched to high (pressed)
if (gpio_get_level(gpio_num) == 1){ //pin still high (on)
if (esp_log_timestamp() - timestampHigh > minOnMs){ //pin in same state long enough
p_state = switchState::TRUE;
state = true;
risingEdge = true;
msReleased = timestampHigh - timestampLow; //calculate duration the button was released
}
}else{
p_state = switchState::FALSE;
}
break;
case switchState::TRUE: //input confirmed high (pressed)
risingEdge = false; //reset edge event
if (gpio_get_level(gpio_num) == 0){ //pin low (off)
timestampLow = esp_log_timestamp();
p_state = switchState::LOW;
} else {
msPressed = esp_log_timestamp() - timestampHigh; //update duration pressed
}
break;
case switchState::LOW: //input recently switched to low (released)
if (gpio_get_level(gpio_num) == 0){ //pin still low (off)
if (esp_log_timestamp() - timestampLow > minOffMs){ //pin in same state long enough
p_state = switchState::FALSE;
msPressed = timestampLow - timestampHigh; //calculate duration the button was pressed
state=false;
fallingEdge=true;
}
}else{
p_state = switchState::TRUE;
}
break;
}
}else{
//=========================================================
//========= Statemachine for not inverted switch ==========
//=================== (switch to GND) =====================
//=========================================================
switch (p_state){
default:
p_state = switchState::FALSE;
break;
case switchState::FALSE: //input confirmed high (released)
fallingEdge = false; //reset edge event
if (gpio_get_level(gpio_num) == 0){ //pin low (on)
p_state = switchState::LOW;
timestampLow = esp_log_timestamp(); //save timestamp switched from high to low
} else {
msReleased = esp_log_timestamp() - timestampHigh; //update duration released
}
break;
case switchState::LOW: //input recently switched to low (pressed)
if (gpio_get_level(gpio_num) == 0){ //pin still low (on)
if (esp_log_timestamp() - timestampLow > minOnMs){ //pin in same state long enough
p_state = switchState::TRUE;
state = true;
risingEdge = true;
msReleased = timestampLow - timestampHigh; //calculate duration the button was released
}
}else{
p_state = switchState::FALSE;
}
break;
case switchState::TRUE: //input confirmed low (pressed)
risingEdge = false; //reset edge event
if (gpio_get_level(gpio_num) == 1){ //pin high (off)
timestampHigh = esp_log_timestamp();
p_state = switchState::HIGH;
} else {
msPressed = esp_log_timestamp() - timestampLow; //update duration pressed
}
break;
case switchState::HIGH: //input recently switched to high (released)
if (gpio_get_level(gpio_num) == 1){ //pin still high (off)
if (esp_log_timestamp() - timestampHigh > minOffMs){ //pin in same state long enough
p_state = switchState::FALSE;
msPressed = timestampHigh - timestampLow; //calculate duration the button was pressed
state=false;
fallingEdge=true;
}
}else{
p_state = switchState::TRUE;
}
break;
}
}
}

@ -0,0 +1,59 @@
#pragma once
#include <stdio.h>
extern "C"
{
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "esp_log.h"
}
//constructor examples:
//switch to gnd and us internal pullup:
//gpio_evaluatedSwitch s3(GPIO_NUM_14);
//switch to gnd dont use internal pullup:
//gpio_evaluatedSwitch s3(GPIO_NUM_14 false);
//switch to VCC (inverted) and dont use internal pullup:
//gpio_evaluatedSwitch s3(GPIO_NUM_14 false, true);
class gpio_evaluatedSwitch {
public:
//--- input ---
uint32_t minOnMs = 30;
uint32_t minOffMs = 30;
gpio_evaluatedSwitch( //constructor minimal (default parameters pullup=true, inverted=false)
gpio_num_t gpio_num_declare
);
gpio_evaluatedSwitch( //constructor with optional parameters
gpio_num_t gpio_num_declare,
bool pullup_declare,
bool inverted_declare=false
);
//--- output --- TODO make readonly? (e.g. public section: const int& x = m_x;)
bool state = false;
bool risingEdge = false;
bool fallingEdge = false;
uint32_t msPressed = 0;
uint32_t msReleased = 0;
//--- functions ---
void handle(); //Statemachine for debouncing and edge detection
private:
gpio_num_t gpio_num;
bool pullup;
bool inverted;
enum class switchState {TRUE, FALSE, LOW, HIGH};
switchState p_state = switchState::FALSE;
uint32_t timestampLow = 0;
uint32_t timestampHigh = 0;
void init();
};

@ -1,2 +1,9 @@
idf_component_register(SRCS "main.c"
INCLUDE_DIRS ".")
idf_component_register(
SRCS
"main.cpp"
"config.cpp"
"control.cpp"
"buzzer.cpp"
INCLUDE_DIRS
"."
)

95
main/buzzer.cpp Normal file

@ -0,0 +1,95 @@
#include "buzzer.hpp"
#include "config.hpp"
static const char *TAG_BUZZER = "buzzer";
//============================
//========== init ============
//============================
//define gpio pin as output, initialize queue
void buzzer_t::init(){
//define buzzer pin as output
gpio_pad_select_gpio(gpio_pin);
gpio_set_direction(gpio_pin, GPIO_MODE_OUTPUT);
//create queue
beepQueue = xQueueCreate( 20, sizeof( struct beepEntry ) );
}
//=============================
//======== constructor ========
//=============================
//copy provided config parameters to private variables, run init function
buzzer_t::buzzer_t(gpio_num_t gpio_pin_f, uint16_t msGap_f){
ESP_LOGI(TAG_BUZZER, "Initializing buzzer");
//copy configuration parameters to variables
gpio_pin = gpio_pin_f;
msGap = msGap_f;
//run init function to initialize gpio and queue
init();
};
//============================
//=========== beep ===========
//============================
//function to add a beep command to the queue
void buzzer_t::beep(uint8_t count, uint16_t msOn, uint16_t msOff){
//create entry struct with provided data
struct beepEntry entryInsert = {
count = count,
msOn = msOn,
msOff = msOff
};
// Send a pointer to a struct AMessage object. Don't block if the
// queue is already full.
//struct beepEntry *entryInsertPointer;
//entryInsertPointer = &entryInsertData;
ESP_LOGW(TAG_BUZZER, "Inserted object to queue - count=%d, msOn=%d, msOff=%d", entryInsert.count, entryInsert.msOn, entryInsert.msOff);
//xQueueGenericSend( beepQueue, ( void * ) &entryInsertPointer, ( TickType_t ) 0, queueSEND_TO_BACK );
xQueueSend( beepQueue, ( void * )&entryInsert, ( TickType_t ) 0 );
}
//==============================
//======== processQueue ========
//==============================
void buzzer_t::processQueue(){
//struct for receiving incomming events
struct beepEntry entryRead = { };
//loop forever
while(1){
ESP_LOGD(TAG_BUZZER, "processQueue: waiting for beep command");
//if queue is ready
if( beepQueue != 0 )
{
// wait for a queue entry to be available indefinetely if INCLUDE_vTaskSuspend is enabled in the FreeRTOS config
// otherwise waits for at least 7 weeks
if( xQueueReceive( beepQueue, &entryRead, portMAX_DELAY ) )
{
ESP_LOGW(TAG_BUZZER, "Read entry from queue: count=%d, msOn=%d, msOff=%d", entryRead.count, entryRead.msOn, entryRead.msOff);
//beep requested count with requested delays
for (int i = entryRead.count; i--;){
//turn on
ESP_LOGD(TAG_BUZZER, "turning buzzer on");
gpio_set_level(gpio_pin, 1);
vTaskDelay(entryRead.msOn / portTICK_PERIOD_MS);
//turn off
ESP_LOGD(TAG_BUZZER, "turning buzzer off");
gpio_set_level(gpio_pin, 0);
vTaskDelay(entryRead.msOff / portTICK_PERIOD_MS);
}
//wait for minimum gap between beep events
vTaskDelay(msGap / portTICK_PERIOD_MS);
}
}else{ //wait for queue to become available
vTaskDelay(50 / portTICK_PERIOD_MS);
}
}
}

56
main/buzzer.hpp Normal file

@ -0,0 +1,56 @@
#pragma once
#include <stdio.h>
extern "C"
{
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "esp_log.h"
}
#include "freertos/queue.h"
//===================================
//========= buzzer_t class ==========
//===================================
//class which blinks a gpio pin for the provided count and durations.
//- 'processQueue' has to be run in a separate task
//- uses a queue to queue up multiple beep commands
class buzzer_t {
public:
//--- constructor ---
buzzer_t(gpio_num_t gpio_pin_f, uint16_t msGap_f = 200);
//--- functions ---
void processQueue(); //has to be run once in a separate task, waits for and processes queued events
void beep(uint8_t count, uint16_t msOn, uint16_t msOff);
//void clear(); (TODO - not implemented yet)
//void createTask(); (TODO - not implemented yet)
//--- variables ---
uint16_t msGap; //gap between beep entries (when multiple queued)
private:
//--- functions ---
void init();
//--- variables ---
gpio_num_t gpio_pin;
struct beepEntry {
uint8_t count;
uint16_t msOn;
uint16_t msOff;
};
//queue for queueing up multiple events while one is still processing
QueueHandle_t beepQueue = NULL;
};

15
main/config.cpp Normal file

@ -0,0 +1,15 @@
#include "config.hpp"
//--- inputs ---
//create objects for switches at bottom screw temerinals
gpio_evaluatedSwitch SW_START(GPIO_SW_START, true, false); //pullup true, not inverted (switch to GND, pullup on receiver pcb)
gpio_evaluatedSwitch SW_RESET(GPIO_SW_RESET, true, false); //pullup true, not inverted (switch to GND, pullup on receiver pcb)
gpio_evaluatedSwitch SW_SET(GPIO_SW_SET, true, false); //pullup true, not inverted (switch to GND, pullup on receiver pcb)
gpio_evaluatedSwitch SW_PRESET1(GPIO_SW_PRESET1, true, false); //pullup true, not inverted (switch to GND, pullup on receiver pcb)
gpio_evaluatedSwitch SW_PRESET2(GPIO_SW_PRESET2, true, false); //pullup true, not inverted (switch to GND, pullup on receiver pcb)
gpio_evaluatedSwitch SW_PRESET3(GPIO_SW_PRESET3, true, false); //pullup true, not inverted (switch to GND, pullup on receiver pcb)
//create buzzer object with gap between queued events of 100ms
buzzer_t buzzer(GPIO_BUZZER, 100);

74
main/config.hpp Normal file

@ -0,0 +1,74 @@
#pragma once
#include "gpio_evaluateSwitch.hpp"
#include "buzzer.hpp"
//===================================
//===== define output gpio pins =====
//===================================
//4x stepper mosfet outputs for VFD
#define GPIO_VFD_FWD GPIO_NUM_4
#define GPIO_VFD_D0 GPIO_NUM_16
#define GPIO_VFD_D1 GPIO_NUM_2
#define GPIO_VFD_D2 GPIO_NUM_15
#define GPIO_MOS1 GPIO_NUM_18
#define GPIO_MOS2 GPIO_NUM_5
#define GPIO_RELAY GPIO_NUM_13
#define GPIO_BUZZER GPIO_NUM_12
//==================================
//===== define input gpio pins =====
//==================================
#define GPIO_SW_START GPIO_NUM_26
#define GPIO_SW_RESET GPIO_NUM_25
#define GPIO_SW_SET GPIO_NUM_33
#define GPIO_SW_PRESET1 GPIO_NUM_32
#define GPIO_SW_PRESET2 GPIO_NUM_34
#define GPIO_SW_PRESET3 GPIO_NUM_39
#define GPIO_POTI GPIO_NUM_36
//--------------------------
//----- display config -----
//--------------------------
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 0, 0)
#define HOST HSPI_HOST
#else
#define HOST SPI2_HOST
#endif
#define DISPLAY_PIN_NUM_MOSI GPIO_NUM_23
#define DISPLAY_PIN_NUM_CLK GPIO_NUM_22
#define DISPLAY_PIN_NUM_CS GPIO_NUM_27
#define DISPLAY_DELAY 2000
//--------------------------
//----- encoder config -----
//--------------------------
#define TAG "app"
#define ROT_ENC_A_GPIO GPIO_NUM_19
#define ROT_ENC_B_GPIO GPIO_NUM_21
#define ENABLE_HALF_STEPS false // Set to true to enable tracking of rotary encoder at half step resolution
#define FLIP_DIRECTION false // Set to true to reverse the clockwise/counterclockwise sense
#define MEASURING_ROLL_DIAMETER 44
#define PI 3.14159265358979323846
//============================
//===== global variables =====
//============================
//create global evaluated switch objects
//--- inputs ---
//create objects for switches at bottom screw temerinals
extern gpio_evaluatedSwitch SW_START;
extern gpio_evaluatedSwitch SW_RESET;
extern gpio_evaluatedSwitch SW_SET;
extern gpio_evaluatedSwitch SW_PRESET1;
extern gpio_evaluatedSwitch SW_PRESET2;
extern gpio_evaluatedSwitch SW_PRESET3;
//create global buzzer object
extern buzzer_t buzzer;

10
main/control.cpp Normal file

@ -0,0 +1,10 @@
#include "control.hpp"
void task_control(void *pvParameter)
{
while(1){
vTaskDelay(500 / portTICK_PERIOD_MS);
}
}

14
main/control.hpp Normal file

@ -0,0 +1,14 @@
#pragma once
#include <stdio.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <esp_idf_version.h>
#include "freertos/queue.h"
#include "esp_system.h"
#include "esp_log.h"
#include "config.hpp"
void task_control(void *pvParameter);

@ -1,3 +1,5 @@
extern "C"
{
#include <stdio.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
@ -8,36 +10,43 @@
#include <max7219.h>
#include "rotary_encoder.h"
}
//--------------------------
//----- display config -----
//--------------------------
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 0, 0)
#define HOST HSPI_HOST
#else
#define HOST SPI2_HOST
#endif
#define DISPLAY_PIN_NUM_MOSI 23
#define DISPLAY_PIN_NUM_CLK 18
#define DISPLAY_PIN_NUM_CS 21
#define DISPLAY_DELAY 2000
//--------------------------
//----- encoder config -----
//--------------------------
#define TAG "app"
#define ROT_ENC_A_GPIO 16
#define ROT_ENC_B_GPIO 17
#define ENABLE_HALF_STEPS false // Set to true to enable tracking of rotary encoder at half step resolution
#define FLIP_DIRECTION false // Set to true to reverse the clockwise/counterclockwise sense
#define MEASURING_ROLL_DIAMETER 44
#define PI 3.14159265358979323846
#include "gpio_evaluateSwitch.hpp"
#include "config.hpp"
#include "control.hpp"
#include "buzzer.hpp"
//function to configure gpio pin as output
void gpio_configure_output(gpio_num_t gpio_pin){
gpio_pad_select_gpio(gpio_pin);
gpio_set_direction(gpio_pin, GPIO_MODE_OUTPUT);
}
void task(void *pvParameter)
void init_gpios(){
//initialize all outputs
//4x stepper mosfets
gpio_configure_output(GPIO_VFD_FWD);
gpio_configure_output(GPIO_VFD_D0);
gpio_configure_output(GPIO_VFD_D1);
gpio_configure_output(GPIO_VFD_D2);
//2x power mosfets
gpio_configure_output(GPIO_MOS1);
gpio_configure_output(GPIO_MOS2);
//onboard relay and buzzer
gpio_configure_output(GPIO_RELAY);
gpio_configure_output(GPIO_BUZZER);
//5v regulator
gpio_configure_output(GPIO_NUM_17);
}
//task for testing the encoder and display
void task_testing(void *pvParameter)
{
//========================
@ -47,7 +56,7 @@ void task(void *pvParameter)
ESP_ERROR_CHECK(gpio_install_isr_service(0));
// Initialise the rotary encoder device with the GPIOs for A and B signals
rotary_encoder_info_t info = { 0 };
rotary_encoder_info_t info;
ESP_ERROR_CHECK(rotary_encoder_init(&info, ROT_ENC_A_GPIO, ROT_ENC_B_GPIO));
ESP_ERROR_CHECK(rotary_encoder_enable_half_steps(&info, ENABLE_HALF_STEPS));
#ifdef FLIP_DIRECTION
@ -66,23 +75,21 @@ void task(void *pvParameter)
//===== init display =====
//========================
// Configure SPI bus
spi_bus_config_t cfg = {
.mosi_io_num = DISPLAY_PIN_NUM_MOSI,
.miso_io_num = -1,
.sclk_io_num = DISPLAY_PIN_NUM_CLK,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = 0,
.flags = 0
};
spi_bus_config_t cfg;
cfg.mosi_io_num = DISPLAY_PIN_NUM_MOSI;
cfg.miso_io_num = -1;
cfg.sclk_io_num = DISPLAY_PIN_NUM_CLK;
cfg.quadwp_io_num = -1;
cfg.quadhd_io_num = -1;
cfg.max_transfer_sz = 0;
cfg.flags = 0;
ESP_ERROR_CHECK(spi_bus_initialize(HOST, &cfg, 1));
// Configure device
max7219_t dev = {
.cascade_size = 1,
.digits = 8,
.mirrored = true
};
max7219_t dev;
dev.cascade_size = 1;
dev.digits = 8;
dev.mirrored = true;
ESP_ERROR_CHECK(max7219_init_desc(&dev, HOST, MAX7219_MAX_CLOCK_SPEED_HZ, DISPLAY_PIN_NUM_CS));
ESP_ERROR_CHECK(max7219_init(&dev));
@ -111,7 +118,7 @@ void task(void *pvParameter)
// Wait for incoming events on the event queue.
rotary_encoder_event_t event = { 0 };
rotary_encoder_event_t event;
if (xQueueReceive(event_queue, &event, 1000 / portTICK_PERIOD_MS) == pdTRUE)
{
ESP_LOGI(TAG, "Event: position %d, direction %s", event.state.position,
@ -131,7 +138,7 @@ void task(void *pvParameter)
else //no event for 1s
{
// Poll current position and direction
rotary_encoder_state_t state = { 0 };
rotary_encoder_state_t state;
ESP_ERROR_CHECK(rotary_encoder_get_state(&info, &state));
ESP_LOGI(TAG, "Poll: position %d, direction %s", state.position,
state.direction ? (state.direction == ROTARY_ENCODER_DIRECTION_CLOCKWISE ? "CW" : "CCW") : "NOT_SET");
@ -143,8 +150,6 @@ void task(void *pvParameter)
//display test
//float count = 0;
@ -183,9 +188,40 @@ void task(void *pvParameter)
// }
//}
void app_main()
{
xTaskCreate(task, "task", configMINIMAL_STACK_SIZE * 3, NULL, 5, NULL);
//======================================
//============ buzzer task =============
//======================================
//TODO: move the task creation to buzzer class (buzzer.cpp)
//e.g. only have function buzzer.createTask() in app_main
void task_buzzer( void * pvParameters ){
ESP_LOGI("task_buzzer", "Start of buzzer task...");
//run function that waits for a beep events to arrive in the queue
//and processes them
buzzer.processQueue();
}
extern "C" void app_main()
{
//init outputs
init_gpios();
//enable 5V volate regulator
gpio_set_level(GPIO_NUM_17, 1);
//--- create task testing ---
xTaskCreate(task_testing, "task_testing", configMINIMAL_STACK_SIZE * 3, NULL, 5, NULL);
//--- create task control ---
xTaskCreate(task_control, "task_control", configMINIMAL_STACK_SIZE * 3, NULL, 5, NULL);
//--- create task for buzzer ---
xTaskCreate(&task_buzzer, "task_buzzer", 2048, NULL, 2, NULL);
//beep at startup
buzzer.beep(3, 70, 50);
}