private void DataReceived(IAsyncResult ar) { if (ConnectionState == ConnectionStates.Disconnected && CentralexState == CentralexStates.None) { return; } if (_client.Client == null) { Disconnect(); return; } int dataReadCount; try { dataReadCount = _client.Client.EndReceive(ar); } catch { Disconnect(); return; } if (dataReadCount == 0) { Disconnect(); return; } byte[] byteData = ar.AsyncState as byte[]; byte[] newData = byteData.Take(dataReadCount).ToArray(); if (ConnectionState == ConnectionStates.Connected) { if (newData[0] <= 0x09 || newData[0] >= 0x10 && newData[0] < 0x1F) { ConnectionState = ConnectionStates.ItelexTexting; } else { ConnectionState = ConnectionStates.AsciiTexting; } Update?.Invoke(); } if (ConnectionState == ConnectionStates.AsciiTexting) { // ascii string asciiText = Encoding.ASCII.GetString(newData, 0, newData.Length); asciiText = asciiText.Replace('@', CodeManager.ASC_WRU); Received?.Invoke(asciiText); _lastSendRecvIdleMs = Helper.GetTicksMs(); } else { // i-telex int dataPos = 0; while (dataPos + 2 <= newData.Length) { //Debug.WriteLine($"datapos={dataPos} cmd={newData[dataPos]:X02}"); int packetLen = newData[dataPos + 1] + 2; if (dataPos + packetLen > newData.Length) { // short packet data break; } byte[] packetData = new byte[packetLen]; Buffer.BlockCopy(newData, dataPos, packetData, 0, packetLen); dataPos += packetLen; if (packetData.Length >= 2 && packetData.Length >= packetData[1] + 2) { ItelexPacket packet = new ItelexPacket(packetData); //Debug.WriteLine($"packet={packet}"); DecodePacket(packet); } } } StartReceive(); #if false // if data comes in different frame (untested) if (newData.Length > 0) { // append newData to _incommingData byte[] newIncomingData = new byte[_incomingData.Length + newData.Length]; Buffer.BlockCopy(_incomingData, 0, newIncomingData, 0, _incomingData.Length); Buffer.BlockCopy(newData, 0, newIncomingData, _incomingData.Length, newData.Length); _incomingData = newData; } bool exitWhile = false; while (exitWhile) { exitWhile = true; if (_incomingData.Length > 2) { if (_incomingData[1] <= _incomingData.Length + 2) { // telegram complete } } } #endif }
private void DecodePacket(ItelexPacket packet) { /* * if (packet.CommandType != ItelexCommands.Ack) * { * //Logging.Instance.Log(LogTypes.Debug, TAG, nameof(DecodePacket), * // $"Recv packet {packet.CommandType} {packet.Command:X02} {packet.GetDebugData()}"); * Logging.Instance.Debug(TAG, nameof(DecodePacket), * $"Recv packet {packet.CommandType} {packet.GetDebugPacket()}"); * } * if (packet.CommandType != ItelexCommands.Heartbeat && packet.CommandType != ItelexCommands.Ack) * { * Debug.WriteLine($"Recv packet {packet.CommandType} {packet.GetDebugPacket()}"); * } */ switch ((ItelexCommands)packet.Command) { case ItelexCommands.Heartbeat: Logging.Instance.Debug(TAG, nameof(DecodePacket), $"recv heartbeat {packet.GetDebugPacket()}"); break; case ItelexCommands.DirectDial: Logging.Instance.Info(TAG, nameof(DecodePacket), $"recv direct dial cmd {packet.GetDebugPacket()}, number={packet.Data[0]}"); int directDial = packet.Data[0]; Message?.Invoke($"received direct dial cmd {directDial}"); if (directDial == _config.IncomingExtensionNumber) { ConnectInit(); } else { // not connected byte[] data = Encoding.ASCII.GetBytes("nc"); SendCmd(ItelexCommands.Reject, data); Message?.Invoke($"send reject ncc"); Disconnect(); } break; case ItelexCommands.BaudotData: if (packet.Len > 0) { Logging.Instance.AppendBinary(packet.Data, Logging.BinaryModes.Recv); string asciiStr = CodeManager.BaudotStringToAscii(packet.Data, ref _shiftState, _config.CodeSet, CodeManager.SendRecv.Recv); Logging.Instance.Debug(TAG, nameof(DecodePacket), $"recv baudot data {packet.Len} \"{CodeManager.AsciiToDebugStr(asciiStr)}\""); AddReceivedCharCount(packet.Data.Length); _lastSendRecvIdleMs = Helper.GetTicksMs(); Received?.Invoke(asciiStr); BaudotSendRecv?.Invoke(packet.Data); Update?.Invoke(); } break; case ItelexCommands.End: Logging.Instance.Info(TAG, nameof(DecodePacket), $"recv end cmd {packet.GetDebugPacket()}"); Disconnect(); break; case ItelexCommands.Reject: string reason = Encoding.ASCII.GetString(packet.Data, 0, packet.Data.Length); Logging.Instance.Info(TAG, nameof(DecodePacket), $"recv reject cmd {packet.GetDebugPacket()}, reason={reason}"); Message?.Invoke($"{LngText(LngKeys.Message_Reject)} {reason.ToUpper()} ({ReasonToString(reason).ToUpper()})"); if (CentralexState == CentralexStates.CentralexConnect && reason == "na") { CentralexState = CentralexStates.CentralexRejected; } else { Disconnect(); } break; case ItelexCommands.Ack: lock (_sendLock) { _n_ack = packet.Data[0]; _ackRecvFlag = true; _lastAckReceived = Helper.GetTicksMs(); } //Debug.WriteLine($"recv ack cmd {_n_ack} ({CharsAckCount})"); Logging.Instance.Debug(TAG, nameof(DecodePacket), $"recv ack cmd {packet.GetDebugPacket()} ack={_n_ack} ({CharsAckCount})"); Update?.Invoke(); break; case ItelexCommands.ProtocolVersion: string versionStr = ""; if (packet.Data.Length > 1) { // get version string versionStr = Encoding.ASCII.GetString(packet.Data, 1, packet.Data.Length - 1); versionStr = versionStr.TrimEnd('\x00'); // remove 00-byte suffix } Message?.Invoke($"received protocol version {packet.Data[0]:X2} '{versionStr}'"); Logging.Instance.Log(LogTypes.Info, TAG, nameof(DecodePacket), $"recv protocol version cmd {packet.GetDebugPacket()}, version={packet.Data[0]} '{versionStr}'"); if (_connectionDirection == ConnectionDirections.In) { // answer with own version SendVersionCodeCmd(); } break; case ItelexCommands.SelfTest: Logging.Instance.Log(LogTypes.Info, TAG, nameof(DecodePacket), $"recv self test cmd {packet.GetDebugPacket()}"); break; case ItelexCommands.RemoteConfig: Logging.Instance.Log(LogTypes.Info, TAG, nameof(DecodePacket), $"recv remote config cmd {packet.GetDebugPacket()}"); break; case ItelexCommands.RemoteConfirm: CentralexState = CentralexStates.CentralexConnected; break; case ItelexCommands.RemoteCall: SendAcceptCallRemoteCmd(); ConnectInit(); _connectionDirection = ConnectionDirections.In; if (_config.IncomingExtensionNumber != 0) { // set to connected and wait for direct dial command ConnectionState = ConnectionStates.TcpConnected; } else { // no direct dial command neccessary ConnectInit(); } Message?.Invoke($"{LngText(LngKeys.Message_IncomingConnection)} centralex"); Logging.Instance.Log(LogTypes.Info, TAG, nameof(Listener), $"incoming connection from centralex"); Update?.Invoke(); break; } }
public void SendCmd(int cmdCode, byte[] data = null) { if (ConnectionState == ConnectionStates.Disconnected && CentralexState == CentralexStates.None) { return; } if (_client.Client == null) { Disconnect(); return; } byte[] sendData; if (data != null) { sendData = new byte[data.Length + 2]; sendData[0] = (byte)cmdCode; sendData[1] = (byte)data.Length; Buffer.BlockCopy(data, 0, sendData, 2, data.Length); } else { sendData = new byte[2]; sendData[0] = (byte)cmdCode; sendData[1] = 0; } ItelexPacket packet = new ItelexPacket(sendData); if (packet.CommandType != ItelexCommands.Ack) { //Logging.Instance.Log(LogTypes.Debug, TAG, nameof(DecodePacket), // $"Send packet {packet.CommandType} {packet.Command:X02} {packet.GetDebugData()}"); Logging.Instance.Log(LogTypes.Debug, TAG, nameof(SendCmd), $"Send packet {packet.CommandType} {packet.GetDebugPacket()}"); } switch ((ItelexCommands)packet.Command) { case ItelexCommands.BaudotData: AddTransCharCount(data.Length); Logging.Instance.AppendBinary(packet.Data, Logging.BinaryModes.Send); //Debug.WriteLine($"BaudotData {packet.GetDebugData()}"); break; case ItelexCommands.Heartbeat: case ItelexCommands.Ack: break; case ItelexCommands.DirectDial: case ItelexCommands.End: case ItelexCommands.Reject: case ItelexCommands.ProtocolVersion: case ItelexCommands.SelfTest: case ItelexCommands.RemoteConfig: break; } try { _client.Client.BeginSend(sendData, 0, sendData.Length, SocketFlags.None, EndSend, null); } catch (Exception ex) { Logging.Instance.Error(TAG, nameof(SendCmd), "", ex); Disconnect(); } }