123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505 |
- /*
- * serial.c
- *
- * Copyright (c) 2012, 2013, Thomas Buck <xythobuz@me.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- #include <avr/io.h>
- #include <avr/interrupt.h>
- #include <stdint.h>
-
- #include "serial.h"
- #include "avr/serial_device.h"
-
- /** \addtogroup uart UART Library
- * UART Library enabling you to control all available
- * UART Modules. With XON/XOFF Flow Control and buffered
- * Receiving and Transmitting.
- * @{
- */
-
- /** \file serial.c
- * UART Library Implementation
- */
-
- /** If you define this, a '\\r' (CR) will be put in front of a '\\n' (LF) when sending a byte.
- * Binary Communication will then be impossible!
- */
- // #define SERIALINJECTCR
-
- #ifndef RX_BUFFER_SIZE
- #define RX_BUFFER_SIZE 16 /**< RX Buffer Size in Bytes (Power of 2) */
- #endif
-
- #ifndef TX_BUFFER_SIZE
- #define TX_BUFFER_SIZE 128 /**< TX Buffer Size in Bytes (Power of 2) */
- #endif
-
- /** Defining this enables incoming XON XOFF (sends XOFF if rx buff is full) */
- //#define FLOWCONTROL
-
- #define FLOWMARK 5 /**< Space remaining to trigger xoff/xon */
- #define XON 0x11 /**< XON Value */
- #define XOFF 0x13 /**< XOFF Value */
-
- #if (RX_BUFFER_SIZE < 2) || (TX_BUFFER_SIZE < 2)
- #error SERIAL BUFFER TOO SMALL!
- #endif
-
- #ifdef FLOWCONTROL
- #if (RX_BUFFER_SIZE < 8) || (TX_BUFFER_SIZE < 8)
- #error SERIAL BUFFER TOO SMALL!
- #endif
- #endif
-
- #if ((RX_BUFFER_SIZE + TX_BUFFER_SIZE) * UART_COUNT) >= (RAMEND - 0x60)
- #error SERIAL BUFFER TOO LARGE!
- #endif
-
- // serialRegisters
- #define SERIALDATA 0
- #define SERIALB 1
- #define SERIALC 2
- #define SERIALA 3
- #define SERIALUBRRH 4
- #define SERIALUBRRL 5
-
- // serialBits
- #define SERIALUCSZ0 0
- #define SERIALUCSZ1 1
- #define SERIALRXCIE 2
- #define SERIALRXEN 3
- #define SERIALTXEN 4
- #define SERIALUDRIE 5
- #define SERIALUDRE 6
-
- uint8_t volatile rxBuffer[UART_COUNT][RX_BUFFER_SIZE];
- uint8_t volatile txBuffer[UART_COUNT][TX_BUFFER_SIZE];
- uint16_t volatile rxRead[UART_COUNT];
- uint16_t volatile rxWrite[UART_COUNT];
- uint16_t volatile txRead[UART_COUNT];
- uint16_t volatile txWrite[UART_COUNT];
- uint8_t volatile shouldStartTransmission[UART_COUNT];
-
- #ifdef FLOWCONTROL
- uint8_t volatile sendThisNext[UART_COUNT];
- uint8_t volatile flow[UART_COUNT];
- uint8_t volatile rxBufferElements[UART_COUNT];
- #endif
-
- uint8_t serialAvailable(void) {
- return UART_COUNT;
- }
-
- void serialInit(uint8_t uart, uint16_t baud) {
- if (uart >= UART_COUNT)
- return;
-
- // Initialize state variables
- rxRead[uart] = 0;
- rxWrite[uart] = 0;
- txRead[uart] = 0;
- txWrite[uart] = 0;
- shouldStartTransmission[uart] = 1;
- #ifdef FLOWCONTROL
- sendThisNext[uart] = 0;
- flow[uart] = 1;
- rxBufferElements[uart] = 0;
- #endif
-
- // Default Configuration: 8N1
- *serialRegisters[uart][SERIALC] = (1 << serialBits[uart][SERIALUCSZ0]) | (1 << serialBits[uart][SERIALUCSZ1]);
-
- // Set baudrate
- #if SERIALBAUDBIT == 8
- *serialRegisters[uart][SERIALUBRRH] = (baud >> 8);
- *serialRegisters[uart][SERIALUBRRL] = baud;
- #else
- *serialBaudRegisters[uart] = baud;
- #endif
-
- *serialRegisters[uart][SERIALB] = (1 << serialBits[uart][SERIALRXCIE]); // Enable Interrupts
- *serialRegisters[uart][SERIALB] |= (1 << serialBits[uart][SERIALRXEN]) | (1 << serialBits[uart][SERIALTXEN]); // Enable Receiver/Transmitter
- }
-
- void serialClose(uint8_t uart) {
- if (uart >= UART_COUNT)
- return;
-
- uint8_t sreg = SREG;
- sei();
- while (!serialTxBufferEmpty(uart));
- while (*serialRegisters[uart][SERIALB] & (1 << serialBits[uart][SERIALUDRIE])); // Wait while Transmit Interrupt is on
- cli();
- *serialRegisters[uart][SERIALB] = 0;
- *serialRegisters[uart][SERIALC] = 0;
- SREG = sreg;
- }
-
- #ifdef FLOWCONTROL
- void setFlow(uint8_t uart, uint8_t on) {
- if (uart >= UART_COUNT)
- return;
-
- if (flow[uart] != on) {
- if (on == 1) {
- // Send XON
- while (sendThisNext[uart] != 0);
- sendThisNext[uart] = XON;
- flow[uart] = 1;
- if (shouldStartTransmission[uart]) {
- shouldStartTransmission[uart] = 0;
- *serialRegisters[uart][SERIALB] |= (1 << serialBits[uart][SERIALUDRIE]);
- *serialRegisters[uart][SERIALA] |= (1 << serialBits[uart][SERIALUDRE]); // Trigger Interrupt
- }
- } else {
- // Send XOFF
- sendThisNext[uart] = XOFF;
- flow[uart] = 0;
- if (shouldStartTransmission[uart]) {
- shouldStartTransmission[uart] = 0;
- *serialRegisters[uart][SERIALB] |= (1 << serialBits[uart][SERIALUDRIE]);
- *serialRegisters[uart][SERIALA] |= (1 << serialBits[uart][SERIALUDRE]); // Trigger Interrupt
- }
- }
- // Wait till it's transmitted
- while (*serialRegisters[uart][SERIALB] & (1 << serialBits[uart][SERIALUDRIE]));
- }
- }
- #endif
-
- // ---------------------
- // | Reception |
- // ---------------------
-
- uint8_t serialHasChar(uint8_t uart) {
- if (uart >= UART_COUNT)
- return 0;
-
- if (rxRead[uart] != rxWrite[uart]) { // True if char available
- return 1;
- } else {
- return 0;
- }
- }
-
- uint8_t serialGetBlocking(uint8_t uart) {
- if (uart >= UART_COUNT)
- return 0;
-
- while(!serialHasChar(uart));
- return serialGet(uart);
- }
-
- uint8_t serialGet(uint8_t uart) {
- if (uart >= UART_COUNT)
- return 0;
-
- uint8_t c;
-
- #ifdef FLOWCONTROL
- rxBufferElements[uart]--;
- if ((flow[uart] == 0) && (rxBufferElements[uart] <= FLOWMARK)) {
- while (sendThisNext[uart] != 0);
- sendThisNext[uart] = XON;
- flow[uart] = 1;
- if (shouldStartTransmission[uart]) {
- shouldStartTransmission[uart] = 0;
- *serialRegisters[uart][SERIALB] |= (1 << serialBits[uart][SERIALUDRIE]); // Enable Interrupt
- *serialRegisters[uart][SERIALA] |= (1 << serialBits[uart][SERIALUDRE]); // Trigger Interrupt
- }
- }
- #endif
-
- if (rxRead[uart] != rxWrite[uart]) {
- c = rxBuffer[uart][rxRead[uart]];
- rxBuffer[uart][rxRead[uart]] = 0;
- if (rxRead[uart] < (RX_BUFFER_SIZE - 1)) {
- rxRead[uart]++;
- } else {
- rxRead[uart] = 0;
- }
- return c;
- } else {
- return 0;
- }
- }
-
- uint8_t serialRxBufferFull(uint8_t uart) {
- if (uart >= UART_COUNT)
- return 0;
-
- return (((rxWrite[uart] + 1) == rxRead[uart]) || ((rxRead[uart] == 0) && ((rxWrite[uart] + 1) == RX_BUFFER_SIZE)));
- }
-
- uint8_t serialRxBufferEmpty(uint8_t uart) {
- if (uart >= UART_COUNT)
- return 0;
-
- if (rxRead[uart] != rxWrite[uart]) {
- return 0;
- } else {
- return 1;
- }
- }
-
- // ----------------------
- // | Transmission |
- // ----------------------
-
- void serialWrite(uint8_t uart, uint8_t data) {
- if (uart >= UART_COUNT)
- return;
-
- #ifdef SERIALINJECTCR
- if (data == '\n') {
- serialWrite(uart, '\r');
- }
- #endif
- while (serialTxBufferFull(uart));
-
- txBuffer[uart][txWrite[uart]] = data;
- if (txWrite[uart] < (TX_BUFFER_SIZE - 1)) {
- txWrite[uart]++;
- } else {
- txWrite[uart] = 0;
- }
- if (shouldStartTransmission[uart]) {
- shouldStartTransmission[uart] = 0;
- *serialRegisters[uart][SERIALB] |= (1 << serialBits[uart][SERIALUDRIE]); // Enable Interrupt
- *serialRegisters[uart][SERIALA] |= (1 << serialBits[uart][SERIALUDRE]); // Trigger Interrupt
- }
- }
-
- void serialWriteString(uint8_t uart, const char *data) {
- if (uart >= UART_COUNT)
- return;
-
- if (data == 0) {
- serialWriteString(uart, "NULL");
- } else {
- while (*data != '\0') {
- serialWrite(uart, *data++);
- }
- }
- }
-
- void serialWriteHex(uint8_t uart, uint8_t value) {
- char buff[3] = { 0, 0, '\0' };
-
- if (value >= 16) {
- buff[0] = value / 16;
- value = value % 16;
- }
- buff[1] = value;
-
- if ((buff[0] >= 0) && (buff[0] <= 9)) {
- buff[0] += '0';
- } else {
- buff[0] -= 10;
- buff[0] += 'A';
- }
-
- if ((buff[1] >= 0) && (buff[1] <= 9)) {
- buff[1] += '0';
- } else {
- buff[1] -= 10;
- buff[1] += 'A';
- }
-
- serialWriteString(uart, buff);
- }
-
- void serialWriteUnsigned8(uint8_t uart, uint8_t value) {
- char buff[4] = { '0', '0', '0', '\0' };
-
- uint8_t pos = sizeof(buff) - 2;
- while (value > 0) {
- buff[pos--] = '0' + (value % 10);
- value /= 10;
- }
-
- uint8_t start = 0;
- while ((start < (sizeof(buff) - 2)) && (buff[start] == '0')) {
- start++;
- }
-
- serialWriteString(uart, buff + start);
- }
-
- void serialWriteUnsigned16(uint8_t uart, uint16_t value) {
- char buff[6] = { '0', '0', '0', '0', '0', '\0' };
-
- uint8_t pos = sizeof(buff) - 2;
- while (value > 0) {
- buff[pos--] = '0' + (value % 10);
- value /= 10;
- }
-
- uint8_t start = 0;
- while ((start < (sizeof(buff) - 2)) && (buff[start] == '0')) {
- start++;
- }
-
- serialWriteString(uart, buff + start);
- }
-
- void serialWriteUnsigned32(uint8_t uart, uint32_t value) {
- char buff[11] = { '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '\0' };
-
- uint8_t pos = sizeof(buff) - 2;
- while (value > 0) {
- buff[pos--] = '0' + (value % 10);
- value /= 10;
- }
-
- uint8_t start = 0;
- while ((start < (sizeof(buff) - 2)) && (buff[start] == '0')) {
- start++;
- }
-
- serialWriteString(uart, buff + start);
- }
-
- void serialWriteUnsigned64(uint8_t uart, uint64_t value) {
- char buff[21] = { '0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
- '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '\0' };
-
- uint8_t pos = sizeof(buff) - 2;
- while (value > 0) {
- buff[pos--] = '0' + (value % 10);
- value /= 10;
- }
-
- uint8_t start = 0;
- while ((start < (sizeof(buff) - 2)) && (buff[start] == '0')) {
- start++;
- }
-
- serialWriteString(uart, buff + start);
- }
-
- uint8_t serialTxBufferFull(uint8_t uart) {
- if (uart >= UART_COUNT)
- return 0;
-
- return (((txWrite[uart] + 1) == txRead[uart]) || ((txRead[uart] == 0) && ((txWrite[uart] + 1) == TX_BUFFER_SIZE)));
- }
-
- uint8_t serialTxBufferEmpty(uint8_t uart) {
- if (uart >= UART_COUNT)
- return 0;
-
- if (txRead[uart] != txWrite[uart]) {
- return 0;
- } else {
- return 1;
- }
- }
-
- void serialReceiveInterrupt(uint8_t uart) {
- rxBuffer[uart][rxWrite[uart]] = *serialRegisters[uart][SERIALDATA];
- if (rxWrite[uart] < (RX_BUFFER_SIZE - 1)) {
- rxWrite[uart]++;
- } else {
- rxWrite[uart] = 0;
- }
-
- #ifdef FLOWCONTROL
- rxBufferElements[uart]++;
- if ((flow[uart] == 1) && (rxBufferElements[uart] >= (RX_BUFFER_SIZE - FLOWMARK))) {
- sendThisNext[uart] = XOFF;
- flow[uart] = 0;
- if (shouldStartTransmission[uart]) {
- shouldStartTransmission[uart] = 0;
- *serialRegisters[uart][SERIALB] |= (1 << serialBits[uart][SERIALUDRIE]); // Enable Interrupt
- *serialRegisters[uart][SERIALA] |= (1 << serialBits[uart][SERIALUDRE]); // Trigger Interrupt
- }
- }
- #endif
- }
-
- void serialTransmitInterrupt(uint8_t uart) {
- #ifdef FLOWCONTROL
- if (sendThisNext[uart]) {
- *serialRegisters[uart][SERIALDATA] = sendThisNext[uart];
- sendThisNext[uart] = 0;
- } else {
- #endif
- if (txRead[uart] != txWrite[uart]) {
- *serialRegisters[uart][SERIALDATA] = txBuffer[uart][txRead[uart]];
- if (txRead[uart] < (TX_BUFFER_SIZE -1)) {
- txRead[uart]++;
- } else {
- txRead[uart] = 0;
- }
- } else {
- shouldStartTransmission[uart] = 1;
- *serialRegisters[uart][SERIALB] &= ~(1 << serialBits[uart][SERIALUDRIE]); // Disable Interrupt
- }
- #ifdef FLOWCONTROL
- }
- #endif
- }
-
- ISR(SERIALRECIEVEINTERRUPT) { // Receive complete
- serialReceiveInterrupt(0);
- }
-
- ISR(SERIALTRANSMITINTERRUPT) { // Data register empty
- serialTransmitInterrupt(0);
- }
-
- #if UART_COUNT > 1
- ISR(SERIALRECIEVEINTERRUPT1) { // Receive complete
- serialReceiveInterrupt(1);
- }
-
- ISR(SERIALTRANSMITINTERRUPT1) { // Data register empty
- serialTransmitInterrupt(1);
- }
- #endif
-
- #if UART_COUNT > 2
- ISR(SERIALRECIEVEINTERRUPT2) { // Receive complete
- serialReceiveInterrupt(2);
- }
-
- ISR(SERIALTRANSMITINTERRUPT2) { // Data register empty
- serialTransmitInterrupt(2);
- }
- #endif
-
- #if UART_COUNT > 3
- ISR(SERIALRECIEVEINTERRUPT3) { // Receive complete
- serialReceiveInterrupt(3);
- }
-
- ISR(SERIALTRANSMITINTERRUPT3) { // Data register empty
- serialTransmitInterrupt(3);
- }
- #endif
- /** @} */
|