Add KRONE 8200 PST driver
This commit is contained in:
parent
72d349401b
commit
818ad88915
|
@ -0,0 +1,3 @@
|
|||
idf_component_register(SRCS sel_k8200_pst.c
|
||||
INCLUDE_DIRS include
|
||||
REQUIRES util)
|
|
@ -0,0 +1,53 @@
|
|||
menu "KRONE 8200 PST Split-Flap Configuration (Selection Mode)"
|
||||
|
||||
config K8200_PST_SEL_TX_IO
|
||||
int "Tx GPIO"
|
||||
default 0
|
||||
help
|
||||
GPIO pin for data transmitted to split-flap modules
|
||||
|
||||
config K8200_PST_SEL_RX_IO
|
||||
int "Rx GPIO"
|
||||
default 0
|
||||
help
|
||||
GPIO pin for data received from split-flap modules
|
||||
|
||||
config K8200_PST_SEL_NMI_IO
|
||||
int "NMI GPIO"
|
||||
default 0
|
||||
help
|
||||
GPIO pin for interrupt signal to split-flap modules
|
||||
|
||||
config K8200_PST_SEL_NMI_ACT_HIGH
|
||||
bool "NMI active-high"
|
||||
default false
|
||||
help
|
||||
NMI GPIO active-low or active-high
|
||||
|
||||
choice K8200_PST_SEL_UART
|
||||
bool "UART to use"
|
||||
default K8200_PST_SEL_UART_1
|
||||
|
||||
config K8200_PST_SEL_UART_0
|
||||
bool "UART0"
|
||||
|
||||
config K8200_PST_SEL_UART_1
|
||||
bool "UART1"
|
||||
|
||||
config K8200_PST_SEL_UART_2
|
||||
bool "UART2"
|
||||
endchoice
|
||||
|
||||
config K8200_PST_SEL_RX_BUF_SIZE
|
||||
int "Rx buffer size in bytes"
|
||||
default 64
|
||||
help
|
||||
UART receive buffer size. Must be greater that UART_FIFO_LEN.
|
||||
|
||||
config K8200_PST_SEL_TX_BUF_SIZE
|
||||
int "Tx buffer size in bytes"
|
||||
default 256
|
||||
help
|
||||
UART transmit buffer size. Set to 0 to disable buffer and block while sending data. Otherwise, must be greater that UART_FIFO_LEN.
|
||||
|
||||
endmenu
|
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "nvs.h"
|
||||
|
||||
esp_err_t display_init(nvs_handle_t* nvsHandle, uint8_t* display_framebuf_mask, uint16_t* display_num_units);
|
||||
void display_render_frame(uint8_t* frame, uint8_t* prevFrame, uint16_t frameBufSize, uint8_t* display_framebuf_mask, uint16_t display_num_units);
|
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* Functions for KRONE 8200 PST split-flap displays
|
||||
*/
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include <string.h>
|
||||
#include "driver/uart.h"
|
||||
|
||||
#include "macros.h"
|
||||
#include "util_generic.h"
|
||||
#include "util_gpio.h"
|
||||
#include "util_disp_selection.h"
|
||||
#include "sel_k8200_pst.h"
|
||||
|
||||
#if defined(CONFIG_DISPLAY_DRIVER_SEL_KRONE_8200_PST)
|
||||
|
||||
|
||||
#define LOG_TAG "SEL-K8200-PST"
|
||||
|
||||
// TODO: Do something with Rx pin?
|
||||
|
||||
|
||||
esp_err_t display_init(nvs_handle_t* nvsHandle, uint8_t* display_framebuf_mask, uint16_t* display_num_units) {
|
||||
/*
|
||||
* Set up all needed peripherals
|
||||
*/
|
||||
|
||||
esp_err_t ret;
|
||||
|
||||
ret = display_selection_loadAndParseConfiguration(nvsHandle, display_framebuf_mask, display_num_units, LOG_TAG);
|
||||
if (ret != ESP_OK) return ret;
|
||||
|
||||
uart_config_t uart_config = {
|
||||
.baud_rate = 2400,
|
||||
.data_bits = UART_DATA_8_BITS,
|
||||
.parity = UART_PARITY_DISABLE,
|
||||
.stop_bits = UART_STOP_BITS_2,
|
||||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
||||
.source_clk = UART_SCLK_REF_TICK,
|
||||
};
|
||||
|
||||
if (CONFIG_K8200_PST_SEL_TX_IO >= 0) gpio_reset_pin(CONFIG_K8200_PST_SEL_TX_IO);
|
||||
if (CONFIG_K8200_PST_SEL_RX_IO >= 0) gpio_reset_pin(CONFIG_K8200_PST_SEL_RX_IO);
|
||||
if (CONFIG_K8200_PST_SEL_NMI_IO >= 0) gpio_reset_pin(CONFIG_K8200_PST_SEL_NMI_IO);
|
||||
if (CONFIG_K8200_PST_SEL_TX_IO >= 0) gpio_set_direction(CONFIG_K8200_PST_SEL_TX_IO, GPIO_MODE_OUTPUT);
|
||||
if (CONFIG_K8200_PST_SEL_RX_IO >= 0) gpio_set_direction(CONFIG_K8200_PST_SEL_RX_IO, GPIO_MODE_INPUT);
|
||||
if (CONFIG_K8200_PST_SEL_NMI_IO >= 0) gpio_set_direction(CONFIG_K8200_PST_SEL_NMI_IO, GPIO_MODE_OUTPUT);
|
||||
|
||||
ret = uart_driver_install(K8200_PST_SEL_UART, CONFIG_K8200_PST_SEL_RX_BUF_SIZE, CONFIG_K8200_PST_SEL_TX_BUF_SIZE, 0, NULL, 0);
|
||||
if (ret != ESP_OK) return ret;
|
||||
ret = uart_param_config(K8200_PST_SEL_UART, &uart_config);
|
||||
if (ret != ESP_OK) return ret;
|
||||
ret = uart_set_pin(K8200_PST_SEL_UART, CONFIG_K8200_PST_SEL_TX_IO, CONFIG_K8200_PST_SEL_RX_IO, -1, -1);
|
||||
if (ret != ESP_OK) return ret;
|
||||
ret = uart_set_line_inverse(K8200_PST_SEL_UART, UART_SIGNAL_TXD_INV);
|
||||
if (ret != ESP_OK) return ret;
|
||||
|
||||
k8200_pst_set_nmi(0);
|
||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||
k8200_pst_set_nmi(1);
|
||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||
k8200_pst_set_nmi(0);
|
||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||
k8200_pst_reset();
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void k8200_pst_set_nmi(uint8_t state) {
|
||||
// state: 1 to assert NMI (stop units), 0 to deassert
|
||||
if (CONFIG_K8200_PST_SEL_NMI_IO >= 0) gpio_set_level(CONFIG_K8200_PST_SEL_NMI_IO, CONFIG_K8200_PST_SEL_NMI_ACT_HIGH ? !!state : !state);
|
||||
}
|
||||
|
||||
void k8200_pst_reset(void) {
|
||||
char command = 0x1A;
|
||||
uart_write_bytes(K8200_PST_SEL_UART, &command, 1);
|
||||
}
|
||||
|
||||
void k8200_pst_home(void) {
|
||||
char command = 0x1B;
|
||||
uart_write_bytes(K8200_PST_SEL_UART, &command, 1);
|
||||
}
|
||||
|
||||
void getCommandBytes_SetCode(uint8_t address, uint8_t code, uint8_t* outBuf) {
|
||||
outBuf[0] = 0x3A;
|
||||
outBuf[1] = address;
|
||||
outBuf[2] = uint8_to_bcd(code);
|
||||
}
|
||||
|
||||
void display_render_frame(uint8_t* frame, uint8_t* prevFrame, uint16_t frameBufSize, uint8_t* display_framebuf_mask, uint16_t display_num_units) {
|
||||
// Nothing to do if frame hasn't changed
|
||||
if (prevFrame != NULL && memcmp(frame, prevFrame, frameBufSize) == 0) return;
|
||||
|
||||
esp_err_t ret = uart_wait_tx_done(K8200_PST_SEL_UART, 10 / portTICK_PERIOD_MS);
|
||||
if (ret != ESP_OK) return; // If this is ESP_ERR_TIMEOUT, Tx is still ongoing
|
||||
|
||||
size_t bufSize = display_num_units * 3 + 1; // + 1 for CMD_SET_ALL at the end
|
||||
uint8_t* buf = malloc(bufSize);
|
||||
|
||||
uint16_t bufIdx = 0;
|
||||
for (uint16_t addr = 0; addr < frameBufSize; addr++) {
|
||||
// Skip addresses that aren't present
|
||||
if (!GET_MASK(display_framebuf_mask, addr)) continue;
|
||||
getCommandBytes_SetCode(addr, frame[addr], &buf[bufIdx*3]);
|
||||
bufIdx++;
|
||||
}
|
||||
buf[bufSize-1] = 0x1C; // Start all units
|
||||
|
||||
ESP_LOG_BUFFER_HEX(LOG_TAG, buf, bufSize);
|
||||
for (uint16_t i = 0; i < bufSize; i++) {
|
||||
uart_write_bytes(K8200_PST_SEL_UART, &buf[i], 1);
|
||||
ets_delay_us(7500);
|
||||
}
|
||||
free(buf);
|
||||
|
||||
if (prevFrame != NULL) memcpy(prevFrame, frame, frameBufSize);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,24 @@
|
|||
#pragma once
|
||||
|
||||
#include "esp_system.h"
|
||||
#include "nvs.h"
|
||||
|
||||
#if defined(CONFIG_K8200_PST_SEL_UART_0)
|
||||
#define K8200_PST_SEL_UART 0
|
||||
#elif defined(CONFIG_K8200_PST_SEL_UART_1)
|
||||
#define K8200_PST_SEL_UART 1
|
||||
#elif defined(CONFIG_K8200_PST_SEL_UART_2)
|
||||
#define K8200_PST_SEL_UART 2
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_K8200_PST_SEL_NMI_ACT_HIGH
|
||||
#define CONFIG_K8200_PST_SEL_NMI_ACT_HIGH 0
|
||||
#endif
|
||||
|
||||
|
||||
esp_err_t display_init(nvs_handle_t* nvsHandle, uint8_t* display_framebuf_mask, uint16_t* display_num_units);
|
||||
void k8200_pst_set_nmi(uint8_t state);
|
||||
void k8200_pst_reset(void);
|
||||
void k8200_pst_home(void);
|
||||
void getCommandBytes_SetCode(uint8_t address, uint8_t code, uint8_t* outBuf);
|
||||
void display_render_frame(uint8_t* frame, uint8_t* prevFrame, uint16_t frameBufSize, uint8_t* display_framebuf_mask, uint16_t display_num_units);
|
|
@ -309,6 +309,13 @@
|
|||
input = $("<select>");
|
||||
input.change(updateDisplay);
|
||||
let map = config["maps"][unit["map"]];
|
||||
|
||||
// Add home position
|
||||
let option = $("<option>");
|
||||
option.attr("value", unit["home_pos"]);
|
||||
option.html("<Home>");
|
||||
input.append(option);
|
||||
|
||||
for (const [key, value] of Object.entries(map)) {
|
||||
let option = $("<option>");
|
||||
option.attr("value", key);
|
||||
|
|
|
@ -16,4 +16,6 @@ typedef enum {
|
|||
void buffer_8to1(uint8_t* buf8, uint8_t* buf1, uint16_t width, uint16_t height, buf_merge_t mergeType);
|
||||
void buffer_utf8_to_iso88591(char* dst, char* src);
|
||||
void buffer_iso88591_to_utf8(char* dst, char* src);
|
||||
void buffer_textbuf_to_charbuf(uint8_t* display_text_buffer, uint8_t* display_char_buffer, uint16_t* display_quirk_flags_buffer, uint16_t textBufSize, uint16_t charBufSize);
|
||||
#if defined(CONFIG_DISPLAY_TYPE_CHARACTER)
|
||||
void buffer_textbuf_to_charbuf(uint8_t* display_text_buffer, uint8_t* display_char_buffer, uint16_t* display_quirk_flags_buffer, uint16_t textBufSize, uint16_t charBufSize);
|
||||
#endif
|
|
@ -39,6 +39,7 @@ typedef struct {
|
|||
uint8_t count_set_bits(uint8_t byte);
|
||||
uint8_t int_num_digits(int64_t n, uint8_t includeNegSign);
|
||||
uint8_t uint_num_digits(uint64_t n);
|
||||
uint8_t uint8_to_bcd(uint8_t n);
|
||||
void str_toUpper(char* str);
|
||||
void str_filterAllowed(char* out, char* in, char* allowedChars, bool allowLineBreaks);
|
||||
void str_filterDisallowed(char* out, char* in, char* disallowedChars, bool allowLineBreaks);
|
||||
|
|
|
@ -60,6 +60,7 @@ void buffer_iso88591_to_utf8(char* dst, char* src) {
|
|||
}
|
||||
}
|
||||
|
||||
#if defined(CONFIG_DISPLAY_TYPE_CHARACTER)
|
||||
void buffer_textbuf_to_charbuf(uint8_t* display_text_buffer, uint8_t* display_char_buffer, uint16_t* display_quirk_flags_buffer, uint16_t textBufSize, uint16_t charBufSize) {
|
||||
/*
|
||||
Convert a text buffer to a character buffer and a quirk flag buffer.
|
||||
|
@ -135,4 +136,5 @@ void buffer_textbuf_to_charbuf(uint8_t* display_text_buffer, uint8_t* display_ch
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -35,6 +35,16 @@ uint8_t uint_num_digits(uint64_t n) {
|
|||
return result;
|
||||
}
|
||||
|
||||
uint8_t uint8_to_bcd(uint8_t n) {
|
||||
// Turn a positive integer between in the range [0, 99]
|
||||
// into its hexadecimal BCD representation.
|
||||
// e.g. 37 => 0x37
|
||||
uint8_t tens = n / 10;
|
||||
if (tens > 9) return 0;
|
||||
uint8_t ones = n % 10;
|
||||
return tens * 16 + ones;
|
||||
}
|
||||
|
||||
void str_toUpper(char* str) {
|
||||
while (*str) {
|
||||
*str = toupper((unsigned char) *str);
|
||||
|
|
|
@ -122,6 +122,8 @@ DISPLAY_TEXTBUF_SIZE: Number of characters in the user-facing text buffe
|
|||
#define DISPLAY_DRIVER "char_16seg_led_ws281x"
|
||||
#elif defined(CONFIG_DISPLAY_DRIVER_SEL_KRONE_9000)
|
||||
#define DISPLAY_DRIVER "sel_krone_9000"
|
||||
#elif defined(CONFIG_DISPLAY_DRIVER_SEL_KRONE_8200_PST)
|
||||
#define DISPLAY_DRIVER "sel_krone_8200_pst"
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_DISPLAY_HAS_SHADERS)
|
||||
|
|
|
@ -38,4 +38,6 @@ build_flags =
|
|||
|
||||
[env:16segrgb]
|
||||
|
||||
[env:splitflap_k9000]
|
||||
[env:splitflap_k9000]
|
||||
|
||||
[env:splitflap_k8200_pst]
|
File diff suppressed because it is too large
Load Diff
|
@ -167,6 +167,10 @@ choice DISPLAY_DRIVER
|
|||
config DISPLAY_DRIVER_SEL_KRONE_9000
|
||||
depends on DISPLAY_TYPE_SELECTION
|
||||
bool "KRONE 9000 Split-Flap (using UART peripheral)"
|
||||
|
||||
config DISPLAY_DRIVER_SEL_KRONE_8200_PST
|
||||
depends on DISPLAY_TYPE_SELECTION
|
||||
bool "KRONE 8200 Split-Flap, PST (using UART peripheral)"
|
||||
endchoice
|
||||
|
||||
config DISPLAY_UNIT_BUF_SIZE
|
||||
|
|
|
@ -54,6 +54,8 @@
|
|||
#include "driver_display_char_16seg_led_ws281x.h"
|
||||
#elif defined(CONFIG_DISPLAY_DRIVER_SEL_KRONE_9000)
|
||||
#include "driver_display_sel_krone_9000.h"
|
||||
#elif defined(CONFIG_DISPLAY_DRIVER_SEL_KRONE_8200_PST)
|
||||
#include "driver_display_sel_krone_8200_pst.h"
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_DISPLAY_TYPE_PIXEL)
|
||||
|
|
Loading…
Reference in New Issue