示例#1
0
        private static void OnPacketReceived(object sender, IList <byte> data)
        {
            DateTime receivedTime = DateTime.Now;

            try
            {
                var packet = PacketDecoder.DecodeBytes(data as byte[] ?? data.ToArray());
                if (packet == null)
                {
                    var localBytes = data.ToArray();
                    Task.Run(() => _dataStore?.RecordUndecipherable(localBytes));
                    Task.Run(() =>
                    {
                        OutputWriter.Write(receivedTime.ToString());
                        OutputWriter.Write(" Unhandled Packet: ");
                        OutputWriter.WriteLine(OutputWriter.Encoding.GetString(localBytes));
                    });
                    return;
                }
                //Do this in a Task to avoid waiting if we've scrolled up.
                var consoleTask = Task.Run(() => OutputWriter.WriteLine($"Packet {receivedTime}: {packet}"));
                switch (packet.type)
                {
                case PacketTypes.Weather:
                    foreach (var serverPoster in _serverPosters)
                    {
                        serverPoster?.SendWeatherDataAsync(packet, receivedTime);
                    }
                    break;

                case PacketTypes.Response:
                case PacketTypes.Command:
                case PacketTypes.Ping:
                case PacketTypes.Modem:
                    break;

                default:
                    //nps is often stdOut in debugging, don't write to it from multiple threads:
                    var localBytes = data.ToArray();
                    consoleTask.ContinueWith(notUsed =>
                    {
                        OutputWriter?.Write($"{DateTime.Now} Unhandled Packet: ");
                        OutputWriter?.WriteLine(Encoding.ASCII.GetString(localBytes));
                    });
                    break;
                }
                Task.Run(() => _dataStore?.RecordPacket(packet));
            }
            catch (Exception ex)
            {
                ErrorWriter.WriteLine($"Error {DateTime.Now}: {ex}");
            }
        }
        private void InitMultiple(IEnumerable <byte> stationIDs, bool demandRelay)
        {
            ConcurrentDictionary <byte, BasicResponse> responses    = new ConcurrentDictionary <byte, BasicResponse>();
            Dictionary <byte, AutoResetEvent>          acksReceived = stationIDs
                                                                      .ToDictionary(id => id, id => new AutoResetEvent(false));
            ConcurrentDictionary <byte, byte> unIds = new ConcurrentDictionary <byte, byte>();

            void packetReceived(object sender, IList <byte> data)
            {
                try
                {
                    var packet    = PacketDecoder.DecodeBytes(data.ToArray());
                    var packetSrc = packet.sendingStation;
                    if (packet.type == PacketTypes.Response &&
                        stationIDs.Any(id => id == packetSrc) &&
                        unIds.TryGetValue(packetSrc, out var statUnId) && statUnId == packet.uniqueID)
                    {
                        responses[packetSrc] = (BasicResponse)packet.packetData;
                        acksReceived[packetSrc].Set();
                    }
                }
                catch { }
            }

            _communicator.PacketReceived += packetReceived;
            try
            {
                foreach (var id in stationIDs)
                {
                    unIds[id] = InitUploadToStation(id, demandRelay);
                }
                OutWriter?.WriteLine("Waiting for acknowledgements...");
                if (!WaitHandle.WaitAll(acksReceived.Values.ToArray(), ResponseTimeout))
                {
                    throw new ProgrammerException($"No response received from programming init message. " +
                                                  $"Failed: {acksReceived.Where(kvp => kvp.Value.WaitOne(0) == false).Select(kvp => kvp.Key).ToCsv()}");
                }
                if (responses.Values.Any(r => r != BasicResponse.OK))
                {
                    throw new ProgrammerException($"Non-OK response received from programming init message for stations " +
                                                  $"({responses.Where(kvp => kvp.Value != BasicResponse.OK).Select(kvp => kvp.Key).ToCsv()})");
                }
            }
            finally
            {
                _communicator.PacketReceived -= packetReceived;
            }
        }
        public Task <List <byte> > ReadRemoteImageAsync(byte stationID, CancellationToken token)
        {
            int           imageOffset  = 10;
            const int     packetSize   = 192;
            StringBuilder s            = new StringBuilder();
            byte          lastUniqueID = 0;

            byte[] lastData      = null;
            var    replyReceived = new AutoResetEvent(false);

            return(Task.Run(() =>
            {
                void packetReceived(object sender, IList <byte> bytes)
                {
                    var packet = PacketDecoder.DecodeBytes(bytes.ToArray());
                    if (packet?.type == PacketTypes.Response && packet.uniqueID == lastUniqueID && packet.sendingStation == stationID)
                    {
                        lastData = (byte[])packet.packetData;
                        replyReceived.Set();
                    }
                }
                _communicator.PacketReceived += packetReceived;
                try
                {
                    var ret = new List <byte>(_image.Count);
                    for (int i = 0; i < _image.Count; i += packetSize)
                    {
                        int payloadSize = Math.Min(_image.Count - i, packetSize);
                        do
                        {
                            token.ThrowIfCancellationRequested();
                            lastUniqueID = QueryStationFlash(stationID, (ushort)(i + imageOffset), (byte)payloadSize);
                        }while (WaitHandle.WaitAny(new WaitHandle[] { replyReceived, token.WaitHandle }, ResponseTimeout) == WaitHandle.WaitTimeout ||
                                lastData == null);
                        Debug.Assert(lastData.Length == payloadSize);
                        ret.AddRange(lastData);
                    }
                    Debug.Assert(ret.Count == _image.Count);
                    return ret;
                }
                finally
                {
                    _communicator.PacketReceived -= packetReceived;
                }
            }, token));
        }
        /// <summary>
        /// Finds out which packets a station still needs and sends them until it's got everything.
        /// </summary>
        /// <param name="destinationStationID">The station to upload to.
        /// This cannot be zero - it must be a specific station</param>
        /// <param name="token"></param>
        /// <returns></returns>
        public Task CompleteUploadToStationAsync(byte destinationStationID, CancellationToken token)
        {
            if (destinationStationID == 0)
            {
                throw new ArgumentOutOfRangeException(nameof(destinationStationID), "destinationStationID cannot be zero for complete upload.");
            }
            return(Task.Run(() =>
            {
                AutoResetEvent replyReceived = new AutoResetEvent(false);
                byte lastUniqueID = 0;
                ProgrammingResponse lastResponse = null;

                void packetReceived(object sender, IList <byte> data)
                {
                    try
                    {
                        var packet = PacketDecoder.DecodeBytes(data.ToArray());
                        if (packet?.type == PacketTypes.Response && packet.uniqueID == lastUniqueID && packet.sendingStation == destinationStationID)
                        {
                            lastResponse = packet.packetData as ProgrammingResponse;
                            replyReceived.Set();
                        }
                    }
                    catch
                    { }
                }

                _communicator.PacketReceived += packetReceived;
                try
                {
                    while (true)
                    {
                        token.ThrowIfCancellationRequested();
                        // Get the station status:
                        OutWriter.WriteLine($"Programmer: Query status of {destinationStationID}");
                        lastUniqueID = QueryStationProgramming(destinationStationID);
                        if (WaitHandle.WaitAny(new WaitHandle[] { replyReceived, token.WaitHandle }, ResponseTimeout) == WaitHandle.WaitTimeout ||
                            lastResponse == null)
                        {
                            continue;
                        }
                        // Check that the station is expecting us:
                        if (lastResponse.expectedCRC != CRC)
                        {
                            throw new ProgrammerException($"Station/Programmer CRC mismatch. Station: {lastResponse.expectedCRC:X}, Programmer: {CRC:X}");
                        }
                        if (lastResponse.totalExpectedPackets != PacketCount)
                        {
                            throw new ProgrammerException($"Station/Programmer packet count mismatch. Station: {lastResponse.totalExpectedPackets}, Programmer: {PacketCount}");
                        }
                        // Check if it's all done
                        if (lastResponse.allThere)
                        {
                            if (!lastResponse.crcMatch)
                            {
                                throw new ProgrammerException($"Station total CRC mistmatch."); //Nothing we can do at this point. Gotta fail.
                            }
                            else
                            {
                                return; //All there and CRC matches.
                            }
                        }
                        if (lastResponse.receivedPackets.All(a => a))
                        {
                            throw new ProgrammerException("Packet doesn't report all there, but reports all packets received.");
                        }
                        // Send what's not done:
                        for (int i = 0; i < PacketCount; i++)
                        {
                            token.ThrowIfCancellationRequested();
                            if (lastResponse.receivedPackets[i])
                            {
                                continue;
                            }
                            SendImagePacket(destinationStationID, (byte)'C', i);
                            Thread.Sleep(PacketInterval);
                        }
                    }
                }
                finally
                {
                    _communicator.PacketReceived -= packetReceived;
                }
            }, token));
        }