/******************************************************************************
* Header file inclusions.
******************************************************************************/
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include <avr/io.h>
#include <avr/interrupt.h>
#include "portmacro.h"
#include <stdio.h>
/******************************************************************************
* Private macro definitions.
******************************************************************************/
#define mainLED_TASK_PRIORITY (tskIDLE_PRIORITY)
/******************************************************************************
* Private function prototypes.
******************************************************************************/
static void vBlinkLed(void* pvParameters);
/******************************************************************************
* Public function definitions.
******************************************************************************/
void * xSerialPortInitMinimal( unsigned long ulWantedBaud, unsigned portBASE_TYPE uxQueueLength )
{
unsigned long ulBaudRateCounter;
unsigned char ucByte;
portENTER_CRITICAL();
{
/* Calculate the baud rate register value from the equation in the
data sheet. */
ulBaudRateCounter = ( configCPU_CLOCK_HZ / ( 16 * ulWantedBaud ) ) - ( unsigned long ) 1;
/* Set the baud rate. */
ucByte = ( unsigned char ) ( ulBaudRateCounter & ( unsigned long ) 0xff );
UBRR0L = ucByte;
ulBaudRateCounter >>= ( unsigned long ) 8;
ucByte = ( unsigned char ) ( ulBaudRateCounter & ( unsigned long ) 0xff );
UBRR0H = ucByte;
/* Enable the Rx interrupt. The Tx interrupt will get enabled
later. Also enable the Rx and Tx. */
UCSR0B |= (1 << RXCIE0) | (1 << RXEN0) | (1 << TXEN0);
/* Set the data bits to 8. */
UCSR0C |= (1 << UCSZ01) | (1 << UCSZ00);
}
portEXIT_CRITICAL();
/* Unlike other ports, this serial code does not allow for more than one
com port. We therefore don't return a pointer to a port structure and can
instead just return NULL. */
return NULL;
}
/*-----------------------------------------------------------*/
void uart_putchar(char c, FILE *stream) {
if (c == '\n') {
uart_putchar('\r', stream);
}
loop_until_bit_is_set(UCSR0A, UDRE0);
UDR0 = c;
}
char uart_getchar(FILE *stream) {
loop_until_bit_is_set(UCSR0A, RXC0); /* Wait until data exists. */
return UDR0;
}
void uart_init(void)
{
xSerialPortInitMinimal( 9600, NULL );
FILE uart_output = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE);
FILE uart_input = FDEV_SETUP_STREAM(NULL, uart_getchar, _FDEV_SETUP_READ);
FILE uart_io = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW);
stdout = &uart_output;
stdin = &uart_input;
}
int flag = 0;
// Define constants and variables for buffering incoming serial data. We're
// using a ring buffer (I think), in which head is the index of the location
// to which to write the next incoming character and tail is the index of the
// location from which to read.
#if (RAMEND < 1000)
#define SERIAL_BUFFER_SIZE 16
#else
#define SERIAL_BUFFER_SIZE 64
#endif
typedef struct ring_buffer
{
unsigned char buffer[SERIAL_BUFFER_SIZE];
volatile unsigned int head;
volatile unsigned int tail;
}ring_buffer;
ring_buffer rx_buffer = { { 0 }, 0, 0 };
ring_buffer tx_buffer = { { 0 }, 0, 0 };
inline void store_char(unsigned char c, ring_buffer *buffer)
{
int i = (unsigned int)(buffer->head + 1) % SERIAL_BUFFER_SIZE;
// if we should be storing the received character into the location
// just before the tail (meaning that the head would advance to the
// current location of the tail), we're about to overflow the buffer
// and so we don't write the character or advance the head.
if (i != buffer->tail) {
buffer->buffer[buffer->head] = c;
buffer->head = i;
if ( (c == '\n') || (c == '\r'))
{
// Notification flag
flag = 1;
}
}
}
static void vUSART(void* pvParameters)
{
char input;
int i;
(void *)pvParameters;
for ( ;; )
{
// TODO:
portENTER_CRITICAL();
// Recieve the USART command
if (flag)
{
// Parse the command
printf("Oh sir, you wrote: %s\n", rx_buffer.buffer);
// reset the flag
flag = 0;
memset(rx_buffer.buffer, '\0', SERIAL_BUFFER_SIZE);
rx_buffer.head = rx_buffer.tail = 0;
}
portEXIT_CRITICAL();
}
}
// TODO: fixme
// ISR_BLOCK
// ISR_NOBLOCK
// ISR_NAKED
ISR(USART_RX_vect, ISR_BLOCK)
{
if (bit_is_clear(UCSR0A, UPE0)) {
unsigned char c = UDR0;
store_char(c, &rx_buffer);
} else {
unsigned char c = UDR0;
};
}
/**************************************************************************//**
* \fn int main(void)
*
* \brief Main function.
*
* \return
******************************************************************************/
int main(void)
{
// USART task
xSerialPortInitMinimal( 9600, NULL );
// Redirecting STDIN and STDOUT to UART
FILE uart_output = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE);
FILE uart_input = FDEV_SETUP_STREAM(NULL, uart_getchar, _FDEV_SETUP_READ);
FILE uart_io = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW);
stdout = &uart_output;
stdin = &uart_input;
// Create task.
xTaskHandle blink_handle;
xTaskCreate
(
vBlinkLed,
(signed char*)"blink",
configMINIMAL_STACK_SIZE,
NULL,
mainLED_TASK_PRIORITY + 1,
&blink_handle
);
#if 1
// USART task
xTaskHandle usart_handle;
xTaskCreate
(
vUSART,
(signed char*)"USART",
configMINIMAL_STACK_SIZE,
NULL,
mainLED_TASK_PRIORITY,
&usart_handle
);
#endif
// Start scheduler.
vTaskStartScheduler();
return 0;
}
/**************************************************************************//**
* \fn static vApplicationIdleHook(void)
*
* \brief
******************************************************************************/
void vApplicationIdleHook(void)
{
}
/******************************************************************************
* Private function definitions.
******************************************************************************/
/**************************************************************************//**
* \fn static void vBlinkLed(void* pvParameters)
*
* \brief
*
* \param[in] pvParameters
******************************************************************************/
static void vBlinkLed(void* pvParameters)
{
DDRB |= _BV(PB5);
for ( ;; )
{
PORTB ^= _BV(PB5);
if (bit_is_set(PORTB, PB5))
printf("LED on\n");
else
printf("LED off\n");
vTaskDelay(1000);
}
}