Compare commits

...

3 Commits

  1. 82
      main/gui.c
  2. 305
      main/knob.c

@ -11,6 +11,8 @@ void gui_init() {
printf("GUI init\n"); printf("GUI init\n");
LCD_setup(); LCD_setup();
LCD_setContrast(60);
LCD_clearDisplay(0); LCD_clearDisplay(0);
LCD_setStr("Hello World", 0, 0, 1); LCD_setStr("Hello World", 0, 0, 1);
LCD_updateDisplay(); LCD_updateDisplay();
@ -19,52 +21,66 @@ void gui_init() {
assert (rv == pdPASS); assert (rv == pdPASS);
} }
/**
* Notification API:
*
* 0b1 - knob CW
* 0b10 - knowb CCW
* 0b100 - button released
* 0b1000 - button pressed
*
* @param arg
*/
static void __attribute__((noreturn)) gui_thread(void *arg) { static void __attribute__((noreturn)) gui_thread(void *arg) {
uint32_t pos = 20; uint32_t pos = 20;
bool btn = 0;
#define NMAX 60 #define NMAX 60
while (1) { while (1) {
uint32_t value; uint32_t value = 0;
xTaskNotifyWait(0, ULONG_MAX, &value, portMAX_DELAY); xTaskNotifyWait(0, ULONG_MAX, &value, portMAX_DELAY);
printf("Knob event 0x%02x ", value); // printf("Knob event 0x%02x ", value);
if (value & 0b1000) { if (value & 0b1000) {
printf("PUSH "); // printf("PUSH ");
} btn = 1;
if (value & 0b100) { } else if (value & 0b100) {
printf("RELS "); btn = 0;
} }
if ((value & 0b11) == 0b11) { if (value & 0b01) {
printf("BNCE "); // printf("FWD ");
} else { if (pos == NMAX) {
if (value & 0b01) { pos = 0;
printf("FWD ");
if (pos == NMAX) {
pos = 0;
}
else {
pos += 1;
}
} }
if (value & 0b10) { else {
printf("BACK "); pos += 1;
if (pos == 0) {
pos = NMAX;
}
else {
pos--;
}
} }
} }
printf(">"); if (value & 0b10) {
for (int i=0; i<pos; i++) { // printf("BACK ");
printf(" "); if (pos == 0) {
} pos = NMAX;
printf("#"); }
for (int i=pos; i<NMAX; i++) { else {
printf(" "); pos--;
}
} }
printf("<\n");
LCD_setRect(0, 15, 83, 35, 1, 1);
char buf[10];
sprintf(buf, "%3d %s", pos, btn?"BTN":"");
LCD_setStr(buf, 2, 17, 0);
LCD_updateDisplay();
// printf(">");
// for (int i=0; i<pos; i++) {
// printf(" ");
// }
// printf("#");
// for (int i=pos; i<NMAX; i++) {
// printf(" ");
// }
// printf("<\n");
} }
} }

@ -8,283 +8,100 @@ const int pushPin = 5;
const int wheelPin1 = 18; const int wheelPin1 = 18;
const int wheelPin2 = 23; const int wheelPin2 = 23;
#define DEBOUNCE_WHEEL_MS 6 #define DEBOUNCE_WHEEL_MS 2
#define DEBOUNCE_BTN_MS 20 #define DEBOUNCE_BTN_MS 5
static void handle_pushbtn(void *arg); static void debounce_service(void *arg);
static void handle_wheel(void *arg); static TaskHandle_t hDebouncer;
void knob_init() { void knob_init() {
printf("Knob init\n"); printf("Knob init\n");
// gpio_config_t cfgWheel = {
// .pin_bit_mask = (1 << wheelPin1) /*| (1 << wheelPin2)*/,
// .mode = GPIO_MODE_INPUT,
// .pull_up_en = 1,
// .intr_type = GPIO_INTR_NEGEDGE, // neg means active
// };
// gpio_config(&cfgWheel);
gpio_config_t cfgPush = { gpio_config_t cfgPush = {
.pin_bit_mask = (1 << pushPin) | (1 << wheelPin1), .pin_bit_mask = (1 << pushPin) | (1 << wheelPin1) | (1 << wheelPin2),
.mode = GPIO_MODE_INPUT, .mode = GPIO_MODE_INPUT,
.pull_up_en = 1, .pull_up_en = 1
.intr_type = GPIO_INTR_ANYEDGE, // neg means active
}; };
gpio_config(&cfgPush); gpio_config(&cfgPush);
cfgPush.intr_type = GPIO_INTR_DISABLE; int rv = xTaskCreate(debounce_service, "debo", 4096, NULL, 6, &hDebouncer);
cfgPush.pin_bit_mask = (1 << wheelPin2); assert (rv == pdPASS);
gpio_config(&cfgPush);
gpio_install_isr_service(0);
gpio_intr_enable(pushPin);
gpio_intr_enable(wheelPin1);
// gpio_intr_enable(wheelPin2);
gpio_isr_handler_add(pushPin, handle_pushbtn, (void *)0);
gpio_isr_handler_add(wheelPin1, handle_wheel, (void *)0);
//gpio_isr_handler_add(wheelPin2, handle_wheel, (void *)1);
} }
#if 0 static void __attribute__((noreturn)) debounce_service(void *arg) {
enum state { struct debo {
S_11 = 0, bool state;
uint32_t start_time;
S_FWD_1_01 = 1, uint32_t debo_time;
S_FWD_2_00 = 2, };
S_FWD_3_10 = 3,
S_BCK_1_10 = 4,
S_BCK_2_00 = 5,
S_BCK_3_01 = 6,
S_ILLEGAL = 7,
};
#define SW_FWD 0b10000000
#define SW_BCK 0b01000000
static enum state wheelState = S_11;
const uint8_t switch_table[28] = {
/* -- S_11 -- */
S_ILLEGAL, /* 00 ILLEGAL */
S_FWD_1_01, /* 01 ADVANCE */
S_BCK_1_10, /* 10 BACK */
S_11, /* 11 */
/* -- S_FWD_1_01 -- */
S_FWD_2_00, /* 00 ADVANCE */
S_FWD_1_01, /* 01 */
S_FWD_3_10, /* 10 ILLEGAL */
S_11, /* 11 ABORT */
/* -- S_FWD_2_00 -- */
S_FWD_2_00, /* 00 */
S_FWD_1_01, /* 01 ABORT */
S_FWD_3_10, /* 10 ADVANCE */
S_ILLEGAL, /* 11 ILLEGAL */
/* -- S_FWD_3_10 -- */
S_FWD_2_00, /* 00 ABORT */
S_FWD_1_01, /* 01 ILLEGAL */
S_FWD_3_10, /* 10 */
SW_FWD | S_11, /* 11 ADVANCE */
/* -- S_BCK_1_10 -- */
S_BCK_2_00, /* 00 ADVANCE */
S_BCK_3_01, /* 01 ILLEGAL */
S_BCK_1_10, /* 10 */
S_11, /* 11 ABORT */
/* -- S_BCK_2_00 -- */
S_BCK_2_00, /* 00 */
S_BCK_3_01, /* 01 */
S_BCK_1_10, /* 10 ABORT */
S_ILLEGAL, /* 11 */
/* -- S_BCK_3_01 -- */
S_BCK_2_00, /* 00 */
S_BCK_3_01, /* 01 */
S_BCK_1_10, /* 10 */
SW_BCK | S_11, /* 11 */
};
static uint8_t OldEnc = 0b00;
#endif
static void handle_wheel(void *arg) {
static uint32_t negedge_time = 0;
int dir = 0;
const uint32_t inputs = gpio_input_get();
const bool a = 0 != (inputs & (1 << wheelPin1)); // neg = active
const bool b = 0 != (inputs & (1 << wheelPin2));
const uint32_t time = xTaskGetTickCount();
if (!a) {
// negedge
negedge_time = time;
} else {
// posedge
if (time - negedge_time > pdMS_TO_TICKS(DEBOUNCE_WHEEL_MS)) {
if (b) {
dir = -1;
} else {
dir = 1;
}
} else {
// reset the timer
negedge_time = time;
}
}
struct debo state[3] = {
{.debo_time = pdMS_TO_TICKS(DEBOUNCE_BTN_MS)}, // push
{.debo_time = pdMS_TO_TICKS(DEBOUNCE_WHEEL_MS), .state=1}, // wheel input 1
{.debo_time = pdMS_TO_TICKS(DEBOUNCE_WHEEL_MS), .state=1} // wheel input 2
};
while (1) {
vTaskDelay(pdMS_TO_TICKS(1));
#if 0 uint32_t now = xTaskGetTickCount();
const uint32_t inputs = gpio_input_get();
bool a = 0 == (inputs & (1 << wheelPin1)); // neg = active
bool b = 0 == (inputs & (1 << wheelPin2));
#define ENCODER_POS1 1 const uint32_t inputs = gpio_input_get();
#define ENCODER_POS2 2
#define ENCODER_POS3 3
#define ENCODER_POS0 0
uint8_t NewEnc = a | (b<<1); bool input[3] = {
if (NewEnc ^ OldEnc) { // Encoder value changed??? (inputs & (1 << pushPin)) == 0,
switch(NewEnc) { (inputs & (1 << wheelPin1)) != 0,
case ENCODER_POS1 : // 01 (inputs & (1 << wheelPin2)) != 0,
if (OldEnc == ENCODER_POS0) // 00
dir--;
else
dir++;
break;
case ENCODER_POS3 : // 11
if (OldEnc == ENCODER_POS1) // 01
dir--;
else
dir++;
break;
case ENCODER_POS2 : // 10
if (OldEnc == ENCODER_POS3) // 11
dir--;
else
dir++;
break;
case ENCODER_POS0 : // 00
if (OldEnc == ENCODER_POS2) // 10
dir--;
else
dir++;
break;
}; };
OldEnc = NewEnc;
}; // end if encoder value changed.
#endif
#if 0 enum change {
// Omron version CHG_NONE = 2,
int which = (int)arg; CHG_SET = 1,
CHG_CLEAR = 0,
};
const uint32_t inputs = gpio_input_get(); enum change changes[3] = {CHG_NONE, CHG_NONE, CHG_NONE};
bool a = 0 == (inputs & (1 << wheelPin1)); // neg = active for (int i=0; i<3;i++) {
bool b = 0 == (inputs & (1 << wheelPin2)); if (input[i] == !state[i].state) {
// Change detected
if (state[i].start_time == 0) {
// start counting
state[i].start_time = now;
}
if (which == 0) { // itr from A if ((state[i].start_time != 0) && (now - state[i].start_time > state[i].debo_time)) {
if (a) { state[i].state = !state[i].state;
if (b) { changes[i] = state[i].state ? CHG_SET : CHG_CLEAR;
dir = -1; }
} }
else { else {
dir = 1; // returned back to original, reset counter
state[i].start_time = 0;
} }
} }
}
else { // itr from B uint32_t signal = 0;
if (b) {
if (a) { // Wheel logic
dir = 1; if (changes[1] == CHG_SET) {
if (state[2].state) {
signal |= 0b01;
} }
else { else {
dir = -1; signal |= 0b10;
} }
} }
}
#endif
#if 0
// Naive version
int which = arg;
const uint32_t inputs = gpio_input_get();
bool a = 0 == (inputs & (1 << wheelPin1)); // neg = active
bool b = 0 == (inputs & (1 << wheelPin2));
if (which == 0) { // itr from A
if (b) {
dir = -1;
} /*else {
dir = 1;
}*/
}
else { // itr from B
if (a) {
dir = 1;
} /*else {
dir = -1;
}*/
}
#endif
#if 0
// More complex version
const uint32_t inputs = gpio_input_get();
const uint8_t ab =
(((inputs >> wheelPin2) & 1) << 1) |
((inputs >> wheelPin1) & 1);
if (wheelState == S_ILLEGAL) { // knob
if (ab != 0b11) { if (changes[0] != CHG_NONE) {
return; signal |= 0b100 << changes[0];
} }
}
uint8_t next = switch_table[wheelState*4 + ab];
if (next & SW_FWD) dir = 1;
if (next & SW_BCK) dir = -1;
next &= ~(SW_FWD | SW_BCK);
wheelState = next;
#endif
if (dir != 0) {
BaseType_t higherWoken = 0;
xTaskNotifyFromISR(hGuiThread, dir == 1 ? 0b10 : 0b01, eSetBits, &higherWoken);
if (higherWoken) portYIELD_FROM_ISR();
}
}
static void handle_pushbtn(void *arg) {
static uint32_t negedge_time = 0;
const uint32_t inputs = gpio_input_get();
BaseType_t higherWoken = 0;
bool pushed = (inputs & (1 << pushPin)) == 0;
const uint32_t time = xTaskGetTickCount(); // send event to GUI
if (pushed) { if (signal != 0) {
negedge_time = time; BaseType_t higherWoken = 0;
} else { xTaskNotifyFromISR(hGuiThread, signal, eSetBits, &higherWoken);
if (time - negedge_time > pdMS_TO_TICKS(DEBOUNCE_BTN_MS)) {
xTaskNotifyFromISR(hGuiThread, pushed ? 0b1000 : 0b0100, eSetBits, &higherWoken);
if (higherWoken) portYIELD_FROM_ISR(); if (higherWoken) portYIELD_FROM_ISR();
} }
} }

Loading…
Cancel
Save