public override void ThreadFunction() { ErrorCallback(this, "Network processing startup.", "", false); bool should_exit = false; byte[] remote_bytes = Array.Empty <byte>(); NetworkHeader read_header = null; Utf8JsonWriter jsonwriter; lock (_thread_interlock) { jsonwriter = new Utf8JsonWriter(DeviceStream); CommandQueue.Clear(); } byte[] read_buffer = new byte[block_size]; void DataReader() { try { lock (_thread_interlock) DeviceStream.BeginRead(read_buffer, 0, read_buffer.Length, delegate(IAsyncResult ar) { try { lock (_thread_interlock) { if (DeviceStream == null) { return; } int len = DeviceStream.EndRead(ar); int pos = remote_bytes.Length; Array.Resize(ref remote_bytes, pos + len); Buffer.BlockCopy(read_buffer, 0, remote_bytes, pos, len); } } catch (Exception e) { bool exiting; lock (_thread_interlock) exiting = _thread_end; if (!exiting) { ErrorCallback(this, "Network error.", e.Message, false); } } DataReader(); }, null); } catch (Exception e) { bool exiting; lock (_thread_interlock) exiting = _thread_end; if (!exiting) { ErrorCallback(this, "Network error.", e.Message, false); } } } DataReader(); while (!should_exit) { Thread.Yield(); long consumed = 0; if (read_header == null) { try { lock (_thread_interlock) { if (remote_bytes.Length > 0) { Utf8JsonReader jsonreader = new Utf8JsonReader(new ReadOnlySpan <byte>(remote_bytes)); read_header = JsonSerializer.Deserialize <NetworkHeader>(ref jsonreader); consumed = jsonreader.BytesConsumed; } } } catch (JsonException) { } } else { CommandBase received_command = null; try { lock (_thread_interlock) { if (remote_bytes.Length > 0) { Utf8JsonReader jsonreader = new Utf8JsonReader(new ReadOnlySpan <byte>(remote_bytes)); switch (read_header.ObjectType) { case TransmissionType.Nothing: break; case TransmissionType.Ready: received_command = JsonSerializer.Deserialize <ReadyCommand>(ref jsonreader); break; case TransmissionType.Panic: received_command = JsonSerializer.Deserialize <PanicCommand>(ref jsonreader); break; case TransmissionType.Levels: received_command = JsonSerializer.Deserialize <LevelsCommand>(ref jsonreader); break; case TransmissionType.Raw: received_command = JsonSerializer.Deserialize <RawCommand>(ref jsonreader); break; case TransmissionType.Mode: received_command = JsonSerializer.Deserialize <ModeCommand>(ref jsonreader); break; case TransmissionType.Response: received_command = JsonSerializer.Deserialize <DeviceResponse>(ref jsonreader); break; case TransmissionType.Request: break; case TransmissionType.Error: received_command = JsonSerializer.Deserialize <ErrorCommand>(ref jsonreader); break; } consumed = jsonreader.BytesConsumed; } } } catch (JsonException) { } if (received_command != null) { switch (read_header.ObjectType) { case TransmissionType.Nothing: break; case TransmissionType.Ready: QueueStateCallback(this, 0); break; case TransmissionType.Panic: MassLevelSetCallback(this, 0, 0, 0, true); ErrorCallback(this, "PANIC!", "Panic received from remote!", true); break; case TransmissionType.Levels: LevelsCommand levels = (LevelsCommand)received_command; LastA = levels.A; LastB = levels.B; MassLevelSetCallback(this, levels.A, levels.B, levels.MA, levels.Mode == ControlMode.absolute); break; case TransmissionType.Raw: RawCommand raw = (RawCommand)received_command; if (raw.Address == (int)AddressByte.Pot_A) { LastA = raw.Data; } if (raw.Address == (int)AddressByte.Pot_B) { LastB = raw.Data; } StateUpdatedCallback(this, raw.Address, raw.Data); break; case TransmissionType.Mode: ModeCommand mode = (ModeCommand)received_command; StateUpdatedCallback(this, (int)AddressByte.ModeOverride, mode.Mode); StateUpdatedCallback(this, (int)AddressByte.Pot_MA, mode.MA); break; case TransmissionType.Request: break; case TransmissionType.Response: DeviceResponse response = (DeviceResponse)received_command; DataReturnedCallback(this, response.Address, response.Data); double current_unixtime = UnixTime.Current(); LevelEvent level = new LevelEvent() { unixtime = current_unixtime }; lock (_thread_interlock) { if (response.Address == (int)AddressByte.PulseAmp_A) { level.level = (int)Math.Sqrt(LastA * response.Data); AmpHistoryA.Add(level); } if (response.Address == (int)AddressByte.PulseAmp_B) { level.level = (int)Math.Sqrt(LastB * response.Data); AmpHistoryB.Add(level); } } break; case TransmissionType.Error: ErrorCommand error = (ErrorCommand)received_command; ErrorCallback(this, error.Error, error.Details, false); break; } read_header = null; } } if (consumed > 0) { lock (_thread_interlock) { byte[] remaining = new byte[remote_bytes.Length - consumed]; Buffer.BlockCopy(remote_bytes, (int)consumed, remaining, 0, remaining.Length); remote_bytes = remaining; } } lock (_thread_interlock) { if (CommandQueue.Count > 0) { CommandBase command = CommandQueue.First(); CommandQueue.RemoveAt(0); NetworkHeader write_header = new NetworkHeader() { ObjectType = command.ObjectType }; try { JsonSerializer.Serialize(jsonwriter, write_header, typeof(NetworkHeader)); jsonwriter.Flush(); jsonwriter.Reset(); switch (command.ObjectType) { case TransmissionType.Nothing: break; case TransmissionType.Ready: JsonSerializer.Serialize(jsonwriter, (ReadyCommand)command, typeof(ReadyCommand)); break; case TransmissionType.Panic: JsonSerializer.Serialize(jsonwriter, (PanicCommand)command, typeof(PanicCommand)); break; case TransmissionType.Levels: JsonSerializer.Serialize(jsonwriter, (LevelsCommand)command, typeof(LevelsCommand)); break; case TransmissionType.Raw: JsonSerializer.Serialize(jsonwriter, (RawCommand)command, typeof(RawCommand)); break; case TransmissionType.Mode: JsonSerializer.Serialize(jsonwriter, (ModeCommand)command, typeof(ModeCommand)); break; case TransmissionType.Request: JsonSerializer.Serialize(jsonwriter, (RequestCommand)command, typeof(RequestCommand)); break; case TransmissionType.Response: JsonSerializer.Serialize(jsonwriter, (ResponseCommand)command, typeof(ResponseCommand)); break; case TransmissionType.Error: JsonSerializer.Serialize(jsonwriter, (ErrorCommand)command, typeof(ErrorCommand)); break; } jsonwriter.Flush(); jsonwriter.Reset(); } catch (JsonException) { } catch (IOException e) when(e.InnerException is SocketException) { _thread_end = true; ErrorCallback(this, "Network error.", e.InnerException.Message, false); } catch (IOException e) { _thread_end = true; ErrorCallback(this, "Network error.", e.Message, false); } catch (Exception e) { _thread_end = true; ErrorCallback(this, "Network error.", e.Message, false); } if (CommandQueue.Count == 0 && command.ObjectType != TransmissionType.Ready) { CommandQueue.Add(new ReadyCommand()); } } should_exit = _thread_end; } } try { lock (_thread_interlock) { if (DeviceStream != null) { DeviceStream.Close(); DeviceStream.Dispose(); } DeviceStream = null; } } catch (Exception e) { ErrorCallback(this, "Network error.", e.Message, false); } ErrorCallback(this, "Network processing shutdown.", "", false); }
public override void SetLevels(LevelsCommand levels) { int A, B, MA; double current_unixtime = UnixTime.Current(); lock (_thread_interlock) { if (levels.Mode == ControlMode.absolute) { LastA = levels.A; LastB = levels.B; } else { LastA += levels.A; LastB += levels.B; } if (LastA > 255) { LastA = 255; } if (LastB > 255) { LastB = 255; } if (LastA < 0) { LastA = 0; } if (LastB < 0) { LastB = 0; } AmpHistoryA.Add(new LevelEvent() { unixtime = current_unixtime, level = LastA }); AmpHistoryB.Add(new LevelEvent() { unixtime = current_unixtime, level = LastB }); A = LastA; B = LastB; } StateUpdatedCallback(this, (int)AddressByte.Pot_A, A); StateUpdatedCallback(this, (int)AddressByte.Pot_B, B); if (levels.MA != 0) { lock (_thread_interlock) { LastMA += levels.MA; if (LastMA > 255) { LastMA = 255; } if (LastMA < 0) { LastMA = 0; } MA = LastMA; } StateUpdatedCallback(this, (int)AddressByte.Pot_MA, MA); } }
private void CheckResponse(ref byte[] input) { double current_unixtime = UnixTime.Current(); int expected_bytes = last_command.IsWrite() ? et232_success_sequence.Length : et232_read_response_length; if (input.Length < expected_bytes) { if (current_unixtime - last_command_time > command_timeout) { HandleCommandFailure("Device timeout."); input = Array.Empty <byte>(); } return; } byte[] result_bytes = input; int extra_bytes = result_bytes.Length - expected_bytes; if (extra_bytes > 0) { input = new byte[extra_bytes]; Buffer.BlockCopy(result_bytes, expected_bytes, input, 0, extra_bytes); } else { input = Array.Empty <byte>(); } bool error = false; if (last_command.IsWrite()) { for (int idx = 0; idx < et232_success_sequence.Length; idx++) { if (result_bytes[idx] != et232_success_sequence[idx]) { error = true; } } } else if (result_bytes.Last() != (byte)'\n') { error = true; } if (error) { HandleCommandFailure("Device error."); return; } int ScalingFunction(int user_level, int function) { return((int)(Math.Sqrt(user_level * function))); } command_retries = 0; if (last_command.IsWrite()) { if (last_command.Address == AddressByte.Pot_A) { lock (_thread_interlock) { Governor.RecordA(last_command.Data); LastA = last_command.Data; } } if (last_command.Address == AddressByte.Pot_B) { lock (_thread_interlock) { Governor.RecordB(last_command.Data); LastB = last_command.Data; } } if (last_command.Address == AddressByte.Pot_MA) { lock (_thread_interlock) LastMA = last_command.Data; } if (last_command.Address == AddressByte.ModeOverride) { lock (_thread_interlock) draining_queue = true; Thread.Sleep(mode_delay); StateUpdatedCallback(this, (int)last_command.Address, last_command.Data & ErosTek.ET232.Constants.ForceModeMask); } else { StateUpdatedCallback(this, (int)last_command.Address, last_command.Data); } } else { string result_string = Encoding.ASCII.GetString(result_bytes, 0, 2); try { int result_value = int.Parse(result_string, System.Globalization.NumberStyles.HexNumber); DataReturnedCallback(this, (int)last_command.Address, result_value); LevelEvent level = new LevelEvent() { unixtime = current_unixtime, level = result_value }; if (last_command.Address == AddressByte.PulseAmp_A) { lock (_thread_interlock) { level.level = ScalingFunction(LastA, level.level); AmpHistoryA.Add(level); } } if (last_command.Address == AddressByte.PulseAmp_B) { lock (_thread_interlock) { level.level = ScalingFunction(LastB, level.level); AmpHistoryB.Add(level); } } } catch (Exception) { List <string> details = result_bytes.Select(e => String.Format("0x{0,2:X2}", new object[] { e })).ToList(); ErrorCallback(this, "Device returned invalid data.", "Bytes: " + input.Length + " Data: " + String.Join(", ", details), false); } } last_command = null; lock (_thread_interlock) _state = State.ready; }