MissionPlanner
MissionPlanner copied to clipboard
`The semaphore timeout period has expired` exception followed by disconnect
Issue details
On my setup, MP is connected via USB CDC to a custom Radio Link board which is designed in a way to guarantee data delivery to a remote end (UAV). When (because of whatever reason) a connection between two Radio Link boards is lost, data packets from MP start to accumulate in the Link's USB buffer which has a limited size. When the Link connection is restored, the content of the buffer is transmitted to a remote end and everything works well. However, if the connection is lost for more than ~5 seconds, the buffer gets full and the USB hardware on the Link board starts to respond with USB NAKs to the host, indicating that it is not able to receive because there is no room for the new data. This is natural flow control on the USB bus, just like RTS/CTS.
The issue happens when the Link responds with NAKs for some period of time. Because of ( 500 ms ?? ) timeout, this line of code throws an exception and the MP disconnects from a port.
I think this behavior is wrong, MP should ignore such write timeouts, they are not critical anyway. Or, at least, not disconnect from a port when a timeout happens. I may be wrong, but my suggestion is to decrease the write timeout to a sane minimum and simply ignore all write timeout exceptions. This should make the connection much more reliable.
Version
1.3.80
Platform
[ X ] All [ ] AntennaTracker [ ] Copter [ ] Plane [ ] Rover [ ] Sub
Airframe type
Any
Hardware type
Any
Logs
ERROR MissionPlanner.MainV2 - System.IO.IOException: The semaphore timeout period has expired.
at System.IO.Ports.InternalResources.WinIOError(Int32 errorCode, String str)
at System.IO.Ports.SerialStream.EndWrite(IAsyncResult asyncResult)
at System.IO.Ports.SerialStream.Write(Byte[] array, Int32 offset, Int32 count, Int32 timeout)
at System.IO.Ports.SerialPort.Write(Byte[] buffer, Int32 offset, Int32 count)
at MissionPlanner.Comms.WinSerialPort.MissionPlanner.Comms.ICommsSerial.Write(Byte[] buffer, Int32 offset, Int32 count)
at MissionPlanner.Comms.SerialPort.Write(Byte[] buffer, Int32 offset, Int32 count) in C:\Users\mich1\Desktop\CubePilot\MissionPlanner\ExtLibs\Comms\CommsSerialPort.cs:line 183
at MissionPlanner.MAVLinkInterface.generatePacket(Int32 messageType, Object indata, Int32 sysid, Int32 compid, Boolean forcemavlink2, Boolean forcesigning) in C:\Users\mich1\Desktop\CubePilot\MissionPlanner\ExtLibs\ArduPilot\Mavlink\MAVLinkInterface.cs:line 1345
at MissionPlanner.MAVLinkInterface.sendPacket(Object indata, Int32 sysid, Int32 compid) in C:\Users\mich1\Desktop\CubePilot\MissionPlanner\ExtLibs\ArduPilot\Mavlink\MAVLinkInterface.cs:line 1135
at MissionPlanner.MainV2.<SerialReader>d__131.MoveNext() in C:\Users\mich1\Desktop\CubePilot\MissionPlanner\MainV2.cs:line 3032
INFO MissionPlanner.Utilities.TerrainFollow - OnPacketReceived remove to packets
INFO MissionPlanner.MAVLinkInterface - set giveComport current False new False
INFO MissionPlanner.Comms.WinSerialPort - Closing port COM82
If you are able to modify and compile the code yourself a quick fix is to catch and log the exception. I had to do this for hardware debugging since it also times out when you hit a breakpoint and suspend on the ArduPilot device.
You can modify the relevant write function in CommsSerialPort.cs (MissionPlanner.Comms subproject) as follows.
public void Write(byte[] buffer, int offset, int count)
{
try
{
_baseport.Write(buffer, offset, count);
}
catch(Exception ex)
{
log.Error(ex.Message);
}
}