/// <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();
        }
示例#4
0
        /// <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();
        }