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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -23,27 +23,36 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include "lw_terminal_vt100.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static unsigned int get_mode_mask(unsigned int mode)
{
switch (mode)
{
case LNM : return MASK_LNM;
case DECCKM : return MASK_DECCKM;
case DECANM : return MASK_DECANM;
case DECCOLM : return MASK_DECCOLM;
case DECSCLM : return MASK_DECSCLM;
case DECSCNM : return MASK_DECSCNM;
case DECOM : return MASK_DECOM;
case DECAWM : return MASK_DECAWM;
case DECARM : return MASK_DECARM;
case DECINLM : return MASK_DECINLM;
default: return 0;
static unsigned int get_mode_mask(unsigned int mode) {
switch (mode) {
case LNM:
return MASK_LNM;
case DECCKM:
return MASK_DECCKM;
case DECANM:
return MASK_DECANM;
case DECCOLM:
return MASK_DECCOLM;
case DECSCLM:
return MASK_DECSCLM;
case DECSCNM:
return MASK_DECSCNM;
case DECOM:
return MASK_DECOM;
case DECAWM:
return MASK_DECAWM;
case DECARM:
return MASK_DECARM;
case DECINLM:
return MASK_DECINLM;
default:
return 0;
}
}
@ -179,63 +188,57 @@ static unsigned int get_mode_mask(unsigned int mode)
#define MOD1(a, b) ((a < b) ? a : a - b)
#define SCREEN_PTR(vt100, x, y) \
MOD1((vt100->top_line * vt100->width + x + vt100->width * y), \
(vt100->width * SCROLLBACK * vt100->height))
#define SCREEN_PTR(vt100, x, y) \
MOD1((vt100->top_line * vt100->width + x + vt100->width * y), \
(vt100->width * SCROLLBACK * vt100->height))
#define FROZEN_SCREEN_PTR(vt100, x, y) \
(MOD1(x + vt100->width * y, \
(vt100->width * SCROLLBACK * vt100->height)))
#define FROZEN_SCREEN_PTR(vt100, x, y) \
(MOD1(x + vt100->width * y, (vt100->width * SCROLLBACK * vt100->height)))
static lw_cell_t aget(struct lw_terminal_vt100 *headless_term,
unsigned int x, unsigned int y)
{
static lw_cell_t aget(struct lw_terminal_vt100 *headless_term, unsigned int x,
unsigned int y) {
if (y < headless_term->margin_top || y > headless_term->margin_bottom)
return headless_term->afrozen_screen[FROZEN_SCREEN_PTR(headless_term, x, y)];
return headless_term
->afrozen_screen[FROZEN_SCREEN_PTR(headless_term, x, y)];
else
return headless_term->ascreen[SCREEN_PTR(headless_term, x, y)];
}
static void aset(struct lw_terminal_vt100 *headless_term,
unsigned int x, unsigned int y,
lw_cell_t c)
{
static void aset(struct lw_terminal_vt100 *headless_term, unsigned int x,
unsigned int y, lw_cell_t c) {
if (y < headless_term->margin_top || y > headless_term->margin_bottom)
headless_term->afrozen_screen[FROZEN_SCREEN_PTR(headless_term, x, y)] = c;
headless_term->afrozen_screen[FROZEN_SCREEN_PTR(headless_term, x, y)] =
c;
else
headless_term->ascreen[SCREEN_PTR(headless_term, x, y)] = c;
}
static void set(struct lw_terminal_vt100 *headless_term,
unsigned int x, unsigned int y,
char c) {
aset( headless_term, x, y, (unsigned char)c | headless_term->attr);
static void set(struct lw_terminal_vt100 *headless_term, unsigned int x,
unsigned int y, char c) {
aset(headless_term, x, y, (unsigned char)c | headless_term->attr);
}
lw_cell_t lw_terminal_vt100_aget(struct lw_terminal_vt100 *vt100, unsigned int x, unsigned int y)
{
lw_cell_t lw_terminal_vt100_aget(struct lw_terminal_vt100 *vt100,
unsigned int x, unsigned int y) {
if (y < vt100->margin_top || y > vt100->margin_bottom)
return vt100->afrozen_screen[FROZEN_SCREEN_PTR(vt100, x, y)];
else
return vt100->ascreen[SCREEN_PTR(vt100, x, y)];
}
static void froze_line(struct lw_terminal_vt100 *vt100, unsigned int y)
{
static void froze_line(struct lw_terminal_vt100 *vt100, unsigned int y) {
memcpy(vt100->afrozen_screen + vt100->width * y,
vt100->ascreen + SCREEN_PTR(vt100, 0, y),
vt100->width * sizeof(lw_cell_t));
}
static void unfroze_line(struct lw_terminal_vt100 *vt100, unsigned int y)
{
static void unfroze_line(struct lw_terminal_vt100 *vt100, unsigned int y) {
memcpy(vt100->ascreen + SCREEN_PTR(vt100, 0, y),
vt100->afrozen_screen + vt100->width * y,
vt100->width * sizeof(lw_cell_t));
}
static void blank_screen(struct lw_terminal_vt100 *lw_terminal_vt100)
{
static void blank_screen(struct lw_terminal_vt100 *lw_terminal_vt100) {
unsigned int x;
unsigned int y;
@ -252,8 +255,7 @@ static void blank_screen(struct lw_terminal_vt100 *lw_terminal_vt100)
This sequence causes the cursor position, graphic rendition, and
character set to be saved. (See DECRC).
*/
static void DECSC(struct lw_terminal *term_emul)
{
static void DECSC(struct lw_terminal *term_emul) {
/*TODO: Save graphic rendition and charset.*/
struct lw_terminal_vt100 *vt100;
@ -273,17 +275,14 @@ static void DECSC(struct lw_terminal *term_emul)
Modes following this section).
*/
static void RM(struct lw_terminal *term_emul)
{
static void RM(struct lw_terminal *term_emul) {
struct lw_terminal_vt100 *vt100;
unsigned int mode;
vt100 = (struct lw_terminal_vt100 *)term_emul->user_data;
if (term_emul->argc > 0)
{
if (term_emul->argc > 0) {
mode = term_emul->argv[0];
if (mode == DECCOLM)
{
if (mode == DECCOLM) {
vt100->width = 80;
vt100->x = vt100->y = 0;
blank_screen(vt100);
@ -335,11 +334,10 @@ x Pm = 97 / 107 fg/bg Bright White
x Pm = 99 / 109 fg/bg Bright Default
*/
static int default_map_unicode(void *user_data, int c) {
return '?';
}
static int default_map_unicode(void *user_data, int c) { return '?'; }
static lw_cell_t default_encode_attr(void *user_data, const struct lw_parsed_attr *attr) {
static lw_cell_t default_encode_attr(void *user_data,
const struct lw_parsed_attr *attr) {
(void)user_data;
lw_cell_t result;
@ -350,29 +348,33 @@ static lw_cell_t default_encode_attr(void *user_data, const struct lw_parsed_att
result = attr->fg;
result |= attr->bg << 4;
}
if (attr->bold) result ^= 0x08;
if (attr->blink) result ^= 0x80;
if (attr->bold)
result ^= 0x08;
if (attr->blink)
result ^= 0x80;
return result << 8;
}
static void SGR(struct lw_terminal *term_emul)
{
struct lw_terminal_vt100 *vt100 = (struct lw_terminal_vt100 *)term_emul->user_data;
static void SGR(struct lw_terminal *term_emul) {
struct lw_terminal_vt100 *vt100 =
(struct lw_terminal_vt100 *)term_emul->user_data;
// vim sends "CSI > 4 ; 2 m" and you can't stop it
if (term_emul->flag == '>') { return; }
if (term_emul->flag == '>') {
return;
}
if (term_emul->argc == 0) {
term_emul->argc = 1;
term_emul->argv[0] = 0;
}
for (unsigned int i=0; i<term_emul->argc; i++) {
for (unsigned int i = 0; i < term_emul->argc; i++) {
int p = term_emul->argv[i];
switch(p) {
case 0:
vt100->parsed_attr = LW_DEFAULT_ATTR;
switch (p) {
case 0:
vt100->parsed_attr = LW_DEFAULT_ATTR;
break;
case 1:
@ -447,8 +449,7 @@ static void SGR(struct lw_terminal *term_emul)
The numbering of lines depends on the state of the Origin Mode
(DECOM).
*/
static void CUP(struct lw_terminal *term_emul)
{
static void CUP(struct lw_terminal *term_emul) {
struct lw_terminal_vt100 *vt100;
int arg0;
int arg1;
@ -465,14 +466,17 @@ static void CUP(struct lw_terminal *term_emul)
if (arg1 < 0)
arg1 = 0;
if (MODE_IS_SET(vt100, DECOM))
{
if (MODE_IS_SET(vt100, DECOM)) {
arg0 += vt100->margin_top;
if ((unsigned int)arg0 > vt100->margin_bottom)
arg0 = vt100->margin_bottom;
}
if (arg0 >= vt100->height) { arg0 = vt100->height - 1; }
if (arg1 >= vt100->width) { arg1 = vt100->width - 1; }
if (arg0 >= vt100->height) {
arg0 = vt100->height - 1;
}
if (arg1 >= vt100->width) {
arg1 = vt100->width - 1;
}
vt100->y = arg0;
vt100->x = arg1;
}
@ -488,30 +492,25 @@ static void CUP(struct lw_terminal *term_emul)
it is reset by a reset mode (RM) control sequence.
*/
static void SM(struct lw_terminal *term_emul)
{
static void SM(struct lw_terminal *term_emul) {
struct lw_terminal_vt100 *vt100;
unsigned int mode;
unsigned int saved_argc;
vt100 = (struct lw_terminal_vt100 *)term_emul->user_data;
if (term_emul->argc > 0)
{
if (term_emul->argc > 0) {
mode = term_emul->argv[0];
SET_MODE(vt100, mode);
if (mode == DECANM)
{
if (mode == DECANM) {
/* TODO: Support vt52 mode */
return ;
return;
}
if (mode == DECCOLM)
{
if (mode == DECCOLM) {
vt100->width = 132;
vt100->x = vt100->y = 0;
blank_screen(vt100);
}
if (mode == DECOM)
{
if (mode == DECOM) {
saved_argc = term_emul->argc;
term_emul->argc = 0;
CUP(term_emul);
@ -534,8 +533,7 @@ static void SM(struct lw_terminal *term_emul)
cursor is placed in the home position (see Origin Mode DECOM).
*/
static void DECSTBM(struct lw_terminal *term_emul)
{
static void DECSTBM(struct lw_terminal *term_emul) {
unsigned int margin_top;
unsigned int margin_bottom;
struct lw_terminal_vt100 *vt100;
@ -543,17 +541,14 @@ static void DECSTBM(struct lw_terminal *term_emul)
vt100 = (struct lw_terminal_vt100 *)term_emul->user_data;
if (term_emul->argc == 2)
{
if (term_emul->argc == 2) {
margin_top = term_emul->argv[0] - 1;
margin_bottom = term_emul->argv[1] - 1;
if (margin_bottom >= vt100->height)
return ;
return;
if (margin_bottom - margin_top <= 0)
return ;
}
else
{
return;
} else {
margin_top = 0;
margin_bottom = vt100->height - 1;
}
@ -594,16 +589,14 @@ static void DECSTBM(struct lw_terminal *term_emul)
GPO, STP and AVO ESC [?1;7c
*/
static void DA(struct lw_terminal *term_emul)
{
static void DA(struct lw_terminal *term_emul) {
struct lw_terminal_vt100 *vt100;
vt100 = (struct lw_terminal_vt100 *)term_emul->user_data;
vt100->master_write(vt100->user_data, "\033[?1;0c", 7);
}
static void DSR(struct lw_terminal *term_emul)
{
static void DSR(struct lw_terminal *term_emul) {
struct lw_terminal_vt100 *vt100;
vt100 = (struct lw_terminal_vt100 *)term_emul->user_data;
@ -611,20 +604,18 @@ static void DSR(struct lw_terminal *term_emul)
return;
}
switch(term_emul->argv[0]) {
case 5:
vt100->master_write(vt100->user_data, "\033[0n", 4);
break;
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));
}
switch (term_emul->argv[0]) {
case 5:
vt100->master_write(vt100->user_data, "\033[0n", 4);
break;
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
rendition, and character set to be restored.
*/
static void DECRC(struct lw_terminal *term_emul)
{
static void DECRC(struct lw_terminal *term_emul) {
/*TODO Save graphic rendition and charset */
struct lw_terminal_vt100 *vt100;
@ -655,8 +645,7 @@ static void DECRC(struct lw_terminal *term_emul)
focus and alignment. This command is used by DEC manufacturing and
Field Service personnel.
*/
static void DECALN(struct lw_terminal *term_emul)
{
static void DECALN(struct lw_terminal *term_emul) {
struct lw_terminal_vt100 *vt100;
unsigned int x;
unsigned int y;
@ -676,22 +665,18 @@ static void DECALN(struct lw_terminal *term_emul)
without changing the column position. If the active position is at the
bottom margin, a scroll up is performed. Format Effector
*/
static void IND(struct lw_terminal *term_emul)
{
static void IND(struct lw_terminal *term_emul) {
struct lw_terminal_vt100 *vt100;
unsigned int x;
vt100 = (struct lw_terminal_vt100 *)term_emul->user_data;
if (vt100->y >= vt100->margin_bottom)
{
if (vt100->y >= vt100->margin_bottom) {
/* SCROLL */
vt100->top_line = (vt100->top_line + 1) % (vt100->height * SCROLLBACK);
for (x = 0; x < vt100->width; ++x)
set(vt100, x, vt100->margin_bottom, ' ');
}
else
{
} else {
/* Do not scroll, just move downward on the current display space */
vt100->y += 1;
}
@ -705,18 +690,14 @@ static void IND(struct lw_terminal *term_emul)
preceding line. If the active position is at the top margin, a scroll
down is performed. Format Effector
*/
static void RI(struct lw_terminal *term_emul)
{
static void RI(struct lw_terminal *term_emul) {
struct lw_terminal_vt100 *vt100;
vt100 = (struct lw_terminal_vt100 *)term_emul->user_data;
if (vt100->y == 0)
{
if (vt100->y == 0) {
/* SCROLL */
vt100->top_line = (vt100->top_line - 1) % (vt100->height * SCROLLBACK);
}
else
{
} else {
/* Do not scroll, just move upward on the current display space */
vt100->y -= 1;
}
@ -731,21 +712,17 @@ static void RI(struct lw_terminal *term_emul)
on the next line downward. If the active position is at the bottom
margin, a scroll up is performed. Format Effector
*/
static void NEL(struct lw_terminal *term_emul)
{
static void NEL(struct lw_terminal *term_emul) {
struct lw_terminal_vt100 *vt100;
unsigned int x;
vt100 = (struct lw_terminal_vt100 *)term_emul->user_data;
if (vt100->y >= vt100->margin_bottom)
{
if (vt100->y >= vt100->margin_bottom) {
/* SCROLL */
vt100->top_line = (vt100->top_line + 1) % (vt100->height * SCROLLBACK);
for (x = 0; x < vt100->width; ++x)
set(vt100, x, vt100->margin_bottom, ' ');
}
else
{
} else {
/* Do not scroll, just move downward on the current display space */
vt100->y += 1;
}
@ -764,8 +741,7 @@ static void NEL(struct lw_terminal *term_emul)
upward. If an attempt is made to move the cursor above the top margin,
the cursor stops at the top margin. Editor Function
*/
static void CUU(struct lw_terminal *term_emul)
{
static void CUU(struct lw_terminal *term_emul) {
struct lw_terminal_vt100 *vt100;
unsigned int arg0;
@ -794,8 +770,7 @@ static void CUU(struct lw_terminal *term_emul)
cursor below the bottom margin, the cursor stops at the bottom
margin. Editor Function
*/
static void CUD(struct lw_terminal *term_emul)
{
static void CUD(struct lw_terminal *term_emul) {
struct lw_terminal_vt100 *vt100;
unsigned int arg0;
@ -822,8 +797,7 @@ static void CUD(struct lw_terminal *term_emul)
is made to move the cursor to the right of the right margin, the
cursor stops at the right margin. Editor Function
*/
static void CUF(struct lw_terminal *term_emul)
{
static void CUF(struct lw_terminal *term_emul) {
struct lw_terminal_vt100 *vt100;
unsigned int arg0;
@ -850,8 +824,7 @@ static void CUF(struct lw_terminal *term_emul)
left. If an attempt is made to move the cursor to the left of the left
margin, the cursor stops at the left margin. Editor Function
*/
static void CUB(struct lw_terminal *term_emul)
{
static void CUB(struct lw_terminal *term_emul) {
struct lw_terminal_vt100 *vt100;
unsigned int arg0;
@ -873,8 +846,7 @@ static void CUB(struct lw_terminal *term_emul)
ESC [ Ps P default value: 1
*/
static void DCH(struct lw_terminal *term_emul)
{
static void DCH(struct lw_terminal *term_emul) {
struct lw_terminal_vt100 *vt100;
unsigned int arg0;
unsigned int x;
@ -913,8 +885,7 @@ static void DCH(struct lw_terminal *term_emul)
2 Erase all of the display all lines are erased, changed to
single-width, and the cursor does not move.
*/
static void ED(struct lw_terminal *term_emul)
{
static void ED(struct lw_terminal *term_emul) {
struct lw_terminal_vt100 *vt100;
unsigned int arg0;
unsigned int x;
@ -924,25 +895,20 @@ static void ED(struct lw_terminal *term_emul)
arg0 = 0;
if (term_emul->argc > 0)
arg0 = term_emul->argv[0];
if (arg0 == 0)
{
if (arg0 == 0) {
for (x = vt100->x; x < vt100->width; ++x)
set(vt100, x, vt100->y, ' ');
for (x = 0 ; x < vt100->width; ++x)
for (x = 0; x < vt100->width; ++x)
for (y = vt100->y + 1; y < vt100->height; ++y)
set(vt100, x, y, ' ');
}
else if (arg0 == 1)
{
for (x = 0 ; x < vt100->width; ++x)
} else if (arg0 == 1) {
for (x = 0; x < vt100->width; ++x)
for (y = 0; y < vt100->y; ++y)
set(vt100, x, y, ' ');
for (x = 0; x <= vt100->x; ++x)
set(vt100, x, vt100->y, ' ');
}
else if (arg0 == 2)
{
for (x = 0 ; x < vt100->width; ++x)
} else if (arg0 == 2) {
for (x = 0; x < vt100->width; ++x)
for (y = 0; y < vt100->height; ++y)
set(vt100, x, y, ' ');
}
@ -962,8 +928,7 @@ static void ED(struct lw_terminal *term_emul)
1 Erase from the start of the screen to the active position, inclusive
2 Erase all of the line, inclusive
*/
static void EL(struct lw_terminal *term_emul)
{
static void EL(struct lw_terminal *term_emul) {
struct lw_terminal_vt100 *vt100;
unsigned int arg0;
unsigned int x;
@ -972,18 +937,13 @@ static void EL(struct lw_terminal *term_emul)
arg0 = 0;
if (term_emul->argc > 0)
arg0 = term_emul->argv[0];
if (arg0 == 0)
{
if (arg0 == 0) {
for (x = vt100->x; x < vt100->width; ++x)
set(vt100, x, vt100->y, ' ');
}
else if (arg0 == 1)
{
} else if (arg0 == 1) {
for (x = 0; x <= vt100->x; ++x)
set(vt100, x, vt100->y, ' ');
}
else if (arg0 == 2)
{
} else if (arg0 == 2) {
for (x = 0; x < vt100->width; ++x)
set(vt100, x, vt100->y, ' ');
}
@ -1005,30 +965,22 @@ static void EL(struct lw_terminal *term_emul)
columns depends on the reset or set state of the origin mode
(DECOM). Format Effector
*/
static void HVP(struct lw_terminal *term_emul)
{
CUP(term_emul);
}
static void HVP(struct lw_terminal *term_emul) { CUP(term_emul); }
static void TBC(struct lw_terminal *term_emul)
{
static void TBC(struct lw_terminal *term_emul) {
struct lw_terminal_vt100 *vt100;
unsigned int i;
vt100 = (struct lw_terminal_vt100 *)term_emul->user_data;
if (term_emul->argc == 0 || term_emul->argv[0] == 0)
{
if (term_emul->argc == 0 || term_emul->argv[0] == 0) {
vt100->tabulations[vt100->x] = '-';
}
else if (term_emul->argc == 1 && term_emul->argv[0] == 3)
{
} else if (term_emul->argc == 1 && term_emul->argv[0] == 3) {
for (i = 0; i < 132; ++i)
vt100->tabulations[i] = '-';
}
}
static void HTS(struct lw_terminal *term_emul)
{
static void HTS(struct lw_terminal *term_emul) {
struct lw_terminal_vt100 *vt100;
vt100 = (struct lw_terminal_vt100 *)term_emul->user_data;
@ -1040,50 +992,43 @@ static void vt100_write_unicode(struct lw_terminal *term_emul, int c) {
vt100 = (struct lw_terminal_vt100 *)term_emul->user_data;
if (c == '\r')
{
if (c == '\r') {
vt100->x = 0;
return ;
return;
}
if (c == '\n' || c == '\013' || c == '\014')
{
if (c == '\n' || c == '\013' || c == '\014') {
if (MODE_IS_SET(vt100, LNM))
NEL(term_emul);
else
IND(term_emul);
return ;
return;
}
if (c == '\010' && vt100->x > 0)
{
if (c == '\010' && vt100->x > 0) {
if (vt100->x == vt100->width)
vt100->x -= 1;
vt100->x -= 1;
return ;
return;
}
if (c == '\t')
{
do
{
if (c == '\t') {
do {
set(vt100, vt100->x, vt100->y, ' ');
vt100->x += 1;
} while (vt100->x < vt100->width && vt100->tabulations[vt100->x] == '-');
return ;
} while (vt100->x < vt100->width &&
vt100->tabulations[vt100->x] == '-');
return;
}
if (c == '\016')
{
if (c == '\016') {
vt100->selected_charset = 0;
return ;
return;
}
if (c == '\017')
{
if (c == '\017') {
vt100->selected_charset = 1;
return ;
return;
}
if (c < ' ') {
return;
}
if (vt100->x == vt100->width)
{
if (vt100->x == vt100->width) {
if (MODE_IS_SET(vt100, DECAWM))
NEL(term_emul);
else
@ -1111,13 +1056,13 @@ static void vt100_write(struct lw_terminal *term_emul, char c) {
if (vt100->ustate == 0) {
if (uc < 0x80) {
vt100_write_unicode(term_emul, uc);
} else if((uc & 0xe0) == 0xc0) {
} else if ((uc & 0xe0) == 0xc0) {
vt100->ustate = 1;
vt100->ubits = (uc & 0x1f);
} else if((uc & 0xf0) == 0xe0) {
} else if ((uc & 0xf0) == 0xe0) {
vt100->ustate = 2;
vt100->ubits = (uc & 0xf);
} else if((uc & 0xf8) == 0xf0) {
} else if ((uc & 0xf8) == 0xf0) {
vt100->ustate = 3;
vt100->ubits = (uc & 0x7);
} else {
@ -1135,12 +1080,12 @@ static void vt100_write(struct lw_terminal *term_emul, char c) {
vt100->ubits <<= 6;
vt100->ubits |= uc & 0x3f;
if (--vt100->ustate == 0) {
vt100_write_unicode(term_emul, vt100->ubits);
vt100_write_unicode(term_emul, vt100->ubits);
}
}
}
} else {
vt100_write_unicode(term_emul, uc);
vt100_write_unicode(term_emul, uc);
}
}
@ -1149,15 +1094,16 @@ static void vt100_write(struct lw_terminal *term_emul, char c) {
#else
#define __not_in_flash_func(x) x
#endif
const lw_cell_t *__not_in_flash_func(lw_terminal_vt100_getline)(struct lw_terminal_vt100 *vt100, unsigned int y) {
const lw_cell_t *
__not_in_flash_func(lw_terminal_vt100_getline)(struct lw_terminal_vt100 *vt100,
unsigned int y) {
if (y < vt100->margin_top || y > vt100->margin_bottom)
return vt100->afrozen_screen + FROZEN_SCREEN_PTR(vt100, 0, y);
else
return vt100->ascreen + SCREEN_PTR(vt100, 0, y);
}
const lw_cell_t **lw_terminal_vt100_getlines(struct lw_terminal_vt100 *vt100)
{
const lw_cell_t **lw_terminal_vt100_getlines(struct lw_terminal_vt100 *vt100) {
unsigned int y;
for (y = 0; y < vt100->height; ++y)
@ -1166,15 +1112,17 @@ const lw_cell_t **lw_terminal_vt100_getlines(struct lw_terminal_vt100 *vt100)
}
static void setcells(lw_cell_t *buf, lw_cell_t c, size_t n) {
for(;n--;buf++) *buf = c;
for (; n--; buf++)
*buf = c;
}
struct lw_terminal_vt100 *lw_terminal_vt100_init(void *user_data,
void (*unimplemented)(struct lw_terminal* term_emul, char *seq, char chr),
void (*master_write)(void *user_data, void *buffer, size_t len),
lw_cell_t (*encode_attr)(void *user_data, const struct lw_parsed_attr *attr),
unsigned int width, unsigned int height)
{
struct lw_terminal_vt100 *lw_terminal_vt100_init(
void *user_data,
void (*unimplemented)(struct lw_terminal *term_emul, char *seq, char chr),
void (*master_write)(void *user_data, void *buffer, size_t len),
lw_cell_t (*encode_attr)(void *user_data,
const struct lw_parsed_attr *attr),
unsigned int width, unsigned int height) {
struct lw_terminal_vt100 *this;
this = calloc(1, sizeof(*this));
@ -1192,7 +1140,7 @@ struct lw_terminal_vt100 *lw_terminal_vt100_init(void *user_data,
this->tabulations = malloc(132);
if (this->tabulations == NULL)
goto free_frozen_screen;
for(int i=0; i<132; i++) {
for (int i = 0; i < 132; i++) {
this->tabulations[i] = (i && i % 8 == 0) ? '|' : '-';
}
this->margin_top = 0;
@ -1234,7 +1182,8 @@ struct lw_terminal_vt100 *lw_terminal_vt100_init(void *user_data,
this->master_write = master_write;
this->encode_attr = encode_attr ? encode_attr : default_encode_attr;
this->map_unicode = default_map_unicode;
lw_terminal_vt100_read_str(this, "\033[m\033[?7h"); // set default attributes
lw_terminal_vt100_read_str(this,
"\033[m\033[?7h"); // set default attributes
setcells(this->ascreen, ' ' | this->attr, 132 * SCROLLBACK * this->height);
setcells(this->afrozen_screen, ' ' | this->attr, 132 * this->height);
return this;
@ -1253,7 +1202,7 @@ free_this:
static void show_cursor(struct lw_terminal_vt100 *this) {
unsigned x = this->x, y = this->y;
lw_cell_t cell;
if(x == this->width)
if (x == this->width)
x -= 1;
if (x >= this->width || y >= this->height) {
this->cursor_saved_flag = false;
@ -1268,26 +1217,27 @@ static void show_cursor(struct lw_terminal_vt100 *this) {
}
static void hide_cursor(struct lw_terminal_vt100 *this) {
if (!this->cursor_saved_flag) { return; }
if (!this->cursor_saved_flag) {
return;
}
this->cursor_saved_flag = false;
unsigned x = this->cursor_saved_x, y = this->cursor_saved_y;
aset(this, x, y, aget(this, x, y) ^ CURSOR_ATTR);
}
void lw_terminal_vt100_read_str(struct lw_terminal_vt100 *this, const char *buffer)
{
void lw_terminal_vt100_read_str(struct lw_terminal_vt100 *this,
const char *buffer) {
lw_terminal_vt100_read_buf(this, buffer, strlen(buffer));
}
void lw_terminal_vt100_read_buf(struct lw_terminal_vt100 *this, const char *buffer, size_t len)
{
void lw_terminal_vt100_read_buf(struct lw_terminal_vt100 *this,
const char *buffer, size_t len) {
hide_cursor(this);
lw_terminal_parser_read_buf(this->lw_terminal, buffer, len);
show_cursor(this);
}
void lw_terminal_vt100_destroy(struct lw_terminal_vt100 *this)
{
void lw_terminal_vt100_destroy(struct lw_terminal_vt100 *this) {
lw_terminal_parser_destroy(this->lw_terminal);
free(this->tabulations);
free(this->ascreen);

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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