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:
		
							parent
							
								
									446b6102ac
								
							
						
					
					
						commit
						5ebb104e19
					
				| @ -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; i<bsize; ++i) { | ||||
| 			dev_info(&serdev->dev, | ||||
| 				 "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); | ||||
|  | ||||
| @ -5,7 +5,7 @@ | ||||
| #include <fcntl.h> | ||||
| 
 | ||||
| #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"); | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user