From bffdd20de239d2775ef1a8b446937ed8d6ba24d6 Mon Sep 17 00:00:00 2001 From: demik Date: Tue, 4 May 2021 00:45:23 +0200 Subject: [PATCH] ADB Parsing 90% done, quadrature output issues --- main/adb.c | 156 ++++++++++++++++++++++++++++++++++++++++++++++++---- main/adb.h | 10 ++++ main/gpio.c | 7 ++- main/gpio.h | 1 + main/quad.c | 32 ++++++----- main/quad.h | 2 +- 6 files changed, 181 insertions(+), 27 deletions(-) diff --git a/main/adb.c b/main/adb.c index 25985af..4c7d91e 100644 --- a/main/adb.c +++ b/main/adb.c @@ -39,15 +39,46 @@ /* globals */ rmt_config_t adb_rmt_rx = RMT_DEFAULT_CONFIG_RX(GPIO_ADB, RMT_RX_CHANNEL); extern TaskHandle_t t_green, t_blue, t_yellow, t_red; +extern TaskHandle_t t_click, t_qx, t_qy; /* static defines */ +static void adb_handle_button(bool action); +static bool adb_rx_isone(rmt_item32_t cell); +static bool adb_rx_isstop(rmt_item32_t cell); +static bool adb_rx_iszero(rmt_item32_t cell); static uint16_t adb_rx_mouse(); +static void adb_rx_setup(void); static bool adb_rx_tlt(void); static void adb_tx_as(void); static void adb_tx_one(void); +static void adb_tx_setup(void); static void adb_tx_zero(void); /* functions */ +static void adb_handle_button(bool action) { + static bool status = ADB_B_UP; // Keep state. Click is active low + + if (status == ADB_B_UP && action == ADB_B_UP) + return ; + if (status == ADB_B_DOWN && action == ADB_B_DOWN) + return ; + + /* release button */ + if (status == ADB_B_DOWN && action == ADB_B_UP) { + xTaskNotify(t_click, 0, eSetValueWithOverwrite); + status = ADB_B_UP; + ESP_LOGD("ADB", "ADB button released"); + return ; + } + + /* press button */ + if (status == ADB_B_UP && action == ADB_B_DOWN) { + xTaskNotify(t_click, 1, eSetValueWithOverwrite); + status = ADB_B_DOWN; + ESP_LOGD("ADB", "ADB button pressed"); + return ; + } +} void adb_init(void) { /* initialise */ @@ -71,7 +102,9 @@ void adb_init(void) { } void adb_task_host(void *pvParameters) { + /* Classic Apple Mouse Protocol is 16 bits long */ uint16_t data; + int8_t move = 0; /* put green led to steady if BT is disabled. Otherwise BT init will do it */ if (gpio_get_level(GPIO_BTOFF) == 0) @@ -85,6 +118,34 @@ void adb_task_host(void *pvParameters) { vTaskDelay(20 / portTICK_PERIOD_MS); adb_tx_cmd(ADB_MOUSE|ADB_TALK|ADB_REG0); data = adb_rx_mouse(); + + if (data) { + /* click is active low */ + if (! (data & ADB_CMP_B1) || (! (data & ADB_CMP_B2))) + adb_handle_button(ADB_B_DOWN); + else + adb_handle_button(ADB_B_UP); + + move = (data & ADB_CMD_MX) >> 0; + if (move & 0x40) { + move &= ~0x40; + move |= 0x80; + move += 64; + } + + if (move) + xTaskNotify(t_qx, move, eSetValueWithOverwrite); + + move = (data & ADB_CMD_MY) >> 8; + if (move & 0x40) { + move &= ~0x40; + move |= 0x80; + move += 64; + } + + if (move) + xTaskNotify(t_qy, move, eSetValueWithOverwrite); + } } } @@ -98,7 +159,37 @@ int dur( uint32_t level, uint32_t duration ) { else { return -1.0 * duration; } } +/* + * some ADB mouses are using cells as short as 24µs+49µs, try to get that... + * spec allow ±30% variance + * + * units are in µs + */ + +static bool adb_rx_isone(rmt_item32_t cell) { + if (cell.level0 == 0 && (cell.duration0 >= 22 && cell.duration0 <= 44) && + cell.level1 == 1 && (cell.duration1 >= 46 && cell.duration1 <= 86)) + return true; + return false; +} + +static bool adb_rx_isstop(rmt_item32_t cell) { + /* high part of the well is lengh 0 because of RMT timeout (100µs+) */ + if (cell.level0 == 0 && (cell.duration0 >= 46 && cell.duration0 <= 86) && + cell.level1 == 1 && cell.duration1 == 0) + return true; + return false; +} + +static bool adb_rx_iszero(rmt_item32_t cell) { + if (cell.level0 == 0 && (cell.duration0 >= 46 && cell.duration0 <= 86) && + cell.level1 == 1 && (cell.duration1 >= 22 && cell.duration1 <= 44)) + return true; + return false; +} + static uint16_t adb_rx_mouse() { + uint16_t data = 0; RingbufHandle_t rb = NULL; rmt_item32_t* items = NULL; size_t rx_size = 0; @@ -108,19 +199,59 @@ static uint16_t adb_rx_mouse() { assert(rb != NULL); rmt_rx_start(RMT_RX_CHANNEL, true); items = (rmt_item32_t*) xRingbufferReceive(rb, &rx_size, pdMS_TO_TICKS(10)); - printf( ">>> %i\n", rx_size); + + //printf( ">>> %i\n", rx_size); rmt_rx_stop(RMT_RX_CHANNEL); - if (rx_size > (1 * sizeof(rmt_item32_t))) - xTaskNotify(t_yellow, LED_ONCE, eSetValueWithOverwrite); - else + if (items == NULL) return 0; - for (i = 0; i < (rx_size / sizeof(rmt_item32_t)); i++) { - printf("%d:%dus %d:%dus\n", (items+i)->level0, (items+i)->duration0, (items+i)->level1, (items+i)->duration1); + + /* + * Mouse response size in bits is events / sizeof(rmt_item32_t) (4) + * start bit + 16 data bits + stop bit = 72 bytes in RMT buffer (18 bits received) + */ + + switch (rx_size) { + case 0: + return 0; + case 72: + xTaskNotify(t_yellow, LED_ONCE, eSetValueWithOverwrite); + break; + default: + xTaskNotify(t_red, LED_ONCE, eSetValueWithOverwrite); } + + /* check start and stop bits */ + if (! adb_rx_isone(*(items+0)) && (! adb_rx_isstop(*(items+(rx_size / sizeof(rmt_item32_t) - 1))))) { + xTaskNotify(t_red, LED_ONCE, eSetValueWithOverwrite); + return 0; + } + + /* rebuild our data with RMT buffer */ + for (i = 1; i < ((rx_size / sizeof(rmt_item32_t)) - 1); i++) { + data <<= 1; + + /* check that every data is either one or zero */ + if ((! adb_rx_isone(*(items+i))) && (! adb_rx_iszero(*(items+i)))) { + xTaskNotify(t_red, LED_ONCE, eSetValueWithOverwrite); + return 0; + } + + if (adb_rx_isone(*(items+i))) + data |= 1; + //printf("%d:%dus %d:%dus ", (items+i)->level0, (items+i)->duration0, (items+i)->level1, (items+i)->duration1); + } + printf("\n"); vRingbufferReturnItem(rb, (void*) items); - return 0; + return data; +} + +static inline void adb_rx_setup() { + gpio_set_level(GPIO_DIR, 0); + gpio_set_direction(GPIO_ADB, GPIO_MODE_INPUT); + gpio_pullup_dis(GPIO_ADB); + gpio_pulldown_dis(GPIO_ADB); } static inline void adb_tx_as() { @@ -132,8 +263,7 @@ static inline void adb_tx_as() { } void adb_tx_cmd(unsigned char cmd) { - gpio_set_direction(GPIO_ADB, GPIO_MODE_OUTPUT); - + adb_tx_setup(); adb_tx_as(); /* send actual byte (unrolled loop) */ @@ -148,8 +278,7 @@ void adb_tx_cmd(unsigned char cmd) { /* stop bit */ adb_tx_zero(); - gpio_set_direction(GPIO_ADB, GPIO_MODE_INPUT); - gpio_set_pull_mode(GPIO_ADB, GPIO_PULLUP_ONLY); + adb_rx_setup(); } static inline void adb_tx_one() { @@ -173,6 +302,11 @@ void adb_tx_reset() { ets_delay_us(500); } +static inline void adb_tx_setup() { + gpio_set_direction(GPIO_ADB, GPIO_MODE_OUTPUT); + gpio_set_level(GPIO_DIR, 1); +} + static inline void adb_tx_zero() { /* values from AN591 Datasheet minus the estimated call to ets_delay_us */ gpio_set_level(GPIO_ADB, 0); diff --git a/main/adb.h b/main/adb.h index 2787af2..2f2dbae 100644 --- a/main/adb.h +++ b/main/adb.h @@ -44,6 +44,12 @@ void adb_tx_reset(void); #define ADB_1_LOW 35 #define ADB_1_HIGH 65 +/* Classic Apple Mouse Protocol bitmasks */ +#define ADB_CMP_B1 (1<<15) +#define ADB_CMP_B2 (1<<7) +#define ADB_CMD_MX (127<<0) +#define ADB_CMD_MY (127<<8) + /* ADB commands values from 00591b.pdf page 16-17 */ #define ADB_MOUSE (3<<4) #define ADB_TALK 0xC @@ -51,4 +57,8 @@ void adb_tx_reset(void); #define ADB_REG0 0x0 #define ADB_REG3 0x3 +/* Various stuff */ +#define ADB_B_UP 0 +#define ADB_B_DOWN 1 + #endif diff --git a/main/gpio.c b/main/gpio.c index 06686f8..4926c34 100644 --- a/main/gpio.c +++ b/main/gpio.c @@ -44,7 +44,9 @@ void gpio_init(void) { gpio_set_direction(GPIO_REDLED, GPIO_MODE_OUTPUT); /* External chips */ + gpio_reset_pin(GPIO_DIR); gpio_reset_pin(GPIO_OE); + gpio_set_direction(GPIO_DIR, GPIO_MODE_OUTPUT); gpio_set_direction(GPIO_OE, GPIO_MODE_OUTPUT); /* Modes */ @@ -55,6 +57,7 @@ void gpio_init(void) { /* ADB */ gpio_set_direction(GPIO_ADB, GPIO_MODE_INPUT); + gpio_set_level(GPIO_DIR, 0); /* Quadrature mouse */ gpio_reset_pin(GPIO_CLICK); @@ -75,9 +78,9 @@ void gpio_init(void) { } void gpio_output_disable(void) { - gpio_set_level(GPIO_OE, 0); + gpio_set_level(GPIO_OE, 1); } void gpio_output_enable(void) { - gpio_set_level(GPIO_OE, 1); + gpio_set_level(GPIO_OE, 0); } diff --git a/main/gpio.h b/main/gpio.h index 1c1f9f8..07e1b52 100644 --- a/main/gpio.h +++ b/main/gpio.h @@ -58,6 +58,7 @@ void gpio_output_enable(void); #define GPIO_QY1 14 #define GPIO_QY2 15 +#define GPIO_DIR 19 #define GPIO_OE 22 #define GPIO_ADBSRC 32 #define GPIO_BTOFF 33 diff --git a/main/quad.c b/main/quad.c index 4de4ba7..b273e06 100644 --- a/main/quad.c +++ b/main/quad.c @@ -52,9 +52,12 @@ void quad_init(void) { esp_timer_create_args_t args; /* create quadrature tasks */ - xTaskCreate(quad_click, "CLICK", 1024, NULL, tskIDLE_PRIORITY + 1, &t_click); - xTaskCreate(quad_move_x, "QX", 1024, NULL, tskIDLE_PRIORITY + 1, &t_qx); - xTaskCreate(quad_move_y, "QY", 1024, NULL, tskIDLE_PRIORITY + 1, &t_qy); + xTaskCreate(quad_click, "CLICK", 4 * 1024, NULL, tskIDLE_PRIORITY + 1, &t_click); + xTaskCreate(quad_move_x, "QX", 4 * 1024, NULL, tskIDLE_PRIORITY + 1, &t_qx); + xTaskCreate(quad_move_y, "QY", 4 * 1024, NULL, tskIDLE_PRIORITY + 1, &t_qy); + + printf(">>> T_QX %x\n", (unsigned int)t_qx); + printf(">>> T_QY %x\n", (unsigned int)t_qy); /* click is active low */ gpio_set_level(GPIO_CLICK, 1); @@ -67,11 +70,11 @@ void quad_init(void) { /* create timers for quadrature phases */ args.callback = &quad_timer; - args.arg = &t_qx; + args.arg = t_qx; args.name = "quad_qx"; ESP_ERROR_CHECK(esp_timer_create(&args, &quad_qx)); args.callback = &quad_timer; - args.arg = &t_qy; + args.arg = t_qy; args.name = "quad_qy"; ESP_ERROR_CHECK(esp_timer_create(&args, &quad_qy)); @@ -85,6 +88,7 @@ void quad_click(void *pvParameters) { while (true) { xTaskNotifyWait(0, 0, &click, portMAX_DELAY); + printf("CLICK"); switch (click) { case true: @@ -114,19 +118,19 @@ void quad_move_x(void *pvParameters) { if (move > 0) { while (move--) { i++; + printf("MOVE X %i %i %i\n", move, q1[i % 4], q2[i % 4]); gpio_set_level(GPIO_QX1, q1[i % 4]); gpio_set_level(GPIO_QX2, q2[i % 4]); - ESP_ERROR_CHECK(esp_timer_start_once(quad_qx, QUAD_INTERVAL)); - vTaskSuspend(NULL); + //ets_delay_us(QUAD_INTERVAL); } } else { while (move++) { i--; + printf("MOVE X %i %i %i\n", move, q1[i % 4], q2[i % 4]); gpio_set_level(GPIO_QX1, q1[i % 4]); gpio_set_level(GPIO_QX2, q2[i % 4]); - ESP_ERROR_CHECK(esp_timer_start_once(quad_qx, QUAD_INTERVAL)); - vTaskSuspend(NULL); + //ets_delay_us(QUAD_INTERVAL); } } } @@ -147,19 +151,19 @@ void quad_move_y(void *pvParameters) { if (move > 0) { while (move--) { i++; + printf("MOVE Y %i %i %i\n", move, q1[i % 4], q2[i % 4]); gpio_set_level(GPIO_QY1, q1[i % 4]); gpio_set_level(GPIO_QY2, q2[i % 4]); - ESP_ERROR_CHECK(esp_timer_start_once(quad_qy, QUAD_INTERVAL)); - vTaskSuspend(NULL); + //ets_delay_us(QUAD_INTERVAL); } } else { while (move++) { i--; + printf("MOVE Y %i %i %i\n", move, q1[i % 4], q2[i % 4]); gpio_set_level(GPIO_QY1, q1[i % 4]); gpio_set_level(GPIO_QY2, q2[i % 4]); - ESP_ERROR_CHECK(esp_timer_start_once(quad_qy, QUAD_INTERVAL)); - vTaskSuspend(NULL); + //ets_delay_us(QUAD_INTERVAL); } } } @@ -169,6 +173,8 @@ void quad_move_y(void *pvParameters) { static void quad_timer(void* arg) { BaseType_t xYieldRequired = pdFALSE; + printf(">>> TIMER %x\n", (unsigned int)arg); + xYieldRequired = xTaskResumeFromISR(arg); /* switch context of needed */ diff --git a/main/quad.h b/main/quad.h index feda14b..637a797 100644 --- a/main/quad.h +++ b/main/quad.h @@ -32,7 +32,7 @@ void quad_move_x(void *pvParameters); void quad_move_y(void *pvParameters); /* defines */ -#define QUAD_INTERVAL 100 +#define QUAD_INTERVAL 20 #endif