aboutsummaryrefslogtreecommitdiffstats
path: root/tmk_core/common/debug.h
blob: 3cbe2092d1e9b2fb375dedb5977801bb64267857 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/*
Copyright 2011 Jun Wako <wakojun@gmail.com>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.

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.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef DEBUG_H
#define DEBUG_H 1

#include <stdbool.h>
#include "print.h"


#ifdef __cplusplus
extern "C" {
#endif

/*
 * Debug output control
 */
typedef union {
    struct {
        bool enable:1;
        bool matrix:1;
        bool keyboard:1;
        bool mouse:1;
        uint8_t reserved:4;
    };
    uint8_t raw;
} debug_config_t;

extern debug_config_t debug_config;

#ifdef __cplusplus
}
#endif

/* for backward compatibility */
#define debug_enable    (debug_config.enable)
#define debug_matrix    (debug_config.matrix)
#define debug_keyboard  (debug_config.keyboard)
#define debug_mouse     (debug_config.mouse)


/*
 * Debug print utils
 */
#ifndef NO_DEBUG

#define dprint(s)                   do { if (debug_enable) print(s); } while (0)
#define dprintln(s)                 do { if (debug_enable) println(s); } while (0)
#define dprintf(fmt, ...)           do { if (debug_enable) xprintf(fmt, ##__VA_ARGS__); } while (0)
#define dmsg(s)                     dprintf("%s at %s: %S\n", __FILE__, __LINE__, PSTR(s))

/* Deprecated. DO NOT USE these anymore, use dprintf instead. */
#define debug(s)                    do { if (debug_enable) print(s); } while (0)
#define debugln(s)                  do { if (debug_enable) println(s); } while (0)
#define debug_msg(s)                do { \
    if (debug_enable) { \
        print(__FILE__); print(" at "); print_dec(__LINE__); print(" in "); print(": "); print(s); \
    } \
} while (0)
#define debug_dec(data)             do { if (debug_enable) print_dec(data); } while (0)
#define debug_decs(data)            do { if (debug_enable) print_decs(data); } while (0)
#define debug_hex4(data)            do { if (debug_enable) print_hex4(data); } while (0)
#define debug_hex8(data)            do { if (debug_enable) print_hex8(data); } while (0)
#define debug_hex16(data)           do { if (debug_enable) print_hex16(data); } while (0)
#define debug_hex32(data)           do { if (debug_enable) print_hex32(data); } while (0)
#define debug_bin8(data)            do { if (debug_enable) print_bin8(data); } while (0)
#define debug_bin16(data)           do { if (debug_enable) print_bin16(data); } while (0)
#define debug_bin32(data)           do { if (debug_enable) print_bin32(data); } while (0)
#define debug_bin_reverse8(data)    do { if (debug_enable) print_bin_reverse8(data); } while (0)
#define debug_bin_reverse16(data)   do { if (debug_enable) print_bin_reverse16(data); } while (0)
#define debug_bin_reverse32(data)   do { if (debug_enable) print_bin_reverse32(data); } while (0)
#define debug_hex(data)             debug_hex8(data)
#define debug_bin(data)             debug_bin8(data)
#define debug_bin_reverse(data)     debug_bin8(data)

#else /* NO_DEBUG */

#define dprint(s)
#define dprintln(s)
#define dprintf(fmt, ...)
#define dmsg(s)
#define debug(s)
#define debugln(s)
#define debug_msg(s)
#define debug_dec(data)
#define debug_decs(data)
#define debug_hex4(data)
#define debug_hex8(data)
#define debug_hex16(data)
#define debug_hex32(data)
#define debug_bin8(data)
#define debug_bin16(data)
#define debug_bin32(data)
#define debug_bin_reverse8(data)
#define debug_bin_reverse16(data)
#define debug_bin_reverse32(data)
#define debug_hex(data)
#define debug_bin(data)
#define debug_bin_reverse(data)

#endif /* NO_DEBUG */

#endif
n>; /** Underlying data buffer for \ref USBtoUSART_Buffer, where the stored bytes are located. */ static uint8_t USBtoUSART_Buffer_Data[128]; /** Circular buffer to hold data from the serial port before it is sent to the host. */ static RingBuffer_t USARTtoUSB_Buffer; /** Underlying data buffer for \ref USARTtoUSB_Buffer, where the stored bytes are located. */ static uint8_t USARTtoUSB_Buffer_Data[128]; /** LUFA CDC Class driver interface configuration and state information. This structure is * passed to all CDC Class driver functions, so that multiple instances of the same class * within a device can be differentiated from one another. */ USB_ClassInfo_CDC_Device_t VirtualSerial_CDC_Interface = { .Config = { .ControlInterfaceNumber = INTERFACE_ID_CDC_CCI, .DataINEndpoint = { .Address = CDC_TX_EPADDR, .Size = CDC_TXRX_EPSIZE, .Banks = 1, }, .DataOUTEndpoint = { .Address = CDC_RX_EPADDR, .Size = CDC_TXRX_EPSIZE, .Banks = 1, }, .NotificationEndpoint = { .Address = CDC_NOTIFICATION_EPADDR, .Size = CDC_NOTIFICATION_EPSIZE, .Banks = 1, }, }, }; /** Main program entry point. This routine contains the overall program flow, including initial * setup of all components and the main program loop. */ int main(void) { SetupHardware(); RingBuffer_InitBuffer(&USBtoUSART_Buffer, USBtoUSART_Buffer_Data, sizeof(USBtoUSART_Buffer_Data)); RingBuffer_InitBuffer(&USARTtoUSB_Buffer, USARTtoUSB_Buffer_Data, sizeof(USARTtoUSB_Buffer_Data)); LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY); GlobalInterruptEnable(); for (;;) { /* Only try to read in bytes from the CDC interface if the transmit buffer is not full */ if (!(RingBuffer_IsFull(&USBtoUSART_Buffer))) { int16_t ReceivedByte = CDC_Device_ReceiveByte(&VirtualSerial_CDC_Interface); /* Store received byte into the USART transmit buffer */ if (!(ReceivedByte < 0)) RingBuffer_Insert(&USBtoUSART_Buffer, ReceivedByte); } uint16_t BufferCount = RingBuffer_GetCount(&USARTtoUSB_Buffer); if (BufferCount) { Endpoint_SelectEndpoint(VirtualSerial_CDC_Interface.Config.DataINEndpoint.Address); /* Check if a packet is already enqueued to the host - if so, we shouldn't try to send more data * until it completes as there is a chance nothing is listening and a lengthy timeout could occur */ if (Endpoint_IsINReady()) { /* Never send more than one bank size less one byte to the host at a time, so that we don't block * while a Zero Length Packet (ZLP) to terminate the transfer is sent if the host isn't listening */ uint8_t BytesToSend = MIN(BufferCount, (CDC_TXRX_EPSIZE - 1)); /* Read bytes from the USART receive buffer into the USB IN endpoint */ while (BytesToSend--) { /* Try to send the next byte of data to the host, abort if there is an error without dequeuing */ if (CDC_Device_SendByte(&VirtualSerial_CDC_Interface, RingBuffer_Peek(&USARTtoUSB_Buffer)) != ENDPOINT_READYWAIT_NoError) { break; } /* Dequeue the already sent byte from the buffer now we have confirmed that no transmission error occurred */ RingBuffer_Remove(&USARTtoUSB_Buffer); } } } /* Load the next byte from the USART transmit buffer into the USART if transmit buffer space is available */ if (Serial_IsSendReady() && !(RingBuffer_IsEmpty(&USBtoUSART_Buffer))) Serial_SendByte(RingBuffer_Remove(&USBtoUSART_Buffer)); CDC_Device_USBTask(&VirtualSerial_CDC_Interface); USB_USBTask(); } } /** Configures the board hardware and chip peripherals for the demo's functionality. */ void SetupHardware(void) { #if (ARCH == ARCH_AVR8) /* Disable watchdog if enabled by bootloader/fuses */ MCUSR &= ~(1 << WDRF); wdt_disable(); /* Disable clock division */ clock_prescale_set(clock_div_1); #endif /* Hardware Initialization */ LEDs_Init(); USB_Init(); } /** Event handler for the library USB Connection event. */ void EVENT_USB_Device_Connect(void) { LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING); } /** Event handler for the library USB Disconnection event. */ void EVENT_USB_Device_Disconnect(void) { LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY); } /** Event handler for the library USB Configuration Changed event. */ void EVENT_USB_Device_ConfigurationChanged(void) { bool ConfigSuccess = true; ConfigSuccess &= CDC_Device_ConfigureEndpoints(&VirtualSerial_CDC_Interface); LEDs_SetAllLEDs(ConfigSuccess ? LEDMASK_USB_READY : LEDMASK_USB_ERROR); } /** Event handler for the library USB Control Request reception event. */ void EVENT_USB_Device_ControlRequest(void) { CDC_Device_ProcessControlRequest(&VirtualSerial_CDC_Interface); } /** ISR to manage the reception of data from the serial port, placing received bytes into a circular buffer * for later transmission to the host. */ ISR(USART1_RX_vect, ISR_BLOCK) { uint8_t ReceivedByte = UDR1; if ((USB_DeviceState == DEVICE_STATE_Configured) && !(RingBuffer_IsFull(&USARTtoUSB_Buffer))) RingBuffer_Insert(&USARTtoUSB_Buffer, ReceivedByte); } /** Event handler for the CDC Class driver Line Encoding Changed event. * * \param[in] CDCInterfaceInfo Pointer to the CDC class interface configuration structure being referenced */ void EVENT_CDC_Device_LineEncodingChanged(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo) { uint8_t ConfigMask = 0; switch (CDCInterfaceInfo->State.LineEncoding.ParityType) { case CDC_PARITY_Odd: ConfigMask = ((1 << UPM11) | (1 << UPM10)); break; case CDC_PARITY_Even: ConfigMask = (1 << UPM11); break; } if (CDCInterfaceInfo->State.LineEncoding.CharFormat == CDC_LINEENCODING_TwoStopBits) ConfigMask |= (1 << USBS1); switch (CDCInterfaceInfo->State.LineEncoding.DataBits) { case 6: ConfigMask |= (1 << UCSZ10); break; case 7: ConfigMask |= (1 << UCSZ11); break; case 8: ConfigMask |= ((1 << UCSZ11) | (1 << UCSZ10)); break; } /* Keep the TX line held high (idle) while the USART is reconfigured */ PORTD |= (1 << 3); /* Must turn off USART before reconfiguring it, otherwise incorrect operation may occur */ UCSR1B = 0; UCSR1A = 0; UCSR1C = 0; /* Set the new baud rate before configuring the USART */ UBRR1 = SERIAL_2X_UBBRVAL(CDCInterfaceInfo->State.LineEncoding.BaudRateBPS); /* Reconfigure the USART in double speed mode for a wider baud rate range at the expense of accuracy */ UCSR1C = ConfigMask; UCSR1A = (1 << U2X1); UCSR1B = ((1 << RXCIE1) | (1 << TXEN1) | (1 << RXEN1)); /* Release the TX line after the USART has been reconfigured */ PORTD &= ~(1 << 3); }