From 5ebb104e191a438a13f4346d1fdbc4ef6ea45f79 Mon Sep 17 00:00:00 2001 From: Markus Koch Date: Wed, 13 May 2020 14:08:41 +0200 Subject: [PATCH] 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! --- ioc/kernel-driver/lw35ioc.c | 19 +++-- ioc/lw35-tool/main.c | 4 +- printer/avr/main.c | 143 ++++++++++++++++++++++++++++++++---- 3 files changed, 142 insertions(+), 24 deletions(-) diff --git a/ioc/kernel-driver/lw35ioc.c b/ioc/kernel-driver/lw35ioc.c index ceed250..e59aea6 100644 --- a/ioc/kernel-driver/lw35ioc.c +++ b/ioc/kernel-driver/lw35ioc.c @@ -61,7 +61,7 @@ static int keycode_map[] = { 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}; @@ -290,12 +290,15 @@ static int lw35ioc_chardev_open(struct inode *inodep, struct file *filep) { serdev_device_write(serdev, "XX", 2, 0); dev_info(&serdev->dev, "Put ioc into bypass mode.\n"); break; + case INIT: case PASSIVE: lw35ioc_reset_ioc_hw(serdev); usleep_range(2100000, 2210000); dev_info(&serdev->dev, "Put ioc into active mode.\n"); - serdev_device_write(serdev, "\xFF", 1, 0); - priv->state = ACTIVE; + if (priv->state == INIT) { + serdev_device_write(serdev, "\xFF", 1, 0); + priv->state = ACTIVE; + } break; case ACTIVE: /* Don't do anything when active */ @@ -480,15 +483,12 @@ void pbuf_work_handler(struct work_struct *work) int i; int locked = 0; - dev_info(&serdev->dev, - "pbuf_work_handler\n"); - while (1) { // TODO: We are the only consumer, so we should be fine without a spinlock, right? head = smp_load_acquire(&priv->pbuf_head); tail = priv->pbuf_tail; 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) break; @@ -519,11 +519,13 @@ void pbuf_work_handler(struct work_struct *work) serdev_device_write_buf(serdev, priv->pbuf + tail, bsize); +#ifdef ENABLE_DEBUG for (i=0; idev, "UART TX: %c\n", priv->pbuf[tail + i]); } +#endif smp_store_release(&priv->pbuf_tail, (tail + bsize) & (PBUF_SIZE - 1)); } @@ -604,7 +606,7 @@ static int lw35ioc_probe(struct serdev_device *serdev) 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_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, " input dev: %p\n", priv->input_dev); lw35ioc_set_hw_reset(serdev, 1); + usleep_range(90000, 100000); // Make sure the reset actually happens gpiod_put(priv->gpio_rst); serdev_device_close(priv->serdev); input_unregister_device(priv->input_dev); diff --git a/ioc/lw35-tool/main.c b/ioc/lw35-tool/main.c index be75e45..c5044a4 100644 --- a/ioc/lw35-tool/main.c +++ b/ioc/lw35-tool/main.c @@ -5,7 +5,7 @@ #include #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; @@ -37,6 +37,8 @@ static int set_mode(int argc, char *argv[]) mode = BYPASS; else if (!strcmp(argv[2], "active")) mode = ACTIVE; + else if (!strcmp(argv[2], "init")) + mode = INIT; if (mode == -1) { fprintf(stderr, "Error: Invalid mode.\n"); diff --git a/printer/avr/main.c b/printer/avr/main.c index 91ebe63..cb0a803 100644 --- a/printer/avr/main.c +++ b/printer/avr/main.c @@ -100,6 +100,7 @@ void hardfault() { uart_putc(0xFF); uart_putc(0xFF); uart_putc(0xFF); + uart_putc(0xAA); uart_putc(0x00); uart_putc(0x00); uart_putc(0x00); @@ -576,11 +577,14 @@ void arm_correction() #define DCMOTOR_ISACTIVE (!!(MOTLIM(PORT) & PIN_DCMOTOR)) #define LIMITSWITCH (!(MOTLIM(PIN) & PIN_LIMITSWITCH)) +#define BACKLIGHT_ON MISCIO(PORT) |= PIN_BACKLIGHT +#define BACKLIGHT_OFF MISCIO(PORT) &= ~PIN_BACKLIGHT + /* Communication Functions */ #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 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_rd = 0; @@ -675,7 +679,7 @@ void move_carriage_to_far_left(uint8_t reset) if (LIMITSWITCH) { debug_write("[car] Clearing switch area...\r\n"); cnt = 32; - while (LIMITSWITCH && (cnt> 0)) { + while (LIMITSWITCH && (cnt > 0)) { if (block_for(TIM_CARRIAGE, STEPPER_CFG_CARRIAGE.delay)) { STEPPER_NEXT(CARRIAGE, 1); cnt--; @@ -840,7 +844,7 @@ void move_carriage_to_left_margin() /* It's only called once, so inline is good. */ 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; uint16_t carriage_position; 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() { static enum printer_state state = INIT; @@ -916,21 +1014,17 @@ void printer_process() static uint8_t print_buffer_recovery = 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 end_of_next_line = 0; int8_t temp; - static char debug_character = 0; + static uint8_t debug_character = 0; switch (state) { case IDLE: 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 */ if (!current_is_linebreak) { if (backward) { @@ -997,10 +1091,22 @@ void printer_process() state = HAMMER; break; } - } else { - // TODO: Handle special commands + } else { /* TODO: 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 { DCMOTOR_STOP; } @@ -1016,6 +1122,10 @@ void printer_process() } break; + case SPECIAL_COMMAND: + state = process_special_command(special_command); + break; + case INIT: move_carriage_to_left_margin(); state = IDLE; @@ -1291,7 +1401,7 @@ int main() /* Set up miscellaneous I/O */ MISCIO(DDR) |= PIN_BACKLIGHT; - MISCIO(PORT) |= PIN_BACKLIGHT; /* Permanently enable backlight */ + BACKLIGHT_ON; /* Set up SysTick Timer */ TCCR1B = (1 << WGM12) | (1 << CS11); // f_tim = 8 MHz / 8 @@ -1303,7 +1413,10 @@ int main() update_status(0); debug_write("\n\n\r[sys] STARTING IO CONTROLLER...\r\n"); #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); _delay_ms(250); #endif