Advertisement
Guest User

Untitled

a guest
Apr 18th, 2020
354
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 8.22 KB | None | 0 0
  1. /*
  2.   TinySoftwareSerial.cpp - Hardware serial library for Wiring
  3.   Copyright (c) 2006 Nicholas Zambetti.  All right reserved.
  4.  
  5.   This library is free software; you can redistribute it and/or
  6.   modify it under the terms of the GNU Lesser General Public
  7.   License as published by the Free Software Foundation; either
  8.   version 2.1 of the License, or (at your option) any later version.
  9.  
  10.   This library is distributed in the hope that it will be useful,
  11.   but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13.   Lesser General Public License for more details.
  14.  
  15.   You should have received a copy of the GNU Lesser General Public
  16.   License along with this library; if not, write to the Free Software
  17.   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  18.  
  19.   Modified 23 November 2006 by David A. Mellis
  20.   Modified 28 September 2010 by Mark Sproul
  21. */
  22.  
  23. #include <stdlib.h>
  24. #include <stdio.h>
  25. #include <string.h>
  26. #include <inttypes.h>
  27.  
  28. #include "Arduino.h"
  29. #include "wiring_private.h"
  30.  
  31. #if USE_SOFTWARE_SERIAL
  32. #include "TinySoftwareSerial.h"
  33.  
  34. // Define constants and variables for buffering incoming serial data.  We're
  35. // using a ring buffer (I think), in which rx_buffer_head is the index of the
  36. // location to which to write the next incoming character and rx_buffer_tail
  37. // is the index of the location from which to read.
  38.  
  39. extern "C"{
  40. uint8_t getch() {
  41.   uint8_t ch = 0;
  42.     __asm__ __volatile__ (
  43.     "   rcall uartDelay\n"          // Get to 0.25 of start bit (our baud is too fast, so give room to correct)
  44.     "1: rcall uartDelay\n"              // Wait 0.25 bit period
  45.     "   rcall uartDelay\n"              // Wait 0.25 bit period
  46.     "   rcall uartDelay\n"              // Wait 0.25 bit period
  47.     "   rcall uartDelay\n"              // Wait 0.25 bit period
  48.     "   clc\n"
  49.     "   in r23,%[pin]\n"
  50.     "   and r23, %[mask]\n"
  51.     "   breq 2f\n"
  52.     "   sec\n"
  53.     "2: ror   %0\n"
  54.     "   dec   %[count]\n"
  55.     "   breq  3f\n"
  56.     "   rjmp  1b\n"
  57.     "3: rcall uartDelay\n"              // Wait 0.25 bit period
  58.     "   rcall uartDelay\n"              // Wait 0.25 bit period
  59.     :
  60.       "=r" (ch)
  61.     :
  62.       "0" ((uint8_t)0),
  63.       [count] "r" ((uint8_t)8),
  64.       [pin] "I" (_SFR_IO_ADDR(ANALOG_COMP_PIN)),
  65.       [mask] "r" (Serial._rxmask)
  66.     :
  67.       "r23",
  68.       "r24",
  69.       "r25"
  70.     );
  71.   return ch;
  72. }
  73.  
  74. void uartDelay() {
  75.   __asm__ __volatile__ (
  76.     "mov r25,%[count]\n"
  77.     "1:dec r25\n"
  78.       "brne 1b\n"
  79.       "ret\n"
  80.     ::[count] "r" ((uint8_t)Serial._delayCount)
  81.   );
  82. }
  83.  
  84. #if !defined (ANALOG_COMP_vect) && defined(ANA_COMP_vect)
  85. //rename the vector so we can use it.
  86.   #define ANALOG_COMP_vect ANA_COMP_vect
  87. #elif !defined (ANALOG_COMP_vect)
  88.   #error Tiny Software Serial cannot find the Analog comparator interrupt vector!
  89. #endif
  90. ISR(ANALOG_COMP_vect){
  91.   char ch = getch(); //read in the character softwarily - I know its not a word, but it sounded cool, so you know what: #define softwarily 1
  92.   store_char(ch, Serial._rx_buffer);
  93.   sbi(ACSR,ACI); //clear the flag.
  94. }
  95.  
  96. }
  97. soft_ring_buffer rx_buffer  =  { { 0 }, 0, 0 };
  98.  
  99. // Constructor ////////////////////////////////////////////////////////////////
  100.  
  101. TinySoftwareSerial::TinySoftwareSerial(soft_ring_buffer *rx_buffer, uint8_t txBit, uint8_t rxBit)
  102. {
  103.   _rx_buffer = rx_buffer;
  104.  
  105.   _rxmask = _BV(rxBit);
  106.   _txmask = _BV(txBit);
  107.   _txunmask = ~_txmask;
  108.  
  109.   _delayCount = 0;
  110. }
  111.  
  112. // Public Methods //////////////////////////////////////////////////////////////
  113.  
  114. void TinySoftwareSerial::begin(long baud)
  115. {
  116.   long tempDelay = (((F_CPU/baud)-39)/12);
  117.   if ((tempDelay > 255) || (tempDelay <= 0)){
  118.   end(); //Cannot start as it would screw up uartDelay().
  119.   }
  120.   _delayCount = (uint8_t)tempDelay;
  121.   cbi(ACSR,ACIE);  //turn off the comparator interrupt to allow change of ACD
  122. #ifdef ACBG
  123.   sbi(ACSR,ACBG); //enable the internal bandgap reference - used instead of AIN0 to allow it to be used for TX.
  124. #endif
  125.   cbi(ACSR,ACD);  //turn on the comparator for RX
  126. #ifdef ACIC
  127.   cbi(ACSR,ACIC);  //prevent the comparator from affecting timer1 - just to be safe.
  128. #endif
  129.   sbi(ACSR,ACIS1);  //interrupt on rising edge (this means RX has gone from Mark state to Start bit state).
  130.   sbi(ACSR,ACIS0);
  131.   //Setup the pins in case someone messed with them.
  132.   ANALOG_COMP_DDR &= ~_rxmask; //set RX to an input
  133.   ANALOG_COMP_PORT |= _rxmask; //enable pullup on RX pin - to prevent accidental interrupt triggers.
  134.   ANALOG_COMP_DDR |= _txmask; //set TX to an output.
  135.   ANALOG_COMP_PORT |= _txmask; //set TX pin high
  136.   sbi(ACSR,ACI); //clear the flag.
  137.   sbi(ACSR,ACIE);  //turn on the comparator interrupt to allow us to use it for RX
  138. #ifdef ACSRB
  139.   ACSRB = 0; //Use AIN0 as +, AIN1 as -, no hysteresis - just like ones without this register.
  140. #endif
  141. }
  142.  
  143. void TinySoftwareSerial::end()
  144. {
  145.   sbi(ACSR,ACI); //clear the flag.
  146.   cbi(ACSR,ACIE);  //turn off the comparator interrupt to allow change of ACD, and because it needs to be turned off now too!
  147. #ifdef ACBG
  148.   cbi(ACSR,ACBG); //disable the bandgap reference
  149. #endif
  150.   sbi(ACSR,ACD);  //turn off the comparator to save power
  151.   _delayCount = 0;
  152.   _rx_buffer->head = _rx_buffer->tail;
  153. }
  154.  
  155. int TinySoftwareSerial::available(void)
  156. {
  157.   return (unsigned int)(SERIAL_BUFFER_SIZE + _rx_buffer->head - _rx_buffer->tail) % SERIAL_BUFFER_SIZE;
  158. }
  159.  
  160. void store_char(unsigned char c, soft_ring_buffer *buffer)
  161. {
  162.   int i = (unsigned int)(buffer->head + 1) % SERIAL_BUFFER_SIZE;
  163.  
  164.   // if we should be storing the received character into the location
  165.   // just before the tail (meaning that the head would advance to the
  166.   // current location of the tail), we're about to overflow the buffer
  167.   // and so we don't write the character or advance the head.
  168.   if (i != buffer->tail) {
  169.     buffer->buffer[buffer->head] = c;
  170.     buffer->head = i;
  171.   }
  172. }
  173.  
  174. int TinySoftwareSerial::peek(void)
  175. {
  176.   if (_rx_buffer->head == _rx_buffer->tail) {
  177.     return -1;
  178.   } else {
  179.     return _rx_buffer->buffer[_rx_buffer->tail];
  180.   }
  181. }
  182.  
  183. int TinySoftwareSerial::read(void)
  184. {
  185.   // if the head isn't ahead of the tail, we don't have any characters
  186.   if (_rx_buffer->head == _rx_buffer->tail) {
  187.     return -1;
  188.   } else {
  189.     unsigned char c = _rx_buffer->buffer[_rx_buffer->tail];
  190.     _rx_buffer->tail = (unsigned int)(_rx_buffer->tail + 1) % SERIAL_BUFFER_SIZE;
  191.     return c;
  192.   }
  193. }
  194.  
  195. size_t TinySoftwareSerial::write(uint8_t ch)
  196. {
  197.   uint8_t oldSREG = SREG;
  198.   cli(); //Prevent interrupts from breaking the transmission. Note: TinySoftwareSerial is half duplex.
  199.   //it can either receive or send, not both (because receiving requires an interrupt and would stall transmission
  200.   __asm__ __volatile__ (
  201.     "   com %[ch]\n" // ones complement, carry set
  202.     "   sec\n"
  203.     "1: brcc 2f\n"
  204.   "   in r23,%[uartPort] \n"
  205.     "   and r23,%[uartUnmask]\n"
  206.   "   out %[uartPort],r23 \n"
  207.     "   rjmp 3f\n"
  208.   "2: in r23,%[uartPort] \n"
  209.     "   or r23,%[uartMask]\n"
  210.   "   out %[uartPort],r23 \n"
  211.     "   nop\n"
  212.     "3: rcall uartDelay\n"
  213.     "   rcall uartDelay\n"
  214.     "   rcall uartDelay\n"
  215.     "   rcall uartDelay\n"
  216.     "   lsr %[ch]\n"
  217.     "   dec %[count]\n"
  218.     "   brne 1b\n"
  219.     :
  220.     :
  221.       [ch] "r" (ch),
  222.     [count] "r" ((uint8_t)10),
  223.       [uartPort] "I" (_SFR_IO_ADDR(ANALOG_COMP_PORT)),
  224.       [uartMask] "r" (_txmask),
  225.       [uartUnmask] "r" (_txunmask)
  226.   : "r23",
  227.     "r24",
  228.     "r25"
  229.   );
  230.   SREG = oldSREG;
  231.   return 1;
  232. }
  233.  
  234. void TinySoftwareSerial::flush()
  235. {
  236.  
  237. }
  238.  
  239. TinySoftwareSerial::operator bool() {
  240.   return true;
  241. }
  242.  
  243. // Preinstantiate Objects //////////////////////////////////////////////////////
  244. #ifndef ANALOG_COMP_DDR
  245. #error Please define ANALOG_COMP_DDR in the pins_arduino.h file!
  246. #endif
  247.  
  248. #ifndef ANALOG_COMP_PORT
  249. #error Please define ANALOG_COMP_PORT in the pins_arduino.h file!
  250. #endif
  251.  
  252. #ifndef ANALOG_COMP_PIN
  253. #error Please define ANALOG_COMP_PIN in the pins_arduino.h file!
  254. #endif
  255.  
  256. #ifndef ANALOG_COMP_AIN0_BIT
  257. #error Please define ANALOG_COMP_AIN0_BIT in the pins_arduino.h file!
  258. #endif
  259.  
  260. #ifndef ANALOG_COMP_AIN1_BIT
  261. #error Please define ANALOG_COMP_AIN1_BIT in the pins_arduino.h file!
  262. #endif
  263.  
  264. TinySoftwareSerial Serial(&rx_buffer, ANALOG_COMP_AIN0_BIT, ANALOG_COMP_AIN1_BIT);
  265.  
  266. #endif // whole file
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement