Skip to content

Commit

Permalink
Libraries
Browse files Browse the repository at this point in the history
  • Loading branch information
JamieBlakey committed Jan 26, 2018
1 parent ccbaa29 commit e95045a
Show file tree
Hide file tree
Showing 38 changed files with 3,764 additions and 0 deletions.
350 changes: 350 additions & 0 deletions Libraries/Arduino/AST_AltSoftSerial/AltSoftSerial.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,350 @@
/* An Alternative Software Serial Library
* http://www.pjrc.com/teensy/td_libs_AltSoftSerial.html
* Copyright (c) 2014 PJRC.COM, LLC, Paul Stoffregen, paul@pjrc.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

// Revisions are now tracked on GitHub
// https://github.com/PaulStoffregen/AltSoftSerial
//
// Version 1.2: Support Teensy 3.x
//
// Version 1.1: Improve performance in receiver code
//
// Version 1.0: Initial Release


#include "AltSoftSerial.h"
#include "config/AltSoftSerial_Boards.h"
#include "config/AltSoftSerial_Timers.h"

/****************************************/
/** Initialization **/
/****************************************/

static uint16_t ticks_per_bit=0;
bool AltSoftSerial::timing_error=false;

static uint8_t rx_state;
static uint8_t rx_byte;
static uint8_t rx_bit = 0;
static uint16_t rx_target;
static uint16_t rx_stop_ticks=0;
static volatile uint8_t rx_buffer_head;
static volatile uint8_t rx_buffer_tail;
#define RX_BUFFER_SIZE 80
static volatile uint8_t rx_buffer[RX_BUFFER_SIZE];

static volatile uint8_t tx_state=0;
static uint8_t tx_byte;
static uint8_t tx_bit;
static volatile uint8_t tx_buffer_head;
static volatile uint8_t tx_buffer_tail;
#define TX_BUFFER_SIZE 68
static volatile uint8_t tx_buffer[TX_BUFFER_SIZE];


#ifndef INPUT_PULLUP
#define INPUT_PULLUP INPUT
#endif

#define MAX_COUNTS_PER_BIT 6241 // 65536 / 10.5

void AltSoftSerial::init(uint32_t cycles_per_bit)
{
//Serial.printf("cycles_per_bit = %d\n", cycles_per_bit);
if (cycles_per_bit < MAX_COUNTS_PER_BIT) {
CONFIG_TIMER_NOPRESCALE();
} else {
cycles_per_bit /= 8;
//Serial.printf("cycles_per_bit/8 = %d\n", cycles_per_bit);
if (cycles_per_bit < MAX_COUNTS_PER_BIT) {
CONFIG_TIMER_PRESCALE_8();
} else {
#if defined(CONFIG_TIMER_PRESCALE_256)
cycles_per_bit /= 32;
//Serial.printf("cycles_per_bit/256 = %d\n", cycles_per_bit);
if (cycles_per_bit < MAX_COUNTS_PER_BIT) {
CONFIG_TIMER_PRESCALE_256();
} else {
return; // baud rate too low for AltSoftSerial
}
#elif defined(CONFIG_TIMER_PRESCALE_128)
cycles_per_bit /= 16;
//Serial.printf("cycles_per_bit/128 = %d\n", cycles_per_bit);
if (cycles_per_bit < MAX_COUNTS_PER_BIT) {
CONFIG_TIMER_PRESCALE_128();
} else {
return; // baud rate too low for AltSoftSerial
}
#else
return; // baud rate too low for AltSoftSerial
#endif
}
}
ticks_per_bit = cycles_per_bit;
rx_stop_ticks = cycles_per_bit * 37 / 4;
pinMode(INPUT_CAPTURE_PIN, INPUT_PULLUP);
digitalWrite(OUTPUT_COMPARE_A_PIN, HIGH);
pinMode(OUTPUT_COMPARE_A_PIN, OUTPUT);
rx_state = 0;
rx_buffer_head = 0;
rx_buffer_tail = 0;
tx_state = 0;
tx_buffer_head = 0;
tx_buffer_tail = 0;
ENABLE_INT_INPUT_CAPTURE();
}

void AltSoftSerial::end(void)
{
DISABLE_INT_COMPARE_B();
DISABLE_INT_INPUT_CAPTURE();
flushInput();
flushOutput();
DISABLE_INT_COMPARE_A();
// TODO: restore timer to original settings?
}


/****************************************/
/** Transmission **/
/****************************************/

void AltSoftSerial::writeByte(uint8_t b)
{
uint8_t intr_state, head;

head = tx_buffer_head + 1;
if (head >= TX_BUFFER_SIZE) head = 0;
while (tx_buffer_tail == head) ; // wait until space in buffer
intr_state = SREG;
cli();
if (tx_state) {
tx_buffer[head] = b;
tx_buffer_head = head;
} else {
tx_state = 1;
tx_byte = b;
tx_bit = 0;
ENABLE_INT_COMPARE_A();
CONFIG_MATCH_CLEAR();
SET_COMPARE_A(GET_TIMER_COUNT() + 16);
}
SREG = intr_state;
}


ISR(COMPARE_A_INTERRUPT)
{
uint8_t state, byte, bit, head, tail;
uint16_t target;

state = tx_state;
byte = tx_byte;
target = GET_COMPARE_A();
while (state < 10) {
target += ticks_per_bit;
if (state < 9)
bit = byte & 1;
else
bit = 1; // stopbit
byte >>= 1;
state++;
if (bit != tx_bit) {
if (bit) {
CONFIG_MATCH_SET();
} else {
CONFIG_MATCH_CLEAR();
}
SET_COMPARE_A(target);
tx_bit = bit;
tx_byte = byte;
tx_state = state;
// TODO: how to detect timing_error?
return;
}
}
head = tx_buffer_head;
tail = tx_buffer_tail;
if (head == tail) {
if (state == 10) {
// Wait for final stop bit to finish
tx_state = 11;
SET_COMPARE_A(target + ticks_per_bit);
} else {
tx_state = 0;
CONFIG_MATCH_NORMAL();
DISABLE_INT_COMPARE_A();
}
} else {
if (++tail >= TX_BUFFER_SIZE) tail = 0;
tx_buffer_tail = tail;
tx_byte = tx_buffer[tail];
tx_bit = 0;
CONFIG_MATCH_CLEAR();
if (state == 10)
SET_COMPARE_A(target + ticks_per_bit);
else
SET_COMPARE_A(GET_TIMER_COUNT() + 16);
tx_state = 1;
// TODO: how to detect timing_error?
}
}

void AltSoftSerial::flushOutput(void)
{
while (tx_state) /* wait */ ;
}


/****************************************/
/** Reception **/
/****************************************/

ISR(CAPTURE_INTERRUPT)
{
uint8_t state, bit, head;
uint16_t capture, target;
uint16_t offset, offset_overflow;

capture = GET_INPUT_CAPTURE();
bit = rx_bit;
if (bit) {
CONFIG_CAPTURE_FALLING_EDGE();
rx_bit = 0;
} else {
CONFIG_CAPTURE_RISING_EDGE();
rx_bit = 0x80;
}
state = rx_state;
if (state == 0) {
if (!bit) {
uint16_t end = capture + rx_stop_ticks;
SET_COMPARE_B(end);
ENABLE_INT_COMPARE_B();
rx_target = capture + ticks_per_bit + ticks_per_bit/2;
rx_state = 1;
}
} else {
target = rx_target;
offset_overflow = 65535 - ticks_per_bit;
while (1) {
offset = capture - target;
if (offset > offset_overflow) break;
rx_byte = (rx_byte >> 1) | rx_bit;
target += ticks_per_bit;
state++;
if (state >= 9) {
DISABLE_INT_COMPARE_B();
head = rx_buffer_head + 1;
if (head >= RX_BUFFER_SIZE) head = 0;
if (head != rx_buffer_tail) {
rx_buffer[head] = rx_byte;
rx_buffer_head = head;
}
CONFIG_CAPTURE_FALLING_EDGE();
rx_bit = 0;
rx_state = 0;
return;
}
}
rx_target = target;
rx_state = state;
}
//if (GET_TIMER_COUNT() - capture > ticks_per_bit) AltSoftSerial::timing_error = true;
}

ISR(COMPARE_B_INTERRUPT)
{
uint8_t head, state, bit;

DISABLE_INT_COMPARE_B();
CONFIG_CAPTURE_FALLING_EDGE();
state = rx_state;
bit = rx_bit ^ 0x80;
while (state < 9) {
rx_byte = (rx_byte >> 1) | bit;
state++;
}
head = rx_buffer_head + 1;
if (head >= RX_BUFFER_SIZE) head = 0;
if (head != rx_buffer_tail) {
rx_buffer[head] = rx_byte;
rx_buffer_head = head;
}
rx_state = 0;
CONFIG_CAPTURE_FALLING_EDGE();
rx_bit = 0;
}



int AltSoftSerial::read(void)
{
uint8_t head, tail, out;

head = rx_buffer_head;
tail = rx_buffer_tail;
if (head == tail) return -1;
if (++tail >= RX_BUFFER_SIZE) tail = 0;
out = rx_buffer[tail];
rx_buffer_tail = tail;
return out;
}

int AltSoftSerial::peek(void)
{
uint8_t head, tail;

head = rx_buffer_head;
tail = rx_buffer_tail;
if (head == tail) return -1;
if (++tail >= RX_BUFFER_SIZE) tail = 0;
return rx_buffer[tail];
}

int AltSoftSerial::available(void)
{
uint8_t head, tail;

head = rx_buffer_head;
tail = rx_buffer_tail;
if (head >= tail) return head - tail;
return RX_BUFFER_SIZE + head - tail;
}

void AltSoftSerial::flushInput(void)
{
rx_buffer_head = rx_buffer_tail;
}


#ifdef ALTSS_USE_FTM0
void ftm0_isr(void)
{
uint32_t flags = FTM0_STATUS;
FTM0_STATUS = 0;
if (flags & (1<<0) && (FTM0_C0SC & 0x40)) altss_compare_b_interrupt();
if (flags & (1<<5)) altss_capture_interrupt();
if (flags & (1<<6) && (FTM0_C6SC & 0x40)) altss_compare_a_interrupt();
}
#endif

Loading

0 comments on commit e95045a

Please sign in to comment.