style code with pre-commit
This commit is contained in:
parent
5ee7b51eb4
commit
075cdd423d
20 changed files with 891 additions and 889 deletions
1
.clang-format
Normal file
1
.clang-format
Normal file
|
|
@ -0,0 +1 @@
|
|||
IndentWidth: 4
|
||||
36
.pre-commit-config.yaml
Normal file
36
.pre-commit-config.yaml
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
# SPDX-FileCopyrightText: 2020 Diego Elio Pettenò
|
||||
#
|
||||
# SPDX-License-Identifier: Unlicense
|
||||
|
||||
# CIRCUITPY-CHANGE: CircuitPython-specific.
|
||||
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.0.1
|
||||
hooks:
|
||||
- id: check-yaml
|
||||
- id: end-of-file-fixer
|
||||
- id: trailing-whitespace
|
||||
- repo: https://github.com/codespell-project/codespell
|
||||
rev: v2.2.4
|
||||
hooks:
|
||||
- id: codespell
|
||||
args: [-w]
|
||||
exclude: |
|
||||
(?x)^(
|
||||
hl-vt100
|
||||
)
|
||||
- repo: https://github.com/pre-commit/mirrors-clang-format
|
||||
rev: v14.0.6
|
||||
hooks:
|
||||
- id: clang-format
|
||||
exclude: 5x9.h
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
# Ruff version.
|
||||
rev: v0.6.2
|
||||
hooks:
|
||||
# Run the linter.
|
||||
- id: ruff
|
||||
args: [ --fix ]
|
||||
# Run the formatter.
|
||||
- id: ruff-format
|
||||
|
|
@ -78,4 +78,3 @@ void atkbd_program_init(PIO pio, int sm, int offset, int base_pin) {
|
|||
}
|
||||
|
||||
%}
|
||||
|
||||
|
|
|
|||
390
chargen.c
390
chargen.c
|
|
@ -1,20 +1,24 @@
|
|||
#define _GNU_SOURCE
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "pinout.h"
|
||||
#include "keyboard.h"
|
||||
#include "chargen.h"
|
||||
#include "keyboard.h"
|
||||
#include "pinout.h"
|
||||
|
||||
#include "pico.h"
|
||||
#include "pico/stdlib.h"
|
||||
#include "pico/stdio/driver.h"
|
||||
#include "pico/multicore.h"
|
||||
#include "pico/bootrom.h"
|
||||
#include "RP2040.h"
|
||||
#include "cmsis_compiler.h"
|
||||
#include "hardware/clocks.h"
|
||||
#include "hardware/structs/mpu.h"
|
||||
#include "hardware/watchdog.h"
|
||||
#include "hardware/clocks.h"
|
||||
#include "cmsis_compiler.h"
|
||||
#include "RP2040.h"
|
||||
#include "pico.h"
|
||||
#include "pico/bootrom.h"
|
||||
#include "pico/multicore.h"
|
||||
#include "pico/stdio/driver.h"
|
||||
#include "pico/stdlib.h"
|
||||
|
||||
#include "vga_660x477_60.pio.h"
|
||||
|
||||
|
|
@ -22,10 +26,10 @@
|
|||
|
||||
int pixels_sm;
|
||||
|
||||
#define WRITE_PIXDATA \
|
||||
(pio0->txf[0] = pixels)
|
||||
#define FIFO_WAIT \
|
||||
do { /* NOTHING */ } while(pio_sm_get_tx_fifo_level(pio0, 0) > 2)
|
||||
#define WRITE_PIXDATA (pio0->txf[0] = pixels)
|
||||
#define FIFO_WAIT \
|
||||
do { /* NOTHING */ \
|
||||
} while (pio_sm_get_tx_fifo_level(pio0, 0) > 2)
|
||||
|
||||
#define FB_WIDTH_CHAR (132)
|
||||
#define FB_HEIGHT_CHAR (53)
|
||||
|
|
@ -36,52 +40,79 @@ int pixels_sm;
|
|||
struct lw_terminal_vt100 *vt100;
|
||||
|
||||
// declaring this static breaks it (why?)
|
||||
void scan_convert(const uint32_t * restrict cptr32, const uint16_t * restrict cgptr, const uint16_t * restrict shade);
|
||||
void __not_in_flash_func(scan_convert)(const uint32_t * restrict cptr32, const uint16_t * restrict cgptr, const uint16_t * restrict shade) {
|
||||
#define READ_CHARDATA \
|
||||
(ch = *cptr32++)
|
||||
#define ONE_CHAR(in_shift, op, out_shift) \
|
||||
do { \
|
||||
chardata = cgptr[(ch>>(in_shift)) & 0xff]; \
|
||||
mask = shade[(ch>>(8 + (in_shift)))&7]; \
|
||||
pixels op (shade[(ch >>(11 + (in_shift)))&7] ^ (chardata & mask)) out_shift; \
|
||||
} while(0)
|
||||
void scan_convert(const uint32_t *restrict cptr32,
|
||||
const uint16_t *restrict cgptr,
|
||||
const uint16_t *restrict shade);
|
||||
void __not_in_flash_func(scan_convert)(const uint32_t *restrict cptr32,
|
||||
const uint16_t *restrict cgptr,
|
||||
const uint16_t *restrict shade) {
|
||||
#define READ_CHARDATA (ch = *cptr32++)
|
||||
#define ONE_CHAR(in_shift, op, out_shift) \
|
||||
do { \
|
||||
chardata = cgptr[(ch >> (in_shift)) & 0xff]; \
|
||||
mask = shade[(ch >> (8 + (in_shift))) & 7]; \
|
||||
pixels op(shade[(ch >> (11 + (in_shift))) & 7] ^ (chardata & mask)) \
|
||||
out_shift; \
|
||||
} while (0)
|
||||
|
||||
uint32_t ch;
|
||||
uint16_t chardata, mask;
|
||||
uint32_t pixels;
|
||||
|
||||
#define SIX_CHARS \
|
||||
do { \
|
||||
READ_CHARDATA; \
|
||||
ONE_CHAR(0, =, << 20); \
|
||||
ONE_CHAR(16, |=, << 10); \
|
||||
READ_CHARDATA; \
|
||||
ONE_CHAR(0, |=, ); \
|
||||
WRITE_PIXDATA; \
|
||||
ONE_CHAR(16, =, << 20); \
|
||||
READ_CHARDATA; \
|
||||
ONE_CHAR(0, |=, << 10); \
|
||||
ONE_CHAR(16, |=, ); \
|
||||
WRITE_PIXDATA; \
|
||||
} while(0)
|
||||
#define SIX_CHARS \
|
||||
do { \
|
||||
READ_CHARDATA; \
|
||||
ONE_CHAR(0, =, << 20); \
|
||||
ONE_CHAR(16, |=, << 10); \
|
||||
READ_CHARDATA; \
|
||||
ONE_CHAR(0, |=, ); \
|
||||
WRITE_PIXDATA; \
|
||||
ONE_CHAR(16, =, << 20); \
|
||||
READ_CHARDATA; \
|
||||
ONE_CHAR(0, |=, << 10); \
|
||||
ONE_CHAR(16, |=, ); \
|
||||
WRITE_PIXDATA; \
|
||||
} while (0)
|
||||
|
||||
SIX_CHARS; SIX_CHARS; SIX_CHARS; FIFO_WAIT; /* 18 */ \
|
||||
SIX_CHARS; SIX_CHARS; SIX_CHARS; FIFO_WAIT; /* 36 */ \
|
||||
SIX_CHARS; SIX_CHARS; SIX_CHARS; FIFO_WAIT; /* 54 */ \
|
||||
SIX_CHARS; SIX_CHARS; SIX_CHARS; FIFO_WAIT; /* 72 */ \
|
||||
SIX_CHARS; SIX_CHARS; SIX_CHARS; FIFO_WAIT; /* 90 */ \
|
||||
SIX_CHARS; SIX_CHARS; SIX_CHARS; FIFO_WAIT; /* 108 */ \
|
||||
SIX_CHARS; SIX_CHARS; SIX_CHARS; FIFO_WAIT; /* 126 */ \
|
||||
SIX_CHARS; /* 132 */ \
|
||||
SIX_CHARS;
|
||||
SIX_CHARS;
|
||||
SIX_CHARS;
|
||||
FIFO_WAIT; /* 18 */
|
||||
|
||||
SIX_CHARS;
|
||||
SIX_CHARS;
|
||||
SIX_CHARS;
|
||||
FIFO_WAIT; /* 36 */
|
||||
|
||||
SIX_CHARS;
|
||||
SIX_CHARS;
|
||||
SIX_CHARS;
|
||||
FIFO_WAIT; /* 54 */
|
||||
|
||||
SIX_CHARS;
|
||||
SIX_CHARS;
|
||||
SIX_CHARS;
|
||||
FIFO_WAIT; /* 72 */
|
||||
|
||||
SIX_CHARS;
|
||||
SIX_CHARS;
|
||||
SIX_CHARS;
|
||||
FIFO_WAIT; /* 90 */
|
||||
|
||||
SIX_CHARS;
|
||||
SIX_CHARS;
|
||||
SIX_CHARS;
|
||||
FIFO_WAIT; /* 108 */
|
||||
|
||||
SIX_CHARS;
|
||||
SIX_CHARS;
|
||||
SIX_CHARS;
|
||||
FIFO_WAIT; /* 126 */
|
||||
|
||||
SIX_CHARS; /* 132 */
|
||||
}
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
uint16_t chargen[256*CHAR_Y] = {
|
||||
uint16_t chargen[256 * CHAR_Y] = {
|
||||
#include "5x9.h"
|
||||
};
|
||||
|
||||
|
|
@ -89,16 +120,15 @@ _Static_assert(FB_WIDTH_CHAR % 6 == 0);
|
|||
|
||||
lw_cell_t statusline[FB_WIDTH_CHAR];
|
||||
|
||||
static
|
||||
int status_printf(const char *fmt, ...) {
|
||||
char buf[2*FB_WIDTH_CHAR + 1];
|
||||
static int status_printf(const char *fmt, ...) {
|
||||
char buf[2 * FB_WIDTH_CHAR + 1];
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
int n = vsnprintf(buf, sizeof(buf), fmt, ap);
|
||||
va_end(ap);
|
||||
int attr = 0x300;
|
||||
int i, j;
|
||||
for(i=j=0; j < FB_WIDTH_CHAR && buf[i]; i++) {
|
||||
for (i = j = 0; j < FB_WIDTH_CHAR && buf[i]; i++) {
|
||||
int c = (unsigned char)buf[i];
|
||||
if (c < 32) {
|
||||
attr = c << 8;
|
||||
|
|
@ -106,7 +136,7 @@ int status_printf(const char *fmt, ...) {
|
|||
statusline[j++] = c | attr;
|
||||
}
|
||||
}
|
||||
while(j < FB_WIDTH_CHAR) {
|
||||
while (j < FB_WIDTH_CHAR) {
|
||||
statusline[j++] = 32 | attr;
|
||||
}
|
||||
return n;
|
||||
|
|
@ -122,8 +152,8 @@ int scrnprintf(const char *fmt, ...) {
|
|||
return n;
|
||||
}
|
||||
|
||||
static
|
||||
uint16_t base_shade[] = {0, 0x554, 0xaa8, 0xffc, 0, 0x554, 0xaa8, 0xffc, 0, 0, 0, 0};
|
||||
static uint16_t base_shade[] = {0, 0x554, 0xaa8, 0xffc, 0, 0x554,
|
||||
0xaa8, 0xffc, 0, 0, 0, 0};
|
||||
|
||||
#if !STANDALONE
|
||||
static void setup_vga_hsync(PIO pio) {
|
||||
|
|
@ -152,18 +182,18 @@ static void setup_vga(void) {
|
|||
setup_vga_hsync(pio0);
|
||||
}
|
||||
|
||||
|
||||
__attribute__((noreturn,noinline))
|
||||
static void __not_in_flash_func(core1_loop)(void) {
|
||||
__attribute__((noreturn, noinline)) static void
|
||||
__not_in_flash_func(core1_loop)(void) {
|
||||
int frameno = 0;
|
||||
while(true) {
|
||||
for(int row = 0; row < FB_HEIGHT_CHAR; row++) {
|
||||
uint32_t *chardata = row == FB_HEIGHT_CHAR - 1
|
||||
? (uint32_t*) statusline
|
||||
: (uint32_t*)lw_terminal_vt100_getline(vt100, row);
|
||||
for(int j=0; j<CHAR_Y; j++) {
|
||||
scan_convert(chardata,
|
||||
&chargen[256 * j], frameno & 0x20 ? base_shade : base_shade + 4);
|
||||
while (true) {
|
||||
for (int row = 0; row < FB_HEIGHT_CHAR; row++) {
|
||||
uint32_t *chardata =
|
||||
row == FB_HEIGHT_CHAR - 1
|
||||
? (uint32_t *)statusline
|
||||
: (uint32_t *)lw_terminal_vt100_getline(vt100, row);
|
||||
for (int j = 0; j < CHAR_Y; j++) {
|
||||
scan_convert(chardata, &chargen[256 * j],
|
||||
frameno & 0x20 ? base_shade : base_shade + 4);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -171,19 +201,20 @@ static void __not_in_flash_func(core1_loop)(void) {
|
|||
}
|
||||
}
|
||||
|
||||
static
|
||||
__attribute__((noreturn,noinline))
|
||||
void __not_in_flash_func(core1_entry)(void) {
|
||||
static __attribute__((noreturn, noinline)) void
|
||||
__not_in_flash_func(core1_entry)(void) {
|
||||
setup_vga();
|
||||
|
||||
// Turn off flash access. After this, it will hard fault. Better than messing
|
||||
// up CIRCUITPY.
|
||||
// Turn off flash access. After this, it will hard fault. Better than
|
||||
// messing up CIRCUITPY.
|
||||
MPU->CTRL = MPU_CTRL_PRIVDEFENA_Msk | MPU_CTRL_ENABLE_Msk;
|
||||
MPU->RNR = 6; // 7 is used by pico-sdk stack protection.
|
||||
MPU->RBAR = XIP_MAIN_BASE | MPU_RBAR_VALID_Msk;
|
||||
MPU->RASR = MPU_RASR_XN_Msk | // Set execute never and everything else is restricted.
|
||||
MPU_RASR_ENABLE_Msk |
|
||||
(0x1b << MPU_RASR_SIZE_Pos); // Size is 0x10000000 which masks up to SRAM region.
|
||||
MPU->RASR = MPU_RASR_XN_Msk | // Set execute never and everything else is
|
||||
// restricted.
|
||||
MPU_RASR_ENABLE_Msk |
|
||||
(0x1b << MPU_RASR_SIZE_Pos); // Size is 0x10000000 which masks
|
||||
// up to SRAM region.
|
||||
MPU->RNR = 7;
|
||||
|
||||
core1_loop();
|
||||
|
|
@ -193,19 +224,21 @@ void __not_in_flash_func(core1_entry)(void) {
|
|||
#define BG_ATTR(x) ((x) << 11)
|
||||
#define FG_ATTR(x) ((x) << 8)
|
||||
|
||||
#define MAKE_ATTR(fg, bg) (((fg) ^ (((bg) * 9) & 073)) << 8)
|
||||
#define MAKE_ATTR(fg, bg) (((fg) ^ (((bg)*9) & 073)) << 8)
|
||||
|
||||
static int map_one(int i) {
|
||||
return (i > 0) + (i > 6);
|
||||
}
|
||||
static int map_one(int i) { return (i > 0) + (i > 6); }
|
||||
|
||||
static lw_cell_t char_attr(void *user_data, const struct lw_parsed_attr *attr) {
|
||||
int fg = map_one(attr->fg);
|
||||
int bg = map_one(attr->bg);
|
||||
if (fg == bg && attr->fg != attr->bg) { fg = bg + 1; }
|
||||
if(attr->bold) fg = 3;
|
||||
if(attr->blink) fg ^= 4;
|
||||
if(attr->inverse) {
|
||||
if (fg == bg && attr->fg != attr->bg) {
|
||||
fg = bg + 1;
|
||||
}
|
||||
if (attr->bold)
|
||||
fg = 3;
|
||||
if (attr->blink)
|
||||
fg ^= 4;
|
||||
if (attr->inverse) {
|
||||
return MAKE_ATTR(bg, fg);
|
||||
}
|
||||
return MAKE_ATTR(fg, bg);
|
||||
|
|
@ -213,8 +246,7 @@ static lw_cell_t char_attr(void *user_data, const struct lw_parsed_attr *attr) {
|
|||
|
||||
queue_t keyboard_queue;
|
||||
|
||||
static
|
||||
void reset_cpu(void) {
|
||||
static void reset_cpu(void) {
|
||||
watchdog_reboot(0, SRAM_END, 0);
|
||||
watchdog_start_tick(12);
|
||||
|
||||
|
|
@ -227,7 +259,7 @@ int current_port;
|
|||
|
||||
#define COUNT_OF(x) ((sizeof(x) / sizeof((x)[0])))
|
||||
|
||||
uint baudrates[] = { 300, 1200, 2400, 9600, 19200, 38400, 115200 };
|
||||
uint baudrates[] = {300, 1200, 2400, 9600, 19200, 38400, 115200};
|
||||
#define N_BAUDRATES (COUNT_OF(baudrates))
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -237,14 +269,10 @@ typedef struct {
|
|||
} uart_config_t;
|
||||
|
||||
const uart_config_t uart_configs[] = {
|
||||
{ 8, 1, UART_PARITY_NONE, "8N1" },
|
||||
{ 8, 2, UART_PARITY_NONE, "8N2" },
|
||||
{ 8, 1, UART_PARITY_EVEN, "8E1" },
|
||||
{ 8, 1, UART_PARITY_ODD, "8O1" },
|
||||
{ 7, 1, UART_PARITY_NONE, "7N1" },
|
||||
{ 7, 2, UART_PARITY_NONE, "7N2" },
|
||||
{ 7, 1, UART_PARITY_EVEN, "7E1" },
|
||||
{ 7, 1, UART_PARITY_ODD, "7O1" },
|
||||
{8, 1, UART_PARITY_NONE, "8N1"}, {8, 2, UART_PARITY_NONE, "8N2"},
|
||||
{8, 1, UART_PARITY_EVEN, "8E1"}, {8, 1, UART_PARITY_ODD, "8O1"},
|
||||
{7, 1, UART_PARITY_NONE, "7N1"}, {7, 2, UART_PARITY_NONE, "7N2"},
|
||||
{7, 1, UART_PARITY_EVEN, "7E1"}, {7, 1, UART_PARITY_ODD, "7O1"},
|
||||
};
|
||||
#define N_CONFIGS (COUNT_OF(uart_configs))
|
||||
|
||||
|
|
@ -253,8 +281,8 @@ typedef struct uart_data {
|
|||
} uart_data_t;
|
||||
|
||||
uart_data_t uart_data[] = {
|
||||
{ 0, 0, 1 },
|
||||
{ 0, 12, 13 },
|
||||
{0, 0, 1},
|
||||
{0, 12, 13},
|
||||
};
|
||||
#define N_UARTS (COUNT_OF(uart_data))
|
||||
|
||||
|
|
@ -269,7 +297,6 @@ static void uart_activate(void *data_in) {
|
|||
gpio_set_function(data->rx, UART_FUNCSEL_NUM(inst, data->rx));
|
||||
gpio_set_function(data->tx, UART_FUNCSEL_NUM(inst, data->tx));
|
||||
gpio_pull_up(data->rx);
|
||||
|
||||
}
|
||||
|
||||
static void uart_deactivate(void *data_in) {
|
||||
|
|
@ -282,14 +309,18 @@ static void uart_deactivate(void *data_in) {
|
|||
static int uart_getc_nonblocking(void *data_in) {
|
||||
uart_data_t *data = (uart_data_t *)data_in;
|
||||
uart_inst_t *inst = uart_get_instance(data->uart);
|
||||
if (!uart_is_readable(inst)) { return EOF; }
|
||||
if (!uart_is_readable(inst)) {
|
||||
return EOF;
|
||||
}
|
||||
return uart_getc(inst);
|
||||
}
|
||||
|
||||
static void uart_putc_nonblocking(void *data_in, int c) {
|
||||
uart_data_t *data = (uart_data_t *)data_in;
|
||||
uart_inst_t *inst = uart_get_instance(data->uart);
|
||||
if (uart_is_writable(inst)) { uart_putc_raw(inst, c); }
|
||||
if (uart_is_writable(inst)) {
|
||||
uart_putc_raw(inst, c);
|
||||
}
|
||||
}
|
||||
|
||||
static void uart_cycle_baud_rate(void *data_in) {
|
||||
|
|
@ -310,21 +341,18 @@ static void uart_cycle_settings(void *data_in) {
|
|||
static void uart_describe(void *data_in, char *buf, size_t buflen) {
|
||||
uart_data_t *data = (uart_data_t *)data_in;
|
||||
const uart_config_t *config = &uart_configs[data->cfg_idx];
|
||||
snprintf(buf, buflen, "UART%d %5d %s", current_port, baudrates[data->baud_idx], config->label);
|
||||
snprintf(buf, buflen, "UART%d %5d %s", current_port,
|
||||
baudrates[data->baud_idx], config->label);
|
||||
}
|
||||
|
||||
static void usb_activate(void *data) {
|
||||
vt100->unicode = 1;
|
||||
}
|
||||
static void usb_activate(void *data) { vt100->unicode = 1; }
|
||||
|
||||
static void usb_deactivate(void *data) {}
|
||||
static int usb_getc_nonblocking(void *data) {
|
||||
int c = getchar_timeout_us(1);
|
||||
return (c < 0) ? EOF : c;
|
||||
}
|
||||
static void usb_putc_nonblocking(void *data, int c) {
|
||||
stdio_putchar_raw(c);
|
||||
}
|
||||
static void usb_putc_nonblocking(void *data, int c) { stdio_putchar_raw(c); }
|
||||
|
||||
static void usb_cycle_baud_rate(void *data) {}
|
||||
static void usb_cycle_settings(void *data) {}
|
||||
|
|
@ -376,7 +404,6 @@ static const port_descr_t ports[] = {
|
|||
};
|
||||
#define NUM_PORTS (COUNT_OF(ports))
|
||||
|
||||
|
||||
#define CURRENT_PORT (ports[current_port])
|
||||
|
||||
static bool status_refresh = true;
|
||||
|
|
@ -386,9 +413,7 @@ static void port_deactivate(void) {
|
|||
CURRENT_PORT.deactivate(CURRENT_PORT.data);
|
||||
}
|
||||
|
||||
static void port_activate(void) {
|
||||
CURRENT_PORT.activate(CURRENT_PORT.data);
|
||||
}
|
||||
static void port_activate(void) { CURRENT_PORT.activate(CURRENT_PORT.data); }
|
||||
|
||||
static int port_getc(void) {
|
||||
return CURRENT_PORT.getc_nonblocking(CURRENT_PORT.data);
|
||||
|
|
@ -421,25 +446,24 @@ static void switch_port(void) {
|
|||
port_activate();
|
||||
}
|
||||
|
||||
static
|
||||
int stdio_kbd_in_chars(char *buf, int length) {
|
||||
static int stdio_kbd_in_chars(char *buf, int length) {
|
||||
int rc = 0;
|
||||
int code;
|
||||
keyboard_poll(&keyboard_queue);
|
||||
while (length && queue_try_remove(&keyboard_queue, &code)) {
|
||||
if ((code & 0xc000) == 0xc000) {
|
||||
switch(code) {
|
||||
case CMD_SWITCH_RATE:
|
||||
port_cycle_baud_rate();
|
||||
break;
|
||||
case CMD_SWITCH_SETTINGS:
|
||||
port_cycle_settings();
|
||||
break;
|
||||
case CMD_SWITCH_PORT:
|
||||
switch_port();
|
||||
break;
|
||||
case CMD_REBOOT:
|
||||
reset_cpu();
|
||||
switch (code) {
|
||||
case CMD_SWITCH_RATE:
|
||||
port_cycle_baud_rate();
|
||||
break;
|
||||
case CMD_SWITCH_SETTINGS:
|
||||
port_cycle_settings();
|
||||
break;
|
||||
case CMD_SWITCH_PORT:
|
||||
switch_port();
|
||||
break;
|
||||
case CMD_REBOOT:
|
||||
reset_cpu();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
|
@ -453,7 +477,9 @@ int stdio_kbd_in_chars(char *buf, int length) {
|
|||
static int kbd_getc_nonblocking(void) {
|
||||
char c;
|
||||
int result = stdio_kbd_in_chars(&c, 1);
|
||||
if (result == PICO_ERROR_NO_DATA) { return EOF; }
|
||||
if (result == PICO_ERROR_NO_DATA) {
|
||||
return EOF;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
|
|
@ -463,42 +489,72 @@ static stdio_driver_t stdio_kbd = {
|
|||
};
|
||||
#endif
|
||||
|
||||
static
|
||||
void master_write(void *user_data, void *buffer_in, size_t len) {
|
||||
static void master_write(void *user_data, void *buffer_in, size_t len) {
|
||||
const char *buffer = buffer_in;
|
||||
for(;len--;buffer++) { port_putc(*buffer); }
|
||||
for (; len--; buffer++) {
|
||||
port_putc(*buffer);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
int map_unicode(void *unused, int n) { switch(n) {
|
||||
case 9670: return 1;
|
||||
case 9618: return 2;
|
||||
case 9225: return 3;
|
||||
case 9228: return 4;
|
||||
case 9229: return 5;
|
||||
case 9226: return 6;
|
||||
case 9252: return 9;
|
||||
case 9227: return 10;
|
||||
case 9496: return 11;
|
||||
case 9488: return 12;
|
||||
case 9484: return 13;
|
||||
case 9492: return 14;
|
||||
case 9532: return 15;
|
||||
case 9146: return 16;
|
||||
case 9147: return 17;
|
||||
case 9472: return 18;
|
||||
case 9148: return 19;
|
||||
case 9149: return 20;
|
||||
case 9500: return 21;
|
||||
case 9508: return 22;
|
||||
case 9524: return 23;
|
||||
case 9516: return 24;
|
||||
case 9474: return 25;
|
||||
case 8804: return 26;
|
||||
case 8805: return 27;
|
||||
case 960: return 28;
|
||||
case 8800: return 29;
|
||||
}return '?';}
|
||||
static int map_unicode(void *unused, int n) {
|
||||
switch (n) {
|
||||
case 9670:
|
||||
return 1;
|
||||
case 9618:
|
||||
return 2;
|
||||
case 9225:
|
||||
return 3;
|
||||
case 9228:
|
||||
return 4;
|
||||
case 9229:
|
||||
return 5;
|
||||
case 9226:
|
||||
return 6;
|
||||
case 9252:
|
||||
return 9;
|
||||
case 9227:
|
||||
return 10;
|
||||
case 9496:
|
||||
return 11;
|
||||
case 9488:
|
||||
return 12;
|
||||
case 9484:
|
||||
return 13;
|
||||
case 9492:
|
||||
return 14;
|
||||
case 9532:
|
||||
return 15;
|
||||
case 9146:
|
||||
return 16;
|
||||
case 9147:
|
||||
return 17;
|
||||
case 9472:
|
||||
return 18;
|
||||
case 9148:
|
||||
return 19;
|
||||
case 9149:
|
||||
return 20;
|
||||
case 9500:
|
||||
return 21;
|
||||
case 9508:
|
||||
return 22;
|
||||
case 9524:
|
||||
return 23;
|
||||
case 9516:
|
||||
return 24;
|
||||
case 9474:
|
||||
return 25;
|
||||
case 8804:
|
||||
return 26;
|
||||
case 8805:
|
||||
return 27;
|
||||
case 960:
|
||||
return 28;
|
||||
case 8800:
|
||||
return 29;
|
||||
}
|
||||
return '?';
|
||||
}
|
||||
|
||||
static int old_keyboard_leds;
|
||||
int main(void) {
|
||||
|
|
@ -506,12 +562,13 @@ int main(void) {
|
|||
set_sys_clock_khz(vga_660x477_60_sys_clock_khz, false);
|
||||
stdio_init_all();
|
||||
#endif
|
||||
for(int i=0; i<N_UARTS; i++) {
|
||||
for (int i = 0; i < N_UARTS; i++) {
|
||||
gpio_init(uart_data[i].tx);
|
||||
gpio_pull_up(uart_data[i].tx);
|
||||
}
|
||||
|
||||
vt100 = lw_terminal_vt100_init(NULL, NULL, master_write, char_attr, FB_WIDTH_CHAR, FB_HEIGHT_CHAR - 1);
|
||||
vt100 = lw_terminal_vt100_init(NULL, NULL, master_write, char_attr,
|
||||
FB_WIDTH_CHAR, FB_HEIGHT_CHAR - 1);
|
||||
vt100->map_unicode = map_unicode;
|
||||
multicore_launch_core1(core1_entry);
|
||||
|
||||
|
|
@ -540,10 +597,9 @@ int main(void) {
|
|||
}
|
||||
|
||||
if (status_refresh) {
|
||||
status_printf("\3%s\3 \2 %s %s",
|
||||
port_describe(),
|
||||
keyboard_leds & LED_CAPS ? "\22 CAPS \2" : " ",
|
||||
keyboard_leds & LED_NUM ? "\22 NUM \2" : " ");
|
||||
status_printf("\3%s\3 \2 %s %s", port_describe(),
|
||||
keyboard_leds & LED_CAPS ? "\22 CAPS \2" : " ",
|
||||
keyboard_leds & LED_NUM ? "\22 NUM \2" : " ");
|
||||
status_refresh = false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,25 +1,21 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "../src/lw_terminal_parser.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static void vt100_write(struct lw_terminal *term_emul __attribute__((unused)),
|
||||
char c)
|
||||
{
|
||||
char c) {
|
||||
printf("Got a char : %c\n", c);
|
||||
}
|
||||
|
||||
static void csi_f(struct lw_terminal *term_emul)
|
||||
{
|
||||
static void csi_f(struct lw_terminal *term_emul) {
|
||||
printf("\\033[...f with %d parameters\n", term_emul->argc);
|
||||
}
|
||||
|
||||
static void csi_K(struct lw_terminal *term_emul)
|
||||
{
|
||||
static void csi_K(struct lw_terminal *term_emul) {
|
||||
printf("\\033[...K with %d parameters\n", term_emul->argc);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int main(void) {
|
||||
struct lw_terminal *lw_terminal;
|
||||
|
||||
lw_terminal = lw_terminal_parser_init();
|
||||
|
|
|
|||
|
|
@ -1,15 +1,12 @@
|
|||
#include "hl_vt100.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "hl_vt100.h"
|
||||
|
||||
|
||||
void changed(struct vt100_headless *vt100)
|
||||
{
|
||||
void changed(struct vt100_headless *vt100) {
|
||||
const char **lines;
|
||||
|
||||
lines = vt100_headless_getlines(vt100);
|
||||
for (unsigned int y = 0; y < vt100->term->height; ++y)
|
||||
{
|
||||
for (unsigned int y = 0; y < vt100->term->height; ++y) {
|
||||
write(1, "|", 1);
|
||||
write(1, lines[y], vt100->term->width);
|
||||
write(1, "|\n", 2);
|
||||
|
|
@ -17,8 +14,7 @@ void changed(struct vt100_headless *vt100)
|
|||
write(1, "\n", 1);
|
||||
}
|
||||
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
int main(int ac, char **av) {
|
||||
struct vt100_headless *vt100;
|
||||
char *argv[] = {"top", NULL};
|
||||
|
||||
|
|
|
|||
|
|
@ -11,9 +11,9 @@ def dump(vt100):
|
|||
def main():
|
||||
vt100 = hl_vt100.vt100_headless()
|
||||
vt100.changed_callback = lambda: dump(vt100)
|
||||
vt100.fork('top', ['top'])
|
||||
vt100.fork("top", ["top"])
|
||||
vt100.main_loop()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
|
|||
|
|
@ -9,31 +9,37 @@ from pathlib import Path
|
|||
from setuptools import setup, Extension
|
||||
|
||||
|
||||
hl_vt100_module = Extension('hl_vt100',
|
||||
include_dirs=['src'],
|
||||
define_macros=[('NDEBUG', '1')],
|
||||
sources=['src/vt100_module.c',
|
||||
'src/hl_vt100.c',
|
||||
'src/lw_terminal_parser.c',
|
||||
'src/lw_terminal_vt100.c'])
|
||||
hl_vt100_module = Extension(
|
||||
"hl_vt100",
|
||||
include_dirs=["src"],
|
||||
define_macros=[("NDEBUG", "1")],
|
||||
sources=[
|
||||
"src/vt100_module.c",
|
||||
"src/hl_vt100.c",
|
||||
"src/lw_terminal_parser.c",
|
||||
"src/lw_terminal_vt100.c",
|
||||
],
|
||||
)
|
||||
|
||||
setup(name='hl_vt100',
|
||||
version='0.2',
|
||||
url='https://github.com/JulienPalard/vt100-emulator',
|
||||
author="Julien Palard",
|
||||
author_email='julien@palard.fr',
|
||||
description="""Headless vt100 emulator""",
|
||||
long_description=(Path(__file__).parent / "README.md").read_text(encoding="UTF-8"),
|
||||
long_description_content_type="text/markdown",
|
||||
ext_modules=[hl_vt100_module],
|
||||
include_package_data=True,
|
||||
py_modules=["hl_vt100"],
|
||||
classifiers=[
|
||||
"Programming Language :: C",
|
||||
"Programming Language :: Python",
|
||||
"Development Status :: 5 - Production/Stable",
|
||||
"License :: OSI Approved :: BSD License",
|
||||
"Operating System :: OS Independent",
|
||||
"Topic :: System :: Emulators",
|
||||
"Topic :: Terminals :: Terminal Emulators/X Terminals"
|
||||
])
|
||||
setup(
|
||||
name="hl_vt100",
|
||||
version="0.2",
|
||||
url="https://github.com/JulienPalard/vt100-emulator",
|
||||
author="Julien Palard",
|
||||
author_email="julien@palard.fr",
|
||||
description="""Headless vt100 emulator""",
|
||||
long_description=(Path(__file__).parent / "README.md").read_text(encoding="UTF-8"),
|
||||
long_description_content_type="text/markdown",
|
||||
ext_modules=[hl_vt100_module],
|
||||
include_package_data=True,
|
||||
py_modules=["hl_vt100"],
|
||||
classifiers=[
|
||||
"Programming Language :: C",
|
||||
"Programming Language :: Python",
|
||||
"Development Status :: 5 - Production/Stable",
|
||||
"License :: OSI Approved :: BSD License",
|
||||
"Operating System :: OS Independent",
|
||||
"Topic :: System :: Emulators",
|
||||
"Topic :: Terminals :: Terminal Emulators/X Terminals",
|
||||
],
|
||||
)
|
||||
|
|
|
|||
|
|
@ -24,26 +24,20 @@
|
|||
*/
|
||||
|
||||
#define _XOPEN_SOURCE
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <pty.h>
|
||||
#include <stdlib.h>
|
||||
#include "hl_vt100.h"
|
||||
#include <errno.h>
|
||||
#include <pty.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct vt100_headless *new_vt100_headless(void)
|
||||
{
|
||||
struct vt100_headless *new_vt100_headless(void) {
|
||||
return calloc(1, sizeof(struct vt100_headless));
|
||||
}
|
||||
|
||||
void delete_vt100_headless(struct vt100_headless *this)
|
||||
{
|
||||
free(this);
|
||||
}
|
||||
void delete_vt100_headless(struct vt100_headless *this) { free(this); }
|
||||
|
||||
static void set_non_canonical(struct vt100_headless *this, int fd)
|
||||
{
|
||||
static void set_non_canonical(struct vt100_headless *this, int fd) {
|
||||
struct termios termios;
|
||||
|
||||
ioctl(fd, TCGETS, &this->backup);
|
||||
|
|
@ -54,16 +48,13 @@ static void set_non_canonical(struct vt100_headless *this, int fd)
|
|||
ioctl(fd, TCSETS, &termios);
|
||||
}
|
||||
|
||||
static void restore_termios(struct vt100_headless *this, int fd)
|
||||
{
|
||||
static void restore_termios(struct vt100_headless *this, int fd) {
|
||||
ioctl(fd, TCSETS, &this->backup);
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
static void strdump(char *str)
|
||||
{
|
||||
while (*str != '\0')
|
||||
{
|
||||
static void strdump(char *str) {
|
||||
while (*str != '\0') {
|
||||
if (*str >= ' ' && *str <= '~')
|
||||
fprintf(stderr, "%c", *str);
|
||||
else
|
||||
|
|
@ -74,44 +65,34 @@ static void strdump(char *str)
|
|||
}
|
||||
#endif
|
||||
|
||||
void vt100_headless_stop(struct vt100_headless *this)
|
||||
{
|
||||
this->should_quit = 1;
|
||||
}
|
||||
void vt100_headless_stop(struct vt100_headless *this) { this->should_quit = 1; }
|
||||
|
||||
int vt100_headless_main_loop(struct vt100_headless *this)
|
||||
{
|
||||
int vt100_headless_main_loop(struct vt100_headless *this) {
|
||||
char buffer[4096];
|
||||
fd_set rfds;
|
||||
int retval;
|
||||
ssize_t read_size;
|
||||
|
||||
while (!this->should_quit)
|
||||
{
|
||||
while (!this->should_quit) {
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(this->master, &rfds);
|
||||
FD_SET(0, &rfds);
|
||||
retval = select(this->master + 1, &rfds, NULL, NULL, NULL);
|
||||
if (retval == -1)
|
||||
{
|
||||
if (retval == -1) {
|
||||
perror("select()");
|
||||
}
|
||||
if (FD_ISSET(0, &rfds))
|
||||
{
|
||||
if (FD_ISSET(0, &rfds)) {
|
||||
read_size = read(0, &buffer, 4096);
|
||||
if (read_size == -1)
|
||||
{
|
||||
if (read_size == -1) {
|
||||
perror("read");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
buffer[read_size] = '\0';
|
||||
write(this->master, buffer, read_size);
|
||||
}
|
||||
if (FD_ISSET(this->master, &rfds))
|
||||
{
|
||||
if (FD_ISSET(this->master, &rfds)) {
|
||||
read_size = read(this->master, &buffer, 4096);
|
||||
if (read_size == -1)
|
||||
{
|
||||
if (read_size == -1) {
|
||||
if (errno == EIO) {
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -130,23 +111,19 @@ int vt100_headless_main_loop(struct vt100_headless *this)
|
|||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
void master_write(void *user_data, void *buffer, size_t len)
|
||||
{
|
||||
void master_write(void *user_data, void *buffer, size_t len) {
|
||||
struct vt100_headless *this;
|
||||
|
||||
this = (struct vt100_headless*)user_data;
|
||||
this = (struct vt100_headless *)user_data;
|
||||
write(this->master, buffer, len);
|
||||
}
|
||||
|
||||
const lw_cell_t **vt100_headless_getlines(struct vt100_headless *this)
|
||||
{
|
||||
const lw_cell_t **vt100_headless_getlines(struct vt100_headless *this) {
|
||||
return lw_terminal_vt100_getlines(this->term);
|
||||
}
|
||||
|
||||
void vt100_headless_fork(struct vt100_headless *this,
|
||||
const char *progname,
|
||||
char **argv)
|
||||
{
|
||||
void vt100_headless_fork(struct vt100_headless *this, const char *progname,
|
||||
char **argv) {
|
||||
int child;
|
||||
struct winsize winsize;
|
||||
|
||||
|
|
@ -154,16 +131,15 @@ void vt100_headless_fork(struct vt100_headless *this,
|
|||
winsize.ws_row = 24;
|
||||
winsize.ws_col = 80;
|
||||
child = forkpty(&this->master, NULL, NULL, NULL);
|
||||
if (child == CHILD)
|
||||
{
|
||||
if (child == CHILD) {
|
||||
setsid();
|
||||
putenv("TERM=vt100");
|
||||
execvp(progname, argv);
|
||||
return ;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->term = lw_terminal_vt100_init(this, lw_terminal_parser_default_unimplemented, master_write, NULL, winsize.ws_col, winsize.ws_row);
|
||||
return;
|
||||
} else {
|
||||
this->term = lw_terminal_vt100_init(
|
||||
this, lw_terminal_parser_default_unimplemented, master_write, NULL,
|
||||
winsize.ws_col, winsize.ws_row);
|
||||
ioctl(this->master, TIOCSWINSZ, &winsize);
|
||||
}
|
||||
restore_termios(this, 0);
|
||||
|
|
|
|||
|
|
@ -28,14 +28,13 @@
|
|||
|
||||
#define CHILD 0
|
||||
|
||||
#include <utmp.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
#include "lw_terminal_vt100.h"
|
||||
#include <sys/ioctl.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
#include <utmp.h>
|
||||
|
||||
struct vt100_headless
|
||||
{
|
||||
struct vt100_headless {
|
||||
int master;
|
||||
struct termios backup;
|
||||
struct lw_terminal_vt100 *term;
|
||||
|
|
@ -43,8 +42,8 @@ struct vt100_headless
|
|||
void (*changed)(struct vt100_headless *this);
|
||||
};
|
||||
|
||||
|
||||
void vt100_headless_fork(struct vt100_headless *this, const char *progname, char **argv);
|
||||
void vt100_headless_fork(struct vt100_headless *this, const char *progname,
|
||||
char **argv);
|
||||
int vt100_headless_main_loop(struct vt100_headless *this);
|
||||
void delete_vt100_headless(struct vt100_headless *this);
|
||||
struct vt100_headless *new_vt100_headless(void);
|
||||
|
|
|
|||
|
|
@ -25,36 +25,30 @@
|
|||
|
||||
#include <stdlib.h>
|
||||
#ifndef NDEBUG
|
||||
# include <stdio.h>
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#include "lw_terminal_parser.h"
|
||||
|
||||
static void lw_terminal_parser_push(struct lw_terminal *this, char c)
|
||||
{
|
||||
static void lw_terminal_parser_push(struct lw_terminal *this, char c) {
|
||||
if (this->stack_ptr >= TERM_STACK_SIZE)
|
||||
return ;
|
||||
return;
|
||||
this->stack[this->stack_ptr++] = c;
|
||||
}
|
||||
|
||||
static void lw_terminal_parser_parse_params(struct lw_terminal *this)
|
||||
{
|
||||
static void lw_terminal_parser_parse_params(struct lw_terminal *this) {
|
||||
unsigned int i;
|
||||
int got_something;
|
||||
|
||||
got_something = 0;
|
||||
this->argc = 0;
|
||||
this->argv[0] = 0;
|
||||
for (i = 0; i < this->stack_ptr; ++i)
|
||||
{
|
||||
if (this->stack[i] >= '0' && this->stack[i] <= '9')
|
||||
{
|
||||
for (i = 0; i < this->stack_ptr; ++i) {
|
||||
if (this->stack[i] >= '0' && this->stack[i] <= '9') {
|
||||
got_something = 1;
|
||||
this->argv[this->argc] = this->argv[this->argc] * 10
|
||||
+ this->stack[i] - '0';
|
||||
}
|
||||
else if (this->stack[i] == ';')
|
||||
{
|
||||
this->argv[this->argc] =
|
||||
this->argv[this->argc] * 10 + this->stack[i] - '0';
|
||||
} else if (this->stack[i] == ';') {
|
||||
got_something = 0;
|
||||
this->argc += 1;
|
||||
this->argv[this->argc] = 0;
|
||||
|
|
@ -63,11 +57,9 @@ static void lw_terminal_parser_parse_params(struct lw_terminal *this)
|
|||
this->argc += got_something;
|
||||
}
|
||||
|
||||
static void lw_terminal_parser_call_CSI(struct lw_terminal *this, char c)
|
||||
{
|
||||
static void lw_terminal_parser_call_CSI(struct lw_terminal *this, char c) {
|
||||
lw_terminal_parser_parse_params(this);
|
||||
if (((term_action *)&this->callbacks.csi)[c - '0'] == NULL)
|
||||
{
|
||||
if (((term_action *)&this->callbacks.csi)[c - '0'] == NULL) {
|
||||
if (this->unimplemented != NULL)
|
||||
this->unimplemented(this, "CSI", c);
|
||||
goto leave;
|
||||
|
|
@ -80,10 +72,8 @@ leave:
|
|||
this->argc = 0;
|
||||
}
|
||||
|
||||
static void lw_terminal_parser_call_ESC(struct lw_terminal *this, char c)
|
||||
{
|
||||
if (((term_action *)&this->callbacks.esc)[c - '0'] == NULL)
|
||||
{
|
||||
static void lw_terminal_parser_call_ESC(struct lw_terminal *this, char c) {
|
||||
if (((term_action *)&this->callbacks.esc)[c - '0'] == NULL) {
|
||||
if (this->unimplemented != NULL)
|
||||
this->unimplemented(this, "ESC", c);
|
||||
goto leave;
|
||||
|
|
@ -95,10 +85,8 @@ leave:
|
|||
this->argc = 0;
|
||||
}
|
||||
|
||||
static void lw_terminal_parser_call_HASH(struct lw_terminal *this, char c)
|
||||
{
|
||||
if (((term_action *)&this->callbacks.hash)[c - '0'] == NULL)
|
||||
{
|
||||
static void lw_terminal_parser_call_HASH(struct lw_terminal *this, char c) {
|
||||
if (((term_action *)&this->callbacks.hash)[c - '0'] == NULL) {
|
||||
if (this->unimplemented != NULL)
|
||||
this->unimplemented(this, "HASH", c);
|
||||
goto leave;
|
||||
|
|
@ -110,11 +98,9 @@ leave:
|
|||
this->argc = 0;
|
||||
}
|
||||
|
||||
static void lw_terminal_parser_call_GSET(struct lw_terminal *this, char c)
|
||||
{
|
||||
if (c < '0' || c > 'B'
|
||||
|| ((term_action *)&this->callbacks.scs)[c - '0'] == NULL)
|
||||
{
|
||||
static void lw_terminal_parser_call_GSET(struct lw_terminal *this, char c) {
|
||||
if (c < '0' || c > 'B' ||
|
||||
((term_action *)&this->callbacks.scs)[c - '0'] == NULL) {
|
||||
if (this->unimplemented != NULL)
|
||||
this->unimplemented(this, "GSET", c);
|
||||
goto leave;
|
||||
|
|
@ -141,17 +127,13 @@ leave:
|
|||
** | | \_ term_call_GSET()
|
||||
** \_ term->write()
|
||||
*/
|
||||
void lw_terminal_parser_read(struct lw_terminal *this, char c)
|
||||
{
|
||||
if (this->state == INIT)
|
||||
{
|
||||
void lw_terminal_parser_read(struct lw_terminal *this, char c) {
|
||||
if (this->state == INIT) {
|
||||
if (c == '\033')
|
||||
this->state = ESC;
|
||||
else
|
||||
this->write(this, c);
|
||||
}
|
||||
else if (this->state == ESC)
|
||||
{
|
||||
} else if (this->state == ESC) {
|
||||
if (c == '[')
|
||||
this->state = CSI;
|
||||
else if (c == '#')
|
||||
|
|
@ -162,21 +144,16 @@ void lw_terminal_parser_read(struct lw_terminal *this, char c)
|
|||
this->state = G1SET;
|
||||
else if (c >= '0' && c <= 'z')
|
||||
lw_terminal_parser_call_ESC(this, c);
|
||||
else this->write(this, c);
|
||||
}
|
||||
else if (this->state == HASH)
|
||||
{
|
||||
else
|
||||
this->write(this, c);
|
||||
} else if (this->state == HASH) {
|
||||
if (c >= '0' && c <= '9')
|
||||
lw_terminal_parser_call_HASH(this, c);
|
||||
else
|
||||
this->write(this, c);
|
||||
}
|
||||
else if (this->state == G0SET || this->state == G1SET)
|
||||
{
|
||||
} else if (this->state == G0SET || this->state == G1SET) {
|
||||
lw_terminal_parser_call_GSET(this, c);
|
||||
}
|
||||
else if (this->state == CSI)
|
||||
{
|
||||
} else if (this->state == CSI) {
|
||||
if (c == '?')
|
||||
this->flag = '?';
|
||||
else if (c == '>')
|
||||
|
|
@ -190,26 +167,24 @@ void lw_terminal_parser_read(struct lw_terminal *this, char c)
|
|||
}
|
||||
}
|
||||
|
||||
void lw_terminal_parser_read_buf(struct lw_terminal *this, const char *c, size_t n)
|
||||
{
|
||||
void lw_terminal_parser_read_buf(struct lw_terminal *this, const char *c,
|
||||
size_t n) {
|
||||
while (n--)
|
||||
lw_terminal_parser_read(this, *c++);
|
||||
}
|
||||
|
||||
void lw_terminal_parser_read_str(struct lw_terminal *this, const char *c)
|
||||
{
|
||||
void lw_terminal_parser_read_str(struct lw_terminal *this, const char *c) {
|
||||
while (*c)
|
||||
lw_terminal_parser_read(this, *c++);
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
void lw_terminal_parser_default_unimplemented(struct lw_terminal* this, char *seq, char chr)
|
||||
{
|
||||
void lw_terminal_parser_default_unimplemented(struct lw_terminal *this,
|
||||
char *seq, char chr) {
|
||||
unsigned int argc;
|
||||
|
||||
fprintf(stderr, "WARNING: UNIMPLEMENTED %s (", seq);
|
||||
for (argc = 0; argc < this->argc; ++argc)
|
||||
{
|
||||
for (argc = 0; argc < this->argc; ++argc) {
|
||||
fprintf(stderr, "%d", this->argv[argc]);
|
||||
if (argc != this->argc - 1)
|
||||
fprintf(stderr, ", ");
|
||||
|
|
@ -217,20 +192,16 @@ void lw_terminal_parser_default_unimplemented(struct lw_terminal* this, char *se
|
|||
fprintf(stderr, ")%o\n", chr);
|
||||
}
|
||||
#else
|
||||
void lw_terminal_parser_default_unimplemented(struct lw_terminal* this, char *seq, char chr)
|
||||
{
|
||||
void lw_terminal_parser_default_unimplemented(struct lw_terminal *this,
|
||||
char *seq, char chr) {
|
||||
this = this;
|
||||
seq = seq;
|
||||
chr = chr;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct lw_terminal *lw_terminal_parser_init(void)
|
||||
{
|
||||
struct lw_terminal *lw_terminal_parser_init(void) {
|
||||
return calloc(1, sizeof(struct lw_terminal));
|
||||
}
|
||||
|
||||
void lw_terminal_parser_destroy(struct lw_terminal* this)
|
||||
{
|
||||
free(this);
|
||||
}
|
||||
void lw_terminal_parser_destroy(struct lw_terminal *this) { free(this); }
|
||||
|
|
|
|||
|
|
@ -23,8 +23,9 @@
|
|||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __TERMINAL_H__
|
||||
#define __TERMINAL_H__
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/*
|
||||
**
|
||||
|
|
@ -97,22 +98,13 @@
|
|||
|
||||
#define TERM_STACK_SIZE 1024
|
||||
|
||||
enum term_state
|
||||
{
|
||||
INIT,
|
||||
ESC,
|
||||
HASH,
|
||||
G0SET,
|
||||
G1SET,
|
||||
CSI
|
||||
};
|
||||
enum term_state { INIT, ESC, HASH, G0SET, G1SET, CSI };
|
||||
|
||||
struct lw_terminal;
|
||||
|
||||
typedef void (*term_action)(struct lw_terminal *emul);
|
||||
|
||||
struct ascii_callbacks
|
||||
{
|
||||
struct ascii_callbacks {
|
||||
term_action n0;
|
||||
term_action n1;
|
||||
term_action n2;
|
||||
|
|
@ -194,35 +186,33 @@ struct ascii_callbacks
|
|||
term_action z;
|
||||
};
|
||||
|
||||
struct term_callbacks
|
||||
{
|
||||
struct term_callbacks {
|
||||
struct ascii_callbacks esc;
|
||||
struct ascii_callbacks csi;
|
||||
struct ascii_callbacks hash;
|
||||
struct ascii_callbacks scs;
|
||||
};
|
||||
|
||||
struct lw_terminal
|
||||
{
|
||||
unsigned int cursor_pos_x;
|
||||
unsigned int cursor_pos_y;
|
||||
enum term_state state;
|
||||
unsigned int argc;
|
||||
unsigned int argv[TERM_STACK_SIZE];
|
||||
void (*write)(struct lw_terminal *, char c);
|
||||
char stack[TERM_STACK_SIZE];
|
||||
unsigned int stack_ptr;
|
||||
struct term_callbacks callbacks;
|
||||
char flag;
|
||||
void *user_data;
|
||||
void (*unimplemented)(struct lw_terminal*,
|
||||
char *seq, char chr);
|
||||
struct lw_terminal {
|
||||
unsigned int cursor_pos_x;
|
||||
unsigned int cursor_pos_y;
|
||||
enum term_state state;
|
||||
unsigned int argc;
|
||||
unsigned int argv[TERM_STACK_SIZE];
|
||||
void (*write)(struct lw_terminal *, char c);
|
||||
char stack[TERM_STACK_SIZE];
|
||||
unsigned int stack_ptr;
|
||||
struct term_callbacks callbacks;
|
||||
char flag;
|
||||
void *user_data;
|
||||
void (*unimplemented)(struct lw_terminal *, char *seq, char chr);
|
||||
};
|
||||
|
||||
struct lw_terminal *lw_terminal_parser_init(void);
|
||||
void lw_terminal_parser_default_unimplemented(struct lw_terminal* this, char *seq, char chr);
|
||||
void lw_terminal_parser_default_unimplemented(struct lw_terminal *this,
|
||||
char *seq, char chr);
|
||||
void lw_terminal_parser_read(struct lw_terminal *this, char c);
|
||||
void lw_terminal_parser_read_str(struct lw_terminal *this, const char *c);
|
||||
void lw_terminal_parser_read_buf(struct lw_terminal *this, const char *c, size_t n);
|
||||
void lw_terminal_parser_destroy(struct lw_terminal* this);
|
||||
#endif
|
||||
void lw_terminal_parser_read_buf(struct lw_terminal *this, const char *c,
|
||||
size_t n);
|
||||
void lw_terminal_parser_destroy(struct lw_terminal *this);
|
||||
|
|
|
|||
|
|
@ -23,27 +23,36 @@
|
|||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include "lw_terminal_vt100.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static unsigned int get_mode_mask(unsigned int mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case LNM : return MASK_LNM;
|
||||
case DECCKM : return MASK_DECCKM;
|
||||
case DECANM : return MASK_DECANM;
|
||||
case DECCOLM : return MASK_DECCOLM;
|
||||
case DECSCLM : return MASK_DECSCLM;
|
||||
case DECSCNM : return MASK_DECSCNM;
|
||||
case DECOM : return MASK_DECOM;
|
||||
case DECAWM : return MASK_DECAWM;
|
||||
case DECARM : return MASK_DECARM;
|
||||
case DECINLM : return MASK_DECINLM;
|
||||
default: return 0;
|
||||
static unsigned int get_mode_mask(unsigned int mode) {
|
||||
switch (mode) {
|
||||
case LNM:
|
||||
return MASK_LNM;
|
||||
case DECCKM:
|
||||
return MASK_DECCKM;
|
||||
case DECANM:
|
||||
return MASK_DECANM;
|
||||
case DECCOLM:
|
||||
return MASK_DECCOLM;
|
||||
case DECSCLM:
|
||||
return MASK_DECSCLM;
|
||||
case DECSCNM:
|
||||
return MASK_DECSCNM;
|
||||
case DECOM:
|
||||
return MASK_DECOM;
|
||||
case DECAWM:
|
||||
return MASK_DECAWM;
|
||||
case DECARM:
|
||||
return MASK_DECARM;
|
||||
case DECINLM:
|
||||
return MASK_DECINLM;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -179,63 +188,57 @@ static unsigned int get_mode_mask(unsigned int mode)
|
|||
|
||||
#define MOD1(a, b) ((a < b) ? a : a - b)
|
||||
|
||||
#define SCREEN_PTR(vt100, x, y) \
|
||||
MOD1((vt100->top_line * vt100->width + x + vt100->width * y), \
|
||||
(vt100->width * SCROLLBACK * vt100->height))
|
||||
#define SCREEN_PTR(vt100, x, y) \
|
||||
MOD1((vt100->top_line * vt100->width + x + vt100->width * y), \
|
||||
(vt100->width * SCROLLBACK * vt100->height))
|
||||
|
||||
#define FROZEN_SCREEN_PTR(vt100, x, y) \
|
||||
(MOD1(x + vt100->width * y, \
|
||||
(vt100->width * SCROLLBACK * vt100->height)))
|
||||
#define FROZEN_SCREEN_PTR(vt100, x, y) \
|
||||
(MOD1(x + vt100->width * y, (vt100->width * SCROLLBACK * vt100->height)))
|
||||
|
||||
static lw_cell_t aget(struct lw_terminal_vt100 *headless_term,
|
||||
unsigned int x, unsigned int y)
|
||||
{
|
||||
static lw_cell_t aget(struct lw_terminal_vt100 *headless_term, unsigned int x,
|
||||
unsigned int y) {
|
||||
if (y < headless_term->margin_top || y > headless_term->margin_bottom)
|
||||
return headless_term->afrozen_screen[FROZEN_SCREEN_PTR(headless_term, x, y)];
|
||||
return headless_term
|
||||
->afrozen_screen[FROZEN_SCREEN_PTR(headless_term, x, y)];
|
||||
else
|
||||
return headless_term->ascreen[SCREEN_PTR(headless_term, x, y)];
|
||||
}
|
||||
|
||||
static void aset(struct lw_terminal_vt100 *headless_term,
|
||||
unsigned int x, unsigned int y,
|
||||
lw_cell_t c)
|
||||
{
|
||||
static void aset(struct lw_terminal_vt100 *headless_term, unsigned int x,
|
||||
unsigned int y, lw_cell_t c) {
|
||||
if (y < headless_term->margin_top || y > headless_term->margin_bottom)
|
||||
headless_term->afrozen_screen[FROZEN_SCREEN_PTR(headless_term, x, y)] = c;
|
||||
headless_term->afrozen_screen[FROZEN_SCREEN_PTR(headless_term, x, y)] =
|
||||
c;
|
||||
else
|
||||
headless_term->ascreen[SCREEN_PTR(headless_term, x, y)] = c;
|
||||
}
|
||||
|
||||
static void set(struct lw_terminal_vt100 *headless_term,
|
||||
unsigned int x, unsigned int y,
|
||||
char c) {
|
||||
aset( headless_term, x, y, (unsigned char)c | headless_term->attr);
|
||||
static void set(struct lw_terminal_vt100 *headless_term, unsigned int x,
|
||||
unsigned int y, char c) {
|
||||
aset(headless_term, x, y, (unsigned char)c | headless_term->attr);
|
||||
}
|
||||
|
||||
lw_cell_t lw_terminal_vt100_aget(struct lw_terminal_vt100 *vt100, unsigned int x, unsigned int y)
|
||||
{
|
||||
lw_cell_t lw_terminal_vt100_aget(struct lw_terminal_vt100 *vt100,
|
||||
unsigned int x, unsigned int y) {
|
||||
if (y < vt100->margin_top || y > vt100->margin_bottom)
|
||||
return vt100->afrozen_screen[FROZEN_SCREEN_PTR(vt100, x, y)];
|
||||
else
|
||||
return vt100->ascreen[SCREEN_PTR(vt100, x, y)];
|
||||
}
|
||||
|
||||
static void froze_line(struct lw_terminal_vt100 *vt100, unsigned int y)
|
||||
{
|
||||
static void froze_line(struct lw_terminal_vt100 *vt100, unsigned int y) {
|
||||
memcpy(vt100->afrozen_screen + vt100->width * y,
|
||||
vt100->ascreen + SCREEN_PTR(vt100, 0, y),
|
||||
vt100->width * sizeof(lw_cell_t));
|
||||
}
|
||||
|
||||
static void unfroze_line(struct lw_terminal_vt100 *vt100, unsigned int y)
|
||||
{
|
||||
static void unfroze_line(struct lw_terminal_vt100 *vt100, unsigned int y) {
|
||||
memcpy(vt100->ascreen + SCREEN_PTR(vt100, 0, y),
|
||||
vt100->afrozen_screen + vt100->width * y,
|
||||
vt100->width * sizeof(lw_cell_t));
|
||||
}
|
||||
|
||||
static void blank_screen(struct lw_terminal_vt100 *lw_terminal_vt100)
|
||||
{
|
||||
static void blank_screen(struct lw_terminal_vt100 *lw_terminal_vt100) {
|
||||
unsigned int x;
|
||||
unsigned int y;
|
||||
|
||||
|
|
@ -252,8 +255,7 @@ static void blank_screen(struct lw_terminal_vt100 *lw_terminal_vt100)
|
|||
This sequence causes the cursor position, graphic rendition, and
|
||||
character set to be saved. (See DECRC).
|
||||
*/
|
||||
static void DECSC(struct lw_terminal *term_emul)
|
||||
{
|
||||
static void DECSC(struct lw_terminal *term_emul) {
|
||||
/*TODO: Save graphic rendition and charset.*/
|
||||
struct lw_terminal_vt100 *vt100;
|
||||
|
||||
|
|
@ -273,17 +275,14 @@ static void DECSC(struct lw_terminal *term_emul)
|
|||
Modes following this section).
|
||||
|
||||
*/
|
||||
static void RM(struct lw_terminal *term_emul)
|
||||
{
|
||||
static void RM(struct lw_terminal *term_emul) {
|
||||
struct lw_terminal_vt100 *vt100;
|
||||
unsigned int mode;
|
||||
|
||||
vt100 = (struct lw_terminal_vt100 *)term_emul->user_data;
|
||||
if (term_emul->argc > 0)
|
||||
{
|
||||
if (term_emul->argc > 0) {
|
||||
mode = term_emul->argv[0];
|
||||
if (mode == DECCOLM)
|
||||
{
|
||||
if (mode == DECCOLM) {
|
||||
vt100->width = 80;
|
||||
vt100->x = vt100->y = 0;
|
||||
blank_screen(vt100);
|
||||
|
|
@ -335,11 +334,10 @@ x Pm = 97 / 107 fg/bg Bright White
|
|||
x Pm = 99 / 109 fg/bg Bright Default
|
||||
*/
|
||||
|
||||
static int default_map_unicode(void *user_data, int c) {
|
||||
return '?';
|
||||
}
|
||||
static int default_map_unicode(void *user_data, int c) { return '?'; }
|
||||
|
||||
static lw_cell_t default_encode_attr(void *user_data, const struct lw_parsed_attr *attr) {
|
||||
static lw_cell_t default_encode_attr(void *user_data,
|
||||
const struct lw_parsed_attr *attr) {
|
||||
(void)user_data;
|
||||
|
||||
lw_cell_t result;
|
||||
|
|
@ -350,29 +348,33 @@ static lw_cell_t default_encode_attr(void *user_data, const struct lw_parsed_att
|
|||
result = attr->fg;
|
||||
result |= attr->bg << 4;
|
||||
}
|
||||
if (attr->bold) result ^= 0x08;
|
||||
if (attr->blink) result ^= 0x80;
|
||||
if (attr->bold)
|
||||
result ^= 0x08;
|
||||
if (attr->blink)
|
||||
result ^= 0x80;
|
||||
|
||||
return result << 8;
|
||||
}
|
||||
|
||||
static void SGR(struct lw_terminal *term_emul)
|
||||
{
|
||||
struct lw_terminal_vt100 *vt100 = (struct lw_terminal_vt100 *)term_emul->user_data;
|
||||
static void SGR(struct lw_terminal *term_emul) {
|
||||
struct lw_terminal_vt100 *vt100 =
|
||||
(struct lw_terminal_vt100 *)term_emul->user_data;
|
||||
|
||||
// vim sends "CSI > 4 ; 2 m" and you can't stop it
|
||||
if (term_emul->flag == '>') { return; }
|
||||
if (term_emul->flag == '>') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (term_emul->argc == 0) {
|
||||
term_emul->argc = 1;
|
||||
term_emul->argv[0] = 0;
|
||||
}
|
||||
|
||||
for (unsigned int i=0; i<term_emul->argc; i++) {
|
||||
for (unsigned int i = 0; i < term_emul->argc; i++) {
|
||||
int p = term_emul->argv[i];
|
||||
switch(p) {
|
||||
case 0:
|
||||
vt100->parsed_attr = LW_DEFAULT_ATTR;
|
||||
switch (p) {
|
||||
case 0:
|
||||
vt100->parsed_attr = LW_DEFAULT_ATTR;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
|
|
@ -447,8 +449,7 @@ static void SGR(struct lw_terminal *term_emul)
|
|||
The numbering of lines depends on the state of the Origin Mode
|
||||
(DECOM).
|
||||
*/
|
||||
static void CUP(struct lw_terminal *term_emul)
|
||||
{
|
||||
static void CUP(struct lw_terminal *term_emul) {
|
||||
struct lw_terminal_vt100 *vt100;
|
||||
int arg0;
|
||||
int arg1;
|
||||
|
|
@ -465,14 +466,17 @@ static void CUP(struct lw_terminal *term_emul)
|
|||
if (arg1 < 0)
|
||||
arg1 = 0;
|
||||
|
||||
if (MODE_IS_SET(vt100, DECOM))
|
||||
{
|
||||
if (MODE_IS_SET(vt100, DECOM)) {
|
||||
arg0 += vt100->margin_top;
|
||||
if ((unsigned int)arg0 > vt100->margin_bottom)
|
||||
arg0 = vt100->margin_bottom;
|
||||
}
|
||||
if (arg0 >= vt100->height) { arg0 = vt100->height - 1; }
|
||||
if (arg1 >= vt100->width) { arg1 = vt100->width - 1; }
|
||||
if (arg0 >= vt100->height) {
|
||||
arg0 = vt100->height - 1;
|
||||
}
|
||||
if (arg1 >= vt100->width) {
|
||||
arg1 = vt100->width - 1;
|
||||
}
|
||||
vt100->y = arg0;
|
||||
vt100->x = arg1;
|
||||
}
|
||||
|
|
@ -488,30 +492,25 @@ static void CUP(struct lw_terminal *term_emul)
|
|||
it is reset by a reset mode (RM) control sequence.
|
||||
|
||||
*/
|
||||
static void SM(struct lw_terminal *term_emul)
|
||||
{
|
||||
static void SM(struct lw_terminal *term_emul) {
|
||||
struct lw_terminal_vt100 *vt100;
|
||||
unsigned int mode;
|
||||
unsigned int saved_argc;
|
||||
|
||||
vt100 = (struct lw_terminal_vt100 *)term_emul->user_data;
|
||||
if (term_emul->argc > 0)
|
||||
{
|
||||
if (term_emul->argc > 0) {
|
||||
mode = term_emul->argv[0];
|
||||
SET_MODE(vt100, mode);
|
||||
if (mode == DECANM)
|
||||
{
|
||||
if (mode == DECANM) {
|
||||
/* TODO: Support vt52 mode */
|
||||
return ;
|
||||
return;
|
||||
}
|
||||
if (mode == DECCOLM)
|
||||
{
|
||||
if (mode == DECCOLM) {
|
||||
vt100->width = 132;
|
||||
vt100->x = vt100->y = 0;
|
||||
blank_screen(vt100);
|
||||
}
|
||||
if (mode == DECOM)
|
||||
{
|
||||
if (mode == DECOM) {
|
||||
saved_argc = term_emul->argc;
|
||||
term_emul->argc = 0;
|
||||
CUP(term_emul);
|
||||
|
|
@ -534,8 +533,7 @@ static void SM(struct lw_terminal *term_emul)
|
|||
cursor is placed in the home position (see Origin Mode DECOM).
|
||||
|
||||
*/
|
||||
static void DECSTBM(struct lw_terminal *term_emul)
|
||||
{
|
||||
static void DECSTBM(struct lw_terminal *term_emul) {
|
||||
unsigned int margin_top;
|
||||
unsigned int margin_bottom;
|
||||
struct lw_terminal_vt100 *vt100;
|
||||
|
|
@ -543,17 +541,14 @@ static void DECSTBM(struct lw_terminal *term_emul)
|
|||
|
||||
vt100 = (struct lw_terminal_vt100 *)term_emul->user_data;
|
||||
|
||||
if (term_emul->argc == 2)
|
||||
{
|
||||
if (term_emul->argc == 2) {
|
||||
margin_top = term_emul->argv[0] - 1;
|
||||
margin_bottom = term_emul->argv[1] - 1;
|
||||
if (margin_bottom >= vt100->height)
|
||||
return ;
|
||||
return;
|
||||
if (margin_bottom - margin_top <= 0)
|
||||
return ;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
} else {
|
||||
margin_top = 0;
|
||||
margin_bottom = vt100->height - 1;
|
||||
}
|
||||
|
|
@ -594,16 +589,14 @@ static void DECSTBM(struct lw_terminal *term_emul)
|
|||
GPO, STP and AVO ESC [?1;7c
|
||||
|
||||
*/
|
||||
static void DA(struct lw_terminal *term_emul)
|
||||
{
|
||||
static void DA(struct lw_terminal *term_emul) {
|
||||
struct lw_terminal_vt100 *vt100;
|
||||
|
||||
vt100 = (struct lw_terminal_vt100 *)term_emul->user_data;
|
||||
vt100->master_write(vt100->user_data, "\033[?1;0c", 7);
|
||||
}
|
||||
|
||||
static void DSR(struct lw_terminal *term_emul)
|
||||
{
|
||||
static void DSR(struct lw_terminal *term_emul) {
|
||||
struct lw_terminal_vt100 *vt100;
|
||||
vt100 = (struct lw_terminal_vt100 *)term_emul->user_data;
|
||||
|
||||
|
|
@ -611,20 +604,18 @@ static void DSR(struct lw_terminal *term_emul)
|
|||
return;
|
||||
}
|
||||
|
||||
switch(term_emul->argv[0]) {
|
||||
case 5:
|
||||
vt100->master_write(vt100->user_data, "\033[0n", 4);
|
||||
break;
|
||||
switch (term_emul->argv[0]) {
|
||||
case 5:
|
||||
vt100->master_write(vt100->user_data, "\033[0n", 4);
|
||||
break;
|
||||
|
||||
case 6:
|
||||
{
|
||||
char buf[16];
|
||||
snprintf(buf, sizeof(buf), "\033[%d;%dR", vt100->y + 1, vt100->x + 1);
|
||||
vt100->master_write(vt100->user_data, buf, strlen(buf));
|
||||
}
|
||||
case 6: {
|
||||
char buf[16];
|
||||
snprintf(buf, sizeof(buf), "\033[%d;%dR", vt100->y + 1, vt100->x + 1);
|
||||
vt100->master_write(vt100->user_data, buf, strlen(buf));
|
||||
}
|
||||
|
||||
default:
|
||||
;
|
||||
default:;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -636,8 +627,7 @@ static void DSR(struct lw_terminal *term_emul)
|
|||
This sequence causes the previously saved cursor position, graphic
|
||||
rendition, and character set to be restored.
|
||||
*/
|
||||
static void DECRC(struct lw_terminal *term_emul)
|
||||
{
|
||||
static void DECRC(struct lw_terminal *term_emul) {
|
||||
/*TODO Save graphic rendition and charset */
|
||||
struct lw_terminal_vt100 *vt100;
|
||||
|
||||
|
|
@ -655,8 +645,7 @@ static void DECRC(struct lw_terminal *term_emul)
|
|||
focus and alignment. This command is used by DEC manufacturing and
|
||||
Field Service personnel.
|
||||
*/
|
||||
static void DECALN(struct lw_terminal *term_emul)
|
||||
{
|
||||
static void DECALN(struct lw_terminal *term_emul) {
|
||||
struct lw_terminal_vt100 *vt100;
|
||||
unsigned int x;
|
||||
unsigned int y;
|
||||
|
|
@ -676,22 +665,18 @@ static void DECALN(struct lw_terminal *term_emul)
|
|||
without changing the column position. If the active position is at the
|
||||
bottom margin, a scroll up is performed. Format Effector
|
||||
*/
|
||||
static void IND(struct lw_terminal *term_emul)
|
||||
{
|
||||
static void IND(struct lw_terminal *term_emul) {
|
||||
struct lw_terminal_vt100 *vt100;
|
||||
unsigned int x;
|
||||
|
||||
vt100 = (struct lw_terminal_vt100 *)term_emul->user_data;
|
||||
if (vt100->y >= vt100->margin_bottom)
|
||||
{
|
||||
if (vt100->y >= vt100->margin_bottom) {
|
||||
/* SCROLL */
|
||||
vt100->top_line = (vt100->top_line + 1) % (vt100->height * SCROLLBACK);
|
||||
for (x = 0; x < vt100->width; ++x)
|
||||
set(vt100, x, vt100->margin_bottom, ' ');
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
/* Do not scroll, just move downward on the current display space */
|
||||
vt100->y += 1;
|
||||
}
|
||||
|
|
@ -705,18 +690,14 @@ static void IND(struct lw_terminal *term_emul)
|
|||
preceding line. If the active position is at the top margin, a scroll
|
||||
down is performed. Format Effector
|
||||
*/
|
||||
static void RI(struct lw_terminal *term_emul)
|
||||
{
|
||||
static void RI(struct lw_terminal *term_emul) {
|
||||
struct lw_terminal_vt100 *vt100;
|
||||
|
||||
vt100 = (struct lw_terminal_vt100 *)term_emul->user_data;
|
||||
if (vt100->y == 0)
|
||||
{
|
||||
if (vt100->y == 0) {
|
||||
/* SCROLL */
|
||||
vt100->top_line = (vt100->top_line - 1) % (vt100->height * SCROLLBACK);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
/* Do not scroll, just move upward on the current display space */
|
||||
vt100->y -= 1;
|
||||
}
|
||||
|
|
@ -731,21 +712,17 @@ static void RI(struct lw_terminal *term_emul)
|
|||
on the next line downward. If the active position is at the bottom
|
||||
margin, a scroll up is performed. Format Effector
|
||||
*/
|
||||
static void NEL(struct lw_terminal *term_emul)
|
||||
{
|
||||
static void NEL(struct lw_terminal *term_emul) {
|
||||
struct lw_terminal_vt100 *vt100;
|
||||
unsigned int x;
|
||||
|
||||
vt100 = (struct lw_terminal_vt100 *)term_emul->user_data;
|
||||
if (vt100->y >= vt100->margin_bottom)
|
||||
{
|
||||
if (vt100->y >= vt100->margin_bottom) {
|
||||
/* SCROLL */
|
||||
vt100->top_line = (vt100->top_line + 1) % (vt100->height * SCROLLBACK);
|
||||
for (x = 0; x < vt100->width; ++x)
|
||||
set(vt100, x, vt100->margin_bottom, ' ');
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
/* Do not scroll, just move downward on the current display space */
|
||||
vt100->y += 1;
|
||||
}
|
||||
|
|
@ -764,8 +741,7 @@ static void NEL(struct lw_terminal *term_emul)
|
|||
upward. If an attempt is made to move the cursor above the top margin,
|
||||
the cursor stops at the top margin. Editor Function
|
||||
*/
|
||||
static void CUU(struct lw_terminal *term_emul)
|
||||
{
|
||||
static void CUU(struct lw_terminal *term_emul) {
|
||||
struct lw_terminal_vt100 *vt100;
|
||||
unsigned int arg0;
|
||||
|
||||
|
|
@ -794,8 +770,7 @@ static void CUU(struct lw_terminal *term_emul)
|
|||
cursor below the bottom margin, the cursor stops at the bottom
|
||||
margin. Editor Function
|
||||
*/
|
||||
static void CUD(struct lw_terminal *term_emul)
|
||||
{
|
||||
static void CUD(struct lw_terminal *term_emul) {
|
||||
struct lw_terminal_vt100 *vt100;
|
||||
unsigned int arg0;
|
||||
|
||||
|
|
@ -822,8 +797,7 @@ static void CUD(struct lw_terminal *term_emul)
|
|||
is made to move the cursor to the right of the right margin, the
|
||||
cursor stops at the right margin. Editor Function
|
||||
*/
|
||||
static void CUF(struct lw_terminal *term_emul)
|
||||
{
|
||||
static void CUF(struct lw_terminal *term_emul) {
|
||||
struct lw_terminal_vt100 *vt100;
|
||||
unsigned int arg0;
|
||||
|
||||
|
|
@ -850,8 +824,7 @@ static void CUF(struct lw_terminal *term_emul)
|
|||
left. If an attempt is made to move the cursor to the left of the left
|
||||
margin, the cursor stops at the left margin. Editor Function
|
||||
*/
|
||||
static void CUB(struct lw_terminal *term_emul)
|
||||
{
|
||||
static void CUB(struct lw_terminal *term_emul) {
|
||||
struct lw_terminal_vt100 *vt100;
|
||||
unsigned int arg0;
|
||||
|
||||
|
|
@ -873,8 +846,7 @@ static void CUB(struct lw_terminal *term_emul)
|
|||
ESC [ Ps P default value: 1
|
||||
|
||||
*/
|
||||
static void DCH(struct lw_terminal *term_emul)
|
||||
{
|
||||
static void DCH(struct lw_terminal *term_emul) {
|
||||
struct lw_terminal_vt100 *vt100;
|
||||
unsigned int arg0;
|
||||
unsigned int x;
|
||||
|
|
@ -913,8 +885,7 @@ static void DCH(struct lw_terminal *term_emul)
|
|||
2 Erase all of the display – all lines are erased, changed to
|
||||
single-width, and the cursor does not move.
|
||||
*/
|
||||
static void ED(struct lw_terminal *term_emul)
|
||||
{
|
||||
static void ED(struct lw_terminal *term_emul) {
|
||||
struct lw_terminal_vt100 *vt100;
|
||||
unsigned int arg0;
|
||||
unsigned int x;
|
||||
|
|
@ -924,25 +895,20 @@ static void ED(struct lw_terminal *term_emul)
|
|||
arg0 = 0;
|
||||
if (term_emul->argc > 0)
|
||||
arg0 = term_emul->argv[0];
|
||||
if (arg0 == 0)
|
||||
{
|
||||
if (arg0 == 0) {
|
||||
for (x = vt100->x; x < vt100->width; ++x)
|
||||
set(vt100, x, vt100->y, ' ');
|
||||
for (x = 0 ; x < vt100->width; ++x)
|
||||
for (x = 0; x < vt100->width; ++x)
|
||||
for (y = vt100->y + 1; y < vt100->height; ++y)
|
||||
set(vt100, x, y, ' ');
|
||||
}
|
||||
else if (arg0 == 1)
|
||||
{
|
||||
for (x = 0 ; x < vt100->width; ++x)
|
||||
} else if (arg0 == 1) {
|
||||
for (x = 0; x < vt100->width; ++x)
|
||||
for (y = 0; y < vt100->y; ++y)
|
||||
set(vt100, x, y, ' ');
|
||||
for (x = 0; x <= vt100->x; ++x)
|
||||
set(vt100, x, vt100->y, ' ');
|
||||
}
|
||||
else if (arg0 == 2)
|
||||
{
|
||||
for (x = 0 ; x < vt100->width; ++x)
|
||||
} else if (arg0 == 2) {
|
||||
for (x = 0; x < vt100->width; ++x)
|
||||
for (y = 0; y < vt100->height; ++y)
|
||||
set(vt100, x, y, ' ');
|
||||
}
|
||||
|
|
@ -962,8 +928,7 @@ static void ED(struct lw_terminal *term_emul)
|
|||
1 Erase from the start of the screen to the active position, inclusive
|
||||
2 Erase all of the line, inclusive
|
||||
*/
|
||||
static void EL(struct lw_terminal *term_emul)
|
||||
{
|
||||
static void EL(struct lw_terminal *term_emul) {
|
||||
struct lw_terminal_vt100 *vt100;
|
||||
unsigned int arg0;
|
||||
unsigned int x;
|
||||
|
|
@ -972,18 +937,13 @@ static void EL(struct lw_terminal *term_emul)
|
|||
arg0 = 0;
|
||||
if (term_emul->argc > 0)
|
||||
arg0 = term_emul->argv[0];
|
||||
if (arg0 == 0)
|
||||
{
|
||||
if (arg0 == 0) {
|
||||
for (x = vt100->x; x < vt100->width; ++x)
|
||||
set(vt100, x, vt100->y, ' ');
|
||||
}
|
||||
else if (arg0 == 1)
|
||||
{
|
||||
} else if (arg0 == 1) {
|
||||
for (x = 0; x <= vt100->x; ++x)
|
||||
set(vt100, x, vt100->y, ' ');
|
||||
}
|
||||
else if (arg0 == 2)
|
||||
{
|
||||
} else if (arg0 == 2) {
|
||||
for (x = 0; x < vt100->width; ++x)
|
||||
set(vt100, x, vt100->y, ' ');
|
||||
}
|
||||
|
|
@ -1005,30 +965,22 @@ static void EL(struct lw_terminal *term_emul)
|
|||
columns depends on the reset or set state of the origin mode
|
||||
(DECOM). Format Effector
|
||||
*/
|
||||
static void HVP(struct lw_terminal *term_emul)
|
||||
{
|
||||
CUP(term_emul);
|
||||
}
|
||||
static void HVP(struct lw_terminal *term_emul) { CUP(term_emul); }
|
||||
|
||||
static void TBC(struct lw_terminal *term_emul)
|
||||
{
|
||||
static void TBC(struct lw_terminal *term_emul) {
|
||||
struct lw_terminal_vt100 *vt100;
|
||||
unsigned int i;
|
||||
|
||||
vt100 = (struct lw_terminal_vt100 *)term_emul->user_data;
|
||||
if (term_emul->argc == 0 || term_emul->argv[0] == 0)
|
||||
{
|
||||
if (term_emul->argc == 0 || term_emul->argv[0] == 0) {
|
||||
vt100->tabulations[vt100->x] = '-';
|
||||
}
|
||||
else if (term_emul->argc == 1 && term_emul->argv[0] == 3)
|
||||
{
|
||||
} else if (term_emul->argc == 1 && term_emul->argv[0] == 3) {
|
||||
for (i = 0; i < 132; ++i)
|
||||
vt100->tabulations[i] = '-';
|
||||
}
|
||||
}
|
||||
|
||||
static void HTS(struct lw_terminal *term_emul)
|
||||
{
|
||||
static void HTS(struct lw_terminal *term_emul) {
|
||||
struct lw_terminal_vt100 *vt100;
|
||||
|
||||
vt100 = (struct lw_terminal_vt100 *)term_emul->user_data;
|
||||
|
|
@ -1040,50 +992,43 @@ static void vt100_write_unicode(struct lw_terminal *term_emul, int c) {
|
|||
|
||||
vt100 = (struct lw_terminal_vt100 *)term_emul->user_data;
|
||||
|
||||
if (c == '\r')
|
||||
{
|
||||
if (c == '\r') {
|
||||
vt100->x = 0;
|
||||
return ;
|
||||
return;
|
||||
}
|
||||
if (c == '\n' || c == '\013' || c == '\014')
|
||||
{
|
||||
if (c == '\n' || c == '\013' || c == '\014') {
|
||||
if (MODE_IS_SET(vt100, LNM))
|
||||
NEL(term_emul);
|
||||
else
|
||||
IND(term_emul);
|
||||
return ;
|
||||
return;
|
||||
}
|
||||
if (c == '\010' && vt100->x > 0)
|
||||
{
|
||||
if (c == '\010' && vt100->x > 0) {
|
||||
if (vt100->x == vt100->width)
|
||||
vt100->x -= 1;
|
||||
vt100->x -= 1;
|
||||
return ;
|
||||
return;
|
||||
}
|
||||
if (c == '\t')
|
||||
{
|
||||
do
|
||||
{
|
||||
if (c == '\t') {
|
||||
do {
|
||||
set(vt100, vt100->x, vt100->y, ' ');
|
||||
vt100->x += 1;
|
||||
} while (vt100->x < vt100->width && vt100->tabulations[vt100->x] == '-');
|
||||
return ;
|
||||
} while (vt100->x < vt100->width &&
|
||||
vt100->tabulations[vt100->x] == '-');
|
||||
return;
|
||||
}
|
||||
if (c == '\016')
|
||||
{
|
||||
if (c == '\016') {
|
||||
vt100->selected_charset = 0;
|
||||
return ;
|
||||
return;
|
||||
}
|
||||
if (c == '\017')
|
||||
{
|
||||
if (c == '\017') {
|
||||
vt100->selected_charset = 1;
|
||||
return ;
|
||||
return;
|
||||
}
|
||||
if (c < ' ') {
|
||||
return;
|
||||
}
|
||||
if (vt100->x == vt100->width)
|
||||
{
|
||||
if (vt100->x == vt100->width) {
|
||||
if (MODE_IS_SET(vt100, DECAWM))
|
||||
NEL(term_emul);
|
||||
else
|
||||
|
|
@ -1111,13 +1056,13 @@ static void vt100_write(struct lw_terminal *term_emul, char c) {
|
|||
if (vt100->ustate == 0) {
|
||||
if (uc < 0x80) {
|
||||
vt100_write_unicode(term_emul, uc);
|
||||
} else if((uc & 0xe0) == 0xc0) {
|
||||
} else if ((uc & 0xe0) == 0xc0) {
|
||||
vt100->ustate = 1;
|
||||
vt100->ubits = (uc & 0x1f);
|
||||
} else if((uc & 0xf0) == 0xe0) {
|
||||
} else if ((uc & 0xf0) == 0xe0) {
|
||||
vt100->ustate = 2;
|
||||
vt100->ubits = (uc & 0xf);
|
||||
} else if((uc & 0xf8) == 0xf0) {
|
||||
} else if ((uc & 0xf8) == 0xf0) {
|
||||
vt100->ustate = 3;
|
||||
vt100->ubits = (uc & 0x7);
|
||||
} else {
|
||||
|
|
@ -1135,12 +1080,12 @@ static void vt100_write(struct lw_terminal *term_emul, char c) {
|
|||
vt100->ubits <<= 6;
|
||||
vt100->ubits |= uc & 0x3f;
|
||||
if (--vt100->ustate == 0) {
|
||||
vt100_write_unicode(term_emul, vt100->ubits);
|
||||
vt100_write_unicode(term_emul, vt100->ubits);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
vt100_write_unicode(term_emul, uc);
|
||||
vt100_write_unicode(term_emul, uc);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1149,15 +1094,16 @@ static void vt100_write(struct lw_terminal *term_emul, char c) {
|
|||
#else
|
||||
#define __not_in_flash_func(x) x
|
||||
#endif
|
||||
const lw_cell_t *__not_in_flash_func(lw_terminal_vt100_getline)(struct lw_terminal_vt100 *vt100, unsigned int y) {
|
||||
const lw_cell_t *
|
||||
__not_in_flash_func(lw_terminal_vt100_getline)(struct lw_terminal_vt100 *vt100,
|
||||
unsigned int y) {
|
||||
if (y < vt100->margin_top || y > vt100->margin_bottom)
|
||||
return vt100->afrozen_screen + FROZEN_SCREEN_PTR(vt100, 0, y);
|
||||
else
|
||||
return vt100->ascreen + SCREEN_PTR(vt100, 0, y);
|
||||
}
|
||||
|
||||
const lw_cell_t **lw_terminal_vt100_getlines(struct lw_terminal_vt100 *vt100)
|
||||
{
|
||||
const lw_cell_t **lw_terminal_vt100_getlines(struct lw_terminal_vt100 *vt100) {
|
||||
unsigned int y;
|
||||
|
||||
for (y = 0; y < vt100->height; ++y)
|
||||
|
|
@ -1166,15 +1112,17 @@ const lw_cell_t **lw_terminal_vt100_getlines(struct lw_terminal_vt100 *vt100)
|
|||
}
|
||||
|
||||
static void setcells(lw_cell_t *buf, lw_cell_t c, size_t n) {
|
||||
for(;n--;buf++) *buf = c;
|
||||
for (; n--; buf++)
|
||||
*buf = c;
|
||||
}
|
||||
|
||||
struct lw_terminal_vt100 *lw_terminal_vt100_init(void *user_data,
|
||||
void (*unimplemented)(struct lw_terminal* term_emul, char *seq, char chr),
|
||||
void (*master_write)(void *user_data, void *buffer, size_t len),
|
||||
lw_cell_t (*encode_attr)(void *user_data, const struct lw_parsed_attr *attr),
|
||||
unsigned int width, unsigned int height)
|
||||
{
|
||||
struct lw_terminal_vt100 *lw_terminal_vt100_init(
|
||||
void *user_data,
|
||||
void (*unimplemented)(struct lw_terminal *term_emul, char *seq, char chr),
|
||||
void (*master_write)(void *user_data, void *buffer, size_t len),
|
||||
lw_cell_t (*encode_attr)(void *user_data,
|
||||
const struct lw_parsed_attr *attr),
|
||||
unsigned int width, unsigned int height) {
|
||||
struct lw_terminal_vt100 *this;
|
||||
|
||||
this = calloc(1, sizeof(*this));
|
||||
|
|
@ -1192,7 +1140,7 @@ struct lw_terminal_vt100 *lw_terminal_vt100_init(void *user_data,
|
|||
this->tabulations = malloc(132);
|
||||
if (this->tabulations == NULL)
|
||||
goto free_frozen_screen;
|
||||
for(int i=0; i<132; i++) {
|
||||
for (int i = 0; i < 132; i++) {
|
||||
this->tabulations[i] = (i && i % 8 == 0) ? '|' : '-';
|
||||
}
|
||||
this->margin_top = 0;
|
||||
|
|
@ -1234,7 +1182,8 @@ struct lw_terminal_vt100 *lw_terminal_vt100_init(void *user_data,
|
|||
this->master_write = master_write;
|
||||
this->encode_attr = encode_attr ? encode_attr : default_encode_attr;
|
||||
this->map_unicode = default_map_unicode;
|
||||
lw_terminal_vt100_read_str(this, "\033[m\033[?7h"); // set default attributes
|
||||
lw_terminal_vt100_read_str(this,
|
||||
"\033[m\033[?7h"); // set default attributes
|
||||
setcells(this->ascreen, ' ' | this->attr, 132 * SCROLLBACK * this->height);
|
||||
setcells(this->afrozen_screen, ' ' | this->attr, 132 * this->height);
|
||||
return this;
|
||||
|
|
@ -1253,7 +1202,7 @@ free_this:
|
|||
static void show_cursor(struct lw_terminal_vt100 *this) {
|
||||
unsigned x = this->x, y = this->y;
|
||||
lw_cell_t cell;
|
||||
if(x == this->width)
|
||||
if (x == this->width)
|
||||
x -= 1;
|
||||
if (x >= this->width || y >= this->height) {
|
||||
this->cursor_saved_flag = false;
|
||||
|
|
@ -1268,26 +1217,27 @@ static void show_cursor(struct lw_terminal_vt100 *this) {
|
|||
}
|
||||
|
||||
static void hide_cursor(struct lw_terminal_vt100 *this) {
|
||||
if (!this->cursor_saved_flag) { return; }
|
||||
if (!this->cursor_saved_flag) {
|
||||
return;
|
||||
}
|
||||
this->cursor_saved_flag = false;
|
||||
unsigned x = this->cursor_saved_x, y = this->cursor_saved_y;
|
||||
aset(this, x, y, aget(this, x, y) ^ CURSOR_ATTR);
|
||||
}
|
||||
|
||||
void lw_terminal_vt100_read_str(struct lw_terminal_vt100 *this, const char *buffer)
|
||||
{
|
||||
void lw_terminal_vt100_read_str(struct lw_terminal_vt100 *this,
|
||||
const char *buffer) {
|
||||
lw_terminal_vt100_read_buf(this, buffer, strlen(buffer));
|
||||
}
|
||||
|
||||
void lw_terminal_vt100_read_buf(struct lw_terminal_vt100 *this, const char *buffer, size_t len)
|
||||
{
|
||||
void lw_terminal_vt100_read_buf(struct lw_terminal_vt100 *this,
|
||||
const char *buffer, size_t len) {
|
||||
hide_cursor(this);
|
||||
lw_terminal_parser_read_buf(this->lw_terminal, buffer, len);
|
||||
show_cursor(this);
|
||||
}
|
||||
|
||||
void lw_terminal_vt100_destroy(struct lw_terminal_vt100 *this)
|
||||
{
|
||||
void lw_terminal_vt100_destroy(struct lw_terminal_vt100 *this) {
|
||||
lw_terminal_parser_destroy(this->lw_terminal);
|
||||
free(this->tabulations);
|
||||
free(this->ascreen);
|
||||
|
|
|
|||
|
|
@ -26,8 +26,8 @@
|
|||
#ifndef __LW_TERMINAL_VT100_H__
|
||||
#define __LW_TERMINAL_VT100_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "lw_terminal_parser.h"
|
||||
|
||||
|
|
@ -39,29 +39,28 @@
|
|||
|
||||
#define SCROLLBACK 3
|
||||
|
||||
#define MASK_LNM 1
|
||||
#define MASK_DECCKM 2
|
||||
#define MASK_DECANM 4
|
||||
#define MASK_LNM 1
|
||||
#define MASK_DECCKM 2
|
||||
#define MASK_DECANM 4
|
||||
#define MASK_DECCOLM 8
|
||||
#define MASK_DECSCLM 16
|
||||
#define MASK_DECSCNM 32
|
||||
#define MASK_DECOM 64
|
||||
#define MASK_DECAWM 128
|
||||
#define MASK_DECARM 256
|
||||
#define MASK_DECOM 64
|
||||
#define MASK_DECAWM 128
|
||||
#define MASK_DECARM 256
|
||||
#define MASK_DECINLM 512
|
||||
|
||||
#define LNM 20
|
||||
#define DECCKM 1
|
||||
#define DECANM 2
|
||||
#define LNM 20
|
||||
#define DECCKM 1
|
||||
#define DECANM 2
|
||||
#define DECCOLM 3
|
||||
#define DECSCLM 4
|
||||
#define DECSCNM 5
|
||||
#define DECOM 6
|
||||
#define DECAWM 7
|
||||
#define DECARM 8
|
||||
#define DECOM 6
|
||||
#define DECAWM 7
|
||||
#define DECARM 8
|
||||
#define DECINLM 9
|
||||
|
||||
|
||||
#define SET_MODE(vt100, mode) ((vt100)->modes |= get_mode_mask(mode))
|
||||
#define UNSET_MODE(vt100, mode) ((vt100)->modes &= ~get_mode_mask(mode))
|
||||
#define MODE_IS_SET(vt100, mode) ((vt100)->modes & get_mode_mask(mode))
|
||||
|
|
@ -73,7 +72,7 @@ struct lw_parsed_attr {
|
|||
bool blink, bold, inverse;
|
||||
};
|
||||
|
||||
#define LW_DEFAULT_ATTR ((struct lw_parsed_attr) { 7, 0, false, false, false })
|
||||
#define LW_DEFAULT_ATTR ((struct lw_parsed_attr){7, 0, false, false, false})
|
||||
|
||||
/*
|
||||
** frozen_screen is the frozen part of the screen
|
||||
|
|
@ -81,8 +80,7 @@ struct lw_parsed_attr {
|
|||
** The top of the frozen_screen holds the top margin
|
||||
** while the bottom holds the bottom margin.
|
||||
*/
|
||||
struct lw_terminal_vt100
|
||||
{
|
||||
struct lw_terminal_vt100 {
|
||||
struct lw_terminal *lw_terminal;
|
||||
int ustate, ubits;
|
||||
unsigned int width;
|
||||
|
|
@ -94,36 +92,42 @@ struct lw_terminal_vt100
|
|||
unsigned int margin_top;
|
||||
unsigned int margin_bottom;
|
||||
unsigned int top_line; /* Line at the top of the display */
|
||||
lw_cell_t *ascreen;
|
||||
lw_cell_t *afrozen_screen;
|
||||
char *tabulations;
|
||||
bool unicode;
|
||||
lw_cell_t *ascreen;
|
||||
lw_cell_t *afrozen_screen;
|
||||
char *tabulations;
|
||||
bool unicode;
|
||||
bool cursor_saved_flag;
|
||||
unsigned int selected_charset;
|
||||
unsigned int modes;
|
||||
struct lw_parsed_attr parsed_attr;
|
||||
lw_cell_t attr;
|
||||
lw_cell_t attr;
|
||||
int cursor_saved_x, cursor_saved_y;
|
||||
const lw_cell_t *alines[80];
|
||||
void (*master_write)(void *user_data, void *buffer, size_t len);
|
||||
lw_cell_t (*encode_attr)(void *user_data, const struct lw_parsed_attr *attr);
|
||||
int (*map_unicode)(void *user_data, int c);
|
||||
void *user_data;
|
||||
const lw_cell_t *alines[80];
|
||||
void (*master_write)(void *user_data, void *buffer, size_t len);
|
||||
lw_cell_t (*encode_attr)(void *user_data,
|
||||
const struct lw_parsed_attr *attr);
|
||||
int (*map_unicode)(void *user_data, int c);
|
||||
void *user_data;
|
||||
};
|
||||
|
||||
struct lw_terminal_vt100 *lw_terminal_vt100_init(void *user_data,
|
||||
void (*unimplemented)(struct lw_terminal* term_emul,
|
||||
char *seq, char chr),
|
||||
void (*master_write)(void *user_data, void *buffer, size_t len),
|
||||
lw_cell_t (*encode_attr)(void *user_data,
|
||||
const struct lw_parsed_attr *attr),
|
||||
unsigned int width, unsigned int height);
|
||||
char lw_terminal_vt100_get(struct lw_terminal_vt100 *vt100, unsigned int x, unsigned int y);
|
||||
lw_cell_t lw_terminal_vt100_aget(struct lw_terminal_vt100 *vt100, unsigned int x, unsigned int y);
|
||||
const lw_cell_t *lw_terminal_vt100_getline(struct lw_terminal_vt100 *vt100, unsigned y);
|
||||
struct lw_terminal_vt100 *lw_terminal_vt100_init(
|
||||
void *user_data,
|
||||
void (*unimplemented)(struct lw_terminal *term_emul, char *seq, char chr),
|
||||
void (*master_write)(void *user_data, void *buffer, size_t len),
|
||||
lw_cell_t (*encode_attr)(void *user_data,
|
||||
const struct lw_parsed_attr *attr),
|
||||
unsigned int width, unsigned int height);
|
||||
char lw_terminal_vt100_get(struct lw_terminal_vt100 *vt100, unsigned int x,
|
||||
unsigned int y);
|
||||
lw_cell_t lw_terminal_vt100_aget(struct lw_terminal_vt100 *vt100,
|
||||
unsigned int x, unsigned int y);
|
||||
const lw_cell_t *lw_terminal_vt100_getline(struct lw_terminal_vt100 *vt100,
|
||||
unsigned y);
|
||||
const lw_cell_t **lw_terminal_vt100_getlines(struct lw_terminal_vt100 *vt100);
|
||||
void lw_terminal_vt100_destroy(struct lw_terminal_vt100 *this);
|
||||
void lw_terminal_vt100_read_str(struct lw_terminal_vt100 *this, const char *buffer);
|
||||
void lw_terminal_vt100_read_buf(struct lw_terminal_vt100 *this, const char *buffer, size_t n);
|
||||
void lw_terminal_vt100_read_str(struct lw_terminal_vt100 *this,
|
||||
const char *buffer);
|
||||
void lw_terminal_vt100_read_buf(struct lw_terminal_vt100 *this,
|
||||
const char *buffer, size_t n);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -23,23 +23,21 @@
|
|||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <utmp.h>
|
||||
#include <string.h>
|
||||
#include "hl_vt100.h"
|
||||
#include <pty.h>
|
||||
#include <stdio.h>
|
||||
#include "hl_vt100.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <utmp.h>
|
||||
|
||||
void disp(struct vt100_headless *vt100)
|
||||
{
|
||||
void disp(struct vt100_headless *vt100) {
|
||||
unsigned int x, y;
|
||||
const lw_cell_t **lines;
|
||||
|
||||
lines = vt100_headless_getlines(vt100);
|
||||
write(1, "\n", 1);
|
||||
for (y = 0; y < vt100->term->height; ++y)
|
||||
{
|
||||
for (y = 0; y < vt100->term->height; ++y) {
|
||||
write(1, "|", 1);
|
||||
for (x = 0; x < vt100->term->width; x++) {
|
||||
write(1, &lines[y][x], 1);
|
||||
|
|
@ -48,12 +46,10 @@ void disp(struct vt100_headless *vt100)
|
|||
}
|
||||
}
|
||||
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
int main(int ac, char **av) {
|
||||
struct vt100_headless *vt100_headless;
|
||||
|
||||
if (ac == 1)
|
||||
{
|
||||
if (ac == 1) {
|
||||
puts("Usage: test PROGNAME");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,39 +12,33 @@
|
|||
other files, you'll have to create a file "foobarobject.h"; see
|
||||
floatobject.h for an example. */
|
||||
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "Python.h"
|
||||
#include "structmember.h"
|
||||
|
||||
#include "lw_terminal_vt100.h"
|
||||
#include "hl_vt100.h"
|
||||
#include "lw_terminal_vt100.h"
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
struct vt100_headless *obj;
|
||||
PyObject_HEAD struct vt100_headless *obj;
|
||||
PyObject *changed_callback;
|
||||
} VT100Object;
|
||||
|
||||
static PyTypeObject VT100_Type;
|
||||
|
||||
#define VT100Object_Check(v) Py_IS_TYPE(v, &VT100_Type)
|
||||
|
||||
#define VT100Object_Check(v) Py_IS_TYPE(v, &VT100_Type)
|
||||
|
||||
VT100Object **allocated;
|
||||
size_t allocated_size;
|
||||
|
||||
/* VT100 methods */
|
||||
|
||||
PyDoc_STRVAR(vt100_headless_fork_doc,
|
||||
"fork(progname, argv)\n\
|
||||
PyDoc_STRVAR(vt100_headless_fork_doc, "fork(progname, argv)\n\
|
||||
\n\
|
||||
Fork a process in a new PTY handled by an headless VT100 emulator.");
|
||||
|
||||
static PyObject *
|
||||
VT100_fork(VT100Object *self, PyObject *args)
|
||||
{
|
||||
static PyObject *VT100_fork(VT100Object *self, PyObject *args) {
|
||||
char *progname;
|
||||
PyObject *pyargv;
|
||||
const char **argv;
|
||||
|
|
@ -53,17 +47,14 @@ VT100_fork(VT100Object *self, PyObject *args)
|
|||
|
||||
if (!PyArg_ParseTuple(args, "sO:fork", &progname, &pyargv))
|
||||
return NULL;
|
||||
if (!PyList_Check(pyargv))
|
||||
{
|
||||
if (!PyList_Check(pyargv)) {
|
||||
PyErr_SetString(PyExc_TypeError, "not a list");
|
||||
return NULL;
|
||||
}
|
||||
argc = PyList_Size(pyargv);
|
||||
for (i = 0; i < argc; i++)
|
||||
{
|
||||
for (i = 0; i < argc; i++) {
|
||||
PyObject *o = PyList_GetItem(pyargv, i);
|
||||
if (!PyUnicode_Check(o))
|
||||
{
|
||||
if (!PyUnicode_Check(o)) {
|
||||
PyErr_SetString(PyExc_TypeError, "argv list must contain strings");
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -77,14 +68,12 @@ VT100_fork(VT100Object *self, PyObject *args)
|
|||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(vt100_headless_getattrlines_doc,
|
||||
"getattrlines()\n\
|
||||
PyDoc_STRVAR(vt100_headless_getattrlines_doc, "getattrlines()\n\
|
||||
\n\
|
||||
Get a list of lines (with attributes) as currently seen by the emulator.");
|
||||
|
||||
static PyObject *
|
||||
VT100_getattrlines(VT100Object *self, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
static PyObject *VT100_getattrlines(VT100Object *self,
|
||||
PyObject *Py_UNUSED(ignored)) {
|
||||
const lw_cell_t **lines;
|
||||
PyObject *result;
|
||||
|
||||
|
|
@ -111,14 +100,12 @@ VT100_getattrlines(VT100Object *self, PyObject *Py_UNUSED(ignored))
|
|||
return result;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(vt100_headless_getlines_doc,
|
||||
"getlines()\n\
|
||||
PyDoc_STRVAR(vt100_headless_getlines_doc, "getlines()\n\
|
||||
\n\
|
||||
Get a list of lines as currently seen by the emulator.");
|
||||
|
||||
static PyObject *
|
||||
VT100_getlines(VT100Object *self, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
static PyObject *VT100_getlines(VT100Object *self,
|
||||
PyObject *Py_UNUSED(ignored)) {
|
||||
const lw_cell_t **lines;
|
||||
PyObject *result;
|
||||
|
||||
|
|
@ -140,63 +127,48 @@ VT100_getlines(VT100Object *self, PyObject *Py_UNUSED(ignored))
|
|||
return result;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(vt100_headless_main_loop_doc,
|
||||
"main_loop()\n\
|
||||
PyDoc_STRVAR(vt100_headless_main_loop_doc, "main_loop()\n\
|
||||
\n\
|
||||
Enter the emulator main loop.");
|
||||
|
||||
static PyObject *
|
||||
VT100_main_loop(VT100Object *self, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
static PyObject *VT100_main_loop(VT100Object *self,
|
||||
PyObject *Py_UNUSED(ignored)) {
|
||||
vt100_headless_main_loop(self->obj);
|
||||
if (PyErr_Occurred())
|
||||
return NULL;
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
PyDoc_STRVAR(vt100_headless_stop_doc,
|
||||
"stop()\n\
|
||||
PyDoc_STRVAR(vt100_headless_stop_doc, "stop()\n\
|
||||
\n\
|
||||
Stop emulator main loop.");
|
||||
|
||||
static PyObject *
|
||||
VT100_stop(VT100Object *self, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
static PyObject *VT100_stop(VT100Object *self, PyObject *Py_UNUSED(ignored)) {
|
||||
vt100_headless_stop(self->obj);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
vt100_add_to_allocated(VT100Object *obj)
|
||||
{
|
||||
for (size_t i = 0; i < allocated_size; i++)
|
||||
{
|
||||
if (allocated[i] == NULL)
|
||||
{
|
||||
static int vt100_add_to_allocated(VT100Object *obj) {
|
||||
for (size_t i = 0; i < allocated_size; i++) {
|
||||
if (allocated[i] == NULL) {
|
||||
allocated[i] = obj;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* Out of allocated memory, realloc. */
|
||||
allocated_size *= 2;
|
||||
allocated = PyMem_Realloc(allocated, allocated_size * sizeof(VT100Object*));
|
||||
if (allocated == NULL)
|
||||
{
|
||||
allocated =
|
||||
PyMem_Realloc(allocated, allocated_size * sizeof(VT100Object *));
|
||||
if (allocated == NULL) {
|
||||
PyErr_SetString(PyExc_MemoryError, "cannot allocate vt100 emulator");
|
||||
return -1;
|
||||
}
|
||||
return vt100_add_to_allocated(obj);
|
||||
}
|
||||
|
||||
static int
|
||||
vt100_del_from_allocated(VT100Object *obj)
|
||||
{
|
||||
for (size_t i = 0; i < allocated_size; i++)
|
||||
{
|
||||
if (allocated[i] == obj)
|
||||
{
|
||||
static int vt100_del_from_allocated(VT100Object *obj) {
|
||||
for (size_t i = 0; i < allocated_size; i++) {
|
||||
if (allocated[i] == obj) {
|
||||
allocated[i] = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -204,59 +176,45 @@ vt100_del_from_allocated(VT100Object *obj)
|
|||
return -1;
|
||||
}
|
||||
|
||||
VT100Object *
|
||||
vt100_find_in_allocated(struct vt100_headless *obj)
|
||||
{
|
||||
VT100Object *vt100_find_in_allocated(struct vt100_headless *obj) {
|
||||
for (size_t i = 0; i < allocated_size; i++)
|
||||
if (allocated[i]->obj == obj)
|
||||
return allocated[i];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
hl_vt100_changed_cb(struct vt100_headless *this)
|
||||
{
|
||||
void hl_vt100_changed_cb(struct vt100_headless *this) {
|
||||
VT100Object *obj;
|
||||
PyObject *result;
|
||||
|
||||
obj = vt100_find_in_allocated(this);
|
||||
if (obj->changed_callback != NULL && obj->changed_callback != Py_None)
|
||||
{
|
||||
if (obj->changed_callback != NULL && obj->changed_callback != Py_None) {
|
||||
result = PyObject_CallNoArgs(obj->changed_callback);
|
||||
if (result == NULL)
|
||||
this->should_quit = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
VT100_init(VT100Object *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
static int VT100_init(VT100Object *self, PyObject *args, PyObject *kwds) {
|
||||
self->obj = new_vt100_headless();
|
||||
vt100_add_to_allocated(self);
|
||||
self->obj->changed = hl_vt100_changed_cb;
|
||||
if (self->obj == NULL)
|
||||
{
|
||||
if (self->obj == NULL) {
|
||||
PyErr_SetString(PyExc_MemoryError, "cannot allocate vt100 emulator");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
VT100_getwidth(VT100Object *self, void *closure)
|
||||
{
|
||||
static PyObject *VT100_getwidth(VT100Object *self, void *closure) {
|
||||
return PyLong_FromUnsignedLong(self->obj->term->width);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
VT100_getheight(VT100Object *self, void *closure)
|
||||
{
|
||||
static PyObject *VT100_getheight(VT100Object *self, void *closure) {
|
||||
return PyLong_FromUnsignedLong(self->obj->term->height);
|
||||
}
|
||||
|
||||
static void
|
||||
VT100_dealloc(VT100Object *self)
|
||||
{
|
||||
static void VT100_dealloc(VT100Object *self) {
|
||||
vt100_del_from_allocated(self);
|
||||
Py_XDECREF(self->changed_callback);
|
||||
delete_vt100_headless(self->obj);
|
||||
|
|
@ -264,30 +222,31 @@ VT100_dealloc(VT100Object *self)
|
|||
}
|
||||
|
||||
static PyMethodDef VT100_methods[] = {
|
||||
{"fork", (PyCFunction)VT100_fork, METH_VARARGS, vt100_headless_fork_doc},
|
||||
{"getlines", (PyCFunction)VT100_getlines, METH_NOARGS, vt100_headless_getlines_doc},
|
||||
{"getattrlines", (PyCFunction)VT100_getattrlines, METH_NOARGS, vt100_headless_getattrlines_doc},
|
||||
{"main_loop", (PyCFunction)VT100_main_loop, METH_NOARGS, vt100_headless_main_loop_doc},
|
||||
{"stop", (PyCFunction)VT100_stop, METH_NOARGS, vt100_headless_stop_doc},
|
||||
{NULL, NULL} /* sentinel */
|
||||
{"fork", (PyCFunction)VT100_fork, METH_VARARGS, vt100_headless_fork_doc},
|
||||
{"getlines", (PyCFunction)VT100_getlines, METH_NOARGS,
|
||||
vt100_headless_getlines_doc},
|
||||
{"getattrlines", (PyCFunction)VT100_getattrlines, METH_NOARGS,
|
||||
vt100_headless_getattrlines_doc},
|
||||
{"main_loop", (PyCFunction)VT100_main_loop, METH_NOARGS,
|
||||
vt100_headless_main_loop_doc},
|
||||
{"stop", (PyCFunction)VT100_stop, METH_NOARGS, vt100_headless_stop_doc},
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
|
||||
static PyMemberDef VT100_members[] = {
|
||||
{"changed_callback", T_OBJECT_EX, offsetof(VT100Object, changed_callback), 0,
|
||||
"Changed Callback"},
|
||||
{NULL} /* Sentinel */
|
||||
{"changed_callback", T_OBJECT_EX, offsetof(VT100Object, changed_callback),
|
||||
0, "Changed Callback"},
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
static PyGetSetDef VT100_getsetters[] = {
|
||||
{"width", (getter) VT100_getwidth, NULL, "Terminal width", NULL},
|
||||
{"height", (getter) VT100_getheight, NULL, "Terminal height", NULL},
|
||||
{NULL} /* Sentinel */
|
||||
{"width", (getter)VT100_getwidth, NULL, "Terminal width", NULL},
|
||||
{"height", (getter)VT100_getheight, NULL, "Terminal height", NULL},
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
static PyTypeObject VT100_Type = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
.tp_name = "hl_vt100.vt100_headless",
|
||||
PyVarObject_HEAD_INIT(NULL, 0).tp_name = "hl_vt100.vt100_headless",
|
||||
.tp_basicsize = sizeof(VT100Object),
|
||||
.tp_dealloc = (destructor)VT100_dealloc,
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
|
||||
|
|
@ -298,8 +257,7 @@ static PyTypeObject VT100_Type = {
|
|||
.tp_getset = VT100_getsetters,
|
||||
};
|
||||
|
||||
PyDoc_STRVAR(module_doc,
|
||||
"Headless VT100 Terminal Emulator.");
|
||||
PyDoc_STRVAR(module_doc, "Headless VT100 Terminal Emulator.");
|
||||
|
||||
static struct PyModuleDef hl_vt100_module = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
|
|
@ -307,13 +265,11 @@ static struct PyModuleDef hl_vt100_module = {
|
|||
.m_doc = module_doc,
|
||||
};
|
||||
|
||||
PyMODINIT_FUNC
|
||||
PyInit_hl_vt100(void)
|
||||
{
|
||||
PyMODINIT_FUNC PyInit_hl_vt100(void) {
|
||||
PyObject *m;
|
||||
|
||||
m = PyModule_Create(&hl_vt100_module);
|
||||
allocated = PyMem_Calloc(4096, sizeof(VT100Object*));
|
||||
allocated = PyMem_Calloc(4096, sizeof(VT100Object *));
|
||||
allocated_size = 4096;
|
||||
if (m == NULL)
|
||||
return NULL;
|
||||
|
|
|
|||
120
keyboard.c
120
keyboard.c
|
|
@ -1,11 +1,11 @@
|
|||
#include "atkbd.pio.h"
|
||||
#include "keyboard.h"
|
||||
#include "pinout.h"
|
||||
#include "atkbd.pio.h"
|
||||
#include "chargen.h"
|
||||
#include "pinout.h"
|
||||
|
||||
#include "hardware/clocks.h"
|
||||
#include "pico.h"
|
||||
#include "pico/stdlib.h"
|
||||
#include "hardware/clocks.h"
|
||||
|
||||
#define EOF (-1)
|
||||
|
||||
|
|
@ -18,14 +18,18 @@ static int kbd_sm;
|
|||
static int ll_kbd_read_timeout(int timeout_us) {
|
||||
uint64_t deadline = time_us_64() + timeout_us;
|
||||
while (pio_sm_is_rx_fifo_empty(kbd_pio, kbd_sm)) {
|
||||
if(time_us_64() > deadline) { return EOF; }
|
||||
if (time_us_64() > deadline) {
|
||||
return EOF;
|
||||
}
|
||||
}
|
||||
return pio_sm_get_blocking(kbd_pio, kbd_sm);
|
||||
}
|
||||
|
||||
static int kbd_read_timeout(int timeout_us) {
|
||||
int r = ll_kbd_read_timeout(timeout_us);
|
||||
if (r == EOF) { return EOF; }
|
||||
if (r == EOF) {
|
||||
return EOF;
|
||||
}
|
||||
r = (r >> 22) & 0xff;
|
||||
return r; // todo: check parity, start & end bits!
|
||||
}
|
||||
|
|
@ -54,7 +58,6 @@ static bool write_expect_fa(int value, const char *msg) {
|
|||
pio_sm_clear_fifos(kbd_pio, kbd_sm);
|
||||
kbd_write_blocking(value);
|
||||
return expect(0xfa, msg);
|
||||
|
||||
}
|
||||
bool keyboard_setup(PIO pio) {
|
||||
gpio_init(KEYBOARD_DATA_PIN);
|
||||
|
|
@ -64,8 +67,8 @@ bool keyboard_setup(PIO pio) {
|
|||
gpio_pull_down(KEYBOARD_DATA_PIN + 1);
|
||||
|
||||
int i = 0, j = 1;
|
||||
while(!(gpio_get(KEYBOARD_DATA_PIN) && gpio_get(KEYBOARD_DATA_PIN + 1))) {
|
||||
if(i ++ == j) {
|
||||
while (!(gpio_get(KEYBOARD_DATA_PIN) && gpio_get(KEYBOARD_DATA_PIN + 1))) {
|
||||
if (i++ == j) {
|
||||
scrnprintf("Waiting for keyboard to boot... %d ms so far\r", i);
|
||||
j *= 10;
|
||||
}
|
||||
|
|
@ -99,17 +102,20 @@ bool keyboard_setup(PIO pio) {
|
|||
return ok;
|
||||
}
|
||||
|
||||
|
||||
enum { LSHIFT=1, LCTRL=2, LALT=4, RSHIFT = 8, RCTRL = 16, RALT = 32, MOD_CAPS=64, MOD_NUM = 128, TOGGLING_MODIFIERS = MOD_CAPS | MOD_NUM };
|
||||
enum {
|
||||
LSHIFT = 1,
|
||||
LCTRL = 2,
|
||||
LALT = 4,
|
||||
RSHIFT = 8,
|
||||
RCTRL = 16,
|
||||
RALT = 32,
|
||||
MOD_CAPS = 64,
|
||||
MOD_NUM = 128,
|
||||
TOGGLING_MODIFIERS = MOD_CAPS | MOD_NUM
|
||||
};
|
||||
const char keyboard_modifiers[256] = {
|
||||
[0x12] = LSHIFT,
|
||||
[0x59] = RSHIFT,
|
||||
[0x11] = LCTRL,
|
||||
[0x58] = RCTRL,
|
||||
[0x19] = LALT,
|
||||
[0x39] = RALT,
|
||||
[0x14] = MOD_CAPS,
|
||||
[0x76] = MOD_NUM,
|
||||
[0x12] = LSHIFT, [0x59] = RSHIFT, [0x11] = LCTRL, [0x58] = RCTRL,
|
||||
[0x19] = LALT, [0x39] = RALT, [0x14] = MOD_CAPS, [0x76] = MOD_NUM,
|
||||
};
|
||||
|
||||
enum SYMBOLS {
|
||||
|
|
@ -143,37 +149,21 @@ enum SYMBOLS {
|
|||
|
||||
const char *const symtab[MAX_SYMBOLS] = {
|
||||
#define ENT(x, y) [x] = y
|
||||
ENT(F1, "\eOP"),
|
||||
ENT(F2, "\eOQ"),
|
||||
ENT(F3, "\eOR"),
|
||||
ENT(F4, "\eOS"),
|
||||
ENT(F5, "\e[15~"),
|
||||
ENT(F6, "\e[17~"),
|
||||
ENT(F7, "\e[18~"),
|
||||
ENT(F8, "\e[19~"),
|
||||
ENT(F9, "\e[20~"),
|
||||
ENT(F10, "\e[21~"),
|
||||
ENT(F11, "\e[23~"),
|
||||
ENT(F12, "\e[24~"),
|
||||
ENT(PRTSCR, "\ei"),
|
||||
ENT(PAUSE, ""),
|
||||
ENT(INSERT, "\e[2~"),
|
||||
ENT(DELETE, "\e[3~"),
|
||||
ENT(UPARROW, "\e[A"),
|
||||
ENT(DOWNARROW, "\e[B"),
|
||||
ENT(RIGHTARROW, "\e[C"),
|
||||
ENT(LEFTARROW, "\e[D"),
|
||||
ENT(HOME, "\e[H"),
|
||||
ENT(END, "\e[F"),
|
||||
ENT(PAGEUP, "\e[5~"),
|
||||
ENT(PAGEDOWN, "\e[6~"),
|
||||
ENT(F1, "\eOP"), ENT(F2, "\eOQ"), ENT(F3, "\eOR"),
|
||||
ENT(F4, "\eOS"), ENT(F5, "\e[15~"), ENT(F6, "\e[17~"),
|
||||
ENT(F7, "\e[18~"), ENT(F8, "\e[19~"), ENT(F9, "\e[20~"),
|
||||
ENT(F10, "\e[21~"), ENT(F11, "\e[23~"), ENT(F12, "\e[24~"),
|
||||
ENT(PRTSCR, "\ei"), ENT(PAUSE, ""), ENT(INSERT, "\e[2~"),
|
||||
ENT(DELETE, "\e[3~"), ENT(UPARROW, "\e[A"), ENT(DOWNARROW, "\e[B"),
|
||||
ENT(RIGHTARROW, "\e[C"), ENT(LEFTARROW, "\e[D"), ENT(HOME, "\e[H"),
|
||||
ENT(END, "\e[F"), ENT(PAGEUP, "\e[5~"), ENT(PAGEDOWN, "\e[6~"),
|
||||
#undef ENT
|
||||
};
|
||||
|
||||
#define SYM(x) (0x8000 | (int)(x))
|
||||
#define CMD(x) (0xc000 | (int)(x))
|
||||
#define CHAR2(c, d) (int) c | (((int) d) << 8)
|
||||
#define CHAR2(c, d) (int) c | (((int) d) << 8)
|
||||
#define CHAR2(c, d) (int)c | (((int)d) << 8)
|
||||
#define CHAR2(c, d) (int)c | (((int)d) << 8)
|
||||
#define ALPHA(c) CHAR2(c, c ^ ('a' ^ 'A'))
|
||||
#define NOMOD(c) CHAR2(c, c)
|
||||
|
||||
|
|
@ -260,7 +250,6 @@ const uint16_t keyboard_codes[256] = {
|
|||
[0x6a] = SYM(RIGHTARROW),
|
||||
[0x60] = SYM(DOWNARROW),
|
||||
|
||||
|
||||
[0x6e] = SYM(HOME),
|
||||
[0x65] = SYM(END),
|
||||
[0x6f] = SYM(PAGEUP),
|
||||
|
|
@ -275,20 +264,19 @@ static void queue_add_data(queue_t *q, int data) {
|
|||
}
|
||||
|
||||
static void queue_add_str(queue_t *q, const char *s) {
|
||||
while(*s) queue_add_data(q, *s++);
|
||||
while (*s)
|
||||
queue_add_data(q, *s++);
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
void queue_handle_event(queue_t *q, bool release, int value) {
|
||||
static void queue_handle_event(queue_t *q, bool release, int value) {
|
||||
int modifiers = keyboard_modifiers[value];
|
||||
if (modifiers) {
|
||||
if(release) {
|
||||
if (release) {
|
||||
if (modifiers & TOGGLING_MODIFIERS) {
|
||||
current_modifiers ^= modifiers;
|
||||
keyboard_set_leds(
|
||||
((current_modifiers & MOD_NUM) ? LED_NUM : 0) |
|
||||
((current_modifiers & MOD_CAPS) ? LED_CAPS : 0));
|
||||
((current_modifiers & MOD_NUM) ? LED_NUM : 0) |
|
||||
((current_modifiers & MOD_CAPS) ? LED_CAPS : 0));
|
||||
} else {
|
||||
current_modifiers &= ~modifiers;
|
||||
}
|
||||
|
|
@ -301,7 +289,9 @@ void queue_handle_event(queue_t *q, bool release, int value) {
|
|||
}
|
||||
return;
|
||||
}
|
||||
if(release) { return; }
|
||||
if (release) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool is_shift = current_modifiers & (LSHIFT | RSHIFT);
|
||||
bool is_ctrl = current_modifiers & (LCTRL | RCTRL);
|
||||
|
|
@ -309,19 +299,19 @@ void queue_handle_event(queue_t *q, bool release, int value) {
|
|||
bool is_caps = current_modifiers & (MOD_CAPS);
|
||||
|
||||
int kc = keyboard_codes[value];
|
||||
if(!kc) {
|
||||
if (!kc) {
|
||||
scrnprintf("\r\nUn-mapped key: 0x%02x\r\n", value);
|
||||
return;
|
||||
}
|
||||
|
||||
if((kc & 0xc000) == 0xc000) {
|
||||
if ((kc & 0xc000) == 0xc000) {
|
||||
queue_add_data(q, kc);
|
||||
return;
|
||||
}
|
||||
|
||||
if(kc & 0x8000) {
|
||||
if (kc & 0x8000) {
|
||||
int sym = kc & 0x7fff;
|
||||
if(is_ctrl && is_alt) {
|
||||
if (is_ctrl && is_alt) {
|
||||
if (sym == DELETE) {
|
||||
queue_add_data(q, CMD_REBOOT);
|
||||
}
|
||||
|
|
@ -342,19 +332,20 @@ void queue_handle_event(queue_t *q, bool release, int value) {
|
|||
|
||||
int c = LO(kc);
|
||||
// scrnprintf("c=%d HI=%d is_shift=%d\n", c, HI(kc), is_shift);
|
||||
if(HI(kc) && is_shift) c = HI(kc);
|
||||
if (HI(kc) && is_shift)
|
||||
c = HI(kc);
|
||||
#define CTRLABLE(c) (c >= 64 && c <= 127)
|
||||
if(is_ctrl && CTRLABLE(c)) {
|
||||
if (is_ctrl && CTRLABLE(c)) {
|
||||
c = c & 0x1f;
|
||||
}
|
||||
if(is_ctrl && c == 010) {
|
||||
if (is_ctrl && c == 010) {
|
||||
c = 0377; // ctrl-backspace = RUBOUT
|
||||
}
|
||||
#define IS_ALPHA(c) ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
|
||||
if(is_caps && IS_ALPHA(c)) {
|
||||
if (is_caps && IS_ALPHA(c)) {
|
||||
c ^= ('a' ^ 'A');
|
||||
}
|
||||
if(is_alt) {
|
||||
if (is_alt) {
|
||||
queue_add_data(q, '\033');
|
||||
}
|
||||
queue_add_data(q, c);
|
||||
|
|
@ -364,9 +355,8 @@ void keyboard_poll(queue_t *q) {
|
|||
int value = kbd_read_timeout(0);
|
||||
if (value == EOF) {
|
||||
return;
|
||||
}
|
||||
else if (value == 0xfa) {
|
||||
if(pending_led_flag) {
|
||||
} else if (value == 0xfa) {
|
||||
if (pending_led_flag) {
|
||||
kbd_write_blocking(pending_led_value);
|
||||
pending_led_flag = false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ class TTF:
|
|||
s = struct.calcsize(format)
|
||||
return struct.unpack_from(format, f.read(s))
|
||||
|
||||
scalar_type = read(">I")
|
||||
read(">I") # discard "scalar_type
|
||||
numTables, searchRange, entrySelector, rangeShift = read(">HHHH")
|
||||
|
||||
print(numTables)
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import array
|
||||
from dataclasses import dataclass
|
||||
import sys
|
||||
|
||||
import click
|
||||
from adafruit_bitmap_font import bitmap_font, Bitmap
|
||||
|
||||
|
||||
def extract_deposit_bits(*positions):
|
||||
data_out = 0
|
||||
for p in positions:
|
||||
|
|
@ -13,6 +13,7 @@ def extract_deposit_bits(*positions):
|
|||
data_out |= 1 << dest
|
||||
return data_out
|
||||
|
||||
|
||||
class OffsetBitmap:
|
||||
def __init__(self, dx, dy, glyph):
|
||||
self.dx = dx
|
||||
|
|
@ -26,21 +27,22 @@ class OffsetBitmap:
|
|||
|
||||
print(pos, x, y)
|
||||
if 0 <= x < self.glyph.bitmap.width and 0 <= y < self.glyph.bitmap.height:
|
||||
return self.glyph.bitmap[x,y]
|
||||
return self.glyph.bitmap[x, y]
|
||||
return 0
|
||||
|
||||
|
||||
@click.command
|
||||
@click.argument("bdf", type=click.Path(exists=True))
|
||||
@click.argument("header", type=click.File(mode='w'), default=sys.stdout)
|
||||
@click.argument("header", type=click.File(mode="w"), default=sys.stdout)
|
||||
def main(bdf, header):
|
||||
font = bitmap_font.load_font(bdf, Bitmap)
|
||||
width, height, dx, dy = font.get_bounding_box()
|
||||
|
||||
print(width, height, dx, dy)
|
||||
# if width != 5 or height != 9:
|
||||
# raise SystemExit("sorry, only 5x9 monospace fonts supported")
|
||||
# if width != 5 or height != 9:
|
||||
# raise SystemExit("sorry, only 5x9 monospace fonts supported")
|
||||
|
||||
output_data = array.array('H', [0] * 9 * 256)
|
||||
output_data = array.array("H", [0] * 9 * 256)
|
||||
|
||||
font.load_glyphs(range(256))
|
||||
|
||||
|
|
@ -56,9 +58,11 @@ def main(bdf, header):
|
|||
(bitmap[3, j], 2, 3),
|
||||
(bitmap[2, j], 4, 5),
|
||||
(bitmap[1, j], 6, 7),
|
||||
(bitmap[0, j], 8, 9))
|
||||
(bitmap[0, j], 8, 9),
|
||||
)
|
||||
output_data[j * 256 + i] = d << 2
|
||||
print(", ".join(f"0x{x:04x}" for x in output_data), file=header)
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
|
|||
174
vgamode.py
174
vgamode.py
|
|
@ -1,13 +1,14 @@
|
|||
#!/usr/bin/env python
|
||||
import sys
|
||||
|
||||
from enum import Enum, auto
|
||||
from dataclasses import dataclass, replace
|
||||
|
||||
|
||||
class Polarity:
|
||||
Negative = 0
|
||||
Positive = 1
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class VideoMode:
|
||||
pixel_clock_khz: int
|
||||
|
|
@ -20,7 +21,9 @@ class VideoMode:
|
|||
|
||||
@property
|
||||
def total_width(self):
|
||||
return self.visible_width + self.hfront_porch + self.hsync_pulse + self.hback_porch
|
||||
return (
|
||||
self.visible_width + self.hfront_porch + self.hsync_pulse + self.hback_porch
|
||||
)
|
||||
|
||||
@property
|
||||
def line_rate_khz(self):
|
||||
|
|
@ -42,7 +45,12 @@ class VideoMode:
|
|||
|
||||
@property
|
||||
def total_lines(self):
|
||||
return self.visible_height + self.vfront_porch + self.vsync_pulse + self.vback_porch
|
||||
return (
|
||||
self.visible_height
|
||||
+ self.vfront_porch
|
||||
+ self.vsync_pulse
|
||||
+ self.vback_porch
|
||||
)
|
||||
|
||||
@property
|
||||
def frame_rate_hz(self):
|
||||
|
|
@ -55,17 +63,18 @@ class VideoMode:
|
|||
def __repr__(self):
|
||||
return f"<VideoMode {self.visible_width}x{self.visible_height} {self.line_rate_khz:.2f}kHz/{self.frame_rate_hz:.2f}Hz pclk={self.pixel_clock_khz:.0f}KHz hvis={self.visible_line_time_us:.2f}us>"
|
||||
|
||||
|
||||
def change_visible_width(mode_in, new_w, new_clock=None):
|
||||
print(mode_in)
|
||||
if new_clock is None:
|
||||
new_clock = mode_in.pixel_clock_khz * new_w / mode_in.visible_width
|
||||
new_mode = replace(mode_in,
|
||||
pixel_clock_khz = new_clock,
|
||||
visible_width = new_w,
|
||||
new_clock = mode_in.pixel_clock_khz * new_w / mode_in.visible_width
|
||||
new_mode = replace(
|
||||
mode_in,
|
||||
pixel_clock_khz=new_clock,
|
||||
visible_width=new_w,
|
||||
)
|
||||
print(new_mode)
|
||||
ratio = new_clock / mode_in.pixel_clock_khz
|
||||
new_visible_time = new_mode.visible_line_time_us
|
||||
new_line_counts = round(mode_in.total_width * ratio)
|
||||
print(new_line_counts, mode_in.total_width * ratio)
|
||||
new_pulse = round(mode_in.hsync_pulse * ratio)
|
||||
|
|
@ -73,29 +82,35 @@ def change_visible_width(mode_in, new_w, new_clock=None):
|
|||
porch_ratio = mode_in.hfront_porch / (mode_in.hfront_porch + mode_in.hback_porch)
|
||||
new_front = round(new_porch_counts * porch_ratio)
|
||||
new_back = new_porch_counts - new_front
|
||||
print((mode_in.hfront_porch, mode_in.hsync_pulse, mode_in.hback_porch), "->", (new_front, new_pulse, new_back))
|
||||
print(
|
||||
(mode_in.hfront_porch, mode_in.hsync_pulse, mode_in.hback_porch),
|
||||
"->",
|
||||
(new_front, new_pulse, new_back),
|
||||
)
|
||||
new_mode = replace(
|
||||
new_mode,
|
||||
hfront_porch = new_front,
|
||||
hsync_pulse = new_pulse,
|
||||
hback_porch = new_back)
|
||||
new_mode, hfront_porch=new_front, hsync_pulse=new_pulse, hback_porch=new_back
|
||||
)
|
||||
print(new_mode)
|
||||
print()
|
||||
return new_mode
|
||||
|
||||
|
||||
def change_visible_height(mode_in, new_h):
|
||||
delta_rows = mode_in.visible_height - new_h
|
||||
delta_front_porch = delta_rows // 2
|
||||
delta_back_porch = delta_rows - delta_front_porch
|
||||
new_mode = replace(mode_in,
|
||||
visible_height = new_h,
|
||||
vfront_porch = mode_in.vfront_porch + delta_front_porch,
|
||||
vback_porch = mode_in.vback_porch + delta_back_porch)
|
||||
new_mode = replace(
|
||||
mode_in,
|
||||
visible_height=new_h,
|
||||
vfront_porch=mode_in.vfront_porch + delta_front_porch,
|
||||
vback_porch=mode_in.vback_porch + delta_back_porch,
|
||||
)
|
||||
print(new_mode)
|
||||
print()
|
||||
assert new_mode.total_lines == mode_in.total_lines
|
||||
return new_mode
|
||||
|
||||
|
||||
def pio_hard_delay(instr, n, file):
|
||||
assert n > 0
|
||||
assert n < 128
|
||||
|
|
@ -105,10 +120,14 @@ def pio_hard_delay(instr, n, file):
|
|||
n -= cycles
|
||||
print(file=file)
|
||||
|
||||
def print_pio_hsync_program(program_name_base, mode, h_divisor, cycles_per_pixel, file=sys.stdout):
|
||||
|
||||
def print_pio_hsync_program(
|
||||
program_name_base, mode, h_divisor, cycles_per_pixel, file=sys.stdout
|
||||
):
|
||||
net_khz = mode.pixel_clock_khz / h_divisor
|
||||
err = (mode.visible_width + mode.hfront_porch) % h_divisor
|
||||
print(f"""
|
||||
print(
|
||||
f"""
|
||||
; Horizontal sync program for {mode}
|
||||
; PIO clock frequency = {mode.pixel_clock_khz:.1f}/{h_divisor}khz = {net_khz:.1f}
|
||||
;
|
||||
|
|
@ -119,19 +138,28 @@ def print_pio_hsync_program(program_name_base, mode, h_divisor, cycles_per_pixel
|
|||
activeporch:
|
||||
jmp x-- activeporch ; Remain high in active mode and front porch
|
||||
|
||||
""", file=file)
|
||||
""",
|
||||
file=file,
|
||||
)
|
||||
|
||||
cycles, err = divmod(mode.hsync_pulse + err, h_divisor)
|
||||
print(f"syncpulse: ; {mode.hsync_pulse}/{h_divisor} clocks [actual {cycles} error {err}]", file=file)
|
||||
print(
|
||||
f"syncpulse: ; {mode.hsync_pulse}/{h_divisor} clocks [actual {cycles} error {err}]",
|
||||
file=file,
|
||||
)
|
||||
pio_hard_delay(f"set pins, {mode.hsync_polarity:d}", cycles, file=file)
|
||||
|
||||
cycles, err = divmod(mode.hback_porch + err, h_divisor)
|
||||
print(f"backporch: ; {mode.hback_porch}/{h_divisor} clocks [actual {cycles} error {err}]", file=file)
|
||||
print(
|
||||
f"backporch: ; {mode.hback_porch}/{h_divisor} clocks [actual {cycles} error {err}]",
|
||||
file=file,
|
||||
)
|
||||
pio_hard_delay(f"set pins, {not mode.hsync_polarity:d}", cycles - 1, file=file)
|
||||
print(" irq 0 [1]", file=file)
|
||||
print(".wrap", file=file)
|
||||
|
||||
print(f"""
|
||||
print(
|
||||
f"""
|
||||
% c-sdk {{
|
||||
static inline void {program_name_base}_hsync_program_init(PIO pio, uint sm, uint offset, uint pin) {{
|
||||
|
||||
|
|
@ -158,7 +186,10 @@ static inline void {program_name_base}_hsync_program_init(PIO pio, uint sm, uint
|
|||
}}
|
||||
|
||||
%}}
|
||||
""", file=file)
|
||||
""",
|
||||
file=file,
|
||||
)
|
||||
|
||||
|
||||
def pio_yloop(instr, n, label, comment, file):
|
||||
assert n <= 65
|
||||
|
|
@ -183,22 +214,45 @@ def pio_yloop(instr, n, label, comment, file):
|
|||
print(f" {instr}", file=file)
|
||||
print(file=file)
|
||||
|
||||
|
||||
def print_pio_vsync_program(program_name_base, mode, cycles_per_pixel, file=sys.stdout):
|
||||
print(f"""
|
||||
print(
|
||||
f"""
|
||||
.program {program_name_base}_vsync
|
||||
.side_set 1 opt
|
||||
; Vertical sync program for {mode}
|
||||
;
|
||||
.wrap_target ; Program wraps to here
|
||||
""", file=file)
|
||||
""",
|
||||
file=file,
|
||||
)
|
||||
|
||||
pio_yloop("wait 1 irq 0", mode.vfront_porch, "frontporch", f"{mode.vfront_porch} lines", file=file)
|
||||
pio_yloop(
|
||||
"wait 1 irq 0",
|
||||
mode.vfront_porch,
|
||||
"frontporch",
|
||||
f"{mode.vfront_porch} lines",
|
||||
file=file,
|
||||
)
|
||||
|
||||
pio_yloop(f"wait 1 irq 0 side {mode.vsync_polarity:d}", mode.vsync_pulse, "syncpulse", f"{mode.vsync_pulse} lines", file=file)
|
||||
pio_yloop(
|
||||
f"wait 1 irq 0 side {mode.vsync_polarity:d}",
|
||||
mode.vsync_pulse,
|
||||
"syncpulse",
|
||||
f"{mode.vsync_pulse} lines",
|
||||
file=file,
|
||||
)
|
||||
|
||||
pio_yloop(f"wait 1 irq 0 side {not mode.vsync_polarity:d}", mode.vback_porch, "backporch", f"{mode.vback_porch} lines", file=file)
|
||||
pio_yloop(
|
||||
f"wait 1 irq 0 side {not mode.vsync_polarity:d}",
|
||||
mode.vback_porch,
|
||||
"backporch",
|
||||
f"{mode.vback_porch} lines",
|
||||
file=file,
|
||||
)
|
||||
|
||||
print(f"""
|
||||
print(
|
||||
"""
|
||||
; ACTIVE
|
||||
mov x, osr ; Copy value from OSR to x scratch register
|
||||
active:
|
||||
|
|
@ -206,12 +260,14 @@ active:
|
|||
irq 1 ; Signal that we're in active mode
|
||||
jmp x-- active ; Remain in active mode, decrementing counter
|
||||
|
||||
""", file=file)
|
||||
|
||||
""",
|
||||
file=file,
|
||||
)
|
||||
|
||||
print(".wrap", file=file)
|
||||
|
||||
print(f"""
|
||||
print(
|
||||
f"""
|
||||
% c-sdk {{
|
||||
static inline void {program_name_base}_vsync_program_init(PIO pio, uint sm, uint offset, uint pin) {{
|
||||
|
||||
|
|
@ -242,14 +298,18 @@ static inline void {program_name_base}_vsync_program_init(PIO pio, uint sm, uint
|
|||
}}
|
||||
|
||||
%}}
|
||||
""", file=file)
|
||||
""",
|
||||
file=file,
|
||||
)
|
||||
|
||||
|
||||
|
||||
def print_pio_pixel_program(program_name_base, mode, out_instr, cycles_per_pixel, file=sys.stdout):
|
||||
def print_pio_pixel_program(
|
||||
program_name_base, mode, out_instr, cycles_per_pixel, file=sys.stdout
|
||||
):
|
||||
net_khz = cycles_per_pixel * mode.pixel_clock_khz
|
||||
assert cycles_per_pixel >= 2
|
||||
print(f"""
|
||||
print(
|
||||
f"""
|
||||
.program {program_name_base}_pixel
|
||||
; Pixel generator program for {mode}
|
||||
; PIO clock frequency = {cycles_per_pixel}×{mode.pixel_clock_khz}khz = {net_khz}
|
||||
|
|
@ -264,9 +324,12 @@ colorout:
|
|||
{out_instr} [{cycles_per_pixel-2}]
|
||||
jmp x-- colorout ; Stay here thru horizontal active mode
|
||||
|
||||
.wrap""", file=file)
|
||||
.wrap""",
|
||||
file=file,
|
||||
)
|
||||
|
||||
print(f"""
|
||||
print(
|
||||
f"""
|
||||
% c-sdk {{
|
||||
enum {{ {program_name_base}_pixel_clock_khz = {mode.pixel_clock_khz}, {program_name_base}_sys_clock_khz = {cycles_per_pixel * mode.pixel_clock_khz} }};
|
||||
|
||||
|
|
@ -283,7 +346,7 @@ static inline void {program_name_base}_pixel_program_init(PIO pio, uint sm, uint
|
|||
|
||||
// Set this pin's GPIO function (connect PIO to the pad)
|
||||
for(uint i=0; i<n_pin; i++) {{
|
||||
gpio_set_slew_rate(pin + i, GPIO_SLEW_RATE_FAST);
|
||||
// gpio_set_slew_rate(pin + i, GPIO_SLEW_RATE_FAST);
|
||||
gpio_set_drive_strength(pin + i, GPIO_DRIVE_STRENGTH_8MA);
|
||||
pio_gpio_init(pio, pin + i);
|
||||
}}
|
||||
|
|
@ -304,29 +367,42 @@ static inline void {program_name_base}_pixel_program_init(PIO pio, uint sm, uint
|
|||
}}
|
||||
|
||||
%}}
|
||||
""", file=file)
|
||||
""",
|
||||
file=file,
|
||||
)
|
||||
|
||||
mode_vga_640x480 = VideoMode(25_175, 640, 16, 96, 48, Polarity.Negative, 480, 10, 2, 33, Polarity.Negative)
|
||||
|
||||
mode_vga_640x480 = VideoMode(
|
||||
25_175, 640, 16, 96, 48, Polarity.Negative, 480, 10, 2, 33, Polarity.Negative
|
||||
)
|
||||
mode_vga_660x480 = change_visible_width(mode_vga_640x480, 660, 26_000)
|
||||
mode_vga_660x477 = change_visible_height(mode_vga_660x480, 477)
|
||||
|
||||
mode_vga_720x400 = VideoMode(28_321, 720, 18, 108, 54, Polarity.Negative, 400, 10, 2, 36, Polarity.Positive)
|
||||
mode_vga_720x400 = VideoMode(
|
||||
28_321, 720, 18, 108, 54, Polarity.Negative, 400, 10, 2, 36, Polarity.Positive
|
||||
)
|
||||
mode_vga_660x400 = change_visible_width(mode_vga_720x400, 660, 26_000)
|
||||
|
||||
if 0:
|
||||
print(mode_vga_640x480, 6*mode_vga_640x480.pixel_clock_khz)
|
||||
print(mode_vga_660x480, 6*mode_vga_660x480.pixel_clock_khz)
|
||||
print(mode_vga_640x480, 6 * mode_vga_640x480.pixel_clock_khz)
|
||||
print(mode_vga_660x480, 6 * mode_vga_660x480.pixel_clock_khz)
|
||||
|
||||
print(mode_vga_720x400, 6*mode_vga_720x400.pixel_clock_khz)
|
||||
print(mode_vga_660x400, 6*mode_vga_660x400.pixel_clock_khz)
|
||||
print(mode_vga_720x400, 6 * mode_vga_720x400.pixel_clock_khz)
|
||||
print(mode_vga_660x400, 6 * mode_vga_660x400.pixel_clock_khz)
|
||||
|
||||
def print_all(mode, h_divisor=1, out_instr="out pins, 2", cycles_per_pixel=6, file=sys.stdout):
|
||||
program_name = f"vga_{mode.visible_width}x{mode.visible_height}_{mode.frame_rate_hz:.0f}"
|
||||
|
||||
def print_all(
|
||||
mode, h_divisor=1, out_instr="out pins, 2", cycles_per_pixel=6, file=sys.stdout
|
||||
):
|
||||
program_name = (
|
||||
f"vga_{mode.visible_width}x{mode.visible_height}_{mode.frame_rate_hz:.0f}"
|
||||
)
|
||||
print_pio_hsync_program(program_name, mode, h_divisor, cycles_per_pixel, file=file)
|
||||
print("\n\n\n", file=file)
|
||||
print_pio_vsync_program(program_name, mode, cycles_per_pixel, file=file)
|
||||
print("\n\n\n", file=file)
|
||||
print_pio_pixel_program(program_name, mode, out_instr, cycles_per_pixel, file=file)
|
||||
|
||||
|
||||
with open("vga_660x477_60.pio", "wt", encoding="utf-8") as f:
|
||||
print_all(mode_vga_660x477, file=f)
|
||||
|
|
|
|||
Loading…
Reference in a new issue