mirror of
https://github.com/DCC-EX/CommandStation-EX.git
synced 2024-12-23 12:51:24 +01:00
HAL driver enhancements
Performance enhancements in IODevice::loop() function. Improved error handling, device is placed off line if not responding. Improved error reporting, device shown as offline if not operational (faulty or not present).
This commit is contained in:
parent
08835e25c6
commit
302b16547e
52
IODevice.cpp
52
IODevice.cpp
@ -53,9 +53,7 @@ void IODevice::begin() {
|
||||
MCP23017::create(180, 16, 0x21);
|
||||
|
||||
// Call the begin() methods of each configured device in turn
|
||||
unsigned long currentMicros = micros();
|
||||
for (IODevice *dev=_firstDevice; dev!=NULL; dev = dev->_nextDevice) {
|
||||
dev->_nextEntryTime = currentMicros;
|
||||
dev->_begin();
|
||||
}
|
||||
_initPhase = false;
|
||||
@ -69,18 +67,24 @@ void IODevice::begin() {
|
||||
// doesn't need to invoke it.
|
||||
void IODevice::loop() {
|
||||
unsigned long currentMicros = micros();
|
||||
// Call every device's loop function in turn, one per entry.
|
||||
if (!_nextLoopDevice) _nextLoopDevice = _firstDevice;
|
||||
// Check if device exists, and is due to run
|
||||
if (_nextLoopDevice /* && ((long)(currentMicros-_nextLoopDevice->_nextEntryTime) >= 0) */ ) {
|
||||
// Move _nextEntryTime on, so that we can guarantee that the device will continue to
|
||||
// be serviced if it doesn't update _nextEntryTime.
|
||||
_nextLoopDevice->_nextEntryTime = currentMicros;
|
||||
// Invoke device's _loop function
|
||||
_nextLoopDevice->_loop(currentMicros);
|
||||
// Move to next device.
|
||||
_nextLoopDevice = _nextLoopDevice->_nextDevice;
|
||||
}
|
||||
|
||||
IODevice *lastLoopDevice = _nextLoopDevice; // So we know when to stop...
|
||||
// Loop through devices until we find one ready to be serviced.
|
||||
do {
|
||||
if (!_nextLoopDevice) _nextLoopDevice = _firstDevice;
|
||||
if (_nextLoopDevice) {
|
||||
if (_nextLoopDevice->_deviceState != DEVSTATE_FAILED
|
||||
&& ((long)(currentMicros - _nextLoopDevice->_nextEntryTime)) >= 0) {
|
||||
// Found one ready to run, so invoke its _loop method.
|
||||
_nextLoopDevice->_nextEntryTime = currentMicros;
|
||||
_nextLoopDevice->_loop(currentMicros);
|
||||
_nextLoopDevice = _nextLoopDevice->_nextDevice;
|
||||
break;
|
||||
}
|
||||
// Not this one, move to next one
|
||||
_nextLoopDevice = _nextLoopDevice->_nextDevice;
|
||||
}
|
||||
} while (_nextLoopDevice != lastLoopDevice); // Stop looking when we've done all.
|
||||
|
||||
// Report loop time if diags enabled
|
||||
#if defined(DIAG_LOOPTIMES)
|
||||
@ -127,7 +131,8 @@ bool IODevice::hasCallback(VPIN vpin) {
|
||||
|
||||
// Display (to diagnostics) details of the device.
|
||||
void IODevice::_display() {
|
||||
DIAG(F("Unknown device Vpins:%d-%d"), (int)_firstVpin, (int)_firstVpin+_nPins-1);
|
||||
DIAG(F("Unknown device Vpins:%d-%d %S"),
|
||||
(int)_firstVpin, (int)_firstVpin+_nPins-1, _deviceState==DEVSTATE_FAILED ? F("OFFLINE") : F(""));
|
||||
}
|
||||
|
||||
// Find device associated with nominated Vpin and pass configuration values on to it.
|
||||
@ -151,13 +156,18 @@ void IODevice::write(VPIN vpin, int value) {
|
||||
#endif
|
||||
}
|
||||
|
||||
// Write analogue value to virtual pin(s). If multiple devices are allocated the same pin
|
||||
// then only the first one found will be used. Duration is the time that the
|
||||
// operation is to be performed over (e.g. as an animation) in deciseconds (0-3276 sec)
|
||||
void IODevice::writeAnalogue(VPIN vpin, int value, uint8_t profile, uint16_t duration) {
|
||||
// Write analogue value to virtual pin(s). If multiple devices are allocated
|
||||
// the same pin then only the first one found will be used.
|
||||
//
|
||||
// The significance of param1 and param2 may vary from device to device.
|
||||
// For servo controllers, param1 is the profile of the transition and param2
|
||||
// the duration, i.e. the time that the operation is to be animated over
|
||||
// in deciseconds (0-3276 sec)
|
||||
//
|
||||
void IODevice::writeAnalogue(VPIN vpin, int value, uint8_t param1, uint16_t param2) {
|
||||
IODevice *dev = findDevice(vpin);
|
||||
if (dev) {
|
||||
dev->_writeAnalogue(vpin, value, profile, duration);
|
||||
dev->_writeAnalogue(vpin, value, param1, param2);
|
||||
return;
|
||||
}
|
||||
#ifdef DIAG_IO
|
||||
@ -257,7 +267,7 @@ int IODevice::readAnalogue(VPIN vpin) {
|
||||
return dev->_readAnalogue(vpin);
|
||||
}
|
||||
#ifdef DIAG_IO
|
||||
//DIAG(F("IODevice::readAnalogue(): Vpin %d not found!"), (int)vpin);
|
||||
DIAG(F("IODevice::readAnalogue(): Vpin %d not found!"), (int)vpin);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
16
IODevice.h
16
IODevice.h
@ -163,7 +163,14 @@ public:
|
||||
|
||||
protected:
|
||||
|
||||
// Method to perform initialisation of the device (optionally implemented within device class)
|
||||
// Constructor
|
||||
IODevice(VPIN firstVpin=0, int nPins=0) {
|
||||
_firstVpin = firstVpin;
|
||||
_nPins = nPins;
|
||||
_nextEntryTime = 0;
|
||||
}
|
||||
|
||||
// Method to perform initialisation of the device (optionally implemented within device class)
|
||||
virtual void _begin() {}
|
||||
|
||||
// Method to configure device (optionally implemented within device class)
|
||||
@ -178,8 +185,8 @@ protected:
|
||||
};
|
||||
|
||||
// Method to write an 'analogue' value (optionally implemented within device class)
|
||||
virtual void _writeAnalogue(VPIN vpin, int value, uint8_t profile, uint16_t duration) {
|
||||
(void)vpin; (void)value; (void) profile; (void)duration;
|
||||
virtual void _writeAnalogue(VPIN vpin, int value, uint8_t param1, uint16_t param2) {
|
||||
(void)vpin; (void)value; (void) param1; (void)param2;
|
||||
};
|
||||
|
||||
// Function called to check whether callback notification is supported by this pin.
|
||||
@ -275,7 +282,7 @@ private:
|
||||
// Device-specific write functions.
|
||||
void _write(VPIN vpin, int value) override;
|
||||
void _writeAnalogue(VPIN vpin, int value, uint8_t profile, uint16_t duration) override;
|
||||
int _read(VPIN vpin) override; // returns the busy status of the device
|
||||
int _read(VPIN vpin) override; // returns the digital state or busy status of the device
|
||||
void _loop(unsigned long currentMicros) override;
|
||||
void updatePosition(uint8_t pin);
|
||||
void writeDevice(uint8_t pin, int value);
|
||||
@ -302,7 +309,6 @@ private:
|
||||
static const byte FLASH _bounceProfile[30];
|
||||
|
||||
const unsigned int refreshInterval = 50; // refresh every 50ms
|
||||
unsigned long _lastRefreshTime; // last seen value of micros() count
|
||||
|
||||
// structures for setting up non-blocking writes to servo controller
|
||||
I2CRB requestBlock;
|
||||
|
@ -78,48 +78,52 @@ private:
|
||||
#endif
|
||||
} else {
|
||||
DIAG(F("ADS111x device not found, I2C:%x"), _i2cAddress);
|
||||
_deviceState = DEVSTATE_FAILED;
|
||||
}
|
||||
}
|
||||
void _loop(unsigned long currentMicros) override {
|
||||
|
||||
if (currentMicros - _lastMicros >= scanInterval) {
|
||||
// Check that previous non-blocking write has completed, if not then wait
|
||||
uint8_t status = _i2crb.wait();
|
||||
if (status == I2C_STATUS_OK) {
|
||||
// If _currentPin is in the valid range, continue reading the pin values
|
||||
if (_currentPin < _nPins) {
|
||||
_outBuffer[0] = 0x00; // Conversion register address
|
||||
uint8_t status = I2CManager.read(_i2cAddress, _inBuffer, 2, _outBuffer, 1); // Read register
|
||||
if (status == I2C_STATUS_OK) {
|
||||
_value[_currentPin] = ((uint16_t)_inBuffer[0] << 8) + (uint16_t)_inBuffer[1];
|
||||
#ifdef IO_ANALOGUE_SLOW
|
||||
DIAG(F("ADS111x pin:%d value:%d"), _currentPin, _value[_currentPin]);
|
||||
#endif
|
||||
}
|
||||
// Check that previous non-blocking write has completed, if not then wait
|
||||
uint8_t status = _i2crb.wait();
|
||||
if (status == I2C_STATUS_OK) {
|
||||
// If _currentPin is in the valid range, continue reading the pin values
|
||||
if (_currentPin < _nPins) {
|
||||
_outBuffer[0] = 0x00; // Conversion register address
|
||||
uint8_t status = I2CManager.read(_i2cAddress, _inBuffer, 2, _outBuffer, 1); // Read register
|
||||
if (status == I2C_STATUS_OK) {
|
||||
_value[_currentPin] = ((uint16_t)_inBuffer[0] << 8) + (uint16_t)_inBuffer[1];
|
||||
#ifdef IO_ANALOGUE_SLOW
|
||||
DIAG(F("ADS111x pin:%d value:%d"), _currentPin, _value[_currentPin]);
|
||||
#endif
|
||||
}
|
||||
if (status != I2C_STATUS_OK)
|
||||
DIAG(F("ADS111x I2C:x%d Error:%d"), _i2cAddress, status);
|
||||
}
|
||||
// Move to next pin
|
||||
if (++_currentPin >= _nPins) _currentPin = 0;
|
||||
|
||||
// Configure ADC and multiplexer for next scan. See ADS111x datasheet for details
|
||||
// of configuration register settings.
|
||||
_outBuffer[0] = 0x01; // Config register address
|
||||
_outBuffer[1] = 0xC0 + (_currentPin << 4); // Trigger single-shot, channel n
|
||||
_outBuffer[2] = 0xA3; // 250 samples/sec, comparator off
|
||||
// Write command, without waiting for completion.
|
||||
I2CManager.write(_i2cAddress, _outBuffer, 3, &_i2crb);
|
||||
|
||||
_lastMicros = currentMicros;
|
||||
}
|
||||
if (status != I2C_STATUS_OK) {
|
||||
DIAG(F("ADS111x I2C:x%d Error:%d %S"), _i2cAddress, status, I2CManager.getErrorMessage(status));
|
||||
_deviceState = DEVSTATE_FAILED;
|
||||
}
|
||||
// Move to next pin
|
||||
if (++_currentPin >= _nPins) _currentPin = 0;
|
||||
|
||||
// Configure ADC and multiplexer for next scan. See ADS111x datasheet for details
|
||||
// of configuration register settings.
|
||||
_outBuffer[0] = 0x01; // Config register address
|
||||
_outBuffer[1] = 0xC0 + (_currentPin << 4); // Trigger single-shot, channel n
|
||||
_outBuffer[2] = 0xA3; // 250 samples/sec, comparator off
|
||||
// Write command, without waiting for completion.
|
||||
I2CManager.write(_i2cAddress, _outBuffer, 3, &_i2crb);
|
||||
|
||||
delayUntil(currentMicros + scanInterval);
|
||||
}
|
||||
|
||||
int _readAnalogue(VPIN vpin) override {
|
||||
int pin = vpin - _firstVpin;
|
||||
return _value[pin];
|
||||
}
|
||||
|
||||
void _display() override {
|
||||
DIAG(F("ADS111x I2C:x%x Configured on Vpins:%d-%d"), _i2cAddress, _firstVpin, _firstVpin+_nPins-1);
|
||||
DIAG(F("ADS111x I2C:x%x Configured on Vpins:%d-%d %S"), _i2cAddress, _firstVpin, _firstVpin+_nPins-1,
|
||||
_deviceState == DEVSTATE_FAILED ? F("OFFLINE") : F(""));
|
||||
}
|
||||
|
||||
// ADC conversion rate is 250SPS, or 4ms per conversion. Set the period between updates to 10ms.
|
||||
@ -134,7 +138,6 @@ private:
|
||||
uint8_t _outBuffer[3];
|
||||
uint8_t _inBuffer[2];
|
||||
uint8_t _currentPin; // ADC pin currently being scanned
|
||||
unsigned long _lastMicros = 0;
|
||||
I2CRB _i2crb;
|
||||
};
|
||||
|
||||
|
@ -66,6 +66,7 @@ private:
|
||||
HardwareSerial *_serial;
|
||||
bool _playing = false;
|
||||
uint8_t _inputIndex = 0;
|
||||
unsigned long _commandSendTime; // Allows timeout processing
|
||||
|
||||
public:
|
||||
DFPlayer(VPIN firstVpin, int nPins, HardwareSerial &serial) {
|
||||
@ -81,21 +82,32 @@ public:
|
||||
protected:
|
||||
void _begin() override {
|
||||
_serial->begin(9600);
|
||||
_display();
|
||||
_deviceState = DEVSTATE_INITIALISING;
|
||||
|
||||
// Send a query to the device to see if it responds
|
||||
sendPacket(0x42);
|
||||
_commandSendTime = micros();
|
||||
}
|
||||
|
||||
void _loop(unsigned long) override {
|
||||
void _loop(unsigned long currentMicros) override {
|
||||
// Check for incoming data on _serial, and update busy flag accordingly.
|
||||
// Expected message is in the form "7F FF 06 3D xx xx xx xx xx EF"
|
||||
while (_serial->available()) {
|
||||
int c = _serial->read();
|
||||
// DIAG(F("Received: %x"), c);
|
||||
if (c == 0x7E)
|
||||
_inputIndex = 1;
|
||||
else if ((c==0xFF && _inputIndex==1) || (c==0x06 && _inputIndex==2)
|
||||
|| (c==0x3D && _inputIndex==3) || (_inputIndex >=4 && _inputIndex <= 8))
|
||||
else if ((c==0xFF && _inputIndex==1)
|
||||
|| (c==0x3D && _inputIndex==3)
|
||||
|| (_inputIndex >=4 && _inputIndex <= 8))
|
||||
_inputIndex++;
|
||||
else if (c==0xEF && _inputIndex==9) {
|
||||
else if (c==0x06 && _inputIndex==2) {
|
||||
// Valid command prefix, so consider the device online.
|
||||
_deviceState = DEVSTATE_NORMAL;
|
||||
#ifdef DIAG_IO
|
||||
_display();
|
||||
#endif
|
||||
_inputIndex++;
|
||||
} else if (c==0xEF && _inputIndex==9) {
|
||||
// End of play
|
||||
#ifdef DIAG_IO
|
||||
DIAG(F("DFPlayer: Finished"));
|
||||
@ -104,6 +116,12 @@ protected:
|
||||
_inputIndex = 0;
|
||||
}
|
||||
}
|
||||
// Check if the initial prompt to device has timed out. Allow 1 second
|
||||
if (_deviceState == DEVSTATE_INITIALISING && currentMicros - _commandSendTime > 1000000UL) {
|
||||
DIAG(F("DFPlayer device not responding on serial port"));
|
||||
_deviceState = DEVSTATE_FAILED;
|
||||
}
|
||||
delayUntil(currentMicros + 10000); // Only enter every 10ms
|
||||
}
|
||||
|
||||
// Write with value 1 starts playing a song. The relative pin number is the file number.
|
||||
@ -175,7 +193,8 @@ protected:
|
||||
}
|
||||
|
||||
void _display() override {
|
||||
DIAG(F("DFPlayer Configured on Vpins:%d-%d"), _firstVpin, _firstVpin+_nPins-1);
|
||||
DIAG(F("DFPlayer Configured on Vpins:%d-%d %S"), _firstVpin, _firstVpin+_nPins-1,
|
||||
(_deviceState==DEVSTATE_FAILED) ? F("OFFLINE") : F(""));
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -59,7 +59,6 @@ protected:
|
||||
T _portPullup;
|
||||
// Interval between refreshes of each input port
|
||||
static const int _portTickTime = 4000;
|
||||
unsigned long _lastLoopEntry = 0;
|
||||
|
||||
// Virtual functions for interfacing with I2C GPIO Device
|
||||
virtual void _writeGpioPort() = 0;
|
||||
@ -105,10 +104,12 @@ void GPIOBase<T>::_begin() {
|
||||
_portMode = 0; // default to input mode
|
||||
_portPullup = -1; // default to pullup enabled
|
||||
_portInputState = -1;
|
||||
_setupDevice();
|
||||
_deviceState = DEVSTATE_NORMAL;
|
||||
} else {
|
||||
DIAG(F("%S I2C:x%x Device not detected"), _deviceName, _I2CAddress);
|
||||
_deviceState = DEVSTATE_FAILED;
|
||||
}
|
||||
_setupDevice();
|
||||
_deviceState = DEVSTATE_NORMAL;
|
||||
_lastLoopEntry = micros();
|
||||
}
|
||||
|
||||
// Configuration parameters for inputs:
|
||||
@ -172,27 +173,25 @@ void GPIOBase<T>::_loop(unsigned long currentMicros) {
|
||||
#endif
|
||||
}
|
||||
|
||||
// Check if interrupt configured. If so, and pin is not pulled down, finish.
|
||||
if (_gpioInterruptPin >= 0) {
|
||||
if (digitalRead(_gpioInterruptPin)) return;
|
||||
} else
|
||||
// No interrupt pin. Check if tick has elapsed. If not, finish.
|
||||
if (currentMicros - _lastLoopEntry < (unsigned long)_portTickTime) return;
|
||||
// Check if interrupt configured. If not, or if it is active (pulled down), then
|
||||
// initiate a scan.
|
||||
if (_gpioInterruptPin < 0 || !digitalRead(_gpioInterruptPin)) {
|
||||
// TODO: Could suppress reads if there are no pins configured as inputs!
|
||||
|
||||
// TODO: Could suppress reads if there are no pins configured as inputs!
|
||||
|
||||
// Read input
|
||||
_lastLoopEntry = currentMicros;
|
||||
if (_deviceState == DEVSTATE_NORMAL) {
|
||||
_readGpioPort(false); // Initiate non-blocking read
|
||||
_deviceState= DEVSTATE_SCANNING;
|
||||
// Read input
|
||||
if (_deviceState == DEVSTATE_NORMAL) {
|
||||
_readGpioPort(false); // Initiate non-blocking read
|
||||
_deviceState= DEVSTATE_SCANNING;
|
||||
}
|
||||
}
|
||||
// Delay next entry until tick elapsed.
|
||||
delayUntil(currentMicros + _portTickTime);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void GPIOBase<T>::_display() {
|
||||
DIAG(F("%S I2C:x%x Configured on Vpins:%d-%d"), _deviceName, _I2CAddress,
|
||||
_firstVpin, _firstVpin+_nPins-1);
|
||||
DIAG(F("%S I2C:x%x Configured on Vpins:%d-%d %S"), _deviceName, _I2CAddress,
|
||||
_firstVpin, _firstVpin+_nPins-1, (_deviceState==DEVSTATE_FAILED) ? F("OFFLINE") : F(""));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
|
13
IO_HCSR04.h
13
IO_HCSR04.h
@ -68,8 +68,6 @@ private:
|
||||
uint16_t _distance;
|
||||
// Active=1/inactive=0 state
|
||||
uint8_t _value = 0;
|
||||
// Time of last loop execution
|
||||
unsigned long _lastExecutionTime;
|
||||
// Factor for calculating the distance (cm) from echo time (ms).
|
||||
// Based on a speed of sound of 345 metres/second.
|
||||
const uint16_t factor = 58; // ms/cm
|
||||
@ -97,7 +95,6 @@ protected:
|
||||
pinMode(_trigPin, OUTPUT);
|
||||
pinMode(_echoPin, INPUT);
|
||||
ArduinoPins::fastWriteDigital(_trigPin, 0);
|
||||
_lastExecutionTime = micros();
|
||||
#if defined(DIAG_IO)
|
||||
_display();
|
||||
#endif
|
||||
@ -116,13 +113,9 @@ protected:
|
||||
|
||||
// _loop function - read HC-SR04 once every 50 milliseconds.
|
||||
void _loop(unsigned long currentMicros) override {
|
||||
if (currentMicros - _lastExecutionTime > 50000UL) {
|
||||
_lastExecutionTime = currentMicros;
|
||||
|
||||
read_HCSR04device();
|
||||
// Delay next loop entry until 50ms have elapsed.
|
||||
//delayUntil(currentMicros + 50000UL);
|
||||
}
|
||||
read_HCSR04device();
|
||||
// Delay next loop entry until 50ms have elapsed.
|
||||
delayUntil(currentMicros + 50000UL);
|
||||
}
|
||||
|
||||
void _display() override {
|
||||
|
@ -107,12 +107,14 @@ void PCA9685::_begin() {
|
||||
#if defined(DIAG_IO)
|
||||
_display();
|
||||
#endif
|
||||
}
|
||||
} else
|
||||
_deviceState = DEVSTATE_FAILED;
|
||||
}
|
||||
|
||||
// Device-specific write function, invoked from IODevice::write().
|
||||
// For this function, the configured profile is used.
|
||||
void PCA9685::_write(VPIN vpin, int value) {
|
||||
if (_deviceState == DEVSTATE_FAILED) return;
|
||||
#ifdef DIAG_IO
|
||||
DIAG(F("PCA9685 Write Vpin:%d Value:%d"), vpin, value);
|
||||
#endif
|
||||
@ -137,6 +139,7 @@ void PCA9685::_write(VPIN vpin, int value) {
|
||||
// 4 (Bounce) Servo 'bounces' at extremes.
|
||||
//
|
||||
void PCA9685::_writeAnalogue(VPIN vpin, int value, uint8_t profile, uint16_t duration) {
|
||||
if (_deviceState == DEVSTATE_FAILED) return;
|
||||
#ifdef DIAG_IO
|
||||
DIAG(F("PCA9685 WriteAnalogue Vpin:%d Value:%d Profile:%d Duration:%d"),
|
||||
vpin, value, profile, duration);
|
||||
@ -172,6 +175,7 @@ void PCA9685::_writeAnalogue(VPIN vpin, int value, uint8_t profile, uint16_t dur
|
||||
// _read returns true if the device is currently in executing an animation,
|
||||
// changing the output over a period of time.
|
||||
int PCA9685::_read(VPIN vpin) {
|
||||
if (_deviceState == DEVSTATE_FAILED) return 0;
|
||||
int pin = vpin - _firstVpin;
|
||||
struct ServoData *s = _servoData[pin];
|
||||
if (s == NULL)
|
||||
@ -181,12 +185,10 @@ int PCA9685::_read(VPIN vpin) {
|
||||
}
|
||||
|
||||
void PCA9685::_loop(unsigned long currentMicros) {
|
||||
if (currentMicros - _lastRefreshTime >= refreshInterval * 1000) {
|
||||
for (int pin=0; pin<_nPins; pin++) {
|
||||
updatePosition(pin);
|
||||
}
|
||||
_lastRefreshTime = currentMicros;
|
||||
for (int pin=0; pin<_nPins; pin++) {
|
||||
updatePosition(pin);
|
||||
}
|
||||
delayUntil(currentMicros + refreshInterval * 1000UL);
|
||||
}
|
||||
|
||||
// Private function to reposition servo
|
||||
@ -238,20 +240,25 @@ void PCA9685::writeDevice(uint8_t pin, int value) {
|
||||
DIAG(F("PCA9685 I2C:x%x WriteDevice Pin:%d Value:%d"), _I2CAddress, pin, value);
|
||||
#endif
|
||||
// Wait for previous request to complete
|
||||
requestBlock.wait();
|
||||
// Set up new request.
|
||||
outputBuffer[0] = PCA9685_FIRST_SERVO + 4 * pin;
|
||||
outputBuffer[1] = 0;
|
||||
outputBuffer[2] = (value == 4095 ? 0x10 : 0); // 4095=full on
|
||||
outputBuffer[3] = value & 0xff;
|
||||
outputBuffer[4] = value >> 8;
|
||||
I2CManager.queueRequest(&requestBlock);
|
||||
uint8_t status = requestBlock.wait();
|
||||
if (status != I2C_STATUS_OK) {
|
||||
_deviceState = DEVSTATE_FAILED;
|
||||
DIAG(F("PCA9685 I2C:x%x failed %S"), _I2CAddress, I2CManager.getErrorMessage(status));
|
||||
} else {
|
||||
// Set up new request.
|
||||
outputBuffer[0] = PCA9685_FIRST_SERVO + 4 * pin;
|
||||
outputBuffer[1] = 0;
|
||||
outputBuffer[2] = (value == 4095 ? 0x10 : 0); // 4095=full on
|
||||
outputBuffer[3] = value & 0xff;
|
||||
outputBuffer[4] = value >> 8;
|
||||
I2CManager.queueRequest(&requestBlock);
|
||||
}
|
||||
}
|
||||
|
||||
// Display details of this device.
|
||||
void PCA9685::_display() {
|
||||
DIAG(F("PCA9685 I2C:x%x Configured on Vpins:%d-%d"), _I2CAddress, (int)_firstVpin,
|
||||
(int)_firstVpin+_nPins-1);
|
||||
DIAG(F("PCA9685 I2C:x%x Configured on Vpins:%d-%d %S"), _I2CAddress, (int)_firstVpin,
|
||||
(int)_firstVpin+_nPins-1, (_deviceState==DEVSTATE_FAILED) ? F("OFFLINE") : F(""));
|
||||
}
|
||||
|
||||
// Internal helper function for this device
|
||||
|
45
IO_VL53L0X.h
45
IO_VL53L0X.h
@ -44,7 +44,11 @@
|
||||
* all VL53L0X modules are turned off, the driver works through each module in turn by
|
||||
* setting XSHUT to HIGH to turn the module on,, then writing the module's desired I2C address.
|
||||
* In this way, many VL53L0X modules can be connected to the one I2C bus, each one
|
||||
* using with a distinct I2C address.
|
||||
* using a distinct I2C address.
|
||||
*
|
||||
* WARNING: If the device's XSHUT pin is not connected, then it is very prone to noise,
|
||||
* and the device may even reset when handled. If you're not using XSHUT, then it's
|
||||
* best to tie it to +5V.
|
||||
*
|
||||
* The driver is configured as follows:
|
||||
*
|
||||
@ -98,7 +102,6 @@ private:
|
||||
bool _value;
|
||||
bool _initialising = true;
|
||||
uint8_t _entryCount = 0;
|
||||
unsigned long _lastEntryTime = 0;
|
||||
bool _scanInProgress = false;
|
||||
// Register addresses
|
||||
enum : uint8_t {
|
||||
@ -134,8 +137,9 @@ protected:
|
||||
_entryCount = 3;
|
||||
} else {
|
||||
_entryCount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _loop(unsigned long currentMicros) override {
|
||||
if (_initialising) {
|
||||
switch (_entryCount++) {
|
||||
@ -156,11 +160,17 @@ protected:
|
||||
I2CManager.write(VL53L0X_I2C_DEFAULT_ADDRESS, 2, VL53L0X_REG_I2C_SLAVE_DEVICE_ADDRESS, _i2cAddress);
|
||||
break;
|
||||
case 3:
|
||||
// After two more loops, check if device has been configured.
|
||||
if (I2CManager.exists(_i2cAddress)) {
|
||||
#ifdef DIAG_IO
|
||||
_display();
|
||||
#endif
|
||||
// Set 2.8V mode
|
||||
write_reg(VL53L0X_CONFIG_PAD_SCL_SDA__EXTSUP_HV,
|
||||
read_reg(VL53L0X_CONFIG_PAD_SCL_SDA__EXTSUP_HV) | 0x01);
|
||||
} else {
|
||||
DIAG(F("VL53L0X I2C:x%x device not responding"), _i2cAddress);
|
||||
_deviceState = DEVSTATE_FAILED;
|
||||
}
|
||||
_initialising = false;
|
||||
_entryCount = 0;
|
||||
@ -168,14 +178,17 @@ protected:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (_lastEntryTime - currentMicros > 10000UL) {
|
||||
// Service device every 10ms
|
||||
_lastEntryTime = currentMicros;
|
||||
} else {
|
||||
|
||||
if (!_scanInProgress) {
|
||||
// Not scanning, so initiate a scan
|
||||
write_reg(VL53L0X_REG_SYSRANGE_START, 0x01);
|
||||
_scanInProgress = true;
|
||||
uint8_t status = write_reg(VL53L0X_REG_SYSRANGE_START, 0x01);
|
||||
if (status != I2C_STATUS_OK) {
|
||||
DIAG(F("VL53L0X I2C:x%x Error:%d %S"), _i2cAddress, status, I2CManager.getErrorMessage(status));
|
||||
_deviceState = DEVSTATE_FAILED;
|
||||
_value = false;
|
||||
} else
|
||||
_scanInProgress = true;
|
||||
|
||||
} else {
|
||||
// Scan in progress, so check for completion.
|
||||
@ -198,8 +211,11 @@ protected:
|
||||
_scanInProgress = false;
|
||||
}
|
||||
}
|
||||
// Next entry in 10 milliseconds.
|
||||
delayUntil(currentMicros + 10000UL);
|
||||
}
|
||||
}
|
||||
|
||||
// For analogue read, first pin returns distance, second pin is signal strength, and third is ambient level.
|
||||
int _readAnalogue(VPIN vpin) override {
|
||||
int pin = vpin - _firstVpin;
|
||||
@ -214,13 +230,16 @@ protected:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// For digital read, return the same value for all pins.
|
||||
int _read(VPIN) override {
|
||||
return _value;
|
||||
}
|
||||
|
||||
void _display() override {
|
||||
DIAG(F("VL53L0X I2C:x%x Configured on Vpins:%d-%d On:%dmm Off:%dmm"),
|
||||
_i2cAddress, _firstVpin, _firstVpin+_nPins-1, _onThreshold, _offThreshold);
|
||||
DIAG(F("VL53L0X I2C:x%x Configured on Vpins:%d-%d On:%dmm Off:%dmm %S"),
|
||||
_i2cAddress, _firstVpin, _firstVpin+_nPins-1, _onThreshold, _offThreshold,
|
||||
(_deviceState==DEVSTATE_FAILED) ? F("OFFLINE") : F(""));
|
||||
}
|
||||
|
||||
|
||||
@ -228,12 +247,12 @@ private:
|
||||
inline uint16_t makeuint16(byte lsb, byte msb) {
|
||||
return (((uint16_t)msb) << 8) | lsb;
|
||||
}
|
||||
void write_reg(uint8_t reg, uint8_t data) {
|
||||
uint8_t write_reg(uint8_t reg, uint8_t data) {
|
||||
// write byte to register
|
||||
uint8_t outBuffer[2];
|
||||
outBuffer[0] = reg;
|
||||
outBuffer[1] = data;
|
||||
I2CManager.write(_i2cAddress, outBuffer, 2);
|
||||
return I2CManager.write(_i2cAddress, outBuffer, 2);
|
||||
}
|
||||
uint8_t read_reg(uint8_t reg) {
|
||||
// read byte from register register
|
||||
|
Loading…
Reference in New Issue
Block a user