private void ReceiveEnd(IAsyncResult ar) { // Retrieve state var state = (ConnectionState)ar.AsyncState; // Complete read Int32 chunkLength; try { chunkLength = state.Connection.EndReceive(ar); } catch (ObjectDisposedException) // Occurs during in-flight disposal - we need to catch it for a graceful shutdown { return; // Abort read } catch (SocketException ex) // Occurs when there is a connection error { // Report error RaiseDeviceError(state, ex.Message, false); return; // Abort receive } // If the expected number of bytes hasn't arrived yet, wait for more bytes if (state.ReceiveBufferExpected != state.ReceiveBufferUsed) { // Receive more bytes ReceiveStart(state); return; } // If header hasn't been processed yet, process it if (null == state.ReceiveReceiveMessageType) { // Yes, this could have been in the switch below, but it made for some funky reading // Check sync bytes if (state.ReceiveBuffer[0] != 0x02 || state.ReceiveBuffer[1] != 0x55) { RaiseDeviceError(state, $"Incorrect sync bytes encountered ({state.ReceiveBuffer[0]},{state.ReceiveBuffer[1]}).", true); return; } // Decode message type state.ReceiveReceiveMessageType = (ReceiveMessageTypes)state.ReceiveBuffer[2]; // Decode message length and increase the number of bytes expected var messageLength = BitConverter.ToUInt16(state.ReceiveBuffer, 3); state.ReceiveBufferExpected += messageLength; // Receive more bytes ReceiveStart(state); return; } switch (state.ReceiveReceiveMessageType.Value) { case ReceiveMessageTypes.Hello: // Device is providing basic information about it state.Device = Device.Parse(state.ReceiveBuffer, 5); state.Connection.Send(new Byte[] { 0x02, 0x55 }); // Sync bytes state.Connection.Send((Byte)TransmitMessageTypes.HelloResponse); // Message type state.Connection.Send((UInt16)8); // Message length state.Connection.Send(TelematicsTime.Encode(DateTime.UtcNow)); // Time state.Connection.Send((UInt32)0); // Flags TODO: how to tell device to redirect to OEM? OnDeviceConnected?.Invoke(this, new OnDeviceConnectedArgs() { RemoteAddressString = state.RemoteAddressString, Device = state.Device }); break; case ReceiveMessageTypes.Records: // Device is providing records // It seems that MESSAGE contains multiple RECORDS // which contain multiple FIELDS // which contains multiple things which I'm going to call ATTRIBUTES // Attributes are the actual data. // // In summary: MESSAGE => RECORDS => FIELDS => ATTRIBUTES var position = 5; var records = new List <Record>(); while (position < state.ReceiveBufferExpected) { records.Add(Record.Parse(state.ReceiveBuffer, ref position)); } OnRecordsReceived?.Invoke(this, new OnRecordsReceivedArgs() { RemoteAddressString = state.RemoteAddressString, Device = state.Device, Records = records }); break; case ReceiveMessageTypes.CommitRequest: // Device asking us to confirm that we've successfully received and stored records // Send confirmation // TODO: When would we not confirm a commit? state.Connection.Send(new Byte[] { 0x02, 0x55 }); // Sync bytes state.Connection.Send((Byte)TransmitMessageTypes.CommitResponse); // Message type state.Connection.Send((UInt16)1); // Message length state.Connection.Send((Byte)1); // Success break; case ReceiveMessageTypes.VersionData: // Device providing version information (no idea what this is for!!) RaiseDeviceError(state, $"Version information received and discarded.", false); // TODO: do something with the information break; case ReceiveMessageTypes.TimeRequest: // Device asking for the current time state.Connection.Send(new Byte[] { 0x02, 0x55 }); // Sync bytes state.Connection.Send((Byte)TransmitMessageTypes.TimeResponse); // Message type state.Connection.Send((UInt16)4); // Message length state.Connection.Send(TelematicsTime.Encode(DateTime.UtcNow)); // Current time break; case ReceiveMessageTypes.AsyncMessageResponse: // Device is giving responses to async messages, which is not currently implemented, so should not be recieved RaiseDeviceError(state, $"Message async responses received and discarded.", false); // TODO: do something with the information break; default: RaiseDeviceError(state, $"Unsupported message type received ({state.ReceiveReceiveMessageType.Value}). Message discarded.", false); break; } // Receive more ResetState(state); ReceiveStart(state); }
public void DecodeOne() { Assert.Equal(new DateTime(2013, 01, 01, 0, 0, 1, DateTimeKind.Utc), TelematicsTime.Decode(1)); }
public void EncodeZero() { Assert.Equal((UInt32)0, TelematicsTime.Encode(new DateTime(2013, 01, 01, 0, 0, 0, DateTimeKind.Utc))); }
public void DecodeZero() { Assert.Equal(new DateTime(2013, 01, 01, 0, 0, 0, DateTimeKind.Utc), TelematicsTime.Decode(0)); }