Skip to content

Commit 6ca3dea

Browse files
sbrynenfacchinm
authored andcommitted
[SoftwareSerial] add half-duplex operation
Squash and rebase of arduino/Arduino#3053
1 parent fb7c2cc commit 6ca3dea

File tree

3 files changed

+65
-24
lines changed

3 files changed

+65
-24
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
= SoftwareSerial Library for Arduino (formerly NewSoftSerial) =
2+
3+
The SoftwareSerial library has been developed to allow serial communication (TX and/or RX) on other digital pins of the Arduino and other Atmel chips, using software to replicate the functionality (hence the name "SoftwareSerial"). It is possible to have multiple software serial ports with speeds up to 115200 bps. A parameter enables inverted signaling for devices which require that protocol.
4+
5+
For more information about this library please visit us at
6+
http://www.arduino.cc/en/Reference/SoftwareSerial
7+
8+
== Written by ==
9+
10+
Mikal Hart; with improvements from: ladyada, Paul Stoffregen, Garrett Mace, Brett Hagman and Scott Brynen.
11+
12+
== License ==
13+
14+
This library is free software; you can redistribute it and/or
15+
modify it under the terms of the GNU Lesser General Public
16+
License as published by the Free Software Foundation; either
17+
version 2.1 of the License, or (at your option) any later version.
18+
19+
This library is distributed in the hope that it will be useful,
20+
but WITHOUT ANY WARRANTY; without even the implied warranty of
21+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22+
Lesser General Public License for more details.
23+
24+
You should have received a copy of the GNU Lesser General Public
25+
License along with this library; if not, write to the Free Software
26+
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
27+

libraries/SoftwareSerial/src/SoftwareSerial.cpp

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
/*
2-
SoftwareSerial.cpp (formerly NewSoftSerial.cpp) -
2+
SoftwareSerial.cpp (formerly NewSoftSerial.cpp) -
33
Multi-instance software serial library for Arduino/Wiring
44
-- Interrupt-driven receive and other improvements by ladyada
55
(http://ladyada.net)
66
-- Tuning, circular buffer, derivation from class Print/Stream,
77
multi-instance support, porting to 8MHz processors,
8-
various optimizations, PROGMEM delay tables, inverse logic and
8+
various optimizations, PROGMEM delay tables, inverse logic and
99
direct port writing by Mikal Hart (http://www.arduiniana.org)
1010
-- Pin change interrupt macros by Paul Stoffregen (http://www.pjrc.com)
1111
-- 20MHz processor support by Garrett Mace (http://www.macetech.com)
1212
-- ATmega1280/2560 support by Brett Hagman (http://www.roguerobotics.com/)
13+
-- Transmit or Receive Only by Scott Brynen (http://github.com/sbrynen)
1314
1415
This library is free software; you can redistribute it and/or
1516
modify it under the terms of the GNU Lesser General Public
@@ -35,6 +36,7 @@ The latest version of this library can always be found at
3536
#define _DEBUG 0
3637
#define _DEBUG_PIN1 11
3738
#define _DEBUG_PIN2 13
39+
3840
//
3941
// Includes
4042
//
@@ -48,7 +50,7 @@ The latest version of this library can always be found at
4850
// Statics
4951
//
5052
SoftwareSerial *SoftwareSerial::active_object = 0;
51-
uint8_t SoftwareSerial::_receive_buffer[_SS_MAX_RX_BUFF];
53+
uint8_t SoftwareSerial::_receive_buffer[_SS_MAX_RX_BUFF];
5254
volatile uint8_t SoftwareSerial::_receive_buffer_tail = 0;
5355
volatile uint8_t SoftwareSerial::_receive_buffer_head = 0;
5456

@@ -78,15 +80,15 @@ inline void DebugPulse(uint8_t, uint8_t) {}
7880
//
7981

8082
/* static */
81-
inline void SoftwareSerial::tunedDelay(uint16_t delay) {
83+
inline void SoftwareSerial::tunedDelay(uint16_t delay) {
8284
_delay_loop_2(delay);
8385
}
8486

8587
// This function sets the current object as the "listening"
8688
// one and returns true if it replaces another
8789
bool SoftwareSerial::listen()
8890
{
89-
if (!_rx_delay_stopbit)
91+
if ((_receivePin == SOFTWARESERIAL_UNUSED) || !_rx_delay_stopbit)
9092
return false;
9193

9294
if (active_object != this)
@@ -108,7 +110,7 @@ bool SoftwareSerial::listen()
108110
// Stop listening. Returns true if we were actually listening.
109111
bool SoftwareSerial::stopListening()
110112
{
111-
if (active_object == this)
113+
if ((_receivePin != SOFTWARESERIAL_UNUSED) && (active_object == this))
112114
{
113115
setRxIntMsk(false);
114116
active_object = NULL;
@@ -254,6 +256,7 @@ SoftwareSerial::SoftwareSerial(uint8_t receivePin, uint8_t transmitPin, bool inv
254256
_buffer_overflow(false),
255257
_inverse_logic(inverse_logic)
256258
{
259+
// passing SOFTWARESERIAL_UNUSED for either the TX or RX pin makes the object RX or TX only
257260
setTX(transmitPin);
258261
setRX(receivePin);
259262
}
@@ -272,22 +275,27 @@ void SoftwareSerial::setTX(uint8_t tx)
272275
// the pin would be output low for a short while before switching to
273276
// output high. Now, it is input with pullup for a short while, which
274277
// is fine. With inverse logic, either order is fine.
275-
digitalWrite(tx, _inverse_logic ? LOW : HIGH);
276-
pinMode(tx, OUTPUT);
277-
_transmitBitMask = digitalPinToBitMask(tx);
278-
uint8_t port = digitalPinToPort(tx);
279-
_transmitPortRegister = portOutputRegister(port);
278+
_transmitPin = tx;
279+
if (tx != SOFTWARESERIAL_UNUSED) {
280+
digitalWrite(tx, _inverse_logic ? LOW : HIGH);
281+
pinMode(tx, OUTPUT);
282+
_transmitBitMask = digitalPinToBitMask(tx);
283+
uint8_t port = digitalPinToPort(tx);
284+
_transmitPortRegister = portOutputRegister(port);
285+
}
280286
}
281287

282288
void SoftwareSerial::setRX(uint8_t rx)
283289
{
284-
pinMode(rx, INPUT);
285-
if (!_inverse_logic)
286-
digitalWrite(rx, HIGH); // pullup for normal logic!
287290
_receivePin = rx;
288-
_receiveBitMask = digitalPinToBitMask(rx);
289-
uint8_t port = digitalPinToPort(rx);
290-
_receivePortRegister = portInputRegister(port);
291+
if (rx != SOFTWARESERIAL_UNUSED) {
292+
pinMode(rx, INPUT);
293+
if (!_inverse_logic)
294+
digitalWrite(rx, HIGH); // pullup for normal logic!
295+
_receiveBitMask = digitalPinToBitMask(rx);
296+
uint8_t port = digitalPinToPort(rx);
297+
_receivePortRegister = portInputRegister(port);
298+
}
291299
}
292300

293301
uint16_t SoftwareSerial::subtract_cap(uint16_t num, uint16_t sub) {
@@ -316,7 +324,7 @@ void SoftwareSerial::begin(long speed)
316324
_tx_delay = subtract_cap(bit_delay, 15 / 4);
317325

318326
// Only setup rx when we have a valid PCINT for this pin
319-
if (digitalPinToPCICR(_receivePin)) {
327+
if ((_receivePin != SOFTWARESERIAL_UNUSED) && digitalPinToPCICR(_receivePin)) {
320328
#if GCC_VERSION > 40800
321329
// Timings counted from gcc 4.8.2 output. This works up to 115200 on
322330
// 16Mhz and 57600 on 8Mhz.
@@ -376,10 +384,10 @@ void SoftwareSerial::begin(long speed)
376384

377385
void SoftwareSerial::setRxIntMsk(bool enable)
378386
{
379-
if (enable)
380-
*_pcint_maskreg |= _pcint_maskvalue;
381-
else
382-
*_pcint_maskreg &= ~_pcint_maskvalue;
387+
if (enable)
388+
*_pcint_maskreg |= _pcint_maskvalue;
389+
else
390+
*_pcint_maskreg &= ~_pcint_maskvalue;
383391
}
384392

385393
void SoftwareSerial::end()
@@ -414,7 +422,7 @@ int SoftwareSerial::available()
414422

415423
size_t SoftwareSerial::write(uint8_t b)
416424
{
417-
if (_tx_delay == 0) {
425+
if ((_transmitPin == SOFTWARESERIAL_UNUSED) || (_tx_delay == 0)) {
418426
setWriteError();
419427
return 0;
420428
}

libraries/SoftwareSerial/src/SoftwareSerial.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ Multi-instance software serial library for Arduino/Wiring
1010
-- Pin change interrupt macros by Paul Stoffregen (http://www.pjrc.com)
1111
-- 20MHz processor support by Garrett Mace (http://www.macetech.com)
1212
-- ATmega1280/2560 support by Brett Hagman (http://www.roguerobotics.com/)
13+
-- Transmit or Receive Only by Scott Brynen (http://github.com/sbrynen)
1314
1415
This library is free software; you can redistribute it and/or
1516
modify it under the terms of the GNU Lesser General Public
@@ -43,6 +44,10 @@ The latest version of this library can always be found at
4344
#define _SS_MAX_RX_BUFF 64 // RX buffer size
4445
#endif
4546

47+
#ifndef SOFTWARESERIAL_UNUSED
48+
#define SOFTWARESERIAL_UNUSED -1 // flag for unused TX or RX pins
49+
#endif
50+
4651
#ifndef GCC_VERSION
4752
#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
4853
#endif
@@ -54,6 +59,7 @@ class SoftwareSerial : public Stream
5459
uint8_t _receivePin;
5560
uint8_t _receiveBitMask;
5661
volatile uint8_t *_receivePortRegister;
62+
uint8_t _transmitPin;
5763
uint8_t _transmitBitMask;
5864
volatile uint8_t *_transmitPortRegister;
5965
volatile uint8_t *_pcint_maskreg;
@@ -94,7 +100,7 @@ class SoftwareSerial : public Stream
94100
void begin(long speed);
95101
bool listen();
96102
void end();
97-
bool isListening() { return this == active_object; }
103+
bool isListening() { return (_receivePin != SOFTWARESERIAL_UNUSED) && (this == active_object); }
98104
bool stopListening();
99105
bool overflow() { bool ret = _buffer_overflow; if (ret) _buffer_overflow = false; return ret; }
100106
int peek();

0 commit comments

Comments
 (0)