diff --git a/ShimmerAPI/ShimmerAPI/ShimmerBluetooth.cs b/ShimmerAPI/ShimmerAPI/ShimmerBluetooth.cs index 55e4bd2..a625c6d 100644 --- a/ShimmerAPI/ShimmerAPI/ShimmerBluetooth.cs +++ b/ShimmerAPI/ShimmerAPI/ShimmerBluetooth.cs @@ -466,6 +466,7 @@ public enum PacketTypeShimmer2 : byte //Note that most packet SET_MAG_SAMPLING_RATE_COMMAND = 0x3A, MAG_SAMPLING_RATE_RESPONSE = 0x3B, GET_MAG_SAMPLING_RATE_COMMAND = 0x3C, + NACK_COMMAND = 0xFE, ACK_COMMAND = 0xFF }; @@ -1238,6 +1239,51 @@ void ConnectTimerElapsed(object sender, ElapsedEventArgs e) TimerConnect.Stop(); } + /// + /// The Shimmer answered a command with NACK (0xFE) rather than ACK: it has + /// refused that command, which is not the same as the link being gone. + /// + /// + /// Before this existed a 0xFE fell through to the switch default. While + /// streaming that logged "Misaligned ByteStream Detected" and discarded the + /// packet in progress; otherwise it was dropped silently. Either way the + /// reply the caller was waiting for never arrived, ReadByte() carried on + /// timing out, and once StreamTimeOutCount passed 10 the API raised + /// "Connection lost" and disconnected - roughly ten seconds after a refusal + /// the device had already reported cleanly. + /// + /// The firmware refuses more than it used to: every command except + /// SET_SD_SYNC_COMMAND and ACK while SD sync is enabled, any SET while the + /// device is sensing, a sync-mode mismatch, an out-of-range InfoMem or + /// calibration write, and several commands it accepts but never implemented. + /// + /// Override to surface the refusal to the application; the notification + /// raised below is the default. + /// + protected virtual void ProcessNackFromCommand() + { + System.Console.WriteLine("NACK Received - the Shimmer refused the command"); + + /* The NACK is the whole response packet, so the CRC bytes the firmware + * appended to it are still in the stream and would otherwise be read as + * the next packet header. */ + if (BluetoothCRCMode != BTCRCMode.OFF) + { + for (int k = 0; k < (int)BluetoothCRCMode; k++) + { + ReadByte(); + } + } + + /* A refused START_STREAMING never reaches SHIMMER_STATE_STREAMING, so + * clear the wait rather than leaving it set for the rest of the session. */ + mWaitingForStartStreamingACK = false; + + CustomEventArgs newEventArgs = new CustomEventArgs( + (int)ShimmerIdentifier.MSG_IDENTIFIER_NOTIFICATION_MESSAGE, "Command refused by the Shimmer"); + OnNewEvent(newEventArgs); + } + public void ReadData() { List buffer = new List(); @@ -1355,6 +1401,9 @@ public void ReadData() buffer.Clear(); } break; + case (byte)PacketTypeShimmer2.NACK_COMMAND: + ProcessNackFromCommand(); + break; case (byte)PacketTypeShimmer2.ACK_COMMAND: //Since the ack always proceeds the instreamcmd if (StreamingACKReceived) @@ -1554,6 +1603,9 @@ public void ReadData() case (byte)PacketTypeShimmer3.INTERNAL_EXP_POWER_ENABLE_RESPONSE: SetInternalExpPower(ReadByte()); break; + case (byte)PacketTypeShimmer2.NACK_COMMAND: + ProcessNackFromCommand(); + break; case (byte)PacketTypeShimmer2.ACK_COMMAND: System.Console.WriteLine("ACK Received"); if (mWaitingForStartStreamingACK)