Paul's Compatibility API Wish List

229 views
Skip to first unread message

Paul Stoffregen

unread,
Nov 4, 2013, 9:55:29 AM11/4/13
to devel...@arduino.cc
Here's my current wish-list for APIs for improving compatibility, based
on actual libraries and applications I've ported over the last few years.

1: Interval Timer (interrupt): Several libraries commandeer hardware
timers. There are many use cases, but the most common is merely
configuring for the overflow interrupt to execute at a regular interval
(DmxSimple, VirtualWire, etc). Just solving this 1 case with a simple
API eliminates special code in several libraries.

2: Sampling & Non-blocking Analog: This conversation was started a
month ago, on Oct 6, 2013. It's a big project. I intend to work on it
early next year. I've seen several projects that directly hard-code
analog register access, because they need non-blocking access or low
jitter sampling.

3: Serial.ready(): Like Serial.available(), but for transmitting. I
believe this has been discussed many times and there's generally
consensus? Some applications need to avoid waiting, and currently have
to access hardware registers. LabView's support code is one notable
example.

4: Pinout specified by preprocessor symbols/macros: The existing pinout
lookup tables would be populated using those symbols/macros, so the
pinout is only updated/maintained in 1 place. Several libraries like
the USB Host Shield and GLCD hard-code pinouts for all known boards.
This API could let them easily transition to automatically acquiring the
pinout.

5: digitalWriteFast: We've had consensus on this since 2009, but #4 is
needed for the code to be maintainable. This can eliminate the need for
hard-coding I/O register access, since it compiles to the same code with
a const input. It doesn't solve the non-const case (see below for
that), but it does allow replacement of hard coded registers currently
in sketches and libraries, which is a good thing!

6: Improved pointer-based I/O (eg, better abstraction than AVR-specific
digitalPinToBitMask, portOutputRegister, portInputRegister,
portModeRegister). Many libraries already use these 4 macros, which
leads to hard-coded AVR register semantics (eg, assuming 8 bit types
doesn't work for Due). An improved inline function should provide an
opaque type for the lookup phase, which is then accepted by inline
functions to perform specific operations.

7: Free Memory: Last time this was discussed, as I recall the debate
was regarding the meaning of "free", whether it includes all free
memory, or the largest number that can succeed with malloc? I'm honestly
not sure which is the best way. One use case is in some of Adafruit's
libraries for larger graphical LCDs, which attempt to warn the user if
they're running dangerously low on memory. Either way could allow
architecture independent code, rather than hard-coding extern refs to C
library memory management variables.

8: Hardware Serial Names: Similar to LED_BUILTIN, defined names are
needed to identify the first physical serial port, and the first
"available" serial port (not used for uploading), if they exist.
Libraries that build on top of hardware serial (MIDI, XBee, etc) contain
hard coded or architecture specific #ifdefs, only to initialize a Stream
ref or pointer or otherwise configure which port they use. Simply
defining these names could allow those serial-only libraries to become
architecture independent.

John Plocher

unread,
Nov 4, 2013, 10:31:06 AM11/4/13
to devel...@arduino.cc


On Monday, 4 November 2013 06:55:29 UTC-8, paul wrote:
Here's my current wish-list for APIs for improving compatibility


Amen.

With this sort of support available in core, libraries have a better chance of actually being portable across variants and architectures - and working when they get there.

  -John
 

Angus Gratton

unread,
Nov 4, 2013, 4:30:05 PM11/4/13
to Paul Stoffregen, devel...@arduino.cc
On Mon, Nov 04, 2013 at 06:55:29AM -0800, Paul Stoffregen wrote:
> 4: Pinout specified by preprocessor symbols/macros: The existing
> pinout lookup tables would be populated using those symbols/macros, so
> the pinout is only updated/maintained in 1 place. Several libraries
> like the USB Host Shield and GLCD hard-code pinouts for all known
> boards. This API could let them easily transition to automatically
> acquiring the pinout.
>
> 5: digitalWriteFast: We've had consensus on this since 2009, but #4
> is needed for the code to be maintainable. This can eliminate the
> need for hard-coding I/O register access, since it compiles to the
> same code with a const input. It doesn't solve the non-const case
> (see below for that), but it does allow replacement of hard coded
> registers currently in sketches and libraries, which is a good
> thing!

Hi Paul & everyone,

FWIW at the beginning of the year I did a little bit of hacking on
cleanly moving the Arduino core to preprocessor lookup tables allowing
digitalWriteFast-like behaviour. I was working from ideas put forward
in 2011 but working past the need for dual-listing the pin mappings
(which was the stated reason for not merging it in 2011.)

I lazily sent a totally unsolicited pull request (ignoring the
contributor suggestions, sorry) and then got busy with other things
and didn't get back to it:

https://github.com/arduino/Arduino/pull/1285

The implementation is AVR & 1.0 specific but it might be of some
interest.

Some statistics, advantages & disadvantages are listed in the pull request.

I would be quite interested in working on this some more (bringing it
up to date for multi-platform 1.5 and any other necessary
improvements) if there is interest from the Arduino team.

- Angus

PS Belated apologies for not rebasing the commits into a cleaner
sequence before sending the PR. Just looked at it again today and was
dismayed!

Cristian Maglie

unread,
Nov 5, 2013, 6:55:21 AM11/5/13
to devel...@arduino.cc
In data lunedì 4 novembre 2013 15:55:29, Paul Stoffregen ha scritto:
> Here's my current wish-list for APIs for improving compatibility

Very good list! I can see a lot of discussion coming... :-)

but I think also that some of them may be solved quickly, so let's start with
the simplest ones (that probably have the bigger results/effort ratio), like:

> 8: Hardware Serial Names:

Do you already have a proposal for that?

C

Rob Tillaart

unread,
Nov 5, 2013, 1:02:38 PM11/5/13
to Cristian Maglie, Arduino Developers
> 8: Hardware Serial Names:

Do you already have a proposal for that?

1) an array would be nice.  Serial[n];
2) I would like to be able to do something like 

Serial  MyPC(0);   // now Serial0 is wrapped with the name MyPC
Serial GPS(3);     //  myGPS is connected to Serial3

Then I can name my Serial ports per sketch.

my 2 cents,
Rob





C

--
You received this message because you are subscribed to the Google Groups "Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to developers+...@arduino.cc.

Paul Stoffregen

unread,
Nov 6, 2013, 6:58:36 AM11/6/13
to devel...@arduino.cc
On 11/05/2013 03:55 AM, Cristian Maglie wrote:
>> 8: Hardware Serial Names:
> Do you already have a proposal for that?

Here's an initial proposal.


// These serial port names are intended to allow libraries and
architecture-neutral
// sketches to automatically default to the correct port name for a
particular type
// of use. For example, a GPS module would normally connect to
SERIAL_PORT_HARDWARE_OPEN,
// the first hardware serial port whose RX/TX pins are not dedicated to
another use.
//
// SERIAL_PORT_MONITOR Port which normally prints to the Arduino
Serial Monitor
//
// SERIAL_PORT_USBVIRTUAL Port which is USB virtual serial
//
// SERIAL_PORT_LINUXBRIDGE Port which connects to a Linux system via
Bridge library
//
// SERIAL_PORT_HARDWARE Hardware serial port, physical RX & TX pins.
//
// SERIAL_PORT_HARDWARE_OPEN Hardware serial ports which are open for
use. Their RX & TX
// pins are NOT connected to anything by default.

// Arduino Uno
#define SERIAL_PORT_MONITOR Serial
#define SERIAL_PORT_HARDWARE Serial

// Arduino Mega
#define SERIAL_PORT_MONITOR Serial
#define SERIAL_PORT_HARDWARE Serial
#define SERIAL_PORT_HARDWARE1 Serial1
#define SERIAL_PORT_HARDWARE2 Serial2
#define SERIAL_PORT_HARDWARE3 Serial3
#define SERIAL_PORT_HARDWARE_OPEN Serail1
#define SERIAL_PORT_HARDWARE_OPEN1 Serail2
#define SERIAL_PORT_HARDWARE_OPEN2 Serail3

// Arduino Leonardo
#define SERIAL_PORT_MONITOR Serial
#define SERIAL_PORT_USBVIRTUAL Serial
#define SERIAL_PORT_HARDWARE Serial1
#define SERIAL_PORT_HARDWARE_OPEN Serail1

// Arduino Yun
#define SERIAL_PORT_MONITOR Serial
#define SERIAL_PORT_USBVIRTUAL Serial
#define SERIAL_PORT_LINUXBRIDGE Serial1
#define SERIAL_PORT_HARDWARE Serial1

// Arduino Due (programming port)
#define SERIAL_PORT_MONITOR Serial
#define SERIAL_PORT_USBVIRTUAL SerialUSB
#define SERIAL_PORT_HARDWARE Serial
#define SERIAL_PORT_HARDWARE1 Serial1
#define SERIAL_PORT_HARDWARE2 Serial2
#define SERIAL_PORT_HARDWARE3 Serial3
#define SERIAL_PORT_HARDWARE_OPEN Serail1
#define SERIAL_PORT_HARDWARE_OPEN1 Serail2
#define SERIAL_PORT_HARDWARE_OPEN2 Serail3

// Arduino Due (native port)
#define SERIAL_PORT_MONITOR SerialUSB
#define SERIAL_PORT_USBVIRTUAL SerialUSB
#define SERIAL_PORT_HARDWARE Serial
#define SERIAL_PORT_HARDWARE1 Serial1
#define SERIAL_PORT_HARDWARE2 Serial2
#define SERIAL_PORT_HARDWARE3 Serial3
// TODO: is "Serial" considered open when Due is used in native port mode?
#define SERIAL_PORT_HARDWARE_OPEN Serail1
#define SERIAL_PORT_HARDWARE_OPEN1 Serail2
#define SERIAL_PORT_HARDWARE_OPEN2 Serail3

// Teensy 2.0
#define SERIAL_PORT_MONITOR Serial
#define SERIAL_PORT_USBVIRTUAL Serial
#define SERIAL_PORT_HARDWARE Serial1
#define SERIAL_PORT_HARDWARE_OPEN Serail1

// Teensy 3.0
#define SERIAL_PORT_MONITOR Serial
#define SERIAL_PORT_USBVIRTUAL Serial
#define SERIAL_PORT_HARDWARE Serial1
#define SERIAL_PORT_HARDWARE1 Serial2
#define SERIAL_PORT_HARDWARE2 Serial3
#define SERIAL_PORT_HARDWARE_OPEN Serail1
#define SERIAL_PORT_HARDWARE_OPEN1 Serail2
#define SERIAL_PORT_HARDWARE_OPEN2 Serail3

Tom Igoe

unread,
Nov 6, 2013, 7:04:33 AM11/6/13
to Paul Stoffregen, Arduino Developers
This looks good to me overall. I don’t understand how SERIAL_PORT_HARDWARE_OPEN would be detected, though. Are you imagining an auto-detect, or user-assigned?

t.

Cristian Maglie

unread,
Nov 6, 2013, 7:25:30 AM11/6/13
to devel...@arduino.cc
In data mercoledì 6 novembre 2013 13:04:33, Tom Igoe ha scritto:
> This looks good to me overall. I don’t understand how
> SERIAL_PORT_HARDWARE_OPEN would be detected, though. Are you imagining an
> auto-detect, or user-assigned?

These defines will be put in the variant file relative to the specific board they
refer to: so no autodetection, they will be just constants available in the
sketch (or libraries).

If I understand right, SERIAL_PORT_HARDWARE_OPEN states the first serial port
that is free to use (no serial monitor attached nor linux bridge or any other
stuff). For example on the mega will be defined as:

#define SERIAL_PORT_HARDWARE_OPEN Serial1

C

Rob Tillaart

unread,
Nov 6, 2013, 7:26:02 AM11/6/13
to Tom Igoe, Paul Stoffregen, Arduino Developers

// Arduino Uno
HWSerial SerialPorts[] = { Serial };

// Arduino Mega
HWSerial SerialPorts[] = { Serial, Serial1, Serial2, Serial3 };
...

SerialPortCount = sizeof(SerialPorts)/sizeof(SerialPorts[0]);


Detection is just accessing the Count and you know how many there are.

Paul Stoffregen

unread,
Nov 6, 2013, 7:26:08 AM11/6/13
to Tom Igoe, Arduino Developers
On 11/06/2013 04:04 AM, Tom Igoe wrote:
> This looks good to me overall. I don�t understand how SERIAL_PORT_HARDWARE_OPEN would be detected, though. Are you imagining an auto-detect, or user-assigned?

The #defines go into the pins_arduino.h files in each variant folder.
They're just like other board-specific info variants provides, like
NUM_DIGITAL_PINS, LED_BUILTIN, A0, A1, A2, etc.


Please let me illustrate by an example. In the XBee library has this code:

#if defined(__AVR_ATmega32U4__) || defined(__MK20DX128__)
_serial = &Serial1;
#else
_serial = &Serial;
#endif

The goal is to eliminate the need for these types of #ifdef checks, so
more libraries can become fully architecture independent. For example,
Xbee might be changed to have this:

_serial = &SERIAL_PORT_HARDWARE_OPEN;

Libraries can check if these exist. A board like Yun, which has no open
serial ports, could be detected properly and a fallback to
SoftwareSerial could be used. One alternative that might make sense in
XBee could look like this:

#if !defined(SERIAL_PORT_HARDWARE_OPEN)
#include "SoftwareSerial.h"
SoftwareSerial softSerial(10, 11); // TODO: how to know recommended
default pins?
#endif

.......

#if defined(SERIAL_PORT_HARDWARE_OPEN)
_serial = &SERIAL_PORT_HARDWARE_OPEN;
#else
_serial = &softSerial;
#endif

Of course, there are many possible ways the library author could choose
to adapt their code. The idea is simply to provide more info about the
currently selected board, so they won't have to resort to hard-coding
board details with long #ifdef chains.

Tom Igoe

unread,
Nov 6, 2013, 7:37:11 AM11/6/13
to Paul Stoffregen, Arduino Developers
That sounds like a good solution to me. I will defer to Cristian, of course, but I don’t see any problems with it.

t.

On Nov 6, 2013, at 7:26 AM, Paul Stoffregen <pa...@pjrc.com> wrote:

> On 11/06/2013 04:04 AM, Tom Igoe wrote:
>> This looks good to me overall. I don’t understand how SERIAL_PORT_HARDWARE_OPEN would be detected, though. Are you imagining an auto-detect, or user-assigned?

Bill Perry

unread,
Nov 9, 2013, 3:17:22 PM11/9/13
to devel...@arduino.cc


On Monday, November 4, 2013 8:55:29 AM UTC-6, paul wrote:
Here's my current wish-list for APIs for improving compatibility, based
on actual libraries and applications I've ported over the last few years.

1: Interval Timer (interrupt):  Several libraries commandeer hardware
timers.  There are many use cases, but the most common is merely
configuring for the overflow interrupt to execute at a regular interval
(DmxSimple, VirtualWire, etc).  Just solving this 1 case with a simple
API eliminates special code in several libraries.

 

2: Sampling & Non-blocking Analog:  This conversation was started a
month ago, on Oct 6, 2013.  It's a big project.  I intend to work on it
early next year.  I've seen several projects that directly hard-code
analog register access, because they need non-blocking access or low
jitter sampling.

3: Serial.ready():  Like Serial.available(), but for transmitting. I
believe this has been discussed many times and there's generally
consensus?  Some applications need to avoid waiting, and currently have
to access hardware registers.  LabView's support code is one notable
example.

Theoretically the current write() API can already do this.
The current issue is that the write() function in HardwareSerial does not return 0 when there is no room.
It busy waits until there is room.
I have always found it odd that read() returns immediately when there is no character
but yet write() waits for room.
This is very asymmetric.

My concern with a simple name like "ready()" is that we may fall back into a problem like
flush().
i.e. what does ready really mean?
And then what happens when things like real flow control are supported?
Would ready be associated with the control lines?

To me that best names for all this stuff were worked out decades ago in the
TERMIO ioctl functions. Things really starting going down hill when the C++
guys game along with their iostream stuff and changed the meaning of "flush".
(it used be flush & drain).

Overall I'm agreeing that if it is important to preserver the existing blocking write()
behavior, then there needs to be a new function.
I'm just not sure that "ready()" is the best name.
ready() is probably OK,
as long as it is documented and people don't go monkey with it's meaning later
like what was done with flush(), then it should be ok.

Maybe there could be new names that include tx/rx prefixes to be clear?
Leave all the existing functions for backward compatibility, but add:
txFlush(), rxFlush(), txAvailable(), rxAvailable(), etc...
To make the API very clear and very symmetric.



4: Pinout specified by preprocessor symbols/macros:  The existing pinout
lookup tables would be populated using those symbols/macros, so the
pinout is only updated/maintained in 1 place.  Several libraries like
the USB Host Shield and GLCD hard-code pinouts for all known boards.  
This API could let them easily transition to automatically acquiring the
pinout.

There is a better way to handle this than using preprocessor symbols/defines
and yet another new API.
gcc is smart enough to be able to yank out  data elements from a data array
at compile time. The trick is that the array must be static const and the indexes
must be constant.
The better solution would be to simply provide a smarter digitalWrite()/digitalRead()
macro that can index into to the static const data when the parameters are constants.
This is actually easy to do but it requires that the data tables in the variant files
use a macro for their declaration. The point of the macro is to allow turning on/off
the "static" of the declaration.
This is necessary because you need a static data table for the const compile time
lookups the wrapper macros do and then a non static version for the runtime lookups.
digitalWrite()/digitalRead() become wrapper macros as well as functions.
The wrappers can use the static data when things are constants, if not they call
the older/slower functions to do the lookups run time.
(more below in #5)


5: digitalWriteFast:  We've had consensus on this since 2009, but #4 is
needed for the code to be maintainable.  This can eliminate the need for
hard-coding I/O register access, since it compiles to the same code with
a const input.  It doesn't solve the non-const case (see below for
that), but it does allow replacement of hard coded registers currently
in sketches and libraries, which is a good thing!

PLEASE, PLEASE can we start to move away from this digitalxxxFAST() alternate API stuff?
It is unnecessary to have a totally separate API to get faster I/o.
#4 is not necessary and the smart wrapper macros can have the same names
as the original functions. CPP does not recursively expand a macro name inside itself.
So my suggestion is to re-do the pin mapping declarations in the variant files as
mentioned in #4 above to allow smarter code to reach down into the pin mapping data tables at compile time.
This alone would eliminate the need for all the crazy duplicate preprocessor data to
map pins.

For maximum backward compatibility, including all the hand holding stuff of checking for timers, pwm
and input/output modes is desired,
the best way to implement the faster i/o with full backward compatibility is actually as a library.
So the user would include a header file to turn on the faster i/o.
That header file would do lots of compile time magic
to provide wrapper macros on top of all the existing digitalRead()/digitalWrite()/pinMode() functions
using the SAME names.
And if the declarations are changed in the variant files, then the macro code can reach down into the
pin mapping tables at compile time.
This allows the wrapper macros to provide the exact same API (no sketch code has to change)
and yet provide much faster i/o than the existing run time lookups.

Having it as a "library" allows users to turn it on when they want it
and have the old/existing code/interface by default
And by using a macro in the variant files to control the static declarations,
there is zero impact to any existing core code or sketches.

This has been on my list of things to do, for quite some time, I just
haven't gotten around to do it, mainly because it requires changes
in the variant files to make it work.



6: Improved pointer-based I/O (eg, better abstraction than AVR-specific
digitalPinToBitMask, portOutputRegister, portInputRegister,
portModeRegister).  Many libraries already use these 4 macros, which
leads to hard-coded AVR register semantics (eg, assuming 8 bit types
doesn't work for Due).  An improved inline function should provide an
opaque type for the lookup phase, which is then accepted by inline
functions to perform specific operations.

I've also played with this methodology on pic32 (chipkit)
I used it in fm's LiquidCrystal library. (it is in the FastIO.cpp code)
I did exactly what you described by using opaque types.
Actually it takes two opaque types to make it work.
one for the register, and one for the bitmask.

However, one thing to keep in mind is atomicity
since the i/o operation using this methodology is not atomic.
In order to make it work on pic32 I ended up also porting
the ATOMIC_BLOCK() stuff from AVR over to the pic32.

This is very unfortunate as the pic32 contains atomic
set and clear registers but the current Arduino digitalWrite() API
cannot be mapped to that construct.

What would be nice would be a low level SET/CLEAR pin api.
That way processors that are better/smarter than the AVR could
use their built in hardware capabilities for additional performance.
 

7: Free Memory:  Last time this was discussed, as I recall the debate
was regarding the meaning of "free", whether it includes all free
memory, or the largest number that can succeed with malloc? I'm honestly
not sure which is the best way.  One use case is in some of Adafruit's
libraries for larger graphical LCDs, which attempt to warn the user if
they're running dangerously low on memory.  Either way could allow
architecture independent code, rather than hard-coding extern refs to C
library memory management variables.

8: Hardware Serial Names:  Similar to LED_BUILTIN, defined names are
needed to identify the first physical serial port, and the first
"available" serial port (not used for uploading), if they exist.
Libraries that build on top of hardware serial (MIDI, XBee, etc) contain
hard coded or architecture specific #ifdefs, only to initialize a Stream
ref or pointer or otherwise configure which port they use.  Simply
defining these names could allow those serial-only libraries to become
architecture independent.


All these defines are really polluting up the define space and there
are already starting to be collisions with user sketch code.
I'm surprised that that it hasn't been worse.
I'd prefer that there start be a migration over to a more C++ method
of declaring all these values.
Maybe even have something like an const Arduino data object that can be referenced.
So rather than A0
you could do something like:
Arduino.pin.A0
Arduino.version (for arduino version number)
Arduino.pin.LED_BUILTIN
etc...
Some sort of hierarchy that can be extended.
Just a thought.


Here are a few more items that I've seen that might be useful:

Multi-bit i/o:
One thing not mentioned in all this i/o discussion, is multi-bit i/o.
I also think it would be useful to have multi bit i/o.
The GLCD & openGLCD  libraries need this to boost i/o performance.
These library use multi bit i/o to collapse down multiple pin i/o operations
into few actual register i/o operations.
When the selected pins are all bits are in the same register and in the
proper order, it can collapse down into a single register update.

The multi pin interface looks like:

digitalWrite8Pins(pin0, pin1, pin2, pin3, pin4, pin5, pin6, pin7, byteval);
byteval = digitalRead8Pins(pin0, pin1, pin2, pin3, pin4, pin5, pin6, pin7);

Even if not for performance reasons, a multi-bit i/o API interface
is useful. This allows libraries and sketches to push out or read bytes or nibbles
to pins without having to be responsible for the actual low level
bit stripping/coalescing.

VeryShort h/w Delays (sub microsecond range)
With speed of microcontrolllers today, there is often a need for
very short delays to meet the setup timing requirements of hardware.
Things like LCDs and GLCDs, often need to honor setup timing.
And even when doing s/w bit banging there is sometimes a need for very short delays.
The delays needed in these situations are sub microsecond.
The GLCD/openGLCD libraries are examples of libraries that need
these types of delays. They need delays of 120ns or 450ns etc...
The current Arduino API simply cannot handle these types of very short delays.

GLCD & openGLCD had to create its own nanosecond delay routine
since if these glcd libraries were to use current Arduino delay routines,
performance would drop significantly.
It would be very useful if the Arduino core would include ns type delays for
hardware setup timing.
On AVR it is can be done with a single line function like macro.

Paul Stoffregen

unread,
Nov 11, 2013, 4:28:15 AM11/11/13
to Arduino Developers
Where are we at regarding this hardware serial names proposal?


On 11/06/2013 04:37 AM, Tom Igoe wrote:
> That sounds like a good solution to me. I will defer to Cristian, of course, but I don�t see any problems with it.
>
> t.
>
> On Nov 6, 2013, at 7:26 AM, Paul Stoffregen <pa...@pjrc.com> wrote:
>
>> On 11/06/2013 04:04 AM, Tom Igoe wrote:
>>> This looks good to me overall. I don�t understand how SERIAL_PORT_HARDWARE_OPEN would be detected, though. Are you imagining an auto-detect, or user-assigned?

Cristian Maglie

unread,
Nov 11, 2013, 4:35:46 AM11/11/13
to devel...@arduino.cc
In data lunedì 11 novembre 2013 10:28:15, Paul Stoffregen ha scritto:
> Where are we at regarding this hardware serial names proposal?

I'm working on a pull request just now...

C

Cristian Maglie

unread,
Nov 11, 2013, 7:59:13 AM11/11/13
to devel...@arduino.cc
In data mercoledì 6 novembre 2013 13:26:02, Rob Tillaart ha scritto:
> // Arduino Uno
> HWSerial SerialPorts[] = { Serial };
>
> // Arduino Mega
> HWSerial SerialPorts[] = { Serial, Serial1, Serial2, Serial3 };
> ...
>
> SerialPortCount = sizeof(SerialPorts)/sizeof(SerialPorts[0]);
>
> Detection is just accessing the Count and you know how many there are.

Hi Rob,

not all the serial ports are HardwareSerial, so the definition maybe should be
changed to:

Stream SerialPorts[] = { Serial, SeiralUSB,...... };

but at this point I don't know how the following may work:

SerialPortCount = sizeof(SerialPorts)/sizeof(SerialPorts[0]);

another question is how can we do something similar to this one?

#if defined(SERIAL_PORT_HARDWARE_OPEN)
_serial = &SERIAL_PORT_HARDWARE_OPEN;
#else
_serial = &softSerial;
#endif


C

Cristian Maglie

unread,
Nov 11, 2013, 8:04:45 AM11/11/13
to devel...@arduino.cc
Here the pull request for review:

https://github.com/arduino/Arduino/pull/1669

C

Matthijs Kooijman

unread,
Nov 11, 2013, 8:59:54 AM11/11/13
to Cristian Maglie, devel...@arduino.cc
Hey Christian,

On Mon, Nov 11, 2013 at 01:59:13PM +0100, Cristian Maglie wrote:
> In data mercoledì 6 novembre 2013 13:26:02, Rob Tillaart ha scritto:
> > // Arduino Uno
> > HWSerial SerialPorts[] = { Serial };
> >
> > // Arduino Mega
> > HWSerial SerialPorts[] = { Serial, Serial1, Serial2, Serial3 };
> > ...
> >
> > SerialPortCount = sizeof(SerialPorts)/sizeof(SerialPorts[0]);
> >
> > Detection is just accessing the Count and you know how many there are.
>
> Hi Rob,
>
> not all the serial ports are HardwareSerial, so the definition maybe should be
> changed to:
>
> Stream SerialPorts[] = { Serial, SeiralUSB,...... };
I think this won't work, since this will build new objects of the stream
class instead of referencing the existing ones (and I presume Stream is
abstract).

Using an array of references is apparently not possible in C++, so you'd
have to use pointers:

Stream *SerialPorts[] = { &Serial, &SerialUSB,...... };

> but at this point I don't know how the following may work:
>
> SerialPortCount = sizeof(SerialPorts)/sizeof(SerialPorts[0]);
With the above change, this will work as expected.

> another question is how can we do something similar to this one?
>
> #if defined(SERIAL_PORT_HARDWARE_OPEN)
> _serial = &SERIAL_PORT_HARDWARE_OPEN;
> #else
> _serial = &softSerial;
> #endif

I suspect this should work like:

#if defined(SERIAL_PORT_HARDWARE_OPEN)
_serial = SerialPorts[SERIAL_PORT_HARDWARE_OPEN];
#else
_serial = &softSerial;
#endif

But this conflicts with the change you're about to merge (which defines
SERIAL_PORT_HARDWARE_OPEN to be the object, not some index), so
something like this could also work:

_serial = SerialPorts[SERIAL_PORT_HARDWARE_OPEN_NUM];

e.g., have a _NUM variant with the index.

Not sure if all this is really more useful than the current proposal
and/or a useful addition to it, though. It helps in case you want to
loop over all available serial ports, but otherwise you can just use
Stream* instead of indices everywhere I think?

Gr.

Matthijs
signature.asc

Paul Stoffregen

unread,
Nov 11, 2013, 9:32:42 AM11/11/13
to devel...@arduino.cc
Please, let's try to keep focused on solving the needs of libraries.

Does any library currently contain architecture or board specific lists
of port names, and then iterate over them using an array? If any
libraries need this capability, I believe we should look at the code
they've published so far, to better understand this use case.

So far, every library I've seen build on top of Serial or Stream
attempts default settings using simple names. This proposal is intended
to address the needs to actual libraries, to help them eliminate
hardware dependencies.

Here are 5 examples:



The Bridge library has this: (in its architecture independent "src" folder)

// Bridge instance
#ifdef __AVR_ATmega32U4__
// Leonardo variants (where HardwareSerial is Serial1)
SerialBridgeClass Bridge(Serial1);
#else
SerialBridgeClass Bridge(Serial);
#endif




The MIDI 3.2 library has this: (expecting the user to edit MIDI.h)

#define USE_SERIAL_PORT Serial // Change the number (to
Serial1 for example) if you want
// to use a different
serial port for MIDI I/O.



XBee 0.4 has this:

#if defined(__AVR_ATmega32U4__) || defined(__MK20DX128__)
_serial = &Serial1;
#else
_serial = &Serial;
#endif



The Time library has this in TimeGPS.ino

SoftwareSerial SerialGPS = SoftwareSerial(10, 11); // receive on pin 10
TinyGPS gps;
// To use a hardware serial port, which is far more efficient than
// SoftwareSerial, uncomment this line and remove SoftwareSerial
//#define SerialGPS Serial1



Adafruit_CC3000 has this: (amazingly, for identifying the stream to the
serial monitor)

#if defined(UDR0) || defined(UDR1) || defined(CORE_TEENSY)
CC3KPrinter = &Serial;
#else
CC3KPrinter = 0;
// no default serial port found
#endif








On 11/11/2013 05:59 AM, Matthijs Kooijman wrote:
> Hey Christian,
>
> On Mon, Nov 11, 2013 at 01:59:13PM +0100, Cristian Maglie wrote:

Cristian Maglie

unread,
Nov 12, 2013, 1:00:43 PM11/12/13
to devel...@arduino.cc
In data lunedì 11 novembre 2013 14:04:45, Cristian Maglie ha scritto:
> Here the pull request for review:
>
> https://github.com/arduino/Arduino/pull/1669

This one was merged yesterday. It seems that github has some problems showing
it.

C
Reply all
Reply to author
Forward
0 new messages