From d4da14f28a2fbd65888169df0132c0e53874170f Mon Sep 17 00:00:00 2001 From: Helco Date: Sun, 4 Nov 2018 20:00:14 +0100 Subject: [PATCH] add initial qemu control handler --- Makefile | 2 +- config.mk | 2 + hw/drivers/stm32_usart/stm32_usart.c | 13 ++++ hw/drivers/stm32_usart/stm32_usart.h | 1 + hw/platform/snowy/platform.h | 1 + hw/platform/snowy_family/config.mk | 1 + hw/platform/snowy_family/snowy_qemu.c | 60 +++++++++++++++++ hw/platform/snowy_family/snowy_qemu.h | 7 ++ lib/minilib/inc/minilib.h | 2 + lib/minilib/minilib.c | 32 ++++++--- rcore/power.c | 2 +- rcore/qemu.c | 96 +++++++++++++++++++++++++++ rcore/qemu.h | 44 ++++++++++++ rcore/qemu_endpoints.c | 18 +++++ rcore/rebbleos.c | 2 + 15 files changed, 270 insertions(+), 13 deletions(-) create mode 100644 hw/platform/snowy_family/snowy_qemu.c create mode 100644 hw/platform/snowy_family/snowy_qemu.h create mode 100644 rcore/qemu.c create mode 100644 rcore/qemu.h create mode 100644 rcore/qemu_endpoints.c diff --git a/Makefile b/Makefile index ada66b4b..6ef72b0c 100644 --- a/Makefile +++ b/Makefile @@ -65,7 +65,7 @@ $(eval CFLAGS_$(1) = $(CFLAGS_$(1)) -I$(BUILD)/$(1)/res ) $(1): $(BUILD)/$(1)/$(1).pbz $(1)_qemu: $(BUILD)/$(1)/fw.qemu_flash.bin $(BUILD)/$(1)/fw.qemu_spi.bin - $(QEMU) -rtc base=localtime -serial null -serial null -serial stdio -gdb tcp::63770,server $(QEMUFLAGS_$(1)) -pflash $(BUILD)/$(1)/fw.qemu_flash.bin -$(QEMUSPITYPE_$(1)) $(BUILD)/$(1)/fw.qemu_spi.bin $(QEMUFLAGS) + $(QEMU) -rtc base=localtime -serial null -serial tcp::63771,server -serial stdio -gdb tcp::63770,server $(QEMUFLAGS_$(1)) -pflash $(BUILD)/$(1)/fw.qemu_flash.bin -$(QEMUSPITYPE_$(1)) $(BUILD)/$(1)/fw.qemu_spi.bin $(QEMUFLAGS) $(1)_gdb: $(PFX)gdb -ex 'target remote localhost:63770' -ex "sym $(BUILD)/$(1)/tintin_fw.elf" diff --git a/config.mk b/config.mk index 1c26a406..90d92465 100644 --- a/config.mk +++ b/config.mk @@ -109,6 +109,8 @@ SRCS_all += rcore/resource.c SRCS_all += rcore/watchdog.c SRCS_all += rcore/overlay_manager.c SRCS_all += rcore/rebble_util.c +SRCS_all += rcore/qemu.c +SRCS_all += rcore/qemu_endpoints.c SRCS_all += rcore/protocol/protocol_notification.c SRCS_all += rcore/protocol/protocol_system.c diff --git a/hw/drivers/stm32_usart/stm32_usart.c b/hw/drivers/stm32_usart/stm32_usart.c index d72b4bf1..fd6bf3f9 100644 --- a/hw/drivers/stm32_usart/stm32_usart.c +++ b/hw/drivers/stm32_usart/stm32_usart.c @@ -248,3 +248,16 @@ size_t stm32_usart_read(stm32_usart_t *usart, uint8_t *buf, size_t len) return i; } + +int stm32_usart_has_data(stm32_usart_t *usart) +{ + stm32_power_request(usart->config->usart_periph_bus, usart->config->usart_clock); + stm32_power_request(STM32_POWER_AHB1, usart->config->gpio_clock); + + int result = (usart->config->usart->SR & USART_FLAG_RXNE) != 0; + + stm32_power_release(usart->config->usart_periph_bus, usart->config->usart_clock); + stm32_power_release(STM32_POWER_AHB1, usart->config->gpio_clock); + + return result; +} diff --git a/hw/drivers/stm32_usart/stm32_usart.h b/hw/drivers/stm32_usart/stm32_usart.h index 57bfe6d1..95c603a1 100644 --- a/hw/drivers/stm32_usart/stm32_usart.h +++ b/hw/drivers/stm32_usart/stm32_usart.h @@ -46,6 +46,7 @@ void stm32_usart_init_device(stm32_usart_t *usart); void stm32_usart_set_baud(stm32_usart_t *usart, uint32_t baud); size_t stm32_usart_write(stm32_usart_t *usart, const uint8_t *buf, size_t len); size_t stm32_usart_read(stm32_usart_t *usart, uint8_t *buf, size_t len); +int stm32_usart_has_data(stm32_usart_t *usart); void stm32_usart_send_dma(stm32_usart_t *usart, uint32_t *data, size_t len); void stm32_usart_recv_dma(stm32_usart_t *usart, uint32_t *data, size_t len); diff --git a/hw/platform/snowy/platform.h b/hw/platform/snowy/platform.h index 092c4c1e..fede9cb7 100644 --- a/hw/platform/snowy/platform.h +++ b/hw/platform/snowy/platform.h @@ -18,4 +18,5 @@ #include "snowy_ext_flash.h" #include "btstack_rebble.h" #include "snowy_bluetooth.h" +#include "snowy_qemu.h" #include "debug.h" diff --git a/hw/platform/snowy_family/config.mk b/hw/platform/snowy_family/config.mk index 4de5c469..8b177d51 100644 --- a/hw/platform/snowy_family/config.mk +++ b/hw/platform/snowy_family/config.mk @@ -25,6 +25,7 @@ SRCS_snowy_family += hw/platform/snowy_family/snowy_vibrate.c SRCS_snowy_family += hw/platform/snowy_family/snowy_ambient.c SRCS_snowy_family += hw/platform/snowy_family/snowy_ext_flash.c SRCS_snowy_family += hw/platform/snowy_family/snowy_common.c +SRCS_snowy_family += hw/platform/snowy_family/snowy_qemu.c LDFLAGS_snowy_family = $(LDFLAGS_stm32f4xx) LIBS_snowy_family = $(LIBS_stm32f4xx) diff --git a/hw/platform/snowy_family/snowy_qemu.c b/hw/platform/snowy_family/snowy_qemu.c new file mode 100644 index 00000000..2d502ca2 --- /dev/null +++ b/hw/platform/snowy_family/snowy_qemu.c @@ -0,0 +1,60 @@ +#include "snowy_qemu.h" +#include "stm32_usart.h" +#include "stm32_power.h" +#include "semphr.h" + +static const stm32_usart_config_t _usart2_config = { + .usart = USART2, + .flow_control_enabled = FLOW_CONTROL_DISABLED, + .usart_periph_bus = STM32_POWER_APB1, + .gpio_pin_tx_num = 2, + .gpio_pin_rx_num = 3, // this is even more ignored by QEMU than tx + .gpio_pin_rts_num = 0, + .gpio_pin_cts_num = 0, + .gpio_ptr = GPIOA, + .gpio_clock = RCC_AHB1Periph_GPIOA, + .usart_clock = RCC_APB1Periph_USART2, + .af = GPIO_AF_USART2, +}; + +static stm32_usart_t _usart2 = { + &_usart2_config, + NULL, /* no dma */ + 230400 +}; + +static StaticSemaphore_t _usart2_mutex_mem; +static SemaphoreHandle_t _usart2_mutex; + +void hw_qemu_init(void) +{ + stm32_usart_init_device(&_usart2); + _usart2_mutex = xSemaphoreCreateMutexStatic(&_usart2_mutex_mem); +} + +int hw_qemu_has_data(void) +{ + if (xSemaphoreTake(_usart2_mutex, 0) == pdPASS) + { + int result = stm32_usart_has_data(&_usart2); + xSemaphoreGive(_usart2_mutex); + return result; + } + return 0; +} + +size_t hw_qemu_read(void *buffer, size_t max_len) +{ + xSemaphoreTake(_usart2_mutex, portMAX_DELAY); + size_t bytes_read = stm32_usart_read(&_usart2, (uint8_t*)buffer, max_len); + xSemaphoreGive(_usart2_mutex); + return bytes_read; +} + +size_t hw_qemu_write(const void *buffer, size_t len) +{ + xSemaphoreTake(_usart2_mutex, portMAX_DELAY); + size_t bytes_written = stm32_usart_write(&_usart2, (const uint8_t*)buffer, len); + xSemaphoreGive(_usart2_mutex); + return bytes_written; +} diff --git a/hw/platform/snowy_family/snowy_qemu.h b/hw/platform/snowy_family/snowy_qemu.h new file mode 100644 index 00000000..2e713821 --- /dev/null +++ b/hw/platform/snowy_family/snowy_qemu.h @@ -0,0 +1,7 @@ +#pragma once +#include "platform.h" + +void hw_qemu_init(void); +int hw_qemu_has_data(void); +size_t hw_qemu_read(void *buffer, size_t max_len); +size_t hw_qemu_write(const void *buffer, size_t len); diff --git a/lib/minilib/inc/minilib.h b/lib/minilib/inc/minilib.h index d5723e51..94a67694 100644 --- a/lib/minilib/inc/minilib.h +++ b/lib/minilib/inc/minilib.h @@ -32,6 +32,8 @@ extern void tohex(char *s, unsigned long l); extern void btohex(char *s, unsigned char c); extern unsigned short htons(unsigned short in); extern unsigned int htonl(unsigned int in); +extern unsigned short ntohs(unsigned short in); +extern unsigned int ntohl(unsigned int in); /* crc32.c */ extern void crc32_init(); diff --git a/lib/minilib/minilib.c b/lib/minilib/minilib.c index 6d3584b7..af718cb0 100644 --- a/lib/minilib/minilib.c +++ b/lib/minilib/minilib.c @@ -17,23 +17,23 @@ void _memcpy_fast(void *dest, const void *src, int bytes) { /* I hate everyone */ /* Since we otherwise compile with -O0, we might as well manually speed this up a bit. */ - + char *cdest = dest; const char *csrc = src; int *idest; const int *isrc; int nwords; - + /* Align to src (picked arbitrarily; might as well align to something) */ while (bytes && ((unsigned int)csrc & 3)) { *(cdest++) = *(csrc++); bytes--; } - + idest = (int *)cdest; isrc = (const int *)csrc; - + nwords = bytes / 4; bytes -= bytes & ~3; if (nwords != 0) @@ -48,7 +48,7 @@ void _memcpy_fast(void *dest, const void *src, int bytes) case 2: nwords--; *(idest++) = *(isrc++); case 1: nwords--; *(idest++) = *(isrc++); } while (nwords); - + cdest = (char *)idest; csrc = (const char *)isrc; while (bytes) /* Clean up the remainder */ @@ -62,7 +62,7 @@ void _memcpy_slow(void *dest, const void *src, int bytes) { unsigned char *cdest = dest; const unsigned char *csrc = src; - + while (bytes--) *(cdest++) = *(csrc++); } @@ -108,7 +108,7 @@ void *memmove(void *dest, const void *src, int bytes) *(--cdest) = *(--csrc); } else memcpy(dest, src, bytes); - + return dest; } @@ -151,24 +151,24 @@ int strlen(const char *c) void *strcpy(char *a2, const char *a1) { char *origa2 = a2; - + do { *(a2++) = *a1; } while (*(a1++)); - + return origa2; } void *strcat(char *dest, const char *src) { char *origdest = dest; - + while (*dest) dest++; while (*src) *(dest++) = *(src++); *(dest++) = *(src++); - + return origdest; } static const char hexarr[] = "0123456789ABCDEF"; @@ -201,6 +201,16 @@ unsigned int htonl(unsigned int in) ((in & 0xff000000UL) >> 24); } +unsigned short ntohs(unsigned short in) +{ + return htons(in); // for pebble this is equivalent +} + +unsigned int ntohl(unsigned int in) +{ + return htonl(in); +} + int atoi(const char *c) { if (!c) return 0; diff --git a/rcore/power.c b/rcore/power.c index 2fd7f447..bd2dcd07 100644 --- a/rcore/power.c +++ b/rcore/power.c @@ -57,7 +57,7 @@ void power_update_battery(void) { _bat_voltage = hw_power_get_bat_mv(); _bat_pct = map_range(_bat_voltage, 2600, 3500, 0, 100); - SYS_LOG("PWR", APP_LOG_LEVEL_INFO, "VBAT %ldmV %d%%", _bat_voltage, _bat_pct); + //SYS_LOG("PWR", APP_LOG_LEVEL_INFO, "VBAT %ldmV %d%%", _bat_voltage, _bat_pct); /* battery low */ if (_bat_pct > 20) diff --git a/rcore/qemu.c b/rcore/qemu.c new file mode 100644 index 00000000..138574d4 --- /dev/null +++ b/rcore/qemu.c @@ -0,0 +1,96 @@ +#include "qemu.h" +#include "task.h" +#include "log.h" +#include "rebbleos.h" + +extern const QemuEndpoint qemu_endpoints[]; + +#define STACK_SZ_QEMU configMINIMAL_STACK_SIZE + 600 + +static TaskHandle_t _qemu_task; +static StackType_t _qemu_task_stack[STACK_SZ_QEMU]; +static StaticTask_t _qemu_task_buf; +static uint8_t _qemu_packet_buffer[QEMU_MAX_DATA_LEN]; + +static void _qemu_thread(void *pvParameters); +static void _qemu_handle_packet(); + +uint8_t qemu_init(void) +{ + hw_qemu_init(); + _qemu_task = xTaskCreateStatic(_qemu_thread, + "QEMU", STACK_SZ_QEMU, NULL, + tskIDLE_PRIORITY + 3UL, + _qemu_task_stack, &_qemu_task_buf); + return INIT_RESP_OK; +} + +static QemuEndpointHandler _qemu_find_endpoint_handler(uint16_t protocol) +{ + const QemuEndpoint *endpoint = qemu_endpoints; + while (endpoint->handler != NULL) + { + if (endpoint->protocol == protocol) + return endpoint->handler; + } + return NULL; +} + +static void _qemu_thread(void *pvParameters) +{ + for (;;) + { + if (hw_qemu_has_data()) + _qemu_handle_packet(); + vTaskDelay(pdMS_TO_TICKS(16)); + } +} + +static void _qemu_read_header(QemuCommChannelHeader *header) +{ + hw_qemu_read(_qemu_packet_buffer, sizeof(QemuCommChannelHeader)); + const QemuCommChannelHeader *raw_header = (const QemuCommChannelHeader*)_qemu_packet_buffer; + header->signature = ntohs(raw_header->signature); + header->protocol = ntohs(raw_header->protocol); + header->len = ntohs(raw_header->len); +} + +static void _qemu_read_footer(QemuCommChannelFooter *footer) +{ + hw_qemu_read(_qemu_packet_buffer, sizeof(QemuCommChannelFooter)); + const QemuCommChannelFooter *raw_footer = (const QemuCommChannelFooter*)_qemu_packet_buffer; + footer->signature = ntohs(raw_footer->signature); +} + +static void _qemu_handle_packet(void) +{ + QemuCommChannelHeader header; + _qemu_read_header(&header); + if (header.signature != QEMU_HEADER_SIGNATURE) + { + KERN_LOG("QEMU", APP_LOG_LEVEL_ERROR, "Invalid header signature: %x", header.signature); + return; + } + if (header.len > QEMU_MAX_DATA_LEN) + { + KERN_LOG("QEMU", APP_LOG_LEVEL_ERROR, "Invalid packet size: %d", header.len); + return; + } + QemuEndpointHandler handler = _qemu_find_endpoint_handler(header.protocol); + if (handler == NULL) + { + KERN_LOG("QEMU", APP_LOG_LEVEL_ERROR, "Unknown protocol: %d", header.protocol); + } + + size_t len = header.len; + hw_qemu_read(_qemu_packet_buffer, len); + handler(_qemu_packet_buffer, len); + + const QemuCommChannelFooter footer; + _qemu_read_footer(&footer); + if (footer.signature != QEMU_FOOTER_SIGNATURE) + { + KERN_LOG("QEMU", APP_LOG_LEVEL_ERROR, "Invalid footer signature: %x", footer.signature); + return; + } +} diff --git a/rcore/qemu.h b/rcore/qemu.h new file mode 100644 index 00000000..07a83f65 --- /dev/null +++ b/rcore/qemu.h @@ -0,0 +1,44 @@ +#pragma once +#include "platform.h" + +#define QEMU_HEADER_SIGNATURE 0xFEED +#define QEMU_FOOTER_SIGNATURE 0xBEEF +#define QEMU_MAX_DATA_LEN 2048 + +typedef struct +{ + uint16_t signature; // QEMU_HEADER_SIGNATURE + uint16_t protocol; // one of QemuProtocol + uint16_t len; // number of bytes that follow (not including this header or footer) +} QemuCommChannelHeader; + +typedef struct +{ + uint16_t signature; // QEMU_FOOTER_SIGNATURE +} QemuCommChannelFooter; + +enum +{ + // Pebble standard + QemuProtocol_SPP = 1, + QemuProtocol_Tap = 2, + QemuProtocol_BluetoothConnection = 3, + QemuProtocol_Compass = 4, + QemuProtocol_Battery = 5, + QemuProtocol_Accel = 6, + QemuProtocol_Vibration = 7, + QemuProtocol_Button = 8, + + // Rebble custom + QemuProtocol_Tests = 100 +}; + +typedef void (*QemuEndpointHandler)(const void *data, size_t len); +typedef struct +{ + uint16_t protocol; + QemuEndpointHandler handler; +} QemuEndpoint; + +uint8_t qemu_init(void); +void qemu_send_packet(const void *buffer, size_t len); diff --git a/rcore/qemu_endpoints.c b/rcore/qemu_endpoints.c new file mode 100644 index 00000000..94f81c62 --- /dev/null +++ b/rcore/qemu_endpoints.c @@ -0,0 +1,18 @@ +#include "qemu.h" +#include "log.h" + +void test_handler(const void *data, size_t len) +{ + KERN_LOG("QEMU", APP_LOG_LEVEL_INFO, "I got these %d bytes from qemu:", len); + debug_write((const unsigned char*)data, len); + debug_write("\n", 1); +} + +const QemuEndpoint qemu_endpoints[] = +{ + { + .protocol = QemuProtocol_Tests, + .handler = test_handler + }, + { .handler = NULL } +}; diff --git a/rcore/rebbleos.c b/rcore/rebbleos.c index 2662d9a6..87db75e1 100644 --- a/rcore/rebbleos.c +++ b/rcore/rebbleos.c @@ -14,6 +14,7 @@ #include "overlay_manager.h" #include "notification_manager.h" #include "power.h" +#include "qemu.h" typedef uint8_t (*mod_callback)(void); static TaskHandle_t _os_task; @@ -82,6 +83,7 @@ static void _os_thread(void *pvParameters) _module_init(bluetooth_init, "Bluetooth"); power_init(); KERN_LOG("init", APP_LOG_LEVEL_INFO, "Power Init"); + _module_init(qemu_init, "QEMU"); SYS_LOG("OS", APP_LOG_LEVEL_INFO, "Init: Main hardware up. Starting OS modules"); _module_init(resource_init, "Resources");