Implement special commands and fix some bugs

Note: Special commands are currently broken in backwards mode!
Do not use them when the buffer is not empty!
This commit is contained in:
Markus Koch 2020-05-13 14:08:41 +02:00
parent 446b6102ac
commit 5ebb104e19
3 changed files with 142 additions and 24 deletions

View File

@ -61,7 +61,7 @@ static int keycode_map[] = {
KEY_SYSRQ KEY_SYSRQ
}; };
enum lw35ioc_state {PASSIVE = 0, PROG_KBD, PROG_PRI, BYPASS, ACTIVE, STATE_COUNT}; enum lw35ioc_state {PASSIVE = 0, INIT, PROG_KBD, PROG_PRI, BYPASS, ACTIVE, STATE_COUNT};
enum lw35ioc_packet_state {SYNC, TYPE, KEYBOARD, PRINTER}; enum lw35ioc_packet_state {SYNC, TYPE, KEYBOARD, PRINTER};
@ -290,12 +290,15 @@ static int lw35ioc_chardev_open(struct inode *inodep, struct file *filep) {
serdev_device_write(serdev, "XX", 2, 0); serdev_device_write(serdev, "XX", 2, 0);
dev_info(&serdev->dev, "Put ioc into bypass mode.\n"); dev_info(&serdev->dev, "Put ioc into bypass mode.\n");
break; break;
case INIT:
case PASSIVE: case PASSIVE:
lw35ioc_reset_ioc_hw(serdev); lw35ioc_reset_ioc_hw(serdev);
usleep_range(2100000, 2210000); usleep_range(2100000, 2210000);
dev_info(&serdev->dev, "Put ioc into active mode.\n"); dev_info(&serdev->dev, "Put ioc into active mode.\n");
if (priv->state == INIT) {
serdev_device_write(serdev, "\xFF", 1, 0); serdev_device_write(serdev, "\xFF", 1, 0);
priv->state = ACTIVE; priv->state = ACTIVE;
}
break; break;
case ACTIVE: case ACTIVE:
/* Don't do anything when active */ /* Don't do anything when active */
@ -480,15 +483,12 @@ void pbuf_work_handler(struct work_struct *work)
int i; int i;
int locked = 0; int locked = 0;
dev_info(&serdev->dev,
"pbuf_work_handler\n");
while (1) { while (1) {
// TODO: We are the only consumer, so we should be fine without a spinlock, right? // TODO: We are the only consumer, so we should be fine without a spinlock, right?
head = smp_load_acquire(&priv->pbuf_head); head = smp_load_acquire(&priv->pbuf_head);
tail = priv->pbuf_tail; tail = priv->pbuf_tail;
bsize = CIRC_CNT(head, tail, PBUF_SIZE); bsize = CIRC_CNT(head, tail, PBUF_SIZE);
dev_info(&serdev->dev, "CIRC CNT=%d\n", bsize); //dev_info(&serdev->dev, "CIRC CNT=%d\n", bsize);
if (bsize == 0) if (bsize == 0)
break; break;
@ -519,11 +519,13 @@ void pbuf_work_handler(struct work_struct *work)
serdev_device_write_buf(serdev, serdev_device_write_buf(serdev,
priv->pbuf + tail, priv->pbuf + tail,
bsize); bsize);
#ifdef ENABLE_DEBUG
for (i=0; i<bsize; ++i) { for (i=0; i<bsize; ++i) {
dev_info(&serdev->dev, dev_info(&serdev->dev,
"UART TX: %c\n", "UART TX: %c\n",
priv->pbuf[tail + i]); priv->pbuf[tail + i]);
} }
#endif
smp_store_release(&priv->pbuf_tail, smp_store_release(&priv->pbuf_tail,
(tail + bsize) & (PBUF_SIZE - 1)); (tail + bsize) & (PBUF_SIZE - 1));
} }
@ -604,7 +606,7 @@ static int lw35ioc_probe(struct serdev_device *serdev)
return -ENOMEM; return -ENOMEM;
} }
priv->state = PASSIVE; priv->state = ACTIVE; // TODO: This should be passive
priv->uart_buf_rx_rd = priv->uart_buf_rx; priv->uart_buf_rx_rd = priv->uart_buf_rx;
priv->uart_buf_rx_wr = priv->uart_buf_rx; priv->uart_buf_rx_wr = priv->uart_buf_rx;
@ -701,6 +703,7 @@ static void lw35ioc_remove(struct serdev_device *serdev)
dev_info(&serdev->dev, " serdev: %p\n", priv->serdev); dev_info(&serdev->dev, " serdev: %p\n", priv->serdev);
dev_info(&serdev->dev, " input dev: %p\n", priv->input_dev); dev_info(&serdev->dev, " input dev: %p\n", priv->input_dev);
lw35ioc_set_hw_reset(serdev, 1); lw35ioc_set_hw_reset(serdev, 1);
usleep_range(90000, 100000); // Make sure the reset actually happens
gpiod_put(priv->gpio_rst); gpiod_put(priv->gpio_rst);
serdev_device_close(priv->serdev); serdev_device_close(priv->serdev);
input_unregister_device(priv->input_dev); input_unregister_device(priv->input_dev);

View File

@ -5,7 +5,7 @@
#include <fcntl.h> #include <fcntl.h>
#define IOCTL_SET_MODE 42 #define IOCTL_SET_MODE 42
enum lw35ioc_state {PASSIVE = 0, PROG_KBD, PROG_PRI, BYPASS, ACTIVE, STATE_COUNT}; enum lw35ioc_state {PASSIVE = 0, INIT, PROG_KBD, PROG_PRI, BYPASS, ACTIVE, STATE_COUNT};
int f; int f;
@ -37,6 +37,8 @@ static int set_mode(int argc, char *argv[])
mode = BYPASS; mode = BYPASS;
else if (!strcmp(argv[2], "active")) else if (!strcmp(argv[2], "active"))
mode = ACTIVE; mode = ACTIVE;
else if (!strcmp(argv[2], "init"))
mode = INIT;
if (mode == -1) { if (mode == -1) {
fprintf(stderr, "Error: Invalid mode.\n"); fprintf(stderr, "Error: Invalid mode.\n");

View File

@ -100,6 +100,7 @@ void hardfault() {
uart_putc(0xFF); uart_putc(0xFF);
uart_putc(0xFF); uart_putc(0xFF);
uart_putc(0xFF); uart_putc(0xFF);
uart_putc(0xAA);
uart_putc(0x00); uart_putc(0x00);
uart_putc(0x00); uart_putc(0x00);
uart_putc(0x00); uart_putc(0x00);
@ -576,11 +577,14 @@ void arm_correction()
#define DCMOTOR_ISACTIVE (!!(MOTLIM(PORT) & PIN_DCMOTOR)) #define DCMOTOR_ISACTIVE (!!(MOTLIM(PORT) & PIN_DCMOTOR))
#define LIMITSWITCH (!(MOTLIM(PIN) & PIN_LIMITSWITCH)) #define LIMITSWITCH (!(MOTLIM(PIN) & PIN_LIMITSWITCH))
#define BACKLIGHT_ON MISCIO(PORT) |= PIN_BACKLIGHT
#define BACKLIGHT_OFF MISCIO(PORT) &= ~PIN_BACKLIGHT
/* Communication Functions */ /* Communication Functions */
#define RINGBUF_CNT(wr,rd) ((wr) - (rd)) #define RINGBUF_CNT(wr,rd) ((wr) - (rd))
#define RINGBUF_FREE(wr,rd,sz) ((RINGBUF_CNT(rd,wr+1))) // TODO: 255 is actually not correct... #define RINGBUF_FREE(wr,rd,sz) ((RINGBUF_CNT(rd,wr+1))) // TODO: 255 is actually not correct...
#define PRINT_BUFFER_SIZE 256 // Important: must be 256 atm, when changed, you need to change code handling print_buffer_*. #define PRINT_BUFFER_SIZE 256 // Important: must be 256 atm, when changed, you need to change code handling print_buffer_*.
volatile char print_buffer[PRINT_BUFFER_SIZE]; volatile uint8_t print_buffer[PRINT_BUFFER_SIZE];
volatile uint8_t print_buffer_wr = 0; volatile uint8_t print_buffer_wr = 0;
volatile uint8_t print_buffer_rd = 0; volatile uint8_t print_buffer_rd = 0;
@ -840,7 +844,7 @@ void move_carriage_to_left_margin()
/* It's only called once, so inline is good. */ /* It's only called once, so inline is good. */
inline int8_t simulate_print_run(uint8_t *start_end_index, uint8_t *recovery_index) inline int8_t simulate_print_run(uint8_t *start_end_index, uint8_t *recovery_index)
{ {
char current_char; uint8_t current_char;
uint8_t index; uint8_t index;
uint16_t carriage_position; uint16_t carriage_position;
uint8_t translated; uint8_t translated;
@ -907,7 +911,101 @@ inline int8_t simulate_print_run(uint8_t *start_end_index, uint8_t *recovery_ind
} }
} }
enum printer_state {INIT, IDLE, HAMMER, PAUSED}; #define PRINT_COMMAND_RESET_ALL 0xFF
#define PRINT_COMMAND_HARDFAULLT 0xFE
#define PRINT_COMMAND_RESET_WHEEL 0xF0
#define PRINT_COMMAND_BACKLIGHT_ON 0xFD
#define PRINT_COMMAND_BACKLIGHT_OFF 0xFC
#define PRINT_COMMAND_SET_MARGIN_LEFT 0xE0
#define PRINT_COMMAND_SET_MARGIN_RIGHT 0xE1
#define PRINT_COMMAND_MOVE_CARRIAGE 0xE2
#define PRINT_COMMAND_MOVE_PAPERFEED 0xE3
enum printer_state {INIT, IDLE, HAMMER, PAUSED, SPECIAL_COMMAND};
// TODO: Special commands must currently not be used in reverse (auto) print mode
enum printer_state process_special_command(uint8_t command)
{
uint16_t temp;
uint8_t arg;
switch (command) {
case PRINT_COMMAND_RESET_ALL:
return INIT;
case PRINT_COMMAND_HARDFAULLT:
hardfault();
return INIT;
case PRINT_COMMAND_BACKLIGHT_ON:
BACKLIGHT_ON;
return IDLE;
case PRINT_COMMAND_BACKLIGHT_OFF:
BACKLIGHT_OFF;
return IDLE;
case PRINT_COMMAND_RESET_WHEEL:
stepper_status_CARRIAGE.target_pos = 0; // Go to far left to lock the daisy wheel
DCMOTOR_STOP; // TODO: We only need to issue this and the line before once
if (POSITION_REACHED(WHEEL) && POSITION_REACHED(CARRIAGE) && POSITION_REACHED(LINEFEED)) {
align_daisy_wheel();
return INIT;
}
break;
case PRINT_COMMAND_SET_MARGIN_LEFT:
case PRINT_COMMAND_SET_MARGIN_RIGHT:
if (print_buffer_rd != print_buffer_wr) {
temp = (uint16_t) print_buffer[print_buffer_rd];
print_buffer_rd++;
temp *= PRINT_CHARACTER_WIDTH;
switch (command) {
case PRINT_COMMAND_SET_MARGIN_LEFT:
print_margin_left = temp;
break;
case PRINT_COMMAND_SET_MARGIN_RIGHT:
print_margin_right = temp;
break;
}
return INIT;
}
break;
case PRINT_COMMAND_MOVE_CARRIAGE:
if (print_buffer_rd != print_buffer_wr) {
temp = (uint16_t) print_buffer[print_buffer_rd];
print_buffer_rd++;
temp *= PRINT_CHARACTER_WIDTH;
stepper_status_CARRIAGE.target_pos = temp;
return IDLE;
}
break;
case PRINT_COMMAND_MOVE_PAPERFEED: // [line mult] [+/-] [6b abs amount]
if (print_buffer_rd != print_buffer_wr) {
arg = print_buffer[print_buffer_rd];
print_buffer_rd++;
temp = (uint16_t) (arg & 0x3F);
if (arg & 0x40) {
temp = -temp;
}
if (arg & 0x80) {
temp *= PRINT_LINE_HEIGHT;
}
stepper_status_LINEFEED.target_pos += temp;
return IDLE;
}
break;
default:
return IDLE;
}
return SPECIAL_COMMAND;
}
void printer_process() void printer_process()
{ {
static enum printer_state state = INIT; static enum printer_state state = INIT;
@ -916,21 +1014,17 @@ void printer_process()
static uint8_t print_buffer_recovery = 0; static uint8_t print_buffer_recovery = 0;
static uint8_t current_is_linebreak = 0; static uint8_t current_is_linebreak = 0;
char current_char; uint8_t current_char;
static uint8_t special_command;
uint8_t translated; uint8_t translated;
uint8_t end_of_next_line = 0; uint8_t end_of_next_line = 0;
int8_t temp; int8_t temp;
static char debug_character = 0; static uint8_t debug_character = 0;
switch (state) { switch (state) {
case IDLE: case IDLE:
if (print_buffer_rd != print_buffer_wr) { // TODO: maybe add "|| current_is_linebreak" if (print_buffer_rd != print_buffer_wr) { // TODO: maybe add "|| current_is_linebreak"
if (!DCMOTOR_ISACTIVE) {
DCMOTOR_EN;
_delay_ms(100); /* Let the motor get up to speed */
}
/* Fetch new character from buffer */ /* Fetch new character from buffer */
if (!current_is_linebreak) { if (!current_is_linebreak) {
if (backward) { if (backward) {
@ -997,10 +1091,22 @@ void printer_process()
state = HAMMER; state = HAMMER;
break; break;
} }
} else { } else { /* TODO: Special commands */
// TODO: Handle special commands special_command = current_char;
state = SPECIAL_COMMAND;
/* TODO: below are just notes */
// process_command_forward(&modifier_state);
// After this call, wait until a "return to normal op command".
// I can also call this in simulate_print_run and return to end-of-line modifiers
// to allow BOLD en/dis using the toggle command if en/dis is split over multiple lines.
// TODO: But how do I handle margin changes etc?
} }
if (!DCMOTOR_ISACTIVE && state != SPECIAL_COMMAND) {
DCMOTOR_EN;
_delay_ms(100); /* Let the motor get up to speed */
}
} else { } else {
DCMOTOR_STOP; DCMOTOR_STOP;
} }
@ -1016,6 +1122,10 @@ void printer_process()
} }
break; break;
case SPECIAL_COMMAND:
state = process_special_command(special_command);
break;
case INIT: case INIT:
move_carriage_to_left_margin(); move_carriage_to_left_margin();
state = IDLE; state = IDLE;
@ -1291,7 +1401,7 @@ int main()
/* Set up miscellaneous I/O */ /* Set up miscellaneous I/O */
MISCIO(DDR) |= PIN_BACKLIGHT; MISCIO(DDR) |= PIN_BACKLIGHT;
MISCIO(PORT) |= PIN_BACKLIGHT; /* Permanently enable backlight */ BACKLIGHT_ON;
/* Set up SysTick Timer */ /* Set up SysTick Timer */
TCCR1B = (1 << WGM12) | (1 << CS11); // f_tim = 8 MHz / 8 TCCR1B = (1 << WGM12) | (1 << CS11); // f_tim = 8 MHz / 8
@ -1303,7 +1413,10 @@ int main()
update_status(0); update_status(0);
debug_write("\n\n\r[sys] STARTING IO CONTROLLER...\r\n"); debug_write("\n\n\r[sys] STARTING IO CONTROLLER...\r\n");
#ifndef DEBUG_BUILD #ifndef DEBUG_BUILD
while (!((UCSRA & (1 << RXC)) && (UDR == 0xFF))); /* Wait for init command from driver */ while (!((UCSRA & (1 << RXC)))) {
if (process_special_command(UDR) == INIT)
break;
}
update_status(0); update_status(0);
_delay_ms(250); _delay_ms(250);
#endif #endif