You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

552 lines
18 KiB

//
// Created by dipak on 18.05.18.
//
#include "Serial.h"
#include <stdlib.h>
Serial Debug(0);
Serial *Serial::Serial0 = nullptr;
//Serial *Serial::Serial1 = nullptr;
Serial *Serial::Serial2 = nullptr;
Serial *Serial::Serial3 = nullptr;
Serial::Serial(const uint8_t port)
{
this->portNumber = port;
switch (portNumber) {
case 0:
if (Serial0 == nullptr) {
this->UDRn = &UDR0;
this->UCSRnA = &UCSR0A;
this->UCSRnB = &UCSR0B;
this->UCSRnC = &UCSR0C;
this->UBRRnH = &UBRR0H;
this->UBRRnL = &UBRR0L;
this->TXENn = TXEN0;
this->RXENn = RXEN0;
this->UDREn = UDRE0;
this->U2Xn = U2X0;
this->RXCIEn = RXCIE0;
this->USBSn = USBS0;
this->UPMn0 = UPM00;
this->UPMn1 = UPM01;
this->UCSZn0 = UCSZ00;
this->UCSZn1 = UCSZ01;
this->UCSZn2 = UCSZ02;
this->UMSELn0 = UMSEL00;
this->UMSELn1 = UMSEL01;
this->UDRIEn = UDRIE0;
Serial0 = this;
}
break;
/*
case 1:
if (Serial1 == nullptr) {
this->UDRn = &UDR1;
this->UCSRnA = &UCSR1A;
this->UCSRnB = &UCSR1B;
this->UCSRnC = &UCSR1C;
this->UBRRnH = &UBRR1H;
this->UBRRnL = &UBRR1L;
this->TXENn = TXEN1;
this->RXENn = RXEN1;
this->UDREn = UDRE1;
this->U2Xn = U2X1;
this->RXCIEn = RXCIE1;
this->USBSn = USBS1;
this->UPMn0 = UPM10;
this->UPMn1 = UPM11;
this->UCSZn0 = UCSZ10;
this->UCSZn1 = UCSZ11;
this->UCSZn2 = UCSZ12;
this->UMSELn0 = UMSEL10;
this->UMSELn1 = UMSEL11;
this->UDRIEn = UDRIE1;
Serial1 = this;
}
break;
*/
case 2:
if (Serial2 == nullptr) {
this->UDRn = &UDR2;
this->UCSRnA = &UCSR2A;
this->UCSRnB = &UCSR2B;
this->UCSRnC = &UCSR2C;
this->UBRRnH = &UBRR2H;
this->UBRRnL = &UBRR2L;
this->TXENn = TXEN2;
this->RXENn = RXEN2;
this->UDREn = UDRE2;
this->U2Xn = U2X2;
this->RXCIEn = RXCIE2;
this->USBSn = USBS2;
this->UPMn0 = UPM20;
this->UPMn1 = UPM21;
this->UCSZn0 = UCSZ20;
this->UCSZn1 = UCSZ21;
this->UCSZn2 = UCSZ22;
this->UMSELn0 = UMSEL20;
this->UMSELn1 = UMSEL21;
this->UDRIEn = UDRIE2;
Serial2 = this;
}
break;
case 3:
if (Serial3 == nullptr) {
this->UDRn = &UDR3;
this->UCSRnA = &UCSR3A;
this->UCSRnB = &UCSR3B;
this->UCSRnC = &UCSR3C;
this->UBRRnH = &UBRR3H;
this->UBRRnL = &UBRR3L;
this->TXENn = TXEN3;
this->RXENn = RXEN3;
this->UDREn = UDRE3;
this->U2Xn = U2X3;
this->RXCIEn = RXCIE3;
this->USBSn = USBS3;
this->UPMn0 = UPM30;
this->UPMn1 = UPM31;
this->UCSZn0 = UCSZ30;
this->UCSZn1 = UCSZ31;
this->UCSZn2 = UCSZ32;
this->UMSELn0 = UMSEL30;
this->UMSELn1 = UMSEL31;
this->UDRIEn = UDRIE3;
Serial3 = this;
}
break;
default:break;
}
}
/*!
* Function to initialise USART communication
* @param baud The USART communication baud rate - defaulted to 9600
* @param mode Sets the operating mode. Either Asynchronous Normal mode, Asynchronous Double Speed mode or Synchronous
* Master mode. Possible value are:
* ASYNC_NORMAL = 0,
* ASYNC_DOUBLE_SPEED = 1,
* SYNC_MASTER = 2
* @param parity Sets the parity bit - defaulted to NONE. Possible values are:
* NONE = 0,
* EVEN = 2,
* ODD = 3
* @param stopBits Sets the number of stop bits - default to ONE. Possible values are:
* ONE = 1,
* TWO = 2
* @param frameLength Sets the number of bits per frame - default value of 8 bits(EIGHT_BITS). Possible values are:
* FIVE_BITS = 5,
* SIX_BITS = 6,
* SEVEN_BITS = 7,
* EIGHT_BITS = 8,
* NINE_BITS = 9
*/
void Serial::begin(const uint32_t baud,
const USARTOperatingMode mode,
const USARTParity parity,
const USARTStopBits stopBits,
const USARTFrameLength frameLength)
{
this->Parity = parity;
this->setParity(Parity);
this->StopBits = stopBits;
this->setStopBit(StopBits);
this->FrameLength = frameLength;
this->setFrameLength(FrameLength);
this->flushBuffer();
/* Enable receiver and transmitter */
*(this->UCSRnB) |= (1 << this->TXENn);
*(this->UCSRnB) |= (1 << this->RXENn);
*(this->UCSRnB) |= (1 << this->RXCIEn);
this->OperatingMode = mode;
this->setOpMode(baud, OperatingMode);
}
/*!
* Function sets the Sets the operating mode. Either Asynchronous Normal mode, Asynchronous Double Speed mode or
* Synchronous Master mode
* @param baud The USART communication baud rate
* @param mode The desired operating mode
*/
void Serial::setOpMode(const uint32_t baud,
const enum USARTOperatingMode mode)
{
uint16_t bRate = 0;
// compute baud rate value for UBRR register
/***********************************************************************/
/*UMSELn Bits Settings */
/* UMSELn1 UMSELn0 Mode */
/* 0 0 Asynchronous USART */
/* 0 1 Synchronous USART */
/* 1 0 (Reserved) */
/* 1 1 Master SPI (MSPIM) */
/***********************************************************************/
switch (mode) {
case USARTOperatingMode::SYNC_MASTER:bRate = static_cast<uint16_t>((F_CPU / 2 / baud - 1) / 2);
*(this->UCSRnC) |= (1 << this->UMSELn0);
*(this->UCSRnC) &= ~(1 << this->UMSELn1);
break;
case USARTOperatingMode::ASYNC_DOUBLE_SPEED:bRate = static_cast<uint16_t>((F_CPU / 4 / baud - 1) / 2);
// UMSELn0 = 0 and UMSELn1 = 0 for asynchronous mode
*(this->UCSRnC) &= ~(1 << this->UMSELn0);
*(this->UCSRnC) &= ~(1 << this->UMSELn1);
break;
case USARTOperatingMode::ASYNC_NORMAL:bRate = static_cast<uint16_t>((F_CPU / 16 / baud) - 1);
// UMSELn0 = 0 and UMSELn1 = 0 for asynchronous mode
*(this->UCSRnC) &= ~(1 << this->UMSELn0);
*(this->UCSRnC) &= ~(1 << this->UMSELn1);
break;
}
*(this->UBRRnH) = (uint8_t) (bRate >> 8);
*(this->UBRRnL) = (uint8_t) (bRate & 0xFF);
}
/*!
* Function to set the number of bits per frame
* @param frameLength The frame length value. Possible values are:
* FIVE_BITS = 5,
* SIX_BITS = 6,
* SEVEN_BITS = 7,
* EIGHT_BITS = 8,
* NINE_BITS = 9
*/
void Serial::setFrameLength(enum USARTFrameLength frameLength)
{
/************************************************************************/
/* @method */
/* Set UART/USART frame length (5 to 9 bits) */
/* @param frameLength */
/* the frame length - values from USARTFrameLength.xxx */
/* UCSZn Bits Settings */
/* UCSZn2 UCSZn1 UCSZn0 Character Size */
/* 0 0 0 5-bit */
/* 0 0 1 6-bit */
/* 0 1 0 7-bit */
/* 0 1 1 8-bit */
/* 1 1 1 9-bit */
/************************************************************************/
switch (frameLength) {
case USARTFrameLength::FIVE_BITS:*(this->UCSRnC) &= ~(1 << this->UCSZn0);
*(this->UCSRnC) &= ~(1 << this->UCSZn1);
*(this->UCSRnB) &= ~(1 << this->UCSZn2);
break;
case USARTFrameLength::SIX_BITS:*(this->UCSRnC) |= (1 << this->UCSZn0);
*(this->UCSRnC) &= ~(1 << this->UCSZn1);
*(this->UCSRnB) &= ~(1 << this->UCSZn2);
break;
case USARTFrameLength::SEVEN_BITS:*(this->UCSRnC) &= ~(1 << this->UCSZn0);
*(this->UCSRnC) |= (1 << this->UCSZn1);
*(this->UCSRnB) &= ~(1 << this->UCSZn2);
break;
case USARTFrameLength::EIGHT_BITS:*(this->UCSRnC) |= (1 << this->UCSZn0);
*(this->UCSRnC) |= (1 << this->UCSZn1);
*(this->UCSRnB) &= ~(1 << this->UCSZn2);
break;
case USARTFrameLength::NINE_BITS:
// set data transmission mode: 9-bit (UCSZn2 = 1; UCSZn1 = 1; UCSZn0 = 1;)
*(this->UCSRnC) |= (1 << this->UCSZn0);
*(this->UCSRnC) |= (1 << this->UCSZn1);
*(this->UCSRnB) |= (1 << this->UCSZn2);
break;
default: // Defaulting to 8 bits
*(this->UCSRnC) |= (1 << this->UCSZn0);
*(this->UCSRnC) |= (1 << this->UCSZn1);
*(this->UCSRnB) &= ~(1 << this->UCSZn2);
break;
}
}
/*!
* Function sets the number of stop bits to be used in the USART communication
* @param stopBit Sets the number of stop bits - default to ONE. Possible values are:
* ONE = 1,
* TWO = 2
*/
void Serial::setStopBit(USARTStopBits stopBit)
{
/************************************************************************/
/* @method */
/* Set UART/USART transmission stop bit */
/* @param stopBit */
/* the stop bit - values from StopBits.xxx */
/* USBS Bit Settings */
/* USBSn = 0 => 1 Stop bit */
/* USBSn = 1 => 2 Stop bit */
/************************************************************************/
switch (stopBit) {
// one stop bit
case USARTStopBits::ONE:*(this->UCSRnC) &= ~(1 << this->USBSn);
break;
// two stop bits
case USARTStopBits::TWO:*(this->UCSRnC) |= (1 << this->USBSn);
break;
}
}
/*!
* Function sets the partity bits to be used for the USART communication
* @param parity Sets the parity bit - defaulted to NONE. Possible values are:
* NONE = 0,
* EVEN = 2,
* ODD = 3
*/
void Serial::setParity(enum USARTParity parity)
{
/************************************************************************/
/* @method */
/* Set UART/USART transmission parity */
/* @param parity */
/* the parity - values from USARTParity.xxx */
/* UPMn Bits Settings */
/* UPMn1 UPMn0 Parity Mode */
/* 0 0 Disabled */
/* 0 1 Reserved */
/* 1 0 Enabled, Even Parity */
/* 1 1 Enabled, Odd Parity */
/************************************************************************/
switch (parity) {
case USARTParity::NONE:*(this->UCSRnC) &= ~(1 << this->UPMn0);
*(this->UCSRnC) &= ~(1 << this->UPMn1);
break;
case USARTParity::EVEN:*(this->UCSRnC) &= ~(1 << this->UPMn0);
*(this->UCSRnC) |= (1 << this->UPMn1);
break;
case USARTParity::ODD:*(this->UCSRnC) |= (1 << this->UPMn0);
*(this->UCSRnC) |= (1 << this->UPMn1);
break;
}
}
/*!
* Clear the buffers - reset buffer pointers to their initial state
* @return Either true or False.
*/
bool Serial::clear()
{
/************************************************************************/
/* @method */
/* Clear the buffers - reset buffer pointers to their initial state */
/* @return true so it can be used in logical expressions with ease */
/************************************************************************/
bool txEnabled = (*(this->UCSRnB) & (1 << this->TXENn)) > 0;
// disable USART data receiving until clearing the buffer
if (txEnabled) {
*(this->UCSRnB) &= ~(1 << this->TXENn);
}
this->flushBuffer();
if (txEnabled) {
*(this->UCSRnB) |= (1 << this->TXENn);
}
return true;
}
/*!
* Function flushes the transmission and receive buffer indices
*/
void Serial::flushBuffer()
{
this->rxHeadIndex = 0;
this->rxTailIndex = 0;
this->txHeadIndex = 0;
this->txTailIndex = 0;
}
/*!
* Function reads one byte at a time from the receiver buffer, and increments the tail index by one
* @return one byte from the receiver buffer
*/
uint8_t Serial::read()
{
uint8_t tmptail;
/* calculate /store buffer index */
tmptail = static_cast<uint8_t>((this->rxTailIndex + 1) & (BUFFER_SIZE - 1));
this->rxTailIndex = tmptail;
/* get data from receive buffer */
if (rxBuffer[tmptail] == TERMINATOR) this->pending--; //Read one complete msg
return rxBuffer[tmptail];
}
/*!
* Function to transmit one byte of data
* @param data Data to be transmitted
*/
void Serial::write(const uint8_t data)
{
// Create a temporary index to point to the head of the buffer
uint8_t tmp_head_index;
// Calculate the next value of the head index
tmp_head_index = static_cast<uint8_t>((txHeadIndex + 1) & (BUFFER_SIZE - 1));
while (tmp_head_index == Serial::txTailIndex) { ;/* wait for free space in buffer */
}
// Load data into the transmission buffer and the next free position i.e., tmp_head_index
txBuffer[tmp_head_index] = data;
// Update global index to the incremented value
txHeadIndex = tmp_head_index;
// Enable UDRE interrupt
*(this->UCSRnB) |= (1 << this->UDRIEn); // enable UDRE interrupt
}
/*!
* Function to transmit a char array. Overloaded write() function
* @param data Pointer to the a char array
*/
void Serial::write(const char *data)
{
while ((*data) != '\0') // Looping until end of char array '\0' is encountered
write(static_cast<uint8_t>(*data++));
}
void Serial::writeln(const char *data = "")
{
while ((*data) != '\0') // Looping until end of char array '\0' is encountered
write(static_cast<uint8_t>(*data++));
write(static_cast<uint8_t>('\n'));
}
void Serial::write(char data)
{
write(static_cast<const uint8_t>(data));
}
void Serial::write(const uint8_t *data)
{
while ((*data) != '\0') // Looping until end of char array '\0' is encountered
write(static_cast<const uint8_t>(*data++));
}
uint8_t Serial::msgPending()
{
return this->pending;
}
/*!
* Functions lets know if there is any data received on the receiver buffer
* @return
*/
bool Serial::rxDataAvailable()
{
return rxHeadIndex != rxTailIndex;
}
/*!
* Destructor
*/
Serial::~Serial()
{
}
// Rx & UDRE vectors for USART0
#if defined(HAS_USART0)
void USART0_RX_vect()
{
Serial::Serial0->handleRXInterrupt();
}
void USART0_UDRE_vect()
{
Serial::Serial0->handleUDREInterrupt();
}
#endif
// Rx & UDRE vectors for USART1
#if defined(HAS_USART1)
void USART1_RX_vect()
{
Serial::Serial1->handleRXInterrupt();
}
void USART1_UDRE_vect()
{
Serial::Serial1->handleUDREInterrupt();
}
#endif
// Rx & UDRE vectors for USART2
#if defined(HAS_USART2)
void USART2_RX_vect()
{
Serial::Serial2->handleRXInterrupt();
}
void USART2_UDRE_vect()
{
Serial::Serial2->handleUDREInterrupt();
}
#endif
// Rx & UDRE vectors for USART3
#if defined(HAS_USART3)
void USART3_RX_vect()
{
Serial::Serial3->handleRXInterrupt();
}
void USART3_UDRE_vect()
{
Serial::Serial3->handleUDREInterrupt();
}
#endif
/*!
* Function handles the RX interrupts across all the static instances
*/
void Serial::handleRXInterrupt()
{
/* Calculate buffer index */
uint8_t temp_head = static_cast<uint8_t>((this->rxHeadIndex + 1) & (BUFFER_SIZE - 1));
if (temp_head == this->rxTailIndex) {
/* ERROR! Receive buffer overflow */
/* Do nothing for now */
}
else {
this->rxHeadIndex = temp_head;
this->rxBuffer[this->rxHeadIndex] = *(this->UDRn);
if (this->rxBuffer[this->rxHeadIndex]== TERMINATOR) this->pending++;
}
}
/*!
* Function handles the UDRE interrupts across all the static instances
*/
void Serial::handleUDREInterrupt()
{
unsigned char temp_tail;
/* Check if all data is transmitted */
if (this->txHeadIndex != this->txTailIndex) {
/* Calculate buffer index */
temp_tail = static_cast<unsigned char>((this->txTailIndex + 1) & (BUFFER_SIZE - 1));
/* Store new index */
this->txTailIndex = temp_tail;
/* Start transmission */
*(this->UDRn) = this->txBuffer[temp_tail];
}
else {
*(this->UCSRnB) &= ~(1 << this->UDRIEn); // disable UDRE interrupt
}
}