/* * debugging routines * * Copyright (C) 2014 Michael Buesch * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include "debug.h" #include "util.h" #include #include enum { ENODATA, ERXFE, ERXPE, ERXOV, }; struct usart_rx_result { int8_t error; uint8_t data; }; void usart_tx(uint8_t data) { while (!(UCSRA & (1 << UDRE))); UDR = data; } void usart_tx_hex8(uint8_t number) { usart_tx('0'); usart_tx('x'); usart_tx(hexdigit_to_ascii((number & 0xF0) >> 4)); usart_tx(hexdigit_to_ascii(number & 0x0F)); } void usart_tx_hex16(uint16_t number) { usart_tx('0'); usart_tx('x'); usart_tx(hexdigit_to_ascii((number & 0xF000) >> 12)); usart_tx(hexdigit_to_ascii((number & 0x0F00) >> 8)); usart_tx(hexdigit_to_ascii((number & 0x00F0) >> 4)); usart_tx(hexdigit_to_ascii(number & 0x000F)); } void usart_tx_1num_8bit(const char PROGPTR *d, uint8_t n) { usart_tx_1num_16bit(d, n); } void usart_tx_2num_8bit(const char PROGPTR *d1, uint8_t n1, const char PROGPTR *d2, uint8_t n2) { usart_tx_2num_16bit(d1, n1, d2, n2); } void usart_tx_1num_16bit(const char PROGPTR *d, uint16_t n) { usart_tx_string(d); usart_tx(':'); usart_tx(' '); if (n & 0xFF00) usart_tx_hex16(n); else usart_tx_hex8(n); usart_tx_string(PSTR("\n")); } void usart_tx_2num_16bit(const char PROGPTR *d1, uint16_t n1, const char PROGPTR *d2, uint16_t n2) { usart_tx_string(d1); usart_tx(' '); if (n1 & 0xFF00) usart_tx_hex16(n1); else usart_tx_hex8(n1); usart_tx(' '); usart_tx_string(d2); usart_tx(' '); if (n2 & 0xFF00) usart_tx_hex16(n2); else usart_tx_hex8(n2); usart_tx_string(PSTR("\n")); } void usart_tx_string(const char PROGPTR *flash_string) { uint8_t c; for ( ; ; flash_string++) { c = pgm_read_byte(flash_string); if (c == '\0') break; if (c == '\n') usart_tx('\r'); usart_tx(c); } } void usart_dump_mem(const void *_mem, uint8_t size) { const uint8_t *mem = _mem; uint8_t i; for (i = 0; i < size; i++) { if (i % 16 == 0) { if (i != 0) usart_tx_string(PSTR("\n")); usart_tx_string(PSTR("0x")); usart_tx(hexdigit_to_ascii((i & 0xF0) >> 4)); usart_tx(hexdigit_to_ascii(i & 0x0F)); usart_tx_string(PSTR(": ")); } if (i % 2 == 0) usart_tx(' '); usart_tx(hexdigit_to_ascii((mem[i] & 0xF0) >> 4)); usart_tx(hexdigit_to_ascii(mem[i] & 0x0F)); } usart_tx_string(PSTR("\n")); } static struct usart_rx_result usart_rx(void) { struct usart_rx_result res = { .error = 0, .data = 0, }; uint8_t status; status = UCSRA; if (!(status & (1 << RXC))) { res.error = -ENODATA; goto out; } if (status & ((1 << FE) | (1 << PE) | (1 << DOR))) { if (status & (1 << DOR)) res.error = -ERXOV; else if (status & (1 << PE)) res.error = -ERXPE; else if (status & (1 << FE)) res.error = -ERXFE; goto out; } res.data = UDR; out: return res; } ISR(USART_RXC_vect) { struct usart_rx_result res; while (1) { res = usart_rx(); if (res.error) break; /* We simply echo the data */ usart_tx(res.data); if (res.data == '\r') usart_tx('\n'); } } #define USART_BAUD 19200 #if USART_USE_2X # define UBRR_FACTOR 2 #else # define UBRR_FACTOR 1 #endif void usart_init(void) { /* Set baud rate */ UBRRL = ((F_CPU / 16 / USART_BAUD) * UBRR_FACTOR) & 0xFF; UBRRH = (((F_CPU / 16 / USART_BAUD) * UBRR_FACTOR) >> 8) & ~(1 << URSEL); #if USART_USE_2X UCSRA = (1 << U2X); #endif /* 8 Data bits, 1 Stop bit, No parity */ UCSRC = (1 << UCSZ0) | (1 << UCSZ1) | (1 << URSEL); /* Enable transceiver */ UCSRB = (1 << RXEN) | (1 << TXEN) | (1 << RXCIE); }