// // Created by dipak on 18.05.18. // #include "Serial.h" #include 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((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((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((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((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((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(*data++)); } void Serial::writeln(const char *data = "") { while ((*data) != '\0') // Looping until end of char array '\0' is encountered write(static_cast(*data++)); write(static_cast('\n')); } void Serial::write(char data) { write(static_cast(data)); } void Serial::write(const uint8_t *data) { while ((*data) != '\0') // Looping until end of char array '\0' is encountered write(static_cast(*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((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((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 } }