Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 46 additions & 20 deletions src/devices/Arduino/FirmataDevice.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ internal sealed class FirmataDevice : IDisposable
private Stream? _firmataStream;
private Thread? _inputThread;
private List<SupportedPinConfiguration> _supportedPinConfigurations;
private bool _analogPinMappingsReceived = false;
private BlockingConcurrentBag<byte[]> _pendingResponses;
private List<PinValue> _lastPinValues;
private Dictionary<int, uint> _lastAnalogValues;
Expand Down Expand Up @@ -87,6 +88,7 @@ public FirmataDevice(List<SupportedMode> supportedModes)
InputThreadShouldExit = false;
_dataReceived = new AutoResetEvent(false);
_supportedPinConfigurations = new List<SupportedPinConfiguration>();
_analogPinMappingsReceived = false;
_synchronisationLock = new object();
_lastPinValues = new List<PinValue>();
_lastPinValueLock = new object();
Expand All @@ -107,6 +109,11 @@ internal List<SupportedPinConfiguration> PinConfigurations
{
get
{
if (_analogPinMappingsReceived == false)
{
return new List<SupportedPinConfiguration>();
}

return _supportedPinConfigurations;
}
}
Expand Down Expand Up @@ -415,7 +422,7 @@ private void ProcessInput()

case FirmataSysexCommand.CAPABILITY_RESPONSE:
{
_supportedPinConfigurations.Clear();
List<SupportedPinConfiguration> newPinConfigurations = new List<SupportedPinConfiguration>();
int idx = 1;
SupportedPinConfiguration currentPin = new SupportedPinConfiguration(0);
int pin = 0;
Expand All @@ -424,7 +431,7 @@ private void ProcessInput()
int mode = raw_data[idx++];
if (mode == 0x7F)
{
_supportedPinConfigurations.Add(currentPin);
newPinConfigurations.Add(currentPin);
currentPin = new SupportedPinConfiguration(++pin);
continue;
}
Expand Down Expand Up @@ -452,8 +459,10 @@ private void ProcessInput()
}
}

_analogPinMappingsReceived = false;
_supportedPinConfigurations = newPinConfigurations;
// Add 8 entries, so that later we do not need to check whether a port (bank) is complete
_lastPinValues = new PinValue[_supportedPinConfigurations.Count + 8].ToList();
_lastPinValues = new PinValue[newPinConfigurations.Count + 8].ToList();
_dataReceived.Set();
// Do not add the last instance, should also be terminated by 0xF7
}
Expand Down Expand Up @@ -481,6 +490,7 @@ private void ProcessInput()
pin++;
}

_analogPinMappingsReceived = true;
_dataReceived.Set();
}

Expand Down Expand Up @@ -863,28 +873,44 @@ internal void QueryCapabilities()
throw new ObjectDisposedException(nameof(FirmataDevice));
}

lock (_synchronisationLock)
while (true)
{
_dataReceived.Reset();
_firmataStream.WriteByte((byte)FirmataCommand.START_SYSEX);
_firmataStream.WriteByte((byte)FirmataSysexCommand.CAPABILITY_QUERY);
_firmataStream.WriteByte((byte)FirmataCommand.END_SYSEX);
bool result = _dataReceived.WaitOne(DefaultReplyTimeout);
if (result == false)
lock (_synchronisationLock)
{
throw new TimeoutException("Timeout waiting for device capabilities");
}
_dataReceived.Reset();
_firmataStream.WriteByte((byte)FirmataCommand.START_SYSEX);
_firmataStream.WriteByte((byte)FirmataSysexCommand.CAPABILITY_QUERY);
_firmataStream.WriteByte((byte)FirmataCommand.END_SYSEX);
bool result = _dataReceived.WaitOne(DefaultReplyTimeout);
if (result == false)
{
throw new TimeoutException("Timeout waiting for device capabilities");
}

_dataReceived.Reset();
_firmataStream.WriteByte((byte)FirmataCommand.START_SYSEX);
_firmataStream.WriteByte((byte)FirmataSysexCommand.ANALOG_MAPPING_QUERY);
_firmataStream.WriteByte((byte)FirmataCommand.END_SYSEX);
result = _dataReceived.WaitOne(DefaultReplyTimeout);
if (result == false)
{
throw new TimeoutException("Timeout waiting for PWM port mappings");
_dataReceived.Reset();
_firmataStream.WriteByte((byte)FirmataCommand.START_SYSEX);
_firmataStream.WriteByte((byte)FirmataSysexCommand.ANALOG_MAPPING_QUERY);
_firmataStream.WriteByte((byte)FirmataCommand.END_SYSEX);
result = _dataReceived.WaitOne(DefaultReplyTimeout);
if (result == false)
{
throw new TimeoutException("Timeout waiting for PWM port mappings");
}

if (PinConfigurations.Count == 0)
{
// The device may be resetting itself as part of opening the serial port (this is the typical
// behavior of the Arduino Uno, but not of most newer boards)
goto wait;
}

break;
}

wait:
Thread.Sleep(100);
}

}

private void StopThread()
Expand Down
Loading