style code with pre-commit

This commit is contained in:
Jeff Epler 2024-10-11 15:56:26 -05:00
parent 5ee7b51eb4
commit 075cdd423d
20 changed files with 891 additions and 889 deletions

1
.clang-format Normal file
View file

@ -0,0 +1 @@
IndentWidth: 4

36
.pre-commit-config.yaml Normal file
View 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

View file

@ -15,7 +15,7 @@ start:
; keyboard has signaled start condition ; keyboard has signaled start condition
set x 9 ; will receive 10 bits (data + parity + stop) set x 9 ; will receive 10 bits (data + parity + stop)
wait 1 pin 1 ; wait for clock pin to go high (discard start bit) wait 1 pin 1 ; wait for clock pin to go high (discard start bit)
receive_bit: receive_bit:
wait 0 pin 1 wait 0 pin 1
in pins 1 in pins 1
@ -35,7 +35,7 @@ send_bit:
out pins 1 out pins 1
wait 1 pin 1 wait 1 pin 1
jmp x-- send_bit jmp x-- send_bit
set pindirs 0 ; pins back to input mode set pindirs 0 ; pins back to input mode
wait 0 pin 0 wait 0 pin 0
wait 1 pin 0 ; wait for keyboard ACK wait 1 pin 0 ; wait for keyboard ACK
@ -78,4 +78,3 @@ void atkbd_program_init(PIO pio, int sm, int offset, int base_pin) {
} }
%} %}

396
chargen.c
View file

@ -1,20 +1,24 @@
#define _GNU_SOURCE #define _GNU_SOURCE
#include <stdarg.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pinout.h"
#include "keyboard.h"
#include "chargen.h" #include "chargen.h"
#include "keyboard.h"
#include "pinout.h"
#include "pico.h" #include "RP2040.h"
#include "pico/stdlib.h" #include "cmsis_compiler.h"
#include "pico/stdio/driver.h" #include "hardware/clocks.h"
#include "pico/multicore.h"
#include "pico/bootrom.h"
#include "hardware/structs/mpu.h" #include "hardware/structs/mpu.h"
#include "hardware/watchdog.h" #include "hardware/watchdog.h"
#include "hardware/clocks.h" #include "pico.h"
#include "cmsis_compiler.h" #include "pico/bootrom.h"
#include "RP2040.h" #include "pico/multicore.h"
#include "pico/stdio/driver.h"
#include "pico/stdlib.h"
#include "vga_660x477_60.pio.h" #include "vga_660x477_60.pio.h"
@ -22,10 +26,10 @@
int pixels_sm; int pixels_sm;
#define WRITE_PIXDATA \ #define WRITE_PIXDATA (pio0->txf[0] = pixels)
(pio0->txf[0] = pixels) #define FIFO_WAIT \
#define FIFO_WAIT \ do { /* NOTHING */ \
do { /* NOTHING */ } while(pio_sm_get_tx_fifo_level(pio0, 0) > 2) } while (pio_sm_get_tx_fifo_level(pio0, 0) > 2)
#define FB_WIDTH_CHAR (132) #define FB_WIDTH_CHAR (132)
#define FB_HEIGHT_CHAR (53) #define FB_HEIGHT_CHAR (53)
@ -36,52 +40,79 @@ int pixels_sm;
struct lw_terminal_vt100 *vt100; struct lw_terminal_vt100 *vt100;
// declaring this static breaks it (why?) // 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 scan_convert(const uint32_t *restrict cptr32,
void __not_in_flash_func(scan_convert)(const uint32_t * restrict cptr32, const uint16_t * restrict cgptr, const uint16_t * restrict shade) { const uint16_t *restrict cgptr,
#define READ_CHARDATA \ const uint16_t *restrict shade);
(ch = *cptr32++) void __not_in_flash_func(scan_convert)(const uint32_t *restrict cptr32,
#define ONE_CHAR(in_shift, op, out_shift) \ const uint16_t *restrict cgptr,
do { \ const uint16_t *restrict shade) {
chardata = cgptr[(ch>>(in_shift)) & 0xff]; \ #define READ_CHARDATA (ch = *cptr32++)
mask = shade[(ch>>(8 + (in_shift)))&7]; \ #define ONE_CHAR(in_shift, op, out_shift) \
pixels op (shade[(ch >>(11 + (in_shift)))&7] ^ (chardata & mask)) out_shift; \ do { \
} while(0) 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; uint32_t ch;
uint16_t chardata, mask; uint16_t chardata, mask;
uint32_t pixels; uint32_t pixels;
#define SIX_CHARS \ #define SIX_CHARS \
do { \ do { \
READ_CHARDATA; \ READ_CHARDATA; \
ONE_CHAR(0, =, << 20); \ ONE_CHAR(0, =, << 20); \
ONE_CHAR(16, |=, << 10); \ ONE_CHAR(16, |=, << 10); \
READ_CHARDATA; \ READ_CHARDATA; \
ONE_CHAR(0, |=, ); \ ONE_CHAR(0, |=, ); \
WRITE_PIXDATA; \ WRITE_PIXDATA; \
ONE_CHAR(16, =, << 20); \ ONE_CHAR(16, =, << 20); \
READ_CHARDATA; \ READ_CHARDATA; \
ONE_CHAR(0, |=, << 10); \ ONE_CHAR(0, |=, << 10); \
ONE_CHAR(16, |=, ); \ ONE_CHAR(16, |=, ); \
WRITE_PIXDATA; \ WRITE_PIXDATA; \
} while(0) } while (0)
SIX_CHARS; SIX_CHARS; SIX_CHARS; FIFO_WAIT; /* 18 */ \ SIX_CHARS;
SIX_CHARS; SIX_CHARS; SIX_CHARS; FIFO_WAIT; /* 36 */ \ SIX_CHARS;
SIX_CHARS; SIX_CHARS; SIX_CHARS; FIFO_WAIT; /* 54 */ \ SIX_CHARS;
SIX_CHARS; SIX_CHARS; SIX_CHARS; FIFO_WAIT; /* 72 */ \ FIFO_WAIT; /* 18 */
SIX_CHARS; SIX_CHARS; SIX_CHARS; FIFO_WAIT; /* 90 */ \
SIX_CHARS; SIX_CHARS; SIX_CHARS; FIFO_WAIT; /* 108 */ \ SIX_CHARS;
SIX_CHARS; SIX_CHARS; SIX_CHARS; FIFO_WAIT; /* 126 */ \ SIX_CHARS;
SIX_CHARS; /* 132 */ \ 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> uint16_t chargen[256 * CHAR_Y] = {
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
uint16_t chargen[256*CHAR_Y] = {
#include "5x9.h" #include "5x9.h"
}; };
@ -89,16 +120,15 @@ _Static_assert(FB_WIDTH_CHAR % 6 == 0);
lw_cell_t statusline[FB_WIDTH_CHAR]; lw_cell_t statusline[FB_WIDTH_CHAR];
static static int status_printf(const char *fmt, ...) {
int status_printf(const char *fmt, ...) { char buf[2 * FB_WIDTH_CHAR + 1];
char buf[2*FB_WIDTH_CHAR + 1];
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
int n = vsnprintf(buf, sizeof(buf), fmt, ap); int n = vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap); va_end(ap);
int attr = 0x300; int attr = 0x300;
int i, j; 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]; int c = (unsigned char)buf[i];
if (c < 32) { if (c < 32) {
attr = c << 8; attr = c << 8;
@ -106,7 +136,7 @@ int status_printf(const char *fmt, ...) {
statusline[j++] = c | attr; statusline[j++] = c | attr;
} }
} }
while(j < FB_WIDTH_CHAR) { while (j < FB_WIDTH_CHAR) {
statusline[j++] = 32 | attr; statusline[j++] = 32 | attr;
} }
return n; return n;
@ -122,8 +152,8 @@ int scrnprintf(const char *fmt, ...) {
return n; return n;
} }
static static uint16_t base_shade[] = {0, 0x554, 0xaa8, 0xffc, 0, 0x554,
uint16_t base_shade[] = {0, 0x554, 0xaa8, 0xffc, 0, 0x554, 0xaa8, 0xffc, 0, 0, 0, 0}; 0xaa8, 0xffc, 0, 0, 0, 0};
#if !STANDALONE #if !STANDALONE
static void setup_vga_hsync(PIO pio) { static void setup_vga_hsync(PIO pio) {
@ -152,39 +182,40 @@ static void setup_vga(void) {
setup_vga_hsync(pio0); setup_vga_hsync(pio0);
} }
__attribute__((noreturn, noinline)) static void
__attribute__((noreturn,noinline)) __not_in_flash_func(core1_loop)(void) {
static void __not_in_flash_func(core1_loop)(void) {
int frameno = 0; int frameno = 0;
while(true) { while (true) {
for(int row = 0; row < FB_HEIGHT_CHAR; row++) { for (int row = 0; row < FB_HEIGHT_CHAR; row++) {
uint32_t *chardata = row == FB_HEIGHT_CHAR - 1 uint32_t *chardata =
? (uint32_t*) statusline row == FB_HEIGHT_CHAR - 1
: (uint32_t*)lw_terminal_vt100_getline(vt100, row); ? (uint32_t *)statusline
for(int j=0; j<CHAR_Y; j++) { : (uint32_t *)lw_terminal_vt100_getline(vt100, row);
scan_convert(chardata, for (int j = 0; j < CHAR_Y; j++) {
&chargen[256 * j], frameno & 0x20 ? base_shade : base_shade + 4); scan_convert(chardata, &chargen[256 * j],
frameno & 0x20 ? base_shade : base_shade + 4);
} }
} }
frameno += 1; frameno += 1;
} }
} }
static static __attribute__((noreturn, noinline)) void
__attribute__((noreturn,noinline)) __not_in_flash_func(core1_entry)(void) {
void __not_in_flash_func(core1_entry)(void) {
setup_vga(); setup_vga();
// Turn off flash access. After this, it will hard fault. Better than messing // Turn off flash access. After this, it will hard fault. Better than
// up CIRCUITPY. // messing up CIRCUITPY.
MPU->CTRL = MPU_CTRL_PRIVDEFENA_Msk | MPU_CTRL_ENABLE_Msk; MPU->CTRL = MPU_CTRL_PRIVDEFENA_Msk | MPU_CTRL_ENABLE_Msk;
MPU->RNR = 6; // 7 is used by pico-sdk stack protection. MPU->RNR = 6; // 7 is used by pico-sdk stack protection.
MPU->RBAR = XIP_MAIN_BASE | MPU_RBAR_VALID_Msk; 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 = MPU_RASR_XN_Msk | // Set execute never and everything else is
MPU_RASR_ENABLE_Msk | // restricted.
(0x1b << MPU_RASR_SIZE_Pos); // Size is 0x10000000 which masks up to SRAM region. MPU_RASR_ENABLE_Msk |
MPU->RNR = 7; (0x1b << MPU_RASR_SIZE_Pos); // Size is 0x10000000 which masks
// up to SRAM region.
MPU->RNR = 7;
core1_loop(); core1_loop();
} }
@ -193,19 +224,21 @@ void __not_in_flash_func(core1_entry)(void) {
#define BG_ATTR(x) ((x) << 11) #define BG_ATTR(x) ((x) << 11)
#define FG_ATTR(x) ((x) << 8) #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) { static int map_one(int i) { return (i > 0) + (i > 6); }
return (i > 0) + (i > 6);
}
static lw_cell_t char_attr(void *user_data, const struct lw_parsed_attr *attr) { static lw_cell_t char_attr(void *user_data, const struct lw_parsed_attr *attr) {
int fg = map_one(attr->fg); int fg = map_one(attr->fg);
int bg = map_one(attr->bg); int bg = map_one(attr->bg);
if (fg == bg && attr->fg != attr->bg) { fg = bg + 1; } if (fg == bg && attr->fg != attr->bg) {
if(attr->bold) fg = 3; fg = bg + 1;
if(attr->blink) fg ^= 4; }
if(attr->inverse) { if (attr->bold)
fg = 3;
if (attr->blink)
fg ^= 4;
if (attr->inverse) {
return MAKE_ATTR(bg, fg); return MAKE_ATTR(bg, fg);
} }
return MAKE_ATTR(fg, bg); 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; queue_t keyboard_queue;
static static void reset_cpu(void) {
void reset_cpu(void) {
watchdog_reboot(0, SRAM_END, 0); watchdog_reboot(0, SRAM_END, 0);
watchdog_start_tick(12); watchdog_start_tick(12);
@ -227,7 +259,7 @@ int current_port;
#define COUNT_OF(x) ((sizeof(x) / sizeof((x)[0]))) #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)) #define N_BAUDRATES (COUNT_OF(baudrates))
typedef struct { typedef struct {
@ -237,14 +269,10 @@ typedef struct {
} uart_config_t; } uart_config_t;
const uart_config_t uart_configs[] = { const uart_config_t uart_configs[] = {
{ 8, 1, UART_PARITY_NONE, "8N1" }, {8, 1, UART_PARITY_NONE, "8N1"}, {8, 2, UART_PARITY_NONE, "8N2"},
{ 8, 2, UART_PARITY_NONE, "8N2" }, {8, 1, UART_PARITY_EVEN, "8E1"}, {8, 1, UART_PARITY_ODD, "8O1"},
{ 8, 1, UART_PARITY_EVEN, "8E1" }, {7, 1, UART_PARITY_NONE, "7N1"}, {7, 2, UART_PARITY_NONE, "7N2"},
{ 8, 1, UART_PARITY_ODD, "8O1" }, {7, 1, UART_PARITY_EVEN, "7E1"}, {7, 1, UART_PARITY_ODD, "7O1"},
{ 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)) #define N_CONFIGS (COUNT_OF(uart_configs))
@ -253,8 +281,8 @@ typedef struct uart_data {
} uart_data_t; } uart_data_t;
uart_data_t uart_data[] = { uart_data_t uart_data[] = {
{ 0, 0, 1 }, {0, 0, 1},
{ 0, 12, 13 }, {0, 12, 13},
}; };
#define N_UARTS (COUNT_OF(uart_data)) #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->rx, UART_FUNCSEL_NUM(inst, data->rx));
gpio_set_function(data->tx, UART_FUNCSEL_NUM(inst, data->tx)); gpio_set_function(data->tx, UART_FUNCSEL_NUM(inst, data->tx));
gpio_pull_up(data->rx); gpio_pull_up(data->rx);
} }
static void uart_deactivate(void *data_in) { 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) { static int uart_getc_nonblocking(void *data_in) {
uart_data_t *data = (uart_data_t *)data_in; uart_data_t *data = (uart_data_t *)data_in;
uart_inst_t *inst = uart_get_instance(data->uart); 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); return uart_getc(inst);
} }
static void uart_putc_nonblocking(void *data_in, int c) { static void uart_putc_nonblocking(void *data_in, int c) {
uart_data_t *data = (uart_data_t *)data_in; uart_data_t *data = (uart_data_t *)data_in;
uart_inst_t *inst = uart_get_instance(data->uart); 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) { 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) { static void uart_describe(void *data_in, char *buf, size_t buflen) {
uart_data_t *data = (uart_data_t *)data_in; uart_data_t *data = (uart_data_t *)data_in;
const uart_config_t *config = &uart_configs[data->cfg_idx]; 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) { static void usb_activate(void *data) { vt100->unicode = 1; }
vt100->unicode = 1;
}
static void usb_deactivate(void *data) {} static void usb_deactivate(void *data) {}
static int usb_getc_nonblocking(void *data) { static int usb_getc_nonblocking(void *data) {
int c = getchar_timeout_us(1); int c = getchar_timeout_us(1);
return (c < 0) ? EOF : c; return (c < 0) ? EOF : c;
} }
static void usb_putc_nonblocking(void *data, int c) { static void usb_putc_nonblocking(void *data, int c) { stdio_putchar_raw(c); }
stdio_putchar_raw(c);
}
static void usb_cycle_baud_rate(void *data) {} static void usb_cycle_baud_rate(void *data) {}
static void usb_cycle_settings(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 NUM_PORTS (COUNT_OF(ports))
#define CURRENT_PORT (ports[current_port]) #define CURRENT_PORT (ports[current_port])
static bool status_refresh = true; static bool status_refresh = true;
@ -386,9 +413,7 @@ static void port_deactivate(void) {
CURRENT_PORT.deactivate(CURRENT_PORT.data); CURRENT_PORT.deactivate(CURRENT_PORT.data);
} }
static void port_activate(void) { static void port_activate(void) { CURRENT_PORT.activate(CURRENT_PORT.data); }
CURRENT_PORT.activate(CURRENT_PORT.data);
}
static int port_getc(void) { static int port_getc(void) {
return CURRENT_PORT.getc_nonblocking(CURRENT_PORT.data); return CURRENT_PORT.getc_nonblocking(CURRENT_PORT.data);
@ -421,25 +446,24 @@ static void switch_port(void) {
port_activate(); port_activate();
} }
static static int stdio_kbd_in_chars(char *buf, int length) {
int stdio_kbd_in_chars(char *buf, int length) {
int rc = 0; int rc = 0;
int code; int code;
keyboard_poll(&keyboard_queue); keyboard_poll(&keyboard_queue);
while (length && queue_try_remove(&keyboard_queue, &code)) { while (length && queue_try_remove(&keyboard_queue, &code)) {
if ((code & 0xc000) == 0xc000) { if ((code & 0xc000) == 0xc000) {
switch(code) { switch (code) {
case CMD_SWITCH_RATE: case CMD_SWITCH_RATE:
port_cycle_baud_rate(); port_cycle_baud_rate();
break; break;
case CMD_SWITCH_SETTINGS: case CMD_SWITCH_SETTINGS:
port_cycle_settings(); port_cycle_settings();
break; break;
case CMD_SWITCH_PORT: case CMD_SWITCH_PORT:
switch_port(); switch_port();
break; break;
case CMD_REBOOT: case CMD_REBOOT:
reset_cpu(); reset_cpu();
} }
continue; continue;
} }
@ -453,7 +477,9 @@ int stdio_kbd_in_chars(char *buf, int length) {
static int kbd_getc_nonblocking(void) { static int kbd_getc_nonblocking(void) {
char c; char c;
int result = stdio_kbd_in_chars(&c, 1); 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; return c;
} }
@ -463,42 +489,72 @@ static stdio_driver_t stdio_kbd = {
}; };
#endif #endif
static static void master_write(void *user_data, void *buffer_in, size_t len) {
void master_write(void *user_data, void *buffer_in, size_t len) {
const char *buffer = buffer_in; const char *buffer = buffer_in;
for(;len--;buffer++) { port_putc(*buffer); } for (; len--; buffer++) {
port_putc(*buffer);
}
} }
static static int map_unicode(void *unused, int n) {
int map_unicode(void *unused, int n) { switch(n) { switch (n) {
case 9670: return 1; case 9670:
case 9618: return 2; return 1;
case 9225: return 3; case 9618:
case 9228: return 4; return 2;
case 9229: return 5; case 9225:
case 9226: return 6; return 3;
case 9252: return 9; case 9228:
case 9227: return 10; return 4;
case 9496: return 11; case 9229:
case 9488: return 12; return 5;
case 9484: return 13; case 9226:
case 9492: return 14; return 6;
case 9532: return 15; case 9252:
case 9146: return 16; return 9;
case 9147: return 17; case 9227:
case 9472: return 18; return 10;
case 9148: return 19; case 9496:
case 9149: return 20; return 11;
case 9500: return 21; case 9488:
case 9508: return 22; return 12;
case 9524: return 23; case 9484:
case 9516: return 24; return 13;
case 9474: return 25; case 9492:
case 8804: return 26; return 14;
case 8805: return 27; case 9532:
case 960: return 28; return 15;
case 8800: return 29; case 9146:
}return '?';} 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; static int old_keyboard_leds;
int main(void) { int main(void) {
@ -506,12 +562,13 @@ int main(void) {
set_sys_clock_khz(vga_660x477_60_sys_clock_khz, false); set_sys_clock_khz(vga_660x477_60_sys_clock_khz, false);
stdio_init_all(); stdio_init_all();
#endif #endif
for(int i=0; i<N_UARTS; i++) { for (int i = 0; i < N_UARTS; i++) {
gpio_init(uart_data[i].tx); gpio_init(uart_data[i].tx);
gpio_pull_up(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; vt100->map_unicode = map_unicode;
multicore_launch_core1(core1_entry); multicore_launch_core1(core1_entry);
@ -540,10 +597,9 @@ int main(void) {
} }
if (status_refresh) { if (status_refresh) {
status_printf("\3%s\3 \2 %s %s", status_printf("\3%s\3 \2 %s %s", port_describe(),
port_describe(), keyboard_leds & LED_CAPS ? "\22 CAPS \2" : " ",
keyboard_leds & LED_CAPS ? "\22 CAPS \2" : " ", keyboard_leds & LED_NUM ? "\22 NUM \2" : " ");
keyboard_leds & LED_NUM ? "\22 NUM \2" : " ");
status_refresh = false; status_refresh = false;
} }
} }

View file

@ -1,25 +1,21 @@
#include <stdlib.h>
#include <stdio.h>
#include "../src/lw_terminal_parser.h" #include "../src/lw_terminal_parser.h"
#include <stdio.h>
#include <stdlib.h>
static void vt100_write(struct lw_terminal *term_emul __attribute__((unused)), static void vt100_write(struct lw_terminal *term_emul __attribute__((unused)),
char c) char c) {
{
printf("Got a char : %c\n", 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); 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); printf("\\033[...K with %d parameters\n", term_emul->argc);
} }
int main(void) int main(void) {
{
struct lw_terminal *lw_terminal; struct lw_terminal *lw_terminal;
lw_terminal = lw_terminal_parser_init(); lw_terminal = lw_terminal_parser_init();

View file

@ -1,15 +1,12 @@
#include "hl_vt100.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include "hl_vt100.h"
void changed(struct vt100_headless *vt100) {
void changed(struct vt100_headless *vt100)
{
const char **lines; const char **lines;
lines = vt100_headless_getlines(vt100); 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, "|", 1);
write(1, lines[y], vt100->term->width); write(1, lines[y], vt100->term->width);
write(1, "|\n", 2); write(1, "|\n", 2);
@ -17,8 +14,7 @@ void changed(struct vt100_headless *vt100)
write(1, "\n", 1); write(1, "\n", 1);
} }
int main(int ac, char **av) int main(int ac, char **av) {
{
struct vt100_headless *vt100; struct vt100_headless *vt100;
char *argv[] = {"top", NULL}; char *argv[] = {"top", NULL};

View file

@ -11,9 +11,9 @@ def dump(vt100):
def main(): def main():
vt100 = hl_vt100.vt100_headless() vt100 = hl_vt100.vt100_headless()
vt100.changed_callback = lambda: dump(vt100) vt100.changed_callback = lambda: dump(vt100)
vt100.fork('top', ['top']) vt100.fork("top", ["top"])
vt100.main_loop() vt100.main_loop()
if __name__ == '__main__': if __name__ == "__main__":
main() main()

View file

@ -9,31 +9,37 @@ from pathlib import Path
from setuptools import setup, Extension from setuptools import setup, Extension
hl_vt100_module = Extension('hl_vt100', hl_vt100_module = Extension(
include_dirs=['src'], "hl_vt100",
define_macros=[('NDEBUG', '1')], include_dirs=["src"],
sources=['src/vt100_module.c', define_macros=[("NDEBUG", "1")],
'src/hl_vt100.c', sources=[
'src/lw_terminal_parser.c', "src/vt100_module.c",
'src/lw_terminal_vt100.c']) "src/hl_vt100.c",
"src/lw_terminal_parser.c",
"src/lw_terminal_vt100.c",
],
)
setup(name='hl_vt100', setup(
version='0.2', name="hl_vt100",
url='https://github.com/JulienPalard/vt100-emulator', version="0.2",
author="Julien Palard", url="https://github.com/JulienPalard/vt100-emulator",
author_email='julien@palard.fr', author="Julien Palard",
description="""Headless vt100 emulator""", author_email="julien@palard.fr",
long_description=(Path(__file__).parent / "README.md").read_text(encoding="UTF-8"), description="""Headless vt100 emulator""",
long_description_content_type="text/markdown", long_description=(Path(__file__).parent / "README.md").read_text(encoding="UTF-8"),
ext_modules=[hl_vt100_module], long_description_content_type="text/markdown",
include_package_data=True, ext_modules=[hl_vt100_module],
py_modules=["hl_vt100"], include_package_data=True,
classifiers=[ py_modules=["hl_vt100"],
"Programming Language :: C", classifiers=[
"Programming Language :: Python", "Programming Language :: C",
"Development Status :: 5 - Production/Stable", "Programming Language :: Python",
"License :: OSI Approved :: BSD License", "Development Status :: 5 - Production/Stable",
"Operating System :: OS Independent", "License :: OSI Approved :: BSD License",
"Topic :: System :: Emulators", "Operating System :: OS Independent",
"Topic :: Terminals :: Terminal Emulators/X Terminals" "Topic :: System :: Emulators",
]) "Topic :: Terminals :: Terminal Emulators/X Terminals",
],
)

View file

@ -24,26 +24,20 @@
*/ */
#define _XOPEN_SOURCE #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 "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)); return calloc(1, sizeof(struct vt100_headless));
} }
void delete_vt100_headless(struct vt100_headless *this) void delete_vt100_headless(struct vt100_headless *this) { free(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; struct termios termios;
ioctl(fd, TCGETS, &this->backup); ioctl(fd, TCGETS, &this->backup);
@ -54,16 +48,13 @@ static void set_non_canonical(struct vt100_headless *this, int fd)
ioctl(fd, TCSETS, &termios); 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); ioctl(fd, TCSETS, &this->backup);
} }
#ifndef NDEBUG #ifndef NDEBUG
static void strdump(char *str) static void strdump(char *str) {
{ while (*str != '\0') {
while (*str != '\0')
{
if (*str >= ' ' && *str <= '~') if (*str >= ' ' && *str <= '~')
fprintf(stderr, "%c", *str); fprintf(stderr, "%c", *str);
else else
@ -74,44 +65,34 @@ static void strdump(char *str)
} }
#endif #endif
void vt100_headless_stop(struct vt100_headless *this) void vt100_headless_stop(struct vt100_headless *this) { this->should_quit = 1; }
{
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]; char buffer[4096];
fd_set rfds; fd_set rfds;
int retval; int retval;
ssize_t read_size; ssize_t read_size;
while (!this->should_quit) while (!this->should_quit) {
{
FD_ZERO(&rfds); FD_ZERO(&rfds);
FD_SET(this->master, &rfds); FD_SET(this->master, &rfds);
FD_SET(0, &rfds); FD_SET(0, &rfds);
retval = select(this->master + 1, &rfds, NULL, NULL, NULL); retval = select(this->master + 1, &rfds, NULL, NULL, NULL);
if (retval == -1) if (retval == -1) {
{
perror("select()"); perror("select()");
} }
if (FD_ISSET(0, &rfds)) if (FD_ISSET(0, &rfds)) {
{
read_size = read(0, &buffer, 4096); read_size = read(0, &buffer, 4096);
if (read_size == -1) if (read_size == -1) {
{
perror("read"); perror("read");
return EXIT_FAILURE; return EXIT_FAILURE;
} }
buffer[read_size] = '\0'; buffer[read_size] = '\0';
write(this->master, buffer, read_size); 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); read_size = read(this->master, &buffer, 4096);
if (read_size == -1) if (read_size == -1) {
{
if (errno == EIO) { if (errno == EIO) {
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
@ -130,23 +111,19 @@ int vt100_headless_main_loop(struct vt100_headless *this)
return EXIT_SUCCESS; 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; struct vt100_headless *this;
this = (struct vt100_headless*)user_data; this = (struct vt100_headless *)user_data;
write(this->master, buffer, len); 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); return lw_terminal_vt100_getlines(this->term);
} }
void vt100_headless_fork(struct vt100_headless *this, void vt100_headless_fork(struct vt100_headless *this, const char *progname,
const char *progname, char **argv) {
char **argv)
{
int child; int child;
struct winsize winsize; struct winsize winsize;
@ -154,16 +131,15 @@ void vt100_headless_fork(struct vt100_headless *this,
winsize.ws_row = 24; winsize.ws_row = 24;
winsize.ws_col = 80; winsize.ws_col = 80;
child = forkpty(&this->master, NULL, NULL, NULL); child = forkpty(&this->master, NULL, NULL, NULL);
if (child == CHILD) if (child == CHILD) {
{
setsid(); setsid();
putenv("TERM=vt100"); putenv("TERM=vt100");
execvp(progname, argv); execvp(progname, argv);
return ; return;
} } else {
else this->term = lw_terminal_vt100_init(
{ this, lw_terminal_parser_default_unimplemented, master_write, NULL,
this->term = lw_terminal_vt100_init(this, lw_terminal_parser_default_unimplemented, master_write, NULL, winsize.ws_col, winsize.ws_row); winsize.ws_col, winsize.ws_row);
ioctl(this->master, TIOCSWINSZ, &winsize); ioctl(this->master, TIOCSWINSZ, &winsize);
} }
restore_termios(this, 0); restore_termios(this, 0);

View file

@ -28,14 +28,13 @@
#define CHILD 0 #define CHILD 0
#include <utmp.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <termios.h>
#include "lw_terminal_vt100.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; int master;
struct termios backup; struct termios backup;
struct lw_terminal_vt100 *term; struct lw_terminal_vt100 *term;
@ -43,8 +42,8 @@ struct vt100_headless
void (*changed)(struct vt100_headless *this); void (*changed)(struct vt100_headless *this);
}; };
void vt100_headless_fork(struct vt100_headless *this, const char *progname,
void vt100_headless_fork(struct vt100_headless *this, const char *progname, char **argv); char **argv);
int vt100_headless_main_loop(struct vt100_headless *this); int vt100_headless_main_loop(struct vt100_headless *this);
void delete_vt100_headless(struct vt100_headless *this); void delete_vt100_headless(struct vt100_headless *this);
struct vt100_headless *new_vt100_headless(void); struct vt100_headless *new_vt100_headless(void);

View file

@ -25,36 +25,30 @@
#include <stdlib.h> #include <stdlib.h>
#ifndef NDEBUG #ifndef NDEBUG
# include <stdio.h> #include <stdio.h>
#endif #endif
#include "lw_terminal_parser.h" #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) if (this->stack_ptr >= TERM_STACK_SIZE)
return ; return;
this->stack[this->stack_ptr++] = c; 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; unsigned int i;
int got_something; int got_something;
got_something = 0; got_something = 0;
this->argc = 0; this->argc = 0;
this->argv[0] = 0; this->argv[0] = 0;
for (i = 0; i < this->stack_ptr; ++i) for (i = 0; i < this->stack_ptr; ++i) {
{ if (this->stack[i] >= '0' && this->stack[i] <= '9') {
if (this->stack[i] >= '0' && this->stack[i] <= '9')
{
got_something = 1; got_something = 1;
this->argv[this->argc] = this->argv[this->argc] * 10 this->argv[this->argc] =
+ this->stack[i] - '0'; this->argv[this->argc] * 10 + this->stack[i] - '0';
} } else if (this->stack[i] == ';') {
else if (this->stack[i] == ';')
{
got_something = 0; got_something = 0;
this->argc += 1; this->argc += 1;
this->argv[this->argc] = 0; this->argv[this->argc] = 0;
@ -63,11 +57,9 @@ static void lw_terminal_parser_parse_params(struct lw_terminal *this)
this->argc += got_something; 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); 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) if (this->unimplemented != NULL)
this->unimplemented(this, "CSI", c); this->unimplemented(this, "CSI", c);
goto leave; goto leave;
@ -80,10 +72,8 @@ leave:
this->argc = 0; this->argc = 0;
} }
static void lw_terminal_parser_call_ESC(struct lw_terminal *this, char c) static void lw_terminal_parser_call_ESC(struct lw_terminal *this, char c) {
{ if (((term_action *)&this->callbacks.esc)[c - '0'] == NULL) {
if (((term_action *)&this->callbacks.esc)[c - '0'] == NULL)
{
if (this->unimplemented != NULL) if (this->unimplemented != NULL)
this->unimplemented(this, "ESC", c); this->unimplemented(this, "ESC", c);
goto leave; goto leave;
@ -95,10 +85,8 @@ leave:
this->argc = 0; this->argc = 0;
} }
static void lw_terminal_parser_call_HASH(struct lw_terminal *this, char c) static void lw_terminal_parser_call_HASH(struct lw_terminal *this, char c) {
{ if (((term_action *)&this->callbacks.hash)[c - '0'] == NULL) {
if (((term_action *)&this->callbacks.hash)[c - '0'] == NULL)
{
if (this->unimplemented != NULL) if (this->unimplemented != NULL)
this->unimplemented(this, "HASH", c); this->unimplemented(this, "HASH", c);
goto leave; goto leave;
@ -110,11 +98,9 @@ leave:
this->argc = 0; this->argc = 0;
} }
static void lw_terminal_parser_call_GSET(struct lw_terminal *this, char c) static void lw_terminal_parser_call_GSET(struct lw_terminal *this, char c) {
{ if (c < '0' || c > 'B' ||
if (c < '0' || c > 'B' ((term_action *)&this->callbacks.scs)[c - '0'] == NULL) {
|| ((term_action *)&this->callbacks.scs)[c - '0'] == NULL)
{
if (this->unimplemented != NULL) if (this->unimplemented != NULL)
this->unimplemented(this, "GSET", c); this->unimplemented(this, "GSET", c);
goto leave; goto leave;
@ -141,17 +127,13 @@ leave:
** | | \_ term_call_GSET() ** | | \_ term_call_GSET()
** \_ term->write() ** \_ term->write()
*/ */
void lw_terminal_parser_read(struct lw_terminal *this, char c) void lw_terminal_parser_read(struct lw_terminal *this, char c) {
{ if (this->state == INIT) {
if (this->state == INIT)
{
if (c == '\033') if (c == '\033')
this->state = ESC; this->state = ESC;
else else
this->write(this, c); this->write(this, c);
} } else if (this->state == ESC) {
else if (this->state == ESC)
{
if (c == '[') if (c == '[')
this->state = CSI; this->state = CSI;
else if (c == '#') else if (c == '#')
@ -162,21 +144,16 @@ void lw_terminal_parser_read(struct lw_terminal *this, char c)
this->state = G1SET; this->state = G1SET;
else if (c >= '0' && c <= 'z') else if (c >= '0' && c <= 'z')
lw_terminal_parser_call_ESC(this, c); lw_terminal_parser_call_ESC(this, c);
else this->write(this, c); else
} this->write(this, c);
else if (this->state == HASH) } else if (this->state == HASH) {
{
if (c >= '0' && c <= '9') if (c >= '0' && c <= '9')
lw_terminal_parser_call_HASH(this, c); lw_terminal_parser_call_HASH(this, c);
else else
this->write(this, c); 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); lw_terminal_parser_call_GSET(this, c);
} } else if (this->state == CSI) {
else if (this->state == CSI)
{
if (c == '?') if (c == '?')
this->flag = '?'; this->flag = '?';
else if (c == '>') 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--) while (n--)
lw_terminal_parser_read(this, *c++); 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) while (*c)
lw_terminal_parser_read(this, *c++); lw_terminal_parser_read(this, *c++);
} }
#ifndef NDEBUG #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; unsigned int argc;
fprintf(stderr, "WARNING: UNIMPLEMENTED %s (", seq); 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]); fprintf(stderr, "%d", this->argv[argc]);
if (argc != this->argc - 1) if (argc != this->argc - 1)
fprintf(stderr, ", "); fprintf(stderr, ", ");
@ -217,20 +192,16 @@ void lw_terminal_parser_default_unimplemented(struct lw_terminal* this, char *se
fprintf(stderr, ")%o\n", chr); fprintf(stderr, ")%o\n", chr);
} }
#else #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; this = this;
seq = seq; seq = seq;
chr = chr; chr = chr;
} }
#endif #endif
struct lw_terminal *lw_terminal_parser_init(void) struct lw_terminal *lw_terminal_parser_init(void) {
{
return calloc(1, sizeof(struct lw_terminal)); return calloc(1, sizeof(struct lw_terminal));
} }
void lw_terminal_parser_destroy(struct lw_terminal* this) void lw_terminal_parser_destroy(struct lw_terminal *this) { free(this); }
{
free(this);
}

View file

@ -23,8 +23,9 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef __TERMINAL_H__ #pragma once
#define __TERMINAL_H__
#include <stddef.h>
/* /*
** **
@ -97,22 +98,13 @@
#define TERM_STACK_SIZE 1024 #define TERM_STACK_SIZE 1024
enum term_state enum term_state { INIT, ESC, HASH, G0SET, G1SET, CSI };
{
INIT,
ESC,
HASH,
G0SET,
G1SET,
CSI
};
struct lw_terminal; struct lw_terminal;
typedef void (*term_action)(struct lw_terminal *emul); typedef void (*term_action)(struct lw_terminal *emul);
struct ascii_callbacks struct ascii_callbacks {
{
term_action n0; term_action n0;
term_action n1; term_action n1;
term_action n2; term_action n2;
@ -194,35 +186,33 @@ struct ascii_callbacks
term_action z; term_action z;
}; };
struct term_callbacks struct term_callbacks {
{
struct ascii_callbacks esc; struct ascii_callbacks esc;
struct ascii_callbacks csi; struct ascii_callbacks csi;
struct ascii_callbacks hash; struct ascii_callbacks hash;
struct ascii_callbacks scs; struct ascii_callbacks scs;
}; };
struct lw_terminal struct lw_terminal {
{ unsigned int cursor_pos_x;
unsigned int cursor_pos_x; unsigned int cursor_pos_y;
unsigned int cursor_pos_y; enum term_state state;
enum term_state state; unsigned int argc;
unsigned int argc; unsigned int argv[TERM_STACK_SIZE];
unsigned int argv[TERM_STACK_SIZE]; void (*write)(struct lw_terminal *, char c);
void (*write)(struct lw_terminal *, char c); char stack[TERM_STACK_SIZE];
char stack[TERM_STACK_SIZE]; unsigned int stack_ptr;
unsigned int stack_ptr; struct term_callbacks callbacks;
struct term_callbacks callbacks; char flag;
char flag; void *user_data;
void *user_data; void (*unimplemented)(struct lw_terminal *, char *seq, char chr);
void (*unimplemented)(struct lw_terminal*,
char *seq, char chr);
}; };
struct lw_terminal *lw_terminal_parser_init(void); 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(struct lw_terminal *this, char 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);
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,
void lw_terminal_parser_destroy(struct lw_terminal* this); size_t n);
#endif void lw_terminal_parser_destroy(struct lw_terminal *this);

View file

@ -23,27 +23,36 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 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 "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) static unsigned int get_mode_mask(unsigned int mode) {
{ switch (mode) {
switch (mode) case LNM:
{ return MASK_LNM;
case LNM : return MASK_LNM; case DECCKM:
case DECCKM : return MASK_DECCKM; return MASK_DECCKM;
case DECANM : return MASK_DECANM; case DECANM:
case DECCOLM : return MASK_DECCOLM; return MASK_DECANM;
case DECSCLM : return MASK_DECSCLM; case DECCOLM:
case DECSCNM : return MASK_DECSCNM; return MASK_DECCOLM;
case DECOM : return MASK_DECOM; case DECSCLM:
case DECAWM : return MASK_DECAWM; return MASK_DECSCLM;
case DECARM : return MASK_DECARM; case DECSCNM:
case DECINLM : return MASK_DECINLM; return MASK_DECSCNM;
default: return 0; 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 MOD1(a, b) ((a < b) ? a : a - b)
#define SCREEN_PTR(vt100, x, y) \ #define SCREEN_PTR(vt100, x, y) \
MOD1((vt100->top_line * vt100->width + x + vt100->width * y), \ MOD1((vt100->top_line * vt100->width + x + vt100->width * y), \
(vt100->width * SCROLLBACK * vt100->height)) (vt100->width * SCROLLBACK * vt100->height))
#define FROZEN_SCREEN_PTR(vt100, x, y) \ #define FROZEN_SCREEN_PTR(vt100, x, y) \
(MOD1(x + vt100->width * y, \ (MOD1(x + vt100->width * y, (vt100->width * SCROLLBACK * vt100->height)))
(vt100->width * SCROLLBACK * vt100->height)))
static lw_cell_t aget(struct lw_terminal_vt100 *headless_term, static lw_cell_t aget(struct lw_terminal_vt100 *headless_term, unsigned int x,
unsigned int x, unsigned int y) unsigned int y) {
{
if (y < headless_term->margin_top || y > headless_term->margin_bottom) 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 else
return headless_term->ascreen[SCREEN_PTR(headless_term, x, y)]; return headless_term->ascreen[SCREEN_PTR(headless_term, x, y)];
} }
static void aset(struct lw_terminal_vt100 *headless_term, static void aset(struct lw_terminal_vt100 *headless_term, unsigned int x,
unsigned int x, unsigned int y, unsigned int y, lw_cell_t c) {
lw_cell_t c)
{
if (y < headless_term->margin_top || y > headless_term->margin_bottom) 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 else
headless_term->ascreen[SCREEN_PTR(headless_term, x, y)] = c; headless_term->ascreen[SCREEN_PTR(headless_term, x, y)] = c;
} }
static void set(struct lw_terminal_vt100 *headless_term, static void set(struct lw_terminal_vt100 *headless_term, unsigned int x,
unsigned int x, unsigned int y, unsigned int y, char c) {
char c) { aset(headless_term, x, y, (unsigned char)c | headless_term->attr);
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) if (y < vt100->margin_top || y > vt100->margin_bottom)
return vt100->afrozen_screen[FROZEN_SCREEN_PTR(vt100, x, y)]; return vt100->afrozen_screen[FROZEN_SCREEN_PTR(vt100, x, y)];
else else
return vt100->ascreen[SCREEN_PTR(vt100, x, y)]; 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, memcpy(vt100->afrozen_screen + vt100->width * y,
vt100->ascreen + SCREEN_PTR(vt100, 0, y), vt100->ascreen + SCREEN_PTR(vt100, 0, y),
vt100->width * sizeof(lw_cell_t)); 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), memcpy(vt100->ascreen + SCREEN_PTR(vt100, 0, y),
vt100->afrozen_screen + vt100->width * y, vt100->afrozen_screen + vt100->width * y,
vt100->width * sizeof(lw_cell_t)); 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 x;
unsigned int y; 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 This sequence causes the cursor position, graphic rendition, and
character set to be saved. (See DECRC). 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.*/ /*TODO: Save graphic rendition and charset.*/
struct lw_terminal_vt100 *vt100; struct lw_terminal_vt100 *vt100;
@ -273,17 +275,14 @@ static void DECSC(struct lw_terminal *term_emul)
Modes following this section). 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; struct lw_terminal_vt100 *vt100;
unsigned int mode; unsigned int mode;
vt100 = (struct lw_terminal_vt100 *)term_emul->user_data; vt100 = (struct lw_terminal_vt100 *)term_emul->user_data;
if (term_emul->argc > 0) if (term_emul->argc > 0) {
{
mode = term_emul->argv[0]; mode = term_emul->argv[0];
if (mode == DECCOLM) if (mode == DECCOLM) {
{
vt100->width = 80; vt100->width = 80;
vt100->x = vt100->y = 0; vt100->x = vt100->y = 0;
blank_screen(vt100); blank_screen(vt100);
@ -335,11 +334,10 @@ x Pm = 97 / 107 fg/bg Bright White
x Pm = 99 / 109 fg/bg Bright Default x Pm = 99 / 109 fg/bg Bright Default
*/ */
static int default_map_unicode(void *user_data, int c) { static int default_map_unicode(void *user_data, int c) { return '?'; }
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; (void)user_data;
lw_cell_t result; 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->fg;
result |= attr->bg << 4; result |= attr->bg << 4;
} }
if (attr->bold) result ^= 0x08; if (attr->bold)
if (attr->blink) result ^= 0x80; result ^= 0x08;
if (attr->blink)
result ^= 0x80;
return result << 8; return result << 8;
} }
static void SGR(struct lw_terminal *term_emul) static void SGR(struct lw_terminal *term_emul) {
{ struct lw_terminal_vt100 *vt100 =
struct lw_terminal_vt100 *vt100 = (struct lw_terminal_vt100 *)term_emul->user_data; (struct lw_terminal_vt100 *)term_emul->user_data;
// vim sends "CSI > 4 ; 2 m" and you can't stop it // 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) { if (term_emul->argc == 0) {
term_emul->argc = 1; term_emul->argc = 1;
term_emul->argv[0] = 0; 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]; int p = term_emul->argv[i];
switch(p) { switch (p) {
case 0: case 0:
vt100->parsed_attr = LW_DEFAULT_ATTR; vt100->parsed_attr = LW_DEFAULT_ATTR;
break; break;
case 1: 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 The numbering of lines depends on the state of the Origin Mode
(DECOM). (DECOM).
*/ */
static void CUP(struct lw_terminal *term_emul) static void CUP(struct lw_terminal *term_emul) {
{
struct lw_terminal_vt100 *vt100; struct lw_terminal_vt100 *vt100;
int arg0; int arg0;
int arg1; int arg1;
@ -465,14 +466,17 @@ static void CUP(struct lw_terminal *term_emul)
if (arg1 < 0) if (arg1 < 0)
arg1 = 0; arg1 = 0;
if (MODE_IS_SET(vt100, DECOM)) if (MODE_IS_SET(vt100, DECOM)) {
{
arg0 += vt100->margin_top; arg0 += vt100->margin_top;
if ((unsigned int)arg0 > vt100->margin_bottom) if ((unsigned int)arg0 > vt100->margin_bottom)
arg0 = vt100->margin_bottom; arg0 = vt100->margin_bottom;
} }
if (arg0 >= vt100->height) { arg0 = vt100->height - 1; } if (arg0 >= vt100->height) {
if (arg1 >= vt100->width) { arg1 = vt100->width - 1; } arg0 = vt100->height - 1;
}
if (arg1 >= vt100->width) {
arg1 = vt100->width - 1;
}
vt100->y = arg0; vt100->y = arg0;
vt100->x = arg1; 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. 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; struct lw_terminal_vt100 *vt100;
unsigned int mode; unsigned int mode;
unsigned int saved_argc; unsigned int saved_argc;
vt100 = (struct lw_terminal_vt100 *)term_emul->user_data; vt100 = (struct lw_terminal_vt100 *)term_emul->user_data;
if (term_emul->argc > 0) if (term_emul->argc > 0) {
{
mode = term_emul->argv[0]; mode = term_emul->argv[0];
SET_MODE(vt100, mode); SET_MODE(vt100, mode);
if (mode == DECANM) if (mode == DECANM) {
{
/* TODO: Support vt52 mode */ /* TODO: Support vt52 mode */
return ; return;
} }
if (mode == DECCOLM) if (mode == DECCOLM) {
{
vt100->width = 132; vt100->width = 132;
vt100->x = vt100->y = 0; vt100->x = vt100->y = 0;
blank_screen(vt100); blank_screen(vt100);
} }
if (mode == DECOM) if (mode == DECOM) {
{
saved_argc = term_emul->argc; saved_argc = term_emul->argc;
term_emul->argc = 0; term_emul->argc = 0;
CUP(term_emul); 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). 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_top;
unsigned int margin_bottom; unsigned int margin_bottom;
struct lw_terminal_vt100 *vt100; 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; 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_top = term_emul->argv[0] - 1;
margin_bottom = term_emul->argv[1] - 1; margin_bottom = term_emul->argv[1] - 1;
if (margin_bottom >= vt100->height) if (margin_bottom >= vt100->height)
return ; return;
if (margin_bottom - margin_top <= 0) if (margin_bottom - margin_top <= 0)
return ; return;
} } else {
else
{
margin_top = 0; margin_top = 0;
margin_bottom = vt100->height - 1; margin_bottom = vt100->height - 1;
} }
@ -594,16 +589,14 @@ static void DECSTBM(struct lw_terminal *term_emul)
GPO, STP and AVO ESC [?1;7c 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; struct lw_terminal_vt100 *vt100;
vt100 = (struct lw_terminal_vt100 *)term_emul->user_data; vt100 = (struct lw_terminal_vt100 *)term_emul->user_data;
vt100->master_write(vt100->user_data, "\033[?1;0c", 7); 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; struct lw_terminal_vt100 *vt100;
vt100 = (struct lw_terminal_vt100 *)term_emul->user_data; vt100 = (struct lw_terminal_vt100 *)term_emul->user_data;
@ -611,20 +604,18 @@ static void DSR(struct lw_terminal *term_emul)
return; return;
} }
switch(term_emul->argv[0]) { switch (term_emul->argv[0]) {
case 5: case 5:
vt100->master_write(vt100->user_data, "\033[0n", 4); vt100->master_write(vt100->user_data, "\033[0n", 4);
break; 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));
}
default: 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:;
} }
} }
@ -636,8 +627,7 @@ static void DSR(struct lw_terminal *term_emul)
This sequence causes the previously saved cursor position, graphic This sequence causes the previously saved cursor position, graphic
rendition, and character set to be restored. 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 */ /*TODO Save graphic rendition and charset */
struct lw_terminal_vt100 *vt100; 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 focus and alignment. This command is used by DEC manufacturing and
Field Service personnel. Field Service personnel.
*/ */
static void DECALN(struct lw_terminal *term_emul) static void DECALN(struct lw_terminal *term_emul) {
{
struct lw_terminal_vt100 *vt100; struct lw_terminal_vt100 *vt100;
unsigned int x; unsigned int x;
unsigned int y; 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 without changing the column position. If the active position is at the
bottom margin, a scroll up is performed. Format Effector 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; struct lw_terminal_vt100 *vt100;
unsigned int x; unsigned int x;
vt100 = (struct lw_terminal_vt100 *)term_emul->user_data; vt100 = (struct lw_terminal_vt100 *)term_emul->user_data;
if (vt100->y >= vt100->margin_bottom) if (vt100->y >= vt100->margin_bottom) {
{
/* SCROLL */ /* SCROLL */
vt100->top_line = (vt100->top_line + 1) % (vt100->height * SCROLLBACK); vt100->top_line = (vt100->top_line + 1) % (vt100->height * SCROLLBACK);
for (x = 0; x < vt100->width; ++x) for (x = 0; x < vt100->width; ++x)
set(vt100, x, vt100->margin_bottom, ' '); set(vt100, x, vt100->margin_bottom, ' ');
} } else {
else
{
/* Do not scroll, just move downward on the current display space */ /* Do not scroll, just move downward on the current display space */
vt100->y += 1; 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 preceding line. If the active position is at the top margin, a scroll
down is performed. Format Effector 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; struct lw_terminal_vt100 *vt100;
vt100 = (struct lw_terminal_vt100 *)term_emul->user_data; vt100 = (struct lw_terminal_vt100 *)term_emul->user_data;
if (vt100->y == 0) if (vt100->y == 0) {
{
/* SCROLL */ /* SCROLL */
vt100->top_line = (vt100->top_line - 1) % (vt100->height * SCROLLBACK); vt100->top_line = (vt100->top_line - 1) % (vt100->height * SCROLLBACK);
} } else {
else
{
/* Do not scroll, just move upward on the current display space */ /* Do not scroll, just move upward on the current display space */
vt100->y -= 1; 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 on the next line downward. If the active position is at the bottom
margin, a scroll up is performed. Format Effector 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; struct lw_terminal_vt100 *vt100;
unsigned int x; unsigned int x;
vt100 = (struct lw_terminal_vt100 *)term_emul->user_data; vt100 = (struct lw_terminal_vt100 *)term_emul->user_data;
if (vt100->y >= vt100->margin_bottom) if (vt100->y >= vt100->margin_bottom) {
{
/* SCROLL */ /* SCROLL */
vt100->top_line = (vt100->top_line + 1) % (vt100->height * SCROLLBACK); vt100->top_line = (vt100->top_line + 1) % (vt100->height * SCROLLBACK);
for (x = 0; x < vt100->width; ++x) for (x = 0; x < vt100->width; ++x)
set(vt100, x, vt100->margin_bottom, ' '); set(vt100, x, vt100->margin_bottom, ' ');
} } else {
else
{
/* Do not scroll, just move downward on the current display space */ /* Do not scroll, just move downward on the current display space */
vt100->y += 1; 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, upward. If an attempt is made to move the cursor above the top margin,
the cursor stops at the top margin. Editor Function 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; struct lw_terminal_vt100 *vt100;
unsigned int arg0; 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 cursor below the bottom margin, the cursor stops at the bottom
margin. Editor Function margin. Editor Function
*/ */
static void CUD(struct lw_terminal *term_emul) static void CUD(struct lw_terminal *term_emul) {
{
struct lw_terminal_vt100 *vt100; struct lw_terminal_vt100 *vt100;
unsigned int arg0; 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 is made to move the cursor to the right of the right margin, the
cursor stops at the right margin. Editor Function 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; struct lw_terminal_vt100 *vt100;
unsigned int arg0; 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 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 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; struct lw_terminal_vt100 *vt100;
unsigned int arg0; unsigned int arg0;
@ -873,8 +846,7 @@ static void CUB(struct lw_terminal *term_emul)
ESC [ Ps P default value: 1 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; struct lw_terminal_vt100 *vt100;
unsigned int arg0; unsigned int arg0;
unsigned int x; 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 2 Erase all of the display all lines are erased, changed to
single-width, and the cursor does not move. 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; struct lw_terminal_vt100 *vt100;
unsigned int arg0; unsigned int arg0;
unsigned int x; unsigned int x;
@ -924,25 +895,20 @@ static void ED(struct lw_terminal *term_emul)
arg0 = 0; arg0 = 0;
if (term_emul->argc > 0) if (term_emul->argc > 0)
arg0 = term_emul->argv[0]; arg0 = term_emul->argv[0];
if (arg0 == 0) if (arg0 == 0) {
{
for (x = vt100->x; x < vt100->width; ++x) for (x = vt100->x; x < vt100->width; ++x)
set(vt100, x, vt100->y, ' '); 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) for (y = vt100->y + 1; y < vt100->height; ++y)
set(vt100, x, y, ' '); set(vt100, x, y, ' ');
} } else if (arg0 == 1) {
else if (arg0 == 1) for (x = 0; x < vt100->width; ++x)
{
for (x = 0 ; x < vt100->width; ++x)
for (y = 0; y < vt100->y; ++y) for (y = 0; y < vt100->y; ++y)
set(vt100, x, y, ' '); set(vt100, x, y, ' ');
for (x = 0; x <= vt100->x; ++x) for (x = 0; x <= vt100->x; ++x)
set(vt100, x, vt100->y, ' '); set(vt100, x, vt100->y, ' ');
} } else if (arg0 == 2) {
else if (arg0 == 2) for (x = 0; x < vt100->width; ++x)
{
for (x = 0 ; x < vt100->width; ++x)
for (y = 0; y < vt100->height; ++y) for (y = 0; y < vt100->height; ++y)
set(vt100, x, 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 1 Erase from the start of the screen to the active position, inclusive
2 Erase all of the line, 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; struct lw_terminal_vt100 *vt100;
unsigned int arg0; unsigned int arg0;
unsigned int x; unsigned int x;
@ -972,18 +937,13 @@ static void EL(struct lw_terminal *term_emul)
arg0 = 0; arg0 = 0;
if (term_emul->argc > 0) if (term_emul->argc > 0)
arg0 = term_emul->argv[0]; arg0 = term_emul->argv[0];
if (arg0 == 0) if (arg0 == 0) {
{
for (x = vt100->x; x < vt100->width; ++x) for (x = vt100->x; x < vt100->width; ++x)
set(vt100, x, vt100->y, ' '); set(vt100, x, vt100->y, ' ');
} } else if (arg0 == 1) {
else if (arg0 == 1)
{
for (x = 0; x <= vt100->x; ++x) for (x = 0; x <= vt100->x; ++x)
set(vt100, x, vt100->y, ' '); set(vt100, x, vt100->y, ' ');
} } else if (arg0 == 2) {
else if (arg0 == 2)
{
for (x = 0; x < vt100->width; ++x) for (x = 0; x < vt100->width; ++x)
set(vt100, x, vt100->y, ' '); 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 columns depends on the reset or set state of the origin mode
(DECOM). Format Effector (DECOM). Format Effector
*/ */
static void HVP(struct lw_terminal *term_emul) static void HVP(struct lw_terminal *term_emul) { CUP(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; struct lw_terminal_vt100 *vt100;
unsigned int i; unsigned int i;
vt100 = (struct lw_terminal_vt100 *)term_emul->user_data; 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] = '-'; 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) for (i = 0; i < 132; ++i)
vt100->tabulations[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; struct lw_terminal_vt100 *vt100;
vt100 = (struct lw_terminal_vt100 *)term_emul->user_data; 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; vt100 = (struct lw_terminal_vt100 *)term_emul->user_data;
if (c == '\r') if (c == '\r') {
{
vt100->x = 0; 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)) if (MODE_IS_SET(vt100, LNM))
NEL(term_emul); NEL(term_emul);
else else
IND(term_emul); IND(term_emul);
return ; return;
} }
if (c == '\010' && vt100->x > 0) if (c == '\010' && vt100->x > 0) {
{
if (vt100->x == vt100->width) if (vt100->x == vt100->width)
vt100->x -= 1; vt100->x -= 1;
vt100->x -= 1; vt100->x -= 1;
return ; return;
} }
if (c == '\t') if (c == '\t') {
{ do {
do
{
set(vt100, vt100->x, vt100->y, ' '); set(vt100, vt100->x, vt100->y, ' ');
vt100->x += 1; vt100->x += 1;
} while (vt100->x < vt100->width && vt100->tabulations[vt100->x] == '-'); } while (vt100->x < vt100->width &&
return ; vt100->tabulations[vt100->x] == '-');
return;
} }
if (c == '\016') if (c == '\016') {
{
vt100->selected_charset = 0; vt100->selected_charset = 0;
return ; return;
} }
if (c == '\017') if (c == '\017') {
{
vt100->selected_charset = 1; vt100->selected_charset = 1;
return ; return;
} }
if (c < ' ') { if (c < ' ') {
return; return;
} }
if (vt100->x == vt100->width) if (vt100->x == vt100->width) {
{
if (MODE_IS_SET(vt100, DECAWM)) if (MODE_IS_SET(vt100, DECAWM))
NEL(term_emul); NEL(term_emul);
else else
@ -1111,13 +1056,13 @@ static void vt100_write(struct lw_terminal *term_emul, char c) {
if (vt100->ustate == 0) { if (vt100->ustate == 0) {
if (uc < 0x80) { if (uc < 0x80) {
vt100_write_unicode(term_emul, uc); vt100_write_unicode(term_emul, uc);
} else if((uc & 0xe0) == 0xc0) { } else if ((uc & 0xe0) == 0xc0) {
vt100->ustate = 1; vt100->ustate = 1;
vt100->ubits = (uc & 0x1f); vt100->ubits = (uc & 0x1f);
} else if((uc & 0xf0) == 0xe0) { } else if ((uc & 0xf0) == 0xe0) {
vt100->ustate = 2; vt100->ustate = 2;
vt100->ubits = (uc & 0xf); vt100->ubits = (uc & 0xf);
} else if((uc & 0xf8) == 0xf0) { } else if ((uc & 0xf8) == 0xf0) {
vt100->ustate = 3; vt100->ustate = 3;
vt100->ubits = (uc & 0x7); vt100->ubits = (uc & 0x7);
} else { } else {
@ -1135,12 +1080,12 @@ static void vt100_write(struct lw_terminal *term_emul, char c) {
vt100->ubits <<= 6; vt100->ubits <<= 6;
vt100->ubits |= uc & 0x3f; vt100->ubits |= uc & 0x3f;
if (--vt100->ustate == 0) { if (--vt100->ustate == 0) {
vt100_write_unicode(term_emul, vt100->ubits); vt100_write_unicode(term_emul, vt100->ubits);
} }
} }
} }
} else { } 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 #else
#define __not_in_flash_func(x) x #define __not_in_flash_func(x) x
#endif #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) if (y < vt100->margin_top || y > vt100->margin_bottom)
return vt100->afrozen_screen + FROZEN_SCREEN_PTR(vt100, 0, y); return vt100->afrozen_screen + FROZEN_SCREEN_PTR(vt100, 0, y);
else else
return vt100->ascreen + SCREEN_PTR(vt100, 0, y); 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; unsigned int y;
for (y = 0; y < vt100->height; ++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) { 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, struct lw_terminal_vt100 *lw_terminal_vt100_init(
void (*unimplemented)(struct lw_terminal* term_emul, char *seq, char chr), void *user_data,
void (*master_write)(void *user_data, void *buffer, size_t len), void (*unimplemented)(struct lw_terminal *term_emul, char *seq, char chr),
lw_cell_t (*encode_attr)(void *user_data, const struct lw_parsed_attr *attr), void (*master_write)(void *user_data, void *buffer, size_t len),
unsigned int width, unsigned int height) 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; struct lw_terminal_vt100 *this;
this = calloc(1, sizeof(*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); this->tabulations = malloc(132);
if (this->tabulations == NULL) if (this->tabulations == NULL)
goto free_frozen_screen; 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->tabulations[i] = (i && i % 8 == 0) ? '|' : '-';
} }
this->margin_top = 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->master_write = master_write;
this->encode_attr = encode_attr ? encode_attr : default_encode_attr; this->encode_attr = encode_attr ? encode_attr : default_encode_attr;
this->map_unicode = default_map_unicode; 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->ascreen, ' ' | this->attr, 132 * SCROLLBACK * this->height);
setcells(this->afrozen_screen, ' ' | this->attr, 132 * this->height); setcells(this->afrozen_screen, ' ' | this->attr, 132 * this->height);
return this; return this;
@ -1253,7 +1202,7 @@ free_this:
static void show_cursor(struct lw_terminal_vt100 *this) { static void show_cursor(struct lw_terminal_vt100 *this) {
unsigned x = this->x, y = this->y; unsigned x = this->x, y = this->y;
lw_cell_t cell; lw_cell_t cell;
if(x == this->width) if (x == this->width)
x -= 1; x -= 1;
if (x >= this->width || y >= this->height) { if (x >= this->width || y >= this->height) {
this->cursor_saved_flag = false; 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) { 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; this->cursor_saved_flag = false;
unsigned x = this->cursor_saved_x, y = this->cursor_saved_y; unsigned x = this->cursor_saved_x, y = this->cursor_saved_y;
aset(this, x, y, aget(this, x, y) ^ CURSOR_ATTR); 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)); 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); hide_cursor(this);
lw_terminal_parser_read_buf(this->lw_terminal, buffer, len); lw_terminal_parser_read_buf(this->lw_terminal, buffer, len);
show_cursor(this); 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); lw_terminal_parser_destroy(this->lw_terminal);
free(this->tabulations); free(this->tabulations);
free(this->ascreen); free(this->ascreen);

View file

@ -26,8 +26,8 @@
#ifndef __LW_TERMINAL_VT100_H__ #ifndef __LW_TERMINAL_VT100_H__
#define __LW_TERMINAL_VT100_H__ #define __LW_TERMINAL_VT100_H__
#include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h>
#include "lw_terminal_parser.h" #include "lw_terminal_parser.h"
@ -39,29 +39,28 @@
#define SCROLLBACK 3 #define SCROLLBACK 3
#define MASK_LNM 1 #define MASK_LNM 1
#define MASK_DECCKM 2 #define MASK_DECCKM 2
#define MASK_DECANM 4 #define MASK_DECANM 4
#define MASK_DECCOLM 8 #define MASK_DECCOLM 8
#define MASK_DECSCLM 16 #define MASK_DECSCLM 16
#define MASK_DECSCNM 32 #define MASK_DECSCNM 32
#define MASK_DECOM 64 #define MASK_DECOM 64
#define MASK_DECAWM 128 #define MASK_DECAWM 128
#define MASK_DECARM 256 #define MASK_DECARM 256
#define MASK_DECINLM 512 #define MASK_DECINLM 512
#define LNM 20 #define LNM 20
#define DECCKM 1 #define DECCKM 1
#define DECANM 2 #define DECANM 2
#define DECCOLM 3 #define DECCOLM 3
#define DECSCLM 4 #define DECSCLM 4
#define DECSCNM 5 #define DECSCNM 5
#define DECOM 6 #define DECOM 6
#define DECAWM 7 #define DECAWM 7
#define DECARM 8 #define DECARM 8
#define DECINLM 9 #define DECINLM 9
#define SET_MODE(vt100, mode) ((vt100)->modes |= get_mode_mask(mode)) #define SET_MODE(vt100, mode) ((vt100)->modes |= get_mode_mask(mode))
#define UNSET_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)) #define MODE_IS_SET(vt100, mode) ((vt100)->modes & get_mode_mask(mode))
@ -73,7 +72,7 @@ struct lw_parsed_attr {
bool blink, bold, inverse; 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 ** 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 ** The top of the frozen_screen holds the top margin
** while the bottom holds the bottom margin. ** while the bottom holds the bottom margin.
*/ */
struct lw_terminal_vt100 struct lw_terminal_vt100 {
{
struct lw_terminal *lw_terminal; struct lw_terminal *lw_terminal;
int ustate, ubits; int ustate, ubits;
unsigned int width; unsigned int width;
@ -94,36 +92,42 @@ struct lw_terminal_vt100
unsigned int margin_top; unsigned int margin_top;
unsigned int margin_bottom; unsigned int margin_bottom;
unsigned int top_line; /* Line at the top of the display */ unsigned int top_line; /* Line at the top of the display */
lw_cell_t *ascreen; lw_cell_t *ascreen;
lw_cell_t *afrozen_screen; lw_cell_t *afrozen_screen;
char *tabulations; char *tabulations;
bool unicode; bool unicode;
bool cursor_saved_flag; bool cursor_saved_flag;
unsigned int selected_charset; unsigned int selected_charset;
unsigned int modes; unsigned int modes;
struct lw_parsed_attr parsed_attr; struct lw_parsed_attr parsed_attr;
lw_cell_t attr; lw_cell_t attr;
int cursor_saved_x, cursor_saved_y; int cursor_saved_x, cursor_saved_y;
const lw_cell_t *alines[80]; const lw_cell_t *alines[80];
void (*master_write)(void *user_data, void *buffer, size_t len); 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); lw_cell_t (*encode_attr)(void *user_data,
int (*map_unicode)(void *user_data, int c); const struct lw_parsed_attr *attr);
void *user_data; int (*map_unicode)(void *user_data, int c);
void *user_data;
}; };
struct lw_terminal_vt100 *lw_terminal_vt100_init(void *user_data, struct lw_terminal_vt100 *lw_terminal_vt100_init(
void (*unimplemented)(struct lw_terminal* term_emul, void *user_data,
char *seq, char chr), void (*unimplemented)(struct lw_terminal *term_emul, char *seq, char chr),
void (*master_write)(void *user_data, void *buffer, size_t len), void (*master_write)(void *user_data, void *buffer, size_t len),
lw_cell_t (*encode_attr)(void *user_data, lw_cell_t (*encode_attr)(void *user_data,
const struct lw_parsed_attr *attr), const struct lw_parsed_attr *attr),
unsigned int width, unsigned int height); unsigned int width, unsigned int height);
char lw_terminal_vt100_get(struct lw_terminal_vt100 *vt100, unsigned int x, unsigned int y); char lw_terminal_vt100_get(struct lw_terminal_vt100 *vt100, unsigned int x,
lw_cell_t lw_terminal_vt100_aget(struct lw_terminal_vt100 *vt100, unsigned int x, unsigned int y); unsigned int y);
const lw_cell_t *lw_terminal_vt100_getline(struct lw_terminal_vt100 *vt100, unsigned 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); 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_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_str(struct lw_terminal_vt100 *this,
void lw_terminal_vt100_read_buf(struct lw_terminal_vt100 *this, const char *buffer, size_t n); const char *buffer);
void lw_terminal_vt100_read_buf(struct lw_terminal_vt100 *this,
const char *buffer, size_t n);
#endif #endif

View file

@ -23,23 +23,21 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include <stdlib.h> #include "hl_vt100.h"
#include <unistd.h>
#include <utmp.h>
#include <string.h>
#include <pty.h> #include <pty.h>
#include <stdio.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; unsigned int x, y;
const lw_cell_t **lines; const lw_cell_t **lines;
lines = vt100_headless_getlines(vt100); lines = vt100_headless_getlines(vt100);
write(1, "\n", 1); write(1, "\n", 1);
for (y = 0; y < vt100->term->height; ++y) for (y = 0; y < vt100->term->height; ++y) {
{
write(1, "|", 1); write(1, "|", 1);
for (x = 0; x < vt100->term->width; x++) { for (x = 0; x < vt100->term->width; x++) {
write(1, &lines[y][x], 1); 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; struct vt100_headless *vt100_headless;
if (ac == 1) if (ac == 1) {
{
puts("Usage: test PROGNAME"); puts("Usage: test PROGNAME");
return EXIT_FAILURE; return EXIT_FAILURE;
} }

View file

@ -12,39 +12,33 @@
other files, you'll have to create a file "foobarobject.h"; see other files, you'll have to create a file "foobarobject.h"; see
floatobject.h for an example. */ floatobject.h for an example. */
#include <stddef.h> #include <stddef.h>
#include "Python.h" #include "Python.h"
#include "structmember.h" #include "structmember.h"
#include "lw_terminal_vt100.h"
#include "hl_vt100.h" #include "hl_vt100.h"
#include "lw_terminal_vt100.h"
typedef struct { typedef struct {
PyObject_HEAD PyObject_HEAD struct vt100_headless *obj;
struct vt100_headless *obj;
PyObject *changed_callback; PyObject *changed_callback;
} VT100Object; } VT100Object;
static PyTypeObject VT100_Type; 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; VT100Object **allocated;
size_t allocated_size; size_t allocated_size;
/* VT100 methods */ /* VT100 methods */
PyDoc_STRVAR(vt100_headless_fork_doc, PyDoc_STRVAR(vt100_headless_fork_doc, "fork(progname, argv)\n\
"fork(progname, argv)\n\
\n\ \n\
Fork a process in a new PTY handled by an headless VT100 emulator."); Fork a process in a new PTY handled by an headless VT100 emulator.");
static PyObject * static PyObject *VT100_fork(VT100Object *self, PyObject *args) {
VT100_fork(VT100Object *self, PyObject *args)
{
char *progname; char *progname;
PyObject *pyargv; PyObject *pyargv;
const char **argv; const char **argv;
@ -53,17 +47,14 @@ VT100_fork(VT100Object *self, PyObject *args)
if (!PyArg_ParseTuple(args, "sO:fork", &progname, &pyargv)) if (!PyArg_ParseTuple(args, "sO:fork", &progname, &pyargv))
return NULL; return NULL;
if (!PyList_Check(pyargv)) if (!PyList_Check(pyargv)) {
{
PyErr_SetString(PyExc_TypeError, "not a list"); PyErr_SetString(PyExc_TypeError, "not a list");
return NULL; return NULL;
} }
argc = PyList_Size(pyargv); argc = PyList_Size(pyargv);
for (i = 0; i < argc; i++) for (i = 0; i < argc; i++) {
{
PyObject *o = PyList_GetItem(pyargv, i); PyObject *o = PyList_GetItem(pyargv, i);
if (!PyUnicode_Check(o)) if (!PyUnicode_Check(o)) {
{
PyErr_SetString(PyExc_TypeError, "argv list must contain strings"); PyErr_SetString(PyExc_TypeError, "argv list must contain strings");
return NULL; return NULL;
} }
@ -77,14 +68,12 @@ VT100_fork(VT100Object *self, PyObject *args)
Py_RETURN_NONE; Py_RETURN_NONE;
} }
PyDoc_STRVAR(vt100_headless_getattrlines_doc, PyDoc_STRVAR(vt100_headless_getattrlines_doc, "getattrlines()\n\
"getattrlines()\n\
\n\ \n\
Get a list of lines (with attributes) as currently seen by the emulator."); Get a list of lines (with attributes) as currently seen by the emulator.");
static PyObject * static PyObject *VT100_getattrlines(VT100Object *self,
VT100_getattrlines(VT100Object *self, PyObject *Py_UNUSED(ignored)) PyObject *Py_UNUSED(ignored)) {
{
const lw_cell_t **lines; const lw_cell_t **lines;
PyObject *result; PyObject *result;
@ -111,14 +100,12 @@ VT100_getattrlines(VT100Object *self, PyObject *Py_UNUSED(ignored))
return result; return result;
} }
PyDoc_STRVAR(vt100_headless_getlines_doc, PyDoc_STRVAR(vt100_headless_getlines_doc, "getlines()\n\
"getlines()\n\
\n\ \n\
Get a list of lines as currently seen by the emulator."); Get a list of lines as currently seen by the emulator.");
static PyObject * static PyObject *VT100_getlines(VT100Object *self,
VT100_getlines(VT100Object *self, PyObject *Py_UNUSED(ignored)) PyObject *Py_UNUSED(ignored)) {
{
const lw_cell_t **lines; const lw_cell_t **lines;
PyObject *result; PyObject *result;
@ -140,63 +127,48 @@ VT100_getlines(VT100Object *self, PyObject *Py_UNUSED(ignored))
return result; return result;
} }
PyDoc_STRVAR(vt100_headless_main_loop_doc, PyDoc_STRVAR(vt100_headless_main_loop_doc, "main_loop()\n\
"main_loop()\n\
\n\ \n\
Enter the emulator main loop."); Enter the emulator main loop.");
static PyObject * static PyObject *VT100_main_loop(VT100Object *self,
VT100_main_loop(VT100Object *self, PyObject *Py_UNUSED(ignored)) PyObject *Py_UNUSED(ignored)) {
{
vt100_headless_main_loop(self->obj); vt100_headless_main_loop(self->obj);
if (PyErr_Occurred()) if (PyErr_Occurred())
return NULL; return NULL;
Py_RETURN_NONE; Py_RETURN_NONE;
} }
PyDoc_STRVAR(vt100_headless_stop_doc, "stop()\n\
PyDoc_STRVAR(vt100_headless_stop_doc,
"stop()\n\
\n\ \n\
Stop emulator main loop."); Stop emulator main loop.");
static PyObject * static PyObject *VT100_stop(VT100Object *self, PyObject *Py_UNUSED(ignored)) {
VT100_stop(VT100Object *self, PyObject *Py_UNUSED(ignored))
{
vt100_headless_stop(self->obj); vt100_headless_stop(self->obj);
Py_RETURN_NONE; Py_RETURN_NONE;
} }
static int vt100_add_to_allocated(VT100Object *obj) {
static int for (size_t i = 0; i < allocated_size; i++) {
vt100_add_to_allocated(VT100Object *obj) if (allocated[i] == NULL) {
{
for (size_t i = 0; i < allocated_size; i++)
{
if (allocated[i] == NULL)
{
allocated[i] = obj; allocated[i] = obj;
return 0; return 0;
} }
} }
/* Out of allocated memory, realloc. */ /* Out of allocated memory, realloc. */
allocated_size *= 2; allocated_size *= 2;
allocated = PyMem_Realloc(allocated, allocated_size * sizeof(VT100Object*)); allocated =
if (allocated == NULL) PyMem_Realloc(allocated, allocated_size * sizeof(VT100Object *));
{ if (allocated == NULL) {
PyErr_SetString(PyExc_MemoryError, "cannot allocate vt100 emulator"); PyErr_SetString(PyExc_MemoryError, "cannot allocate vt100 emulator");
return -1; return -1;
} }
return vt100_add_to_allocated(obj); return vt100_add_to_allocated(obj);
} }
static int static int vt100_del_from_allocated(VT100Object *obj) {
vt100_del_from_allocated(VT100Object *obj) for (size_t i = 0; i < allocated_size; i++) {
{ if (allocated[i] == obj) {
for (size_t i = 0; i < allocated_size; i++)
{
if (allocated[i] == obj)
{
allocated[i] = NULL; allocated[i] = NULL;
return 0; return 0;
} }
@ -204,59 +176,45 @@ vt100_del_from_allocated(VT100Object *obj)
return -1; return -1;
} }
VT100Object * VT100Object *vt100_find_in_allocated(struct vt100_headless *obj) {
vt100_find_in_allocated(struct vt100_headless *obj)
{
for (size_t i = 0; i < allocated_size; i++) for (size_t i = 0; i < allocated_size; i++)
if (allocated[i]->obj == obj) if (allocated[i]->obj == obj)
return allocated[i]; return allocated[i];
return NULL; return NULL;
} }
void void hl_vt100_changed_cb(struct vt100_headless *this) {
hl_vt100_changed_cb(struct vt100_headless *this)
{
VT100Object *obj; VT100Object *obj;
PyObject *result; PyObject *result;
obj = vt100_find_in_allocated(this); 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); result = PyObject_CallNoArgs(obj->changed_callback);
if (result == NULL) if (result == NULL)
this->should_quit = 1; this->should_quit = 1;
} }
} }
static int static int VT100_init(VT100Object *self, PyObject *args, PyObject *kwds) {
VT100_init(VT100Object *self, PyObject *args, PyObject *kwds)
{
self->obj = new_vt100_headless(); self->obj = new_vt100_headless();
vt100_add_to_allocated(self); vt100_add_to_allocated(self);
self->obj->changed = hl_vt100_changed_cb; self->obj->changed = hl_vt100_changed_cb;
if (self->obj == NULL) if (self->obj == NULL) {
{
PyErr_SetString(PyExc_MemoryError, "cannot allocate vt100 emulator"); PyErr_SetString(PyExc_MemoryError, "cannot allocate vt100 emulator");
return -1; return -1;
} }
return 0; return 0;
} }
static PyObject * static PyObject *VT100_getwidth(VT100Object *self, void *closure) {
VT100_getwidth(VT100Object *self, void *closure)
{
return PyLong_FromUnsignedLong(self->obj->term->width); return PyLong_FromUnsignedLong(self->obj->term->width);
} }
static PyObject * static PyObject *VT100_getheight(VT100Object *self, void *closure) {
VT100_getheight(VT100Object *self, void *closure)
{
return PyLong_FromUnsignedLong(self->obj->term->height); return PyLong_FromUnsignedLong(self->obj->term->height);
} }
static void static void VT100_dealloc(VT100Object *self) {
VT100_dealloc(VT100Object *self)
{
vt100_del_from_allocated(self); vt100_del_from_allocated(self);
Py_XDECREF(self->changed_callback); Py_XDECREF(self->changed_callback);
delete_vt100_headless(self->obj); delete_vt100_headless(self->obj);
@ -264,30 +222,31 @@ VT100_dealloc(VT100Object *self)
} }
static PyMethodDef VT100_methods[] = { static PyMethodDef VT100_methods[] = {
{"fork", (PyCFunction)VT100_fork, METH_VARARGS, vt100_headless_fork_doc}, {"fork", (PyCFunction)VT100_fork, METH_VARARGS, vt100_headless_fork_doc},
{"getlines", (PyCFunction)VT100_getlines, METH_NOARGS, vt100_headless_getlines_doc}, {"getlines", (PyCFunction)VT100_getlines, METH_NOARGS,
{"getattrlines", (PyCFunction)VT100_getattrlines, METH_NOARGS, vt100_headless_getattrlines_doc}, vt100_headless_getlines_doc},
{"main_loop", (PyCFunction)VT100_main_loop, METH_NOARGS, vt100_headless_main_loop_doc}, {"getattrlines", (PyCFunction)VT100_getattrlines, METH_NOARGS,
{"stop", (PyCFunction)VT100_stop, METH_NOARGS, vt100_headless_stop_doc}, vt100_headless_getattrlines_doc},
{NULL, NULL} /* sentinel */ {"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[] = { static PyMemberDef VT100_members[] = {
{"changed_callback", T_OBJECT_EX, offsetof(VT100Object, changed_callback), 0, {"changed_callback", T_OBJECT_EX, offsetof(VT100Object, changed_callback),
"Changed Callback"}, 0, "Changed Callback"},
{NULL} /* Sentinel */ {NULL} /* Sentinel */
}; };
static PyGetSetDef VT100_getsetters[] = { static PyGetSetDef VT100_getsetters[] = {
{"width", (getter) VT100_getwidth, NULL, "Terminal width", NULL}, {"width", (getter)VT100_getwidth, NULL, "Terminal width", NULL},
{"height", (getter) VT100_getheight, NULL, "Terminal height", NULL}, {"height", (getter)VT100_getheight, NULL, "Terminal height", NULL},
{NULL} /* Sentinel */ {NULL} /* Sentinel */
}; };
static PyTypeObject VT100_Type = { static PyTypeObject VT100_Type = {
PyVarObject_HEAD_INIT(NULL, 0) PyVarObject_HEAD_INIT(NULL, 0).tp_name = "hl_vt100.vt100_headless",
.tp_name = "hl_vt100.vt100_headless",
.tp_basicsize = sizeof(VT100Object), .tp_basicsize = sizeof(VT100Object),
.tp_dealloc = (destructor)VT100_dealloc, .tp_dealloc = (destructor)VT100_dealloc,
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
@ -298,8 +257,7 @@ static PyTypeObject VT100_Type = {
.tp_getset = VT100_getsetters, .tp_getset = VT100_getsetters,
}; };
PyDoc_STRVAR(module_doc, PyDoc_STRVAR(module_doc, "Headless VT100 Terminal Emulator.");
"Headless VT100 Terminal Emulator.");
static struct PyModuleDef hl_vt100_module = { static struct PyModuleDef hl_vt100_module = {
PyModuleDef_HEAD_INIT, PyModuleDef_HEAD_INIT,
@ -307,13 +265,11 @@ static struct PyModuleDef hl_vt100_module = {
.m_doc = module_doc, .m_doc = module_doc,
}; };
PyMODINIT_FUNC PyMODINIT_FUNC PyInit_hl_vt100(void) {
PyInit_hl_vt100(void)
{
PyObject *m; PyObject *m;
m = PyModule_Create(&hl_vt100_module); m = PyModule_Create(&hl_vt100_module);
allocated = PyMem_Calloc(4096, sizeof(VT100Object*)); allocated = PyMem_Calloc(4096, sizeof(VT100Object *));
allocated_size = 4096; allocated_size = 4096;
if (m == NULL) if (m == NULL)
return NULL; return NULL;

View file

@ -1,11 +1,11 @@
#include "atkbd.pio.h"
#include "keyboard.h" #include "keyboard.h"
#include "pinout.h" #include "atkbd.pio.h"
#include "chargen.h" #include "chargen.h"
#include "pinout.h"
#include "hardware/clocks.h"
#include "pico.h" #include "pico.h"
#include "pico/stdlib.h" #include "pico/stdlib.h"
#include "hardware/clocks.h"
#define EOF (-1) #define EOF (-1)
@ -18,14 +18,18 @@ static int kbd_sm;
static int ll_kbd_read_timeout(int timeout_us) { static int ll_kbd_read_timeout(int timeout_us) {
uint64_t deadline = time_us_64() + timeout_us; uint64_t deadline = time_us_64() + timeout_us;
while (pio_sm_is_rx_fifo_empty(kbd_pio, kbd_sm)) { 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); return pio_sm_get_blocking(kbd_pio, kbd_sm);
} }
static int kbd_read_timeout(int timeout_us) { static int kbd_read_timeout(int timeout_us) {
int r = ll_kbd_read_timeout(timeout_us); int r = ll_kbd_read_timeout(timeout_us);
if (r == EOF) { return EOF; } if (r == EOF) {
return EOF;
}
r = (r >> 22) & 0xff; r = (r >> 22) & 0xff;
return r; // todo: check parity, start & end bits! 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); pio_sm_clear_fifos(kbd_pio, kbd_sm);
kbd_write_blocking(value); kbd_write_blocking(value);
return expect(0xfa, msg); return expect(0xfa, msg);
} }
bool keyboard_setup(PIO pio) { bool keyboard_setup(PIO pio) {
gpio_init(KEYBOARD_DATA_PIN); gpio_init(KEYBOARD_DATA_PIN);
@ -64,14 +67,14 @@ bool keyboard_setup(PIO pio) {
gpio_pull_down(KEYBOARD_DATA_PIN + 1); gpio_pull_down(KEYBOARD_DATA_PIN + 1);
int i = 0, j = 1; int i = 0, j = 1;
while(!(gpio_get(KEYBOARD_DATA_PIN) && gpio_get(KEYBOARD_DATA_PIN + 1))) { while (!(gpio_get(KEYBOARD_DATA_PIN) && gpio_get(KEYBOARD_DATA_PIN + 1))) {
if(i ++ == j) { if (i++ == j) {
scrnprintf("Waiting for keyboard to boot... %d ms so far\r", i); scrnprintf("Waiting for keyboard to boot... %d ms so far\r", i);
j *= 10; j *= 10;
} }
sleep_ms(1); sleep_ms(1);
} }
sleep_ms(10); sleep_ms(10);
kbd_pio = pio; kbd_pio = pio;
@ -99,17 +102,20 @@ bool keyboard_setup(PIO pio) {
return ok; return ok;
} }
enum {
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 }; 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] = { const char keyboard_modifiers[256] = {
[0x12] = LSHIFT, [0x12] = LSHIFT, [0x59] = RSHIFT, [0x11] = LCTRL, [0x58] = RCTRL,
[0x59] = RSHIFT, [0x19] = LALT, [0x39] = RALT, [0x14] = MOD_CAPS, [0x76] = MOD_NUM,
[0x11] = LCTRL,
[0x58] = RCTRL,
[0x19] = LALT,
[0x39] = RALT,
[0x14] = MOD_CAPS,
[0x76] = MOD_NUM,
}; };
enum SYMBOLS { enum SYMBOLS {
@ -143,37 +149,21 @@ enum SYMBOLS {
const char *const symtab[MAX_SYMBOLS] = { const char *const symtab[MAX_SYMBOLS] = {
#define ENT(x, y) [x] = y #define ENT(x, y) [x] = y
ENT(F1, "\eOP"), ENT(F1, "\eOP"), ENT(F2, "\eOQ"), ENT(F3, "\eOR"),
ENT(F2, "\eOQ"), ENT(F4, "\eOS"), ENT(F5, "\e[15~"), ENT(F6, "\e[17~"),
ENT(F3, "\eOR"), ENT(F7, "\e[18~"), ENT(F8, "\e[19~"), ENT(F9, "\e[20~"),
ENT(F4, "\eOS"), ENT(F10, "\e[21~"), ENT(F11, "\e[23~"), ENT(F12, "\e[24~"),
ENT(F5, "\e[15~"), ENT(PRTSCR, "\ei"), ENT(PAUSE, ""), ENT(INSERT, "\e[2~"),
ENT(F6, "\e[17~"), ENT(DELETE, "\e[3~"), ENT(UPARROW, "\e[A"), ENT(DOWNARROW, "\e[B"),
ENT(F7, "\e[18~"), ENT(RIGHTARROW, "\e[C"), ENT(LEFTARROW, "\e[D"), ENT(HOME, "\e[H"),
ENT(F8, "\e[19~"), ENT(END, "\e[F"), ENT(PAGEUP, "\e[5~"), ENT(PAGEDOWN, "\e[6~"),
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 #undef ENT
}; };
#define SYM(x) (0x8000 | (int)(x)) #define SYM(x) (0x8000 | (int)(x))
#define CMD(x) (0xc000 | (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 ALPHA(c) CHAR2(c, c ^ ('a' ^ 'A'))
#define NOMOD(c) CHAR2(c, c) #define NOMOD(c) CHAR2(c, c)
@ -199,7 +189,7 @@ const uint16_t keyboard_codes[256] = {
[0x62] = SYM(PAUSE), [0x62] = SYM(PAUSE),
[0x67] = SYM(INSERT), [0x67] = SYM(INSERT),
[0x64] = SYM(DELETE), [0x64] = SYM(DELETE),
[0x0e] = CHAR2('`', '~'), [0x0e] = CHAR2('`', '~'),
[0x16] = CHAR2('1', '!'), [0x16] = CHAR2('1', '!'),
[0x1e] = CHAR2('2', '@'), [0x1e] = CHAR2('2', '@'),
@ -260,7 +250,6 @@ const uint16_t keyboard_codes[256] = {
[0x6a] = SYM(RIGHTARROW), [0x6a] = SYM(RIGHTARROW),
[0x60] = SYM(DOWNARROW), [0x60] = SYM(DOWNARROW),
[0x6e] = SYM(HOME), [0x6e] = SYM(HOME),
[0x65] = SYM(END), [0x65] = SYM(END),
[0x6f] = SYM(PAGEUP), [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) { 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]; int modifiers = keyboard_modifiers[value];
if (modifiers) { if (modifiers) {
if(release) { if (release) {
if (modifiers & TOGGLING_MODIFIERS) { if (modifiers & TOGGLING_MODIFIERS) {
current_modifiers ^= modifiers; current_modifiers ^= modifiers;
keyboard_set_leds( keyboard_set_leds(
((current_modifiers & MOD_NUM) ? LED_NUM : 0) | ((current_modifiers & MOD_NUM) ? LED_NUM : 0) |
((current_modifiers & MOD_CAPS) ? LED_CAPS : 0)); ((current_modifiers & MOD_CAPS) ? LED_CAPS : 0));
} else { } else {
current_modifiers &= ~modifiers; current_modifiers &= ~modifiers;
} }
@ -301,7 +289,9 @@ void queue_handle_event(queue_t *q, bool release, int value) {
} }
return; return;
} }
if(release) { return; } if (release) {
return;
}
bool is_shift = current_modifiers & (LSHIFT | RSHIFT); bool is_shift = current_modifiers & (LSHIFT | RSHIFT);
bool is_ctrl = current_modifiers & (LCTRL | RCTRL); 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); bool is_caps = current_modifiers & (MOD_CAPS);
int kc = keyboard_codes[value]; int kc = keyboard_codes[value];
if(!kc) { if (!kc) {
scrnprintf("\r\nUn-mapped key: 0x%02x\r\n", value); scrnprintf("\r\nUn-mapped key: 0x%02x\r\n", value);
return; return;
} }
if((kc & 0xc000) == 0xc000) { if ((kc & 0xc000) == 0xc000) {
queue_add_data(q, kc); queue_add_data(q, kc);
return; return;
} }
if(kc & 0x8000) { if (kc & 0x8000) {
int sym = kc & 0x7fff; int sym = kc & 0x7fff;
if(is_ctrl && is_alt) { if (is_ctrl && is_alt) {
if (sym == DELETE) { if (sym == DELETE) {
queue_add_data(q, CMD_REBOOT); 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); int c = LO(kc);
// scrnprintf("c=%d HI=%d is_shift=%d\n", c, HI(kc), is_shift); // 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) #define CTRLABLE(c) (c >= 64 && c <= 127)
if(is_ctrl && CTRLABLE(c)) { if (is_ctrl && CTRLABLE(c)) {
c = c & 0x1f; c = c & 0x1f;
} }
if(is_ctrl && c == 010) { if (is_ctrl && c == 010) {
c = 0377; // ctrl-backspace = RUBOUT c = 0377; // ctrl-backspace = RUBOUT
} }
#define IS_ALPHA(c) ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) #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'); c ^= ('a' ^ 'A');
} }
if(is_alt) { if (is_alt) {
queue_add_data(q, '\033'); queue_add_data(q, '\033');
} }
queue_add_data(q, c); queue_add_data(q, c);
@ -364,9 +355,8 @@ void keyboard_poll(queue_t *q) {
int value = kbd_read_timeout(0); int value = kbd_read_timeout(0);
if (value == EOF) { if (value == EOF) {
return; return;
} } else if (value == 0xfa) {
else if (value == 0xfa) { if (pending_led_flag) {
if(pending_led_flag) {
kbd_write_blocking(pending_led_value); kbd_write_blocking(pending_led_value);
pending_led_flag = false; pending_led_flag = false;
} }

View file

@ -28,7 +28,7 @@ class TTF:
s = struct.calcsize(format) s = struct.calcsize(format)
return struct.unpack_from(format, f.read(s)) return struct.unpack_from(format, f.read(s))
scalar_type = read(">I") read(">I") # discard "scalar_type
numTables, searchRange, entrySelector, rangeShift = read(">HHHH") numTables, searchRange, entrySelector, rangeShift = read(">HHHH")
print(numTables) print(numTables)

View file

@ -1,10 +1,10 @@
import array import array
from dataclasses import dataclass
import sys import sys
import click import click
from adafruit_bitmap_font import bitmap_font, Bitmap from adafruit_bitmap_font import bitmap_font, Bitmap
def extract_deposit_bits(*positions): def extract_deposit_bits(*positions):
data_out = 0 data_out = 0
for p in positions: for p in positions:
@ -13,6 +13,7 @@ def extract_deposit_bits(*positions):
data_out |= 1 << dest data_out |= 1 << dest
return data_out return data_out
class OffsetBitmap: class OffsetBitmap:
def __init__(self, dx, dy, glyph): def __init__(self, dx, dy, glyph):
self.dx = dx self.dx = dx
@ -26,21 +27,22 @@ class OffsetBitmap:
print(pos, x, y) print(pos, x, y)
if 0 <= x < self.glyph.bitmap.width and 0 <= y < self.glyph.bitmap.height: 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 return 0
@click.command @click.command
@click.argument("bdf", type=click.Path(exists=True)) @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): def main(bdf, header):
font = bitmap_font.load_font(bdf, Bitmap) font = bitmap_font.load_font(bdf, Bitmap)
width, height, dx, dy = font.get_bounding_box() width, height, dx, dy = font.get_bounding_box()
print(width, height, dx, dy) print(width, height, dx, dy)
# if width != 5 or height != 9: # if width != 5 or height != 9:
# raise SystemExit("sorry, only 5x9 monospace fonts supported") # 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)) font.load_glyphs(range(256))
@ -56,9 +58,11 @@ def main(bdf, header):
(bitmap[3, j], 2, 3), (bitmap[3, j], 2, 3),
(bitmap[2, j], 4, 5), (bitmap[2, j], 4, 5),
(bitmap[1, j], 6, 7), (bitmap[1, j], 6, 7),
(bitmap[0, j], 8, 9)) (bitmap[0, j], 8, 9),
)
output_data[j * 256 + i] = d << 2 output_data[j * 256 + i] = d << 2
print(", ".join(f"0x{x:04x}" for x in output_data), file=header) print(", ".join(f"0x{x:04x}" for x in output_data), file=header)
if __name__ == '__main__':
if __name__ == "__main__":
main() main()

View file

@ -1,13 +1,14 @@
#!/usr/bin/env python #!/usr/bin/env python
import sys import sys
from enum import Enum, auto
from dataclasses import dataclass, replace from dataclasses import dataclass, replace
class Polarity: class Polarity:
Negative = 0 Negative = 0
Positive = 1 Positive = 1
@dataclass(frozen=True) @dataclass(frozen=True)
class VideoMode: class VideoMode:
pixel_clock_khz: int pixel_clock_khz: int
@ -20,7 +21,9 @@ class VideoMode:
@property @property
def total_width(self): 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 @property
def line_rate_khz(self): def line_rate_khz(self):
@ -42,7 +45,12 @@ class VideoMode:
@property @property
def total_lines(self): 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 @property
def frame_rate_hz(self): def frame_rate_hz(self):
@ -55,17 +63,18 @@ class VideoMode:
def __repr__(self): 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>" 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): def change_visible_width(mode_in, new_w, new_clock=None):
print(mode_in) print(mode_in)
if new_clock is None: if new_clock is None:
new_clock = mode_in.pixel_clock_khz * new_w / mode_in.visible_width new_clock = mode_in.pixel_clock_khz * new_w / mode_in.visible_width
new_mode = replace(mode_in, new_mode = replace(
pixel_clock_khz = new_clock, mode_in,
visible_width = new_w, pixel_clock_khz=new_clock,
visible_width=new_w,
) )
print(new_mode) print(new_mode)
ratio = new_clock / mode_in.pixel_clock_khz 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) new_line_counts = round(mode_in.total_width * ratio)
print(new_line_counts, mode_in.total_width * ratio) print(new_line_counts, mode_in.total_width * ratio)
new_pulse = round(mode_in.hsync_pulse * 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) porch_ratio = mode_in.hfront_porch / (mode_in.hfront_porch + mode_in.hback_porch)
new_front = round(new_porch_counts * porch_ratio) new_front = round(new_porch_counts * porch_ratio)
new_back = new_porch_counts - new_front 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 = replace(
new_mode, new_mode, hfront_porch=new_front, hsync_pulse=new_pulse, hback_porch=new_back
hfront_porch = new_front, )
hsync_pulse = new_pulse,
hback_porch = new_back)
print(new_mode) print(new_mode)
print() print()
return new_mode return new_mode
def change_visible_height(mode_in, new_h): def change_visible_height(mode_in, new_h):
delta_rows = mode_in.visible_height - new_h delta_rows = mode_in.visible_height - new_h
delta_front_porch = delta_rows // 2 delta_front_porch = delta_rows // 2
delta_back_porch = delta_rows - delta_front_porch delta_back_porch = delta_rows - delta_front_porch
new_mode = replace(mode_in, new_mode = replace(
visible_height = new_h, mode_in,
vfront_porch = mode_in.vfront_porch + delta_front_porch, visible_height=new_h,
vback_porch = mode_in.vback_porch + delta_back_porch) vfront_porch=mode_in.vfront_porch + delta_front_porch,
vback_porch=mode_in.vback_porch + delta_back_porch,
)
print(new_mode) print(new_mode)
print() print()
assert new_mode.total_lines == mode_in.total_lines assert new_mode.total_lines == mode_in.total_lines
return new_mode return new_mode
def pio_hard_delay(instr, n, file): def pio_hard_delay(instr, n, file):
assert n > 0 assert n > 0
assert n < 128 assert n < 128
@ -105,10 +120,14 @@ def pio_hard_delay(instr, n, file):
n -= cycles n -= cycles
print(file=file) 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 net_khz = mode.pixel_clock_khz / h_divisor
err = (mode.visible_width + mode.hfront_porch) % h_divisor err = (mode.visible_width + mode.hfront_porch) % h_divisor
print(f""" print(
f"""
; Horizontal sync program for {mode} ; Horizontal sync program for {mode}
; PIO clock frequency = {mode.pixel_clock_khz:.1f}/{h_divisor}khz = {net_khz:.1f} ; 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: activeporch:
jmp x-- activeporch ; Remain high in active mode and front porch jmp x-- activeporch ; Remain high in active mode and front porch
""", file=file) """,
file=file,
)
cycles, err = divmod(mode.hsync_pulse + err, h_divisor) 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) pio_hard_delay(f"set pins, {mode.hsync_polarity:d}", cycles, file=file)
cycles, err = divmod(mode.hback_porch + err, h_divisor) 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) pio_hard_delay(f"set pins, {not mode.hsync_polarity:d}", cycles - 1, file=file)
print(" irq 0 [1]", file=file) print(" irq 0 [1]", file=file)
print(".wrap", file=file) print(".wrap", file=file)
print(f""" print(
f"""
% c-sdk {{ % c-sdk {{
static inline void {program_name_base}_hsync_program_init(PIO pio, uint sm, uint offset, uint pin) {{ static inline void {program_name_base}_hsync_program_init(PIO pio, uint sm, uint offset, uint pin) {{
@ -152,13 +180,16 @@ static inline void {program_name_base}_hsync_program_init(PIO pio, uint sm, uint
// Set up the value in the OSR register // Set up the value in the OSR register
pio_sm_put(pio, sm, {mode.visible_width} + {mode.hfront_porch} - 1); pio_sm_put(pio, sm, {mode.visible_width} + {mode.hfront_porch} - 1);
pio_sm_exec_wait_blocking(pio, sm, pio_encode_pull(false, true)); pio_sm_exec_wait_blocking(pio, sm, pio_encode_pull(false, true));
// Set the state machine running // Set the state machine running
pio_sm_set_enabled(pio, sm, true); pio_sm_set_enabled(pio, sm, true);
}} }}
%}} %}}
""", file=file) """,
file=file,
)
def pio_yloop(instr, n, label, comment, file): def pio_yloop(instr, n, label, comment, file):
assert n <= 65 assert n <= 65
@ -183,22 +214,45 @@ def pio_yloop(instr, n, label, comment, file):
print(f" {instr}", file=file) print(f" {instr}", file=file)
print(file=file) print(file=file)
def print_pio_vsync_program(program_name_base, mode, cycles_per_pixel, file=sys.stdout): def print_pio_vsync_program(program_name_base, mode, cycles_per_pixel, file=sys.stdout):
print(f""" print(
f"""
.program {program_name_base}_vsync .program {program_name_base}_vsync
.side_set 1 opt .side_set 1 opt
; Vertical sync program for {mode} ; Vertical sync program for {mode}
; ;
.wrap_target ; Program wraps to here .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 ; ACTIVE
mov x, osr ; Copy value from OSR to x scratch register mov x, osr ; Copy value from OSR to x scratch register
active: active:
@ -206,12 +260,14 @@ active:
irq 1 ; Signal that we're in active mode irq 1 ; Signal that we're in active mode
jmp x-- active ; Remain in active mode, decrementing counter jmp x-- active ; Remain in active mode, decrementing counter
""", file=file) """,
file=file,
)
print(".wrap", file=file) print(".wrap", file=file)
print(f""" print(
f"""
% c-sdk {{ % c-sdk {{
static inline void {program_name_base}_vsync_program_init(PIO pio, uint sm, uint offset, uint pin) {{ 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(
def print_pio_pixel_program(program_name_base, mode, out_instr, cycles_per_pixel, file=sys.stdout): program_name_base, mode, out_instr, cycles_per_pixel, file=sys.stdout
):
net_khz = cycles_per_pixel * mode.pixel_clock_khz net_khz = cycles_per_pixel * mode.pixel_clock_khz
assert cycles_per_pixel >= 2 assert cycles_per_pixel >= 2
print(f""" print(
f"""
.program {program_name_base}_pixel .program {program_name_base}_pixel
; Pixel generator program for {mode} ; Pixel generator program for {mode}
; PIO clock frequency = {cycles_per_pixel}×{mode.pixel_clock_khz}khz = {net_khz} ; PIO clock frequency = {cycles_per_pixel}×{mode.pixel_clock_khz}khz = {net_khz}
@ -264,9 +324,12 @@ colorout:
{out_instr} [{cycles_per_pixel-2}] {out_instr} [{cycles_per_pixel-2}]
jmp x-- colorout ; Stay here thru horizontal active mode jmp x-- colorout ; Stay here thru horizontal active mode
.wrap""", file=file) .wrap""",
file=file,
)
print(f""" print(
f"""
% c-sdk {{ % 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} }}; 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) // Set this pin's GPIO function (connect PIO to the pad)
for(uint i=0; i<n_pin; i++) {{ 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); gpio_set_drive_strength(pin + i, GPIO_DRIVE_STRENGTH_8MA);
pio_gpio_init(pio, pin + i); 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_660x480 = change_visible_width(mode_vga_640x480, 660, 26_000)
mode_vga_660x477 = change_visible_height(mode_vga_660x480, 477) 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) mode_vga_660x400 = change_visible_width(mode_vga_720x400, 660, 26_000)
if 0: if 0:
print(mode_vga_640x480, 6*mode_vga_640x480.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_660x480, 6 * mode_vga_660x480.pixel_clock_khz)
print(mode_vga_720x400, 6*mode_vga_720x400.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_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_pio_hsync_program(program_name, mode, h_divisor, cycles_per_pixel, file=file)
print("\n\n\n", file=file) print("\n\n\n", file=file)
print_pio_vsync_program(program_name, mode, cycles_per_pixel, file=file) print_pio_vsync_program(program_name, mode, cycles_per_pixel, file=file)
print("\n\n\n", file=file) print("\n\n\n", file=file)
print_pio_pixel_program(program_name, mode, out_instr, cycles_per_pixel, 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: with open("vga_660x477_60.pio", "wt", encoding="utf-8") as f:
print_all(mode_vga_660x477, file=f) print_all(mode_vga_660x477, file=f)