I'd like to rename the "Serial" thing ... or I guess I'd like to "store a reference to it" in another variable.
But I have a really hard time finding out what Serial even is. Is serial a class with static methods or is it actually an instance? I'm not too familiar with C++...
In the end I'd like to have two variables "ComputerSerial" and "BluetoothSerial".
And I'd like to be able to set those variables to either a hardware Serial or a SoftwareSerial.
So basically this is what I tried:
SoftwareSerial BluetoothSerial(9,10);
HardwareSerial ComputerSerial = Serial;
void MyFunc(Stream &SerialObj) {
SerialObj.println("test");
}
void setup() {
ComputerSerial.begin(115200);
BluetoothSerial.begin(115200);
}
void loop() {
MyFunc(ComputerSerial); //send "test" to the computer serial
MyFunc(BluetoothSerial); //send "test" to the bluetooth serial
}
I used "Stream" as the datatype for the function parameter because I read somewhere that both HardwareSerial and SoftwareSerial are actually just "Stream"s. This way I can pass any kind of Serial object(?) to the function. And if I ever device to switch a serial connection from hardware to softawre or the other way around, I just need to change the first two lines of the code and the rest can stay the same.
But I'm experiencing very weird behavior with this that I cannot explain...
For example the output of this code:
I used "Stream" as the datatype for the function parameter because I read somewhere that both HardwareSerial and SoftwareSerial are actually just "Stream"s. This way I can pass any kind of Serial object(?) to the function. And if I ever device to switch a serial connection from hardware to softawre or the other way around, I just need to change the first two lines of the code and the rest can stay the same.
This is exactly the kind of forward thinking that prevents headaches later on. Well done.
Please, please use a reference. It is like a pointer, but you don't have to use the arrow notation:
HardwareSerial & bluetooth = Serial2; // an alias
So much cleaner! It's also much easier to search and replace the Serial name, unlike replacing the type and its usage. Function arguments can use the same technique:
felic:
Do I really need the auto thing? Is it a datatype? Could I just use Stream instead?
And about that:
HardwareSerial *ComputerSerial = &Serial;
Does this result in such a ppointer that my syntax changes from dots to arrows? I mean ComputerSerial->print() instead of ComputerSerial.print()?
auto is a special C++11 keyword that lets you declare a variable without having to care about looking up what type it needs to be, the compiler will deduce that for you based on the initialization statement. When you do:
auto& ComputerSerial = Serial;
The compiler creates a reference of the same type as the Serial object. You don't need to tell it what type it is, since the compiler will already know. If you change it to a reference to a SoftwareSerial, it will create a reference to a SoftwareSerial object the next time you compile it. The typing is handled automatically.
You can use a pointer for this, but since you are not doing any pointer arithmetic (ie. iterating over an array) or using dynamic memory, a reference has less things that can go wrong. You don't need to remember to *dereference it or use that -> thing.
I thought the auto storage specifier could only be used with a variable defined with local or block scope and assumes the default storage class for the compiler (e.g., int) if there's no initializer. However, it appears that you can define an auto with global scope, and the definition must have an initializer list. Can anyone state what the rules are?
econjack:
I thought the auto storage specifier could only be used with a variable defined with local or block scope and assumes the default storage class for the compiler (e.g., int) if there's no initializer. However, it appears that you can define an auto with global scope, and the definition must have an initializer list. Can anyone state what the rules are?
Global variables.
Local/Static variables.
auto x = 4; //int
auto a = new auto(1); //int, 'a' is int*
if(auto p = func()){
//...
}
Function return types.
template< typename T, typename U >
auto func( T t, U u ) -> decltype(u+t){
return t + u;
}
Return types for lambdas:
int j;
auto x3 = []()->auto&& { return j; };
Arduino can only utilize C++11 so far, but for future reference, in C++14 generic lambdas have been added, and also function parameters can be auto.
[](auto t){ return t; }
void func( auto a, auto b ){
}
As for the rules, there is too much to copy, format, and paste.