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
Utility.cpp
- Committer:
- mgottscho
- Date:
- 2014-03-12
- Revision:
- 8:e79637fbb035
- Parent:
- 7:a2b7928a81a2
File content as of revision 8:e79637fbb035:
/* Utility.cpp
* Tested with mbed board: FRDM-KL46Z
* Author: Mark Gottscho
* mgottscho@ucla.edu
*/
#include "mbed.h"
#include <string>
#include "Utility.h"
using namespace std;
Utility::Utility(DigitalOut *green_led, DigitalOut *red_led, PinName serial_tx_pin, PinName serial_rx_pin, int baudrate, bool enableSerialInterrupts) :
console(serial_tx_pin, serial_rx_pin),
__green_led(green_led),
__red_led(red_led),
__valid_green(false),
__valid_red(false),
__interrupts_en(enableSerialInterrupts),
__user_fptr(NULL),
__green_led_interrupt(),
__red_led_interrupt(),
__rx_head(0),
__rx_tail(0),
__tx_head(0),
__tx_tail(0),
__have_rx_serial(false)
{
if (__green_led != NULL) {
__valid_green = true;
*__green_led = 1;
}
if (__red_led != NULL) {
__valid_red = true;
*__red_led = 1;
}
console.baud(baudrate); //115200, 230400 confirmed to work, above this seems to fail
//Set up serial interrupt handlers
if (__interrupts_en) {
console.attach(this, &Utility::__console_rx_ISR, Serial::RxIrq);
//console.attach(this, &Utility::__console_tx_ISR, Serial::TxIrq);
}
}
Utility::~Utility() {
detach();
}
void Utility::attach(void (*fptr)(void)) {
//set user function pointer
detach();
if (fptr != NULL)
__user_fptr = new FunctionPointer(fptr);
}
template<typename T> void Utility::attach(T *tptr, void (T::*mptr)(void)) {
//set user function pointer
detach();
if (tptr != NULL && mptr != NULL)
__user_fptr = new FunctionPointer(tptr, mptr);
}
void Utility::detach() {
if (__user_fptr != NULL)
delete __user_fptr;
__user_fptr = NULL;
}
void Utility::panic(string errorMessage, int errorCode) {
//We're dead. This is the point of no return! Permanently ignore interrupts.
__disable_irq();
console.printf(">>> PANIC, CODE # %d: %s <<<\r\n", errorCode, errorMessage.c_str());
if (__valid_green)
*__green_led = 1;
if (__valid_red)
*__red_led = 0;
while(1); //Spinloop for eternity
}
void Utility::warn(string errorMessage, int errorCode) {
console.printf(">>> WARN, CODE # %d: %s <<<\r\n", errorCode, errorMessage.c_str());
}
#ifdef NDEBUG
void Utility::myAssert(bool condition, const char *file, const unsigned long line) { }
#else
void Utility::myAssert(bool condition, const char *file, const unsigned long line) {
if (!condition)
{
char msg[256];
sprintf(msg, "Assertion failed at file %s, line %d", file, line);
panic(msg, -1); \
}
}
#endif
void Utility::blinkGreen(bool enable, float half_period) {
if (__valid_green) {
if (enable) {
if (half_period <= 0.01) {
__green_led_interrupt.detach();
*__green_led = 0;
} else if (half_period <= 1800)
__green_led_interrupt.attach(this, &Utility::__greenLED_ISR, half_period);
}
else {
__green_led_interrupt.detach();
*__green_led = 1;
}
}
}
void Utility::blinkRed(bool enable, float half_period) {
if (__valid_red) {
if (enable) {
if (half_period <= 0.01) {
__red_led_interrupt.detach();
*__red_led = 0;
} else if (half_period <= 1800)
__red_led_interrupt.attach(this, &Utility::__redLED_ISR, half_period);
}
else {
__red_led_interrupt.detach();
*__red_led = 1;
}
}
}
//THIS DOES NOT WORK YET
/*uint32_t Utility::sendLine(const char *line, const uint32_t len) {
int i = 0;
char temp_byte;
bool buf_empty;
if (line == NULL) //check input
return 0;
G_red_led = 0;
// Start critical section - don't interrupt while changing global buffer variables
__disable_irq();
buf_empty = (G_tx_head == G_tx_tail);
while (i < len && line[i] != '\r') { //Loop until we have sent the maximum number of characters or we hit a carriage return
// Wait if tx buffer full
if ((G_tx_head + 1) % BUFFER_SIZE == G_tx_tail) { //If TX buffer is full, wait.
// End critical section - need to let interrupt routine empty buffer by sending
__enable_irq();
while ((G_tx_head + 1) % BUFFER_SIZE == G_tx_tail) { } //Spinloop until TX buffer is not full
// Start critical section - don't interrupt while changing global buffer variables
__disable_irq();
}
G_tx_head = (G_tx_head + 1) % BUFFER_SIZE;
G_tx_buf[G_tx_head] = line[i++];
}
//Now we have buffered all characters in the line. Trigger the TX serial interrupt
if (G_console.writeable() && buf_empty) {
//Write the first byte to get it started
temp_byte = G_tx_buf[G_tx_tail];
G_tx_tail = (G_tx_tail + 1) % BUFFER_SIZE;
// Send first character to start tx interrupts, if stopped
G_console.putc(temp_byte);
}
// End critical section
__enable_irq();
G_red_led = 1;
return i;
}*/
uint32_t Utility::receiveLine(char *line, const uint32_t len) {
int i = 0;
char lastChar = '\0';
if (line == NULL) //check input
return 0;
// Start critical section - don't interrupt while changing global buffer variables
__disable_uart_irq();
while (i < len && lastChar != '\r') { //Loop until maximum number of characters or a newline symbol
//Wait for more characters if the rx buffer is empty
if (__rx_tail == __rx_head) {
// End critical section - need to allow rx interrupt to get new characters for buffer
__enable_uart_irq();
while (__rx_tail == __rx_head) { } //Spinloop until there are some characters
// Start critical section - don't interrupt while changing global buffer variables
__disable_uart_irq();
}
lastChar = __rx_buf[__rx_tail];
if (lastChar == '\r') //newline symbol
line[i] = '\0';
else
line[i] = lastChar;
i++;
__rx_tail = (__rx_tail + 1) % BUFFER_SIZE;
}
//Clear flag
__have_rx_serial = false;
// End critical section
__enable_uart_irq();
return i;
}
bool Utility::haveRxSerialData() {
return __have_rx_serial;
}
void Utility::flushConsole() {
while (console.readable()) {
console.getc();
}
}
void Utility::__greenLED_ISR() {
if (*__green_led == 0) //Just flip the LED status every time we are called
*__green_led = 1;
else
*__green_led = 0;
}
void Utility::__redLED_ISR() {
if (*__red_led == 0) //Just flip the LED status every time we are called
*__red_led = 1;
else
*__red_led = 0;
}
void Utility::__console_rx_ISR() {
char tmp;
if (__user_fptr != NULL) //user callback
__user_fptr->call();
//Loop while the UART inbound FIFO is not empty and the receiving buffer is not full
while (console.readable() && (__rx_head != (__rx_tail - 1) % BUFFER_SIZE)) {
tmp = console.getc(); //read a byte into the buffer from the serial port
__rx_buf[__rx_head] = tmp;
__rx_head = (__rx_head + 1) % BUFFER_SIZE;
if (tmp == '\r')
__have_rx_serial = true;
}
}
//THIS DOES NOT WORK YET
/*void Utility::__console_tx_ISR() {
//Loop while the UART outbound FIFO is not full and the transmitting buffer is not empty
while (G_console.writeable() && (G_tx_tail != G_tx_head)) {
G_console.putc(G_tx_buf[G_tx_tail]); //write a byte to the serial port from the buffer
G_tx_tail = (G_tx_tail + 1) % BUFFER_SIZE;
}
}*/
inline void Utility::__disable_uart_irq() {
// Start critical section - don't interrupt with serial I/O
// Since user specifies UART TX/RX pins, we don't know which we are using, so disable all 3
NVIC_DisableIRQ(UART0_IRQn);
NVIC_DisableIRQ(UART1_IRQn);
NVIC_DisableIRQ(UART2_IRQn);
}
inline void Utility::__enable_uart_irq() {
// End critical section - can now interrupt with serial I/O
// Since user specifies UART TX/RX pins, we don't know which we are using, so enable all 3
NVIC_EnableIRQ(UART0_IRQn);
NVIC_EnableIRQ(UART1_IRQn);
NVIC_EnableIRQ(UART2_IRQn);
}
