1
0
mirror of https://github.com/DCC-EX/CommandStation-EX.git synced 2024-12-23 21:01:25 +01:00
CommandStation-EX/IO_ExampleSerial.cpp
Neil McKechnie 9dacd24d27
Various HAL enhancements. (#182)
* Add <D SERVO vpin position> command

Allow a PWM servo to be driven to any arbitrary position.

* Enhancements for HAL drivers

Add state change notification for external GPIO module drivers;
Allow drivers to be installed statically by declaration (as an alternative to the 'create' call).

* Create IO_HCSR04.h

HAL driver for HC-SR04 ultrasonic distance sensor (sonar).

* Enable servo commands in NO-HAL mode, but return error.

Avoid compile errors in RMFT.cpp when compiled with basic HAL by including the Turnout::createServo function as a stub that returns NULL.

* Update IO_HCSR04.h

Minor changes

* Change <D SERVO>

Give the <D SERVO> command an optional parameter of the profile.  For example, <D SERVO 100 200 3> will slowly move the servo on pin 100 to PWM position corresponding to 200.  If omitted, the servo will move immediately (no animation).

* IODevice (HAL) changes

1) Put new devices on the end of the chain instead of the beginning.  This will give better performance for devices created first (ArduinoPins and extender GPIO devices, typically).
2) Remove unused functions.

* Update IO_HCSR04.h

Allow thresholds for ON and OFF to be separately configured at creation.

* Update IODevice.cpp

Fix compile error on IO_NO_HAL minimal HAL version.

* Update IO_PCA9685.cpp

Remove unnecessary duplicated call to min() function.
2021-08-17 23:41:34 +01:00

128 lines
4.1 KiB
C++

/*
* © 2021, Neil McKechnie. All rights reserved.
*
* This file is part of DCC++EX API
*
* This is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* It is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with CommandStation. If not, see <https://www.gnu.org/licenses/>.
*/
#include <Arduino.h>
#include "IO_ExampleSerial.h"
#include "FSH.h"
// Constructor
IO_ExampleSerial::IO_ExampleSerial(VPIN firstVpin, int nPins, HardwareSerial *serial, unsigned long baud) {
_firstVpin = firstVpin;
_nPins = nPins;
_pinValues = (uint16_t *)calloc(_nPins, sizeof(uint16_t));
_baud = baud;
// Save reference to serial port driver
_serial = serial;
addDevice(this);
}
// Static create method for one module.
void IO_ExampleSerial::create(VPIN firstVpin, int nPins, HardwareSerial *serial, unsigned long baud) {
new IO_ExampleSerial(firstVpin, nPins, serial, baud);
}
// Device-specific initialisation
void IO_ExampleSerial::_begin() {
_serial->begin(_baud);
DIAG(F("ExampleSerial configured Vpins:%d-%d"), _firstVpin, _firstVpin+_nPins-1);
// Send a few # characters to the output
for (uint8_t i=0; i<3; i++)
_serial->write('#');
}
// Device-specific write function. Write a string in the form "#Wm,n#"
// where m is the vpin number, and n is the value.
void IO_ExampleSerial::_write(VPIN vpin, int value) {
int pin = vpin -_firstVpin;
#ifdef DIAG_IO
DIAG(F("IO_ExampleSerial::_write Pin:%d Value:%d"), (int)vpin, value);
#endif
// Send a command string over the serial line
_serial->print('#');
_serial->print('W');
_serial->print(pin);
_serial->print(',');
_serial->print(value);
_serial->println('#');
DIAG(F("ExampleSerial Sent command, p1=%d, p2=%d"), vpin, value);
}
// Device-specific read function.
int IO_ExampleSerial::_read(VPIN vpin) {
// Return a value for the specified vpin.
int result = _pinValues[vpin-_firstVpin];
return result;
}
// Loop function to do background scanning of the input port. State
// machine parses the incoming command as it is received. Command
// is in the form "#Nm,n#" where m is the index and n is the value.
void IO_ExampleSerial::_loop(unsigned long currentMicros) {
(void)currentMicros; // Suppress compiler warnings
if (_serial->available()) {
// Input data available to read. Read a character.
char c = _serial->read();
switch (_inputState) {
case 0: // Waiting for start of command
if (c == '#') // Start of command received.
_inputState = 1;
break;
case 1: // Expecting command character
if (c == 'N') { // 'Notify' character received
_inputState = 2;
_inputValue = _inputIndex = 0;
} else
_inputState = 0; // Unexpected char, reset
break;
case 2: // reading first parameter (index)
if (isdigit(c))
_inputIndex = _inputIndex * 10 + (c-'0');
else if (c==',')
_inputState = 3;
else
_inputState = 0; // Unexpected char, reset
break;
case 3: // reading reading second parameter (value)
if (isdigit(c))
_inputValue = _inputValue * 10 - (c-'0');
else if (c=='#') { // End of command
// Complete command received, do something with it.
DIAG(F("ExampleSerial Received command, p1=%d, p2=%d"), _inputIndex, _inputValue);
if (_inputIndex < _nPins) { // Store value
_pinValues[_inputIndex] = _inputValue;
}
_inputState = 0; // Done, start again.
} else
_inputState = 0; // Unexpected char, reset
break;
}
}
}
void IO_ExampleSerial::_display() {
DIAG(F("IO_ExampleSerial VPins:%d-%d"), (int)_firstVpin,
(int)_firstVpin+_nPins-1);
}