Exemplo n.º 1
0
        /// <summary>
        /// Deserialize a scan head status packet from a raw byte stream.
        /// </summary>
        /// <exception cref="VersionCompatibilityException">Thrown if the scan head version
        /// is incompatible with the client API</exception>"
        /// <param name="buf"></param>
        internal ScanHeadStatus(byte[] buf)
        {
            int idx = 0;

            // The header and version data should never change to maintain backwards compatibility
            Header = new PacketHeader
            {
                Magic = NetworkByteUnpacker.ExtractUShortFromNetworkBuffer(buf, ref idx),
                Size  = NetworkByteUnpacker.ExtractByteFromNetworkBuffer(buf, ref idx),
                Type  = (ScanPacketType)NetworkByteUnpacker.ExtractByteFromNetworkBuffer(buf, ref idx)
            };

            FirmwareVersion = new ScanHeadVersionInformation
            {
                Major      = NetworkByteUnpacker.ExtractUIntFromNetworkBuffer(buf, ref idx),
                Minor      = NetworkByteUnpacker.ExtractUIntFromNetworkBuffer(buf, ref idx),
                Patch      = NetworkByteUnpacker.ExtractUIntFromNetworkBuffer(buf, ref idx),
                Commit     = NetworkByteUnpacker.ExtractUIntFromNetworkBuffer(buf, ref idx),
                HardwareId =
                    (ScanHeadVersionHardwareId)NetworkByteUnpacker.ExtractUShortFromNetworkBuffer(buf, ref idx),
                Flags = NetworkByteUnpacker.ExtractUShortFromNetworkBuffer(buf, ref idx)
            };

            // Minor versions can be differ, but differences in
            // major versions are considered to be incompatible
            if (FirmwareVersion.Major != VersionInformation.Major)
            {
                throw new VersionCompatibilityException(FirmwareVersion);
            }

            // Static Data
            ScanHeadSerialNumber = NetworkByteUnpacker.ExtractIntFromNetworkBuffer(buf, ref idx);
            MaxScanRate          = NetworkByteUnpacker.ExtractIntFromNetworkBuffer(buf, ref idx);
            ScanHeadIPAddress    = NetworkByteUnpacker.ExtractIPAddressFromNetworkBuffer(buf, ref idx);
            ClientIPAddress      = NetworkByteUnpacker.ExtractIPAddressFromNetworkBuffer(buf, ref idx);
            ClientUdpPort        = NetworkByteUnpacker.ExtractUShortFromNetworkBuffer(buf, ref idx);
            ScanSyncID           = NetworkByteUnpacker.ExtractUShortFromNetworkBuffer(buf, ref idx);
            GlobalTime           = NetworkByteUnpacker.ExtractLongFromNetworkBuffer(buf, ref idx);
            NumPacketsSent       = NetworkByteUnpacker.ExtractIntFromNetworkBuffer(buf, ref idx);
            ProfilesSentCount    = NetworkByteUnpacker.ExtractIntFromNetworkBuffer(buf, ref idx);
            NumValidEncoders     = NetworkByteUnpacker.ExtractByteFromNetworkBuffer(buf, ref idx);
            NumValidCameras      = NetworkByteUnpacker.ExtractByteFromNetworkBuffer(buf, ref idx);

            // Variable Length Data
            EncoderValues = new Dictionary <Encoder, long>(NumValidEncoders);
            foreach (int i in Enumerable.Range(0, NumValidEncoders))
            {
                Encoder encoder      = (Encoder)Enum.ToObject(typeof(Encoder), i);
                var     encoderValue = NetworkByteUnpacker.ExtractLongFromNetworkBuffer(buf, ref idx);
                EncoderValues.Add(encoder, encoderValue);
            }

            PixelsInWindow = new Dictionary <Camera, int>(NumValidCameras);
            foreach (int i in Enumerable.Range(0, NumValidCameras))
            {
                Camera camera = (Camera)Enum.ToObject(typeof(Camera), i);
                var    pixels = NetworkByteUnpacker.ExtractIntFromNetworkBuffer(buf, ref idx);
                PixelsInWindow.Add(camera, pixels);
            }

            Temperatures = new Dictionary <TemperatureSensor, float>(NumValidCameras);
            foreach (int i in Enumerable.Range(0, NumValidCameras))
            {
                var temperatureSensor = (TemperatureSensor)Enum.ToObject(typeof(TemperatureSensor), i);
                var temperature       = NetworkByteUnpacker.ExtractFloatFromNetworkBuffer(buf, ref idx);
                Temperatures.Add(temperatureSensor, temperature);
            }
        }
        private void ReceiveMain()
        {
            IPEndPoint ep = new IPEndPoint(IPAddress.Any, 0);

            bytesReceived = 0;
            // this callback will kill the socket when the
            // token was canceled, which is the only way to get out
            // of the blocking udpClient.Receive()
            var demuxerDict = new Dictionary <int, ProfileFragments>();

            for (;;)
            {
                try
                {
                    token.ThrowIfCancellationRequested();

                    // next call blocks!
                    var raw = receiveUdpClient.Receive(ref ep);

                    if (!isRunning)
                    {
                        continue; // we ignore everything
                    }

                    var from   = ep.Address;
                    var header = new PacketHeader(raw);

                    if (header.Magic == 0xFACD) // Data packet
                    {
                        lastReceivedPacketTime = timeBase.ElapsedMilliseconds;
                        goodPackets++;
                        bytesReceived += raw.Length;
                        var p = new DataPacket(raw, timeBase.ElapsedMilliseconds);
                        // handle the de-multiplexing
                        if (p.NumParts == 1) // one part-datagram
                        {
                            // hand straight over to workers
                            profileAssembler.AssembleProfiles(new ProfileFragments(p, timeBase.ElapsedMilliseconds));
                            continue;
                        }

                        // source is a composite of scan head, camera and laser, we use it to identify packets from the same head/camera/laser combo
                        var id = p.Source;
                        if (!demuxerDict.ContainsKey(id))
                        {
                            // first time we see a packet from this source
                            demuxerDict[id] = new ProfileFragments(p, timeBase.ElapsedMilliseconds);
                        }
                        else
                        {
                            if (demuxerDict[id].Timestamp == p.Timestamp)
                            {
                                // the timestamp on this packet is the same as is the dict, so it must belong to the same  profile
                                demuxerDict[id].Add(p);
                                if (demuxerDict[id].Complete)
                                {
                                    CompleteProfilesReceivedCount++;
                                    // hand it off to a processor thread, we're done with it.
                                    profileAssembler.AssembleProfiles(demuxerDict[id]);
                                    demuxerDict.Remove(id);
                                    // but also record the Id in a fixed size queue, so that stragglers and
                                    // duplicates don't create a mess
                                    // TODO: add a done queue
                                }
                            }
                            else
                            {
                                // the timestamp on the current packet is newer than on the existing
                                // set of packets in the dictionary, which means we either received out of order or
                                // a packet got lost
                                // If we got the next in sequence, we now consider the previous profile done
                                // hand it off to a processor thread, since we're done with it.
                                profileAssembler.AssembleProfiles(demuxerDict[id]);

                                demuxerDict.Remove(id);

                                evictedForNextSeq++;
                                demuxerDict[id] = new ProfileFragments(p, timeBase.ElapsedMilliseconds);
                            }

                            // here we would check for timeouts, but that is tricky since the Receive call blocks.
                            // We may need to de-couple receiving from assembling.
                        }
                    }
                    else if (header.Magic == 0xFACE) // Non-data packets
                    {
                        switch (header.Type)
                        {
                        case ScanPacketType.Status:
                            try
                            {
                                scanHead.Status = new StatusPacket(raw, from).ScanHeadStatus;
                            }
                            catch (VersionCompatibilityException e)
                            {
                                IsVersionMismatched   = true;
                                VersionMismatchReason = e.Message;

                                // Versions are not compatible, try to send a disconnect before bailing
                                CreateIPEndPoint(from);
                                Disconnect();
                                Stop();
                                break;
                            }

                            if (scanHead.SerialNumber == scanHead.Status.ScanHeadSerialNumber &&
                                scanHeadDataIpEndPoint == null)
                            {
                                CreateIPEndPoint(from);
                            }

                            if (scanHeadDataIpEndPoint != null)
                            {
                                lastReceivedPacketTime = timeBase.ElapsedMilliseconds;
                            }

                            break;

                        default:
                            // Unknown command
                            BadPacketsCount++;
                            break;
                        }
                    }
                    else
                    {
                        // Wrong signature for received packet: expected 0xFACE or 0xFACD
                        BadPacketsCount++;
                    }
                }
                catch (ObjectDisposedException)
                {
                    // Time to break out of receive loop
                    break;
                }
                catch (SocketException)
                {
                    // We get here if we call Close() on the UdpClient
                    // while it is in the Receive(0 call. Apparently
                    // the only way to abort a Receive call is to
                    // close the underlying Socket.
                    break;
                }
                catch (OperationCanceledException)
                {
                    // Time to break out of receive loop
                    break;
                }
#pragma warning disable CA1031 // Do not catch general exception types
                catch (Exception)
#pragma warning restore CA1031 // Do not catch general exception types
                {
                    BadPacketsCount++;
                }
            }
        }