Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of UtilityLib by
SerialManager.cpp@9:f71dc1b426da, 2014-03-18 (annotated)
- Committer:
- mgottscho
- Date:
- Tue Mar 18 23:56:23 2014 +0000
- Revision:
- 9:f71dc1b426da
Made the Utility class just a SerialManager, and factored out useful functionality not relevant to serial operation into global C functions.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
mgottscho | 9:f71dc1b426da | 1 | /* SerialManager.cpp |
mgottscho | 9:f71dc1b426da | 2 | * Tested with mbed board: FRDM-KL46Z |
mgottscho | 9:f71dc1b426da | 3 | * Author: Mark Gottscho |
mgottscho | 9:f71dc1b426da | 4 | * mgottscho@ucla.edu |
mgottscho | 9:f71dc1b426da | 5 | */ |
mgottscho | 9:f71dc1b426da | 6 | |
mgottscho | 9:f71dc1b426da | 7 | #include "mbed.h" |
mgottscho | 9:f71dc1b426da | 8 | #include "SerialManager.h" |
mgottscho | 9:f71dc1b426da | 9 | |
mgottscho | 9:f71dc1b426da | 10 | using namespace std; |
mgottscho | 9:f71dc1b426da | 11 | |
mgottscho | 9:f71dc1b426da | 12 | SerialManager::SerialManager(PinName serial_tx_pin, PinName serial_rx_pin, int baudrate, bool enableSerialInterrupts) : |
mgottscho | 9:f71dc1b426da | 13 | serial(serial_tx_pin, serial_rx_pin), |
mgottscho | 9:f71dc1b426da | 14 | __interrupts_en(enableSerialInterrupts), |
mgottscho | 9:f71dc1b426da | 15 | __user_fptr(NULL), |
mgottscho | 9:f71dc1b426da | 16 | __rx_head(0), |
mgottscho | 9:f71dc1b426da | 17 | __rx_tail(0), |
mgottscho | 9:f71dc1b426da | 18 | __tx_head(0), |
mgottscho | 9:f71dc1b426da | 19 | __tx_tail(0), |
mgottscho | 9:f71dc1b426da | 20 | __have_rx_serial(false) |
mgottscho | 9:f71dc1b426da | 21 | { |
mgottscho | 9:f71dc1b426da | 22 | |
mgottscho | 9:f71dc1b426da | 23 | serial.baud(baudrate); |
mgottscho | 9:f71dc1b426da | 24 | |
mgottscho | 9:f71dc1b426da | 25 | //Set up serial interrupt handlers |
mgottscho | 9:f71dc1b426da | 26 | if (__interrupts_en) { |
mgottscho | 9:f71dc1b426da | 27 | serial.attach(this, &SerialManager::__serial_rx_ISR, Serial::RxIrq); |
mgottscho | 9:f71dc1b426da | 28 | //serial.attach(this, &SerialManager::__serial_tx_ISR, Serial::TxIrq); |
mgottscho | 9:f71dc1b426da | 29 | } |
mgottscho | 9:f71dc1b426da | 30 | } |
mgottscho | 9:f71dc1b426da | 31 | |
mgottscho | 9:f71dc1b426da | 32 | SerialManager::~SerialManager() { |
mgottscho | 9:f71dc1b426da | 33 | detach_rx(); |
mgottscho | 9:f71dc1b426da | 34 | } |
mgottscho | 9:f71dc1b426da | 35 | |
mgottscho | 9:f71dc1b426da | 36 | void SerialManager::attach_rx(void (*fptr)(void)) { |
mgottscho | 9:f71dc1b426da | 37 | //set user function pointer |
mgottscho | 9:f71dc1b426da | 38 | detach_rx(); |
mgottscho | 9:f71dc1b426da | 39 | if (fptr != NULL) |
mgottscho | 9:f71dc1b426da | 40 | __user_fptr = new FunctionPointer(fptr); |
mgottscho | 9:f71dc1b426da | 41 | } |
mgottscho | 9:f71dc1b426da | 42 | |
mgottscho | 9:f71dc1b426da | 43 | template<typename T> void SerialManager::attach_rx(T *tptr, void (T::*mptr)(void)) { |
mgottscho | 9:f71dc1b426da | 44 | //set user function pointer |
mgottscho | 9:f71dc1b426da | 45 | detach(); |
mgottscho | 9:f71dc1b426da | 46 | if (tptr != NULL && mptr != NULL) |
mgottscho | 9:f71dc1b426da | 47 | __user_fptr = new FunctionPointer(tptr, mptr); |
mgottscho | 9:f71dc1b426da | 48 | } |
mgottscho | 9:f71dc1b426da | 49 | |
mgottscho | 9:f71dc1b426da | 50 | void SerialManager::detach_rx() { |
mgottscho | 9:f71dc1b426da | 51 | if (__user_fptr != NULL) |
mgottscho | 9:f71dc1b426da | 52 | delete __user_fptr; |
mgottscho | 9:f71dc1b426da | 53 | __user_fptr = NULL; |
mgottscho | 9:f71dc1b426da | 54 | } |
mgottscho | 9:f71dc1b426da | 55 | |
mgottscho | 9:f71dc1b426da | 56 | //THIS DOES NOT WORK YET |
mgottscho | 9:f71dc1b426da | 57 | /*uint32_t SerialManager::sendLine(const char *line, const uint32_t len) { |
mgottscho | 9:f71dc1b426da | 58 | int i = 0; |
mgottscho | 9:f71dc1b426da | 59 | char temp_byte; |
mgottscho | 9:f71dc1b426da | 60 | bool buf_empty; |
mgottscho | 9:f71dc1b426da | 61 | |
mgottscho | 9:f71dc1b426da | 62 | if (line == NULL) //check input |
mgottscho | 9:f71dc1b426da | 63 | return 0; |
mgottscho | 9:f71dc1b426da | 64 | |
mgottscho | 9:f71dc1b426da | 65 | G_red_led = 0; |
mgottscho | 9:f71dc1b426da | 66 | |
mgottscho | 9:f71dc1b426da | 67 | // Start critical section - don't interrupt while changing global buffer variables |
mgottscho | 9:f71dc1b426da | 68 | __disable_irq(); |
mgottscho | 9:f71dc1b426da | 69 | buf_empty = (G_tx_head == G_tx_tail); |
mgottscho | 9:f71dc1b426da | 70 | |
mgottscho | 9:f71dc1b426da | 71 | while (i < len && line[i] != '\r') { //Loop until we have sent the maximum number of characters or we hit a carriage return |
mgottscho | 9:f71dc1b426da | 72 | // Wait if tx buffer full |
mgottscho | 9:f71dc1b426da | 73 | if ((G_tx_head + 1) % BUFFER_SIZE == G_tx_tail) { //If TX buffer is full, wait. |
mgottscho | 9:f71dc1b426da | 74 | // End critical section - need to let interrupt routine empty buffer by sending |
mgottscho | 9:f71dc1b426da | 75 | __enable_irq(); |
mgottscho | 9:f71dc1b426da | 76 | while ((G_tx_head + 1) % BUFFER_SIZE == G_tx_tail) { } //Spinloop until TX buffer is not full |
mgottscho | 9:f71dc1b426da | 77 | // Start critical section - don't interrupt while changing global buffer variables |
mgottscho | 9:f71dc1b426da | 78 | __disable_irq(); |
mgottscho | 9:f71dc1b426da | 79 | } |
mgottscho | 9:f71dc1b426da | 80 | G_tx_head = (G_tx_head + 1) % BUFFER_SIZE; |
mgottscho | 9:f71dc1b426da | 81 | G_tx_buf[G_tx_head] = line[i++]; |
mgottscho | 9:f71dc1b426da | 82 | } |
mgottscho | 9:f71dc1b426da | 83 | |
mgottscho | 9:f71dc1b426da | 84 | //Now we have buffered all characters in the line. Trigger the TX serial interrupt |
mgottscho | 9:f71dc1b426da | 85 | if (G_console.writeable() && buf_empty) { |
mgottscho | 9:f71dc1b426da | 86 | //Write the first byte to get it started |
mgottscho | 9:f71dc1b426da | 87 | temp_byte = G_tx_buf[G_tx_tail]; |
mgottscho | 9:f71dc1b426da | 88 | G_tx_tail = (G_tx_tail + 1) % BUFFER_SIZE; |
mgottscho | 9:f71dc1b426da | 89 | |
mgottscho | 9:f71dc1b426da | 90 | // Send first character to start tx interrupts, if stopped |
mgottscho | 9:f71dc1b426da | 91 | G_console.putc(temp_byte); |
mgottscho | 9:f71dc1b426da | 92 | } |
mgottscho | 9:f71dc1b426da | 93 | |
mgottscho | 9:f71dc1b426da | 94 | // End critical section |
mgottscho | 9:f71dc1b426da | 95 | __enable_irq(); |
mgottscho | 9:f71dc1b426da | 96 | |
mgottscho | 9:f71dc1b426da | 97 | G_red_led = 1; |
mgottscho | 9:f71dc1b426da | 98 | |
mgottscho | 9:f71dc1b426da | 99 | return i; |
mgottscho | 9:f71dc1b426da | 100 | }*/ |
mgottscho | 9:f71dc1b426da | 101 | |
mgottscho | 9:f71dc1b426da | 102 | |
mgottscho | 9:f71dc1b426da | 103 | uint32_t SerialManager::receiveLine(char *line, const uint32_t len) { |
mgottscho | 9:f71dc1b426da | 104 | int i = 0; |
mgottscho | 9:f71dc1b426da | 105 | char lastChar = '\0'; |
mgottscho | 9:f71dc1b426da | 106 | |
mgottscho | 9:f71dc1b426da | 107 | if (line == NULL) //check input |
mgottscho | 9:f71dc1b426da | 108 | return 0; |
mgottscho | 9:f71dc1b426da | 109 | |
mgottscho | 9:f71dc1b426da | 110 | // Start critical section - don't interrupt while changing global buffer variables |
mgottscho | 9:f71dc1b426da | 111 | __disable_uart_irq(); |
mgottscho | 9:f71dc1b426da | 112 | |
mgottscho | 9:f71dc1b426da | 113 | while (i < len && lastChar != '\r') { //Loop until maximum number of characters or a newline symbol |
mgottscho | 9:f71dc1b426da | 114 | //Wait for more characters if the rx buffer is empty |
mgottscho | 9:f71dc1b426da | 115 | if (__rx_tail == __rx_head) { |
mgottscho | 9:f71dc1b426da | 116 | // End critical section - need to allow rx interrupt to get new characters for buffer |
mgottscho | 9:f71dc1b426da | 117 | __enable_uart_irq(); |
mgottscho | 9:f71dc1b426da | 118 | while (__rx_tail == __rx_head) { } //Spinloop until there are some characters |
mgottscho | 9:f71dc1b426da | 119 | // Start critical section - don't interrupt while changing global buffer variables |
mgottscho | 9:f71dc1b426da | 120 | __disable_uart_irq(); |
mgottscho | 9:f71dc1b426da | 121 | } |
mgottscho | 9:f71dc1b426da | 122 | |
mgottscho | 9:f71dc1b426da | 123 | lastChar = __rx_buf[__rx_tail]; |
mgottscho | 9:f71dc1b426da | 124 | if (lastChar == '\r') //newline symbol |
mgottscho | 9:f71dc1b426da | 125 | line[i] = '\0'; |
mgottscho | 9:f71dc1b426da | 126 | else |
mgottscho | 9:f71dc1b426da | 127 | line[i] = lastChar; |
mgottscho | 9:f71dc1b426da | 128 | i++; |
mgottscho | 9:f71dc1b426da | 129 | __rx_tail = (__rx_tail + 1) % BUFFER_SIZE; |
mgottscho | 9:f71dc1b426da | 130 | } |
mgottscho | 9:f71dc1b426da | 131 | |
mgottscho | 9:f71dc1b426da | 132 | //Clear flag |
mgottscho | 9:f71dc1b426da | 133 | __have_rx_serial = false; |
mgottscho | 9:f71dc1b426da | 134 | |
mgottscho | 9:f71dc1b426da | 135 | // End critical section |
mgottscho | 9:f71dc1b426da | 136 | __enable_uart_irq(); |
mgottscho | 9:f71dc1b426da | 137 | |
mgottscho | 9:f71dc1b426da | 138 | return i; |
mgottscho | 9:f71dc1b426da | 139 | } |
mgottscho | 9:f71dc1b426da | 140 | |
mgottscho | 9:f71dc1b426da | 141 | bool SerialManager::haveRxSerialData() { |
mgottscho | 9:f71dc1b426da | 142 | return __have_rx_serial; |
mgottscho | 9:f71dc1b426da | 143 | } |
mgottscho | 9:f71dc1b426da | 144 | |
mgottscho | 9:f71dc1b426da | 145 | void SerialManager::flush() { |
mgottscho | 9:f71dc1b426da | 146 | while (serial.readable()) { |
mgottscho | 9:f71dc1b426da | 147 | serial.getc(); |
mgottscho | 9:f71dc1b426da | 148 | } |
mgottscho | 9:f71dc1b426da | 149 | } |
mgottscho | 9:f71dc1b426da | 150 | |
mgottscho | 9:f71dc1b426da | 151 | void SerialManager::print_line(const char *line, int len) { |
mgottscho | 9:f71dc1b426da | 152 | if (line == NULL || len < 1) |
mgottscho | 9:f71dc1b426da | 153 | return; |
mgottscho | 9:f71dc1b426da | 154 | |
mgottscho | 9:f71dc1b426da | 155 | const char *curr = line; |
mgottscho | 9:f71dc1b426da | 156 | while (curr < line+len && *curr != '\0') { |
mgottscho | 9:f71dc1b426da | 157 | serial.putc(*curr); |
mgottscho | 9:f71dc1b426da | 158 | curr++; |
mgottscho | 9:f71dc1b426da | 159 | } |
mgottscho | 9:f71dc1b426da | 160 | } |
mgottscho | 9:f71dc1b426da | 161 | |
mgottscho | 9:f71dc1b426da | 162 | void SerialManager::__serial_rx_ISR() { |
mgottscho | 9:f71dc1b426da | 163 | char tmp; |
mgottscho | 9:f71dc1b426da | 164 | |
mgottscho | 9:f71dc1b426da | 165 | if (__user_fptr != NULL) //user callback |
mgottscho | 9:f71dc1b426da | 166 | __user_fptr->call(); |
mgottscho | 9:f71dc1b426da | 167 | |
mgottscho | 9:f71dc1b426da | 168 | //Loop while the UART inbound FIFO is not empty and the receiving buffer is not full |
mgottscho | 9:f71dc1b426da | 169 | while (serial.readable() && (__rx_head != (__rx_tail - 1) % BUFFER_SIZE)) { |
mgottscho | 9:f71dc1b426da | 170 | tmp = serial.getc(); //read a byte into the buffer from the serial port |
mgottscho | 9:f71dc1b426da | 171 | __rx_buf[__rx_head] = tmp; |
mgottscho | 9:f71dc1b426da | 172 | __rx_head = (__rx_head + 1) % BUFFER_SIZE; |
mgottscho | 9:f71dc1b426da | 173 | if (tmp == '\r') |
mgottscho | 9:f71dc1b426da | 174 | __have_rx_serial = true; |
mgottscho | 9:f71dc1b426da | 175 | } |
mgottscho | 9:f71dc1b426da | 176 | } |
mgottscho | 9:f71dc1b426da | 177 | |
mgottscho | 9:f71dc1b426da | 178 | //THIS DOES NOT WORK YET |
mgottscho | 9:f71dc1b426da | 179 | /*void SerialManager::__serial_tx_ISR() { |
mgottscho | 9:f71dc1b426da | 180 | //Loop while the UART outbound FIFO is not full and the transmitting buffer is not empty |
mgottscho | 9:f71dc1b426da | 181 | while (G_console.writeable() && (G_tx_tail != G_tx_head)) { |
mgottscho | 9:f71dc1b426da | 182 | G_console.putc(G_tx_buf[G_tx_tail]); //write a byte to the serial port from the buffer |
mgottscho | 9:f71dc1b426da | 183 | G_tx_tail = (G_tx_tail + 1) % BUFFER_SIZE; |
mgottscho | 9:f71dc1b426da | 184 | } |
mgottscho | 9:f71dc1b426da | 185 | }*/ |
mgottscho | 9:f71dc1b426da | 186 | |
mgottscho | 9:f71dc1b426da | 187 | inline void SerialManager::__disable_uart_irq() { |
mgottscho | 9:f71dc1b426da | 188 | // Start critical section - don't interrupt with serial I/O |
mgottscho | 9:f71dc1b426da | 189 | // Since user specifies UART TX/RX pins, we don't know which we are using, so disable all 3 |
mgottscho | 9:f71dc1b426da | 190 | NVIC_DisableIRQ(UART0_IRQn); |
mgottscho | 9:f71dc1b426da | 191 | NVIC_DisableIRQ(UART1_IRQn); |
mgottscho | 9:f71dc1b426da | 192 | NVIC_DisableIRQ(UART2_IRQn); |
mgottscho | 9:f71dc1b426da | 193 | } |
mgottscho | 9:f71dc1b426da | 194 | |
mgottscho | 9:f71dc1b426da | 195 | inline void SerialManager::__enable_uart_irq() { |
mgottscho | 9:f71dc1b426da | 196 | // End critical section - can now interrupt with serial I/O |
mgottscho | 9:f71dc1b426da | 197 | // Since user specifies UART TX/RX pins, we don't know which we are using, so enable all 3 |
mgottscho | 9:f71dc1b426da | 198 | NVIC_EnableIRQ(UART0_IRQn); |
mgottscho | 9:f71dc1b426da | 199 | NVIC_EnableIRQ(UART1_IRQn); |
mgottscho | 9:f71dc1b426da | 200 | NVIC_EnableIRQ(UART2_IRQn); |
mgottscho | 9:f71dc1b426da | 201 | } |