/// <summary> /// Serializes and pushes object to the queue with CRC calculation /// </summary> /// <param name="in_object">Object to push (must be Serializable)</param> /// <returns>True if success, false if there is no space left in the queue</returns> public bool Push(byte in_interface, object in_object) { int packet_index; UInt16 crc; // reserve storage for packet packet_index = ReservePushBuffer(); if (packet_index == InvalidPacketIndex) { return(false); } // serialize packet byte[] raw_packet_buffer = m_packets[packet_index].Buffer; GCHandle handle = GCHandle.Alloc(raw_packet_buffer, GCHandleType.Pinned); IntPtr buffer = handle.AddrOfPinnedObject(); Marshal.StructureToPtr(in_object, buffer, false); handle.Free(); // update CRC int raw_packet_size = Marshal.SizeOf(in_object); crc = CRC16.CalculateForBlock(CRC16.InitValue, raw_packet_buffer, raw_packet_size); raw_packet_buffer[raw_packet_size + 0] = ByteAccess.LowByte(crc); raw_packet_buffer[raw_packet_size + 1] = ByteAccess.HighByte(crc); // change buffer state m_packets[packet_index].Interface = in_interface; m_packets[packet_index].Length = (byte)(raw_packet_size + PacketConstants.PacketCRCLength); m_packets[packet_index].Timestamp = DateTime.Now; m_packets[packet_index].State = PacketBufferState.Valid; return(true); }
/// <summary> /// Send packets over the opened socket (internal function only, no error checking, locking, etc. mechanism is implemented) /// Only CRC is calculated before sending packet /// </summary> /// <param name="in_endpoint"></param> /// <param name="in_packet"></param> private void InternalPacketSend(EndPoint in_endpoint, byte[] in_packet) { // copy packet to the buffer in_packet.CopyTo(m_transmit_buffer, 0); // calculate and store CRC UInt16 crc; crc = CRC16.CalculateForBlock(CRC16.InitValue, in_packet, in_packet.Length); m_transmit_buffer[in_packet.Length] = ByteAccess.LowByte(crc); m_transmit_buffer[in_packet.Length + 1] = ByteAccess.HighByte(crc); // send packet m_client.BeginSendTo(m_transmit_buffer, 0, in_packet.Length + PacketConstants.PacketCRCLength, 0, in_endpoint, new AsyncCallback(SendCallback), this); }
/// <summary> /// Main thread function /// </summary> public void Run() { bool event_occured; int i; UInt16 crc; AsyncCallback receiver_callback = new AsyncCallback(ReceiveCallback); // create endpoints m_receiver_endpoint = new IPEndPoint(IPAddress.Any, UDPLocalPort); // init socket m_timestamp = DateTime.MinValue; m_client = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); m_client.Blocking = false; m_client.EnableBroadcast = true; m_client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); m_client.Bind(m_receiver_endpoint); // init m_upstream_bytes = 0; m_downstream_bytes = 0; // start data reception m_client.BeginReceive(m_receive_buffer, 0, m_receive_buffer.Length, 0, receiver_callback, this); // communication loop while (!m_stop_requested) { // wait for event event_occured = m_thread_event.WaitOne(ThreadWaitTimeout); // exit loop if thread must be stopped if (m_stop_requested) { break; } // process received data if (m_received_data_length > 0) { if (m_received_data_length > 2) { // check CRC crc = CRC16.CalculateForBlock(CRC16.InitValue, m_receive_buffer, m_received_data_length - 2); if (ByteAccess.LowByte(crc) == m_receive_buffer[m_received_data_length - 2] && ByteAccess.HighByte(crc) == m_receive_buffer[m_received_data_length - 1]) { // CRC OK -> continue processing received packet PacketType type = (PacketType)m_receive_buffer[PacketConstants.TypeOffset]; // update statistics Interlocked.Add(ref m_upstream_bytes, m_received_data_length); // process received packet switch (type) { // process device annnounce packet case PacketType.CommDeviceAnnounce: { PacketDeviceAnnounce device_info; // get announce packet device_info = (PacketDeviceAnnounce)RawBinarySerialization.DeserializeObject(m_receive_buffer, typeof(PacketDeviceAnnounce)); // check if it is already on the list of active devices DeviceInfo current_device_info = m_detected_devices.Find(x => x.UniqueID == device_info.UniqueID); if (current_device_info != null) { // device is on the list current_device_info.HostAnnouncePending = true; current_device_info.LastInfoTimestamp = DateTime.Now; } else { DeviceInfo new_device = new DeviceInfo(device_info); new_device.HostAnnouncePending = true; if (new_device.Address != IPAddress.None) { m_detected_devices.Add(new_device); if (m_detected_devices.Count == 1) { lock (m_detected_devices) { m_current_device = m_detected_devices[0]; } } } } } break; default: // process received data if (m_received_data_length <= PacketConstants.PacketMaxLength) { m_communication_manager.StoreReceivedPacket(m_communication_channel_index, m_receive_buffer, (byte)m_received_data_length); } break; } } } // restart reception try { m_received_data_length = 0; m_client.BeginReceive(m_receive_buffer, 0, m_receive_buffer.Length, 0, receiver_callback, this); } catch { // TODO: error handling } } // send host announce for devices for (i = 0; i < m_detected_devices.Count; i++) { IPAddress address_mask = new IPAddress(new byte[] { 255, 255, 255, 0 }); if (m_detected_devices[i].HostAnnouncePending) { IPAddress local_ip = GetLocalIPAddress(m_detected_devices[i].Address, address_mask); if (m_sender_lock.Wait(0)) { // create host info packet PacketHostAnnounce info = new PacketHostAnnounce(); info.Address = (uint)IPAddress.NetworkToHostOrder(BitConverter.ToInt32(local_ip.GetAddressBytes(), 0)); byte[] packet = RawBinarySerialization.SerializeObject(info); // send host info packet EndPoint transmitter_endpoint = new IPEndPoint(m_detected_devices[i].Address, UDPRemotePort); InternalPacketSend(transmitter_endpoint, packet); m_detected_devices[i].HostAnnouncePending = false; } } } // delete unreachable or connectecd devices from the list DateTime current_timestamp = DateTime.Now; i = 0; while (i < m_detected_devices.Count) { // if devlice is silent for a while -> remove from the list if ((current_timestamp - m_detected_devices[i].LastInfoTimestamp).TotalMilliseconds > DeviceAnnounceTimeout) { m_detected_devices.RemoveAt(i); } else { i++; } } } // close socket m_client.Shutdown(SocketShutdown.Both); Thread.Sleep(10); m_client.Close(); // thread is finished m_thread_stopped.Set(); }
/// <summary> /// Main thread function /// </summary> public void Run() { bool event_occured; UInt16 crc; int received_data_pos; int received_packet_pos; // init SLIPs m_receiver_slip.ResetDecoder(); try { m_serial_port = new SerialPort(PortName, BaudRate, Parity.None, 8, StopBits.One); m_serial_port.ReadTimeout = 50; m_serial_port.WriteTimeout = 50; m_serial_port.ReadBufferSize = 4096; m_serial_port.Open(); } catch { return; } // init m_upstream_bytes = 0; m_downstream_bytes = 0; received_data_pos = 0; received_packet_pos = 0; // start data reception m_read_pending = true; m_serial_port.BaseStream.BeginRead(m_receive_data_buffer, 0, m_receive_data_buffer.Length, m_receiver_callback, this); // communication loop while (!m_stop_requested) { // wait for event event_occured = m_thread_event.WaitOne(ThreadWaitTimeout); // exit loop if thread must be stopped if (m_stop_requested) { break; } // process received data if (m_received_data_length > 0) { received_data_pos = 0; while (received_data_pos < m_received_data_length) { // SLIP decode data if (m_receiver_slip.DecodeBlock(m_receive_data_buffer, ref received_data_pos, m_received_data_length, m_receive_packet_buffer, ref received_packet_pos)) { // packet decoded -> check CRC if (received_packet_pos > (Marshal.SizeOf(typeof(PacketBase)) + PacketConstants.PacketCRCLength)) { m_received_packet_length = received_packet_pos; crc = CRC16.CalculateForBlock(CRC16.InitValue, m_receive_packet_buffer, m_received_packet_length - PacketConstants.PacketCRCLength); if (ByteAccess.LowByte(crc) == m_receive_packet_buffer[m_received_packet_length - 2] && ByteAccess.HighByte(crc) == m_receive_packet_buffer[m_received_packet_length - 1]) { // CRC OK -> continue processing received packet PacketType type = (PacketType)m_receive_data_buffer[PacketConstants.TypeOffset]; // update statistics Interlocked.Add(ref m_upstream_bytes, m_received_data_length); // process received data if (m_received_packet_length <= PacketConstants.PacketMaxLength) { m_communication_manager.StoreReceivedPacket(m_communication_channel_index, m_receive_packet_buffer, (byte)m_received_packet_length); } } } // restart packet decoding received_packet_pos = 0; } m_read_pending = false; } } // restart reception if (!m_read_pending) { try { m_received_data_length = 0; m_read_pending = true; m_serial_port.BaseStream.BeginRead(m_receive_data_buffer, 0, m_receive_data_buffer.Length, m_receiver_callback, this); } catch { // stop thread because of the unexpected error m_stop_requested = true; m_thread_event.Set(); } } } // close socket m_serial_port.Close(); m_serial_port = null; // thread is finished m_thread_stopped.Set(); }