Пример #1
0
        /// <summary>
        /// Write configuration message and wait for the transmission to complete without caring about
        /// it being acknowledge or not.
        /// </summary>
        /// <param name="data">Communication message to be transmitted</param>
        /// <returns>Task represent the WriteConfigIgnoreResultAsync execution</returns>
        public async Task WriteConfigIgnoreResultAsync(UBXModelBase data)
        {
            if (!UBXModelBase.IsConfigMessage(data))
            {
                throw new NotSupportedException("WriteConfig only available for config type UBX message");
            }

            var notifyToken = new CancellationTokenSource();

            // Register to wait for transmission
            this.transmissionNotification.Add(data, notifyToken);

            // Put in queue
            TransmitMessage(data);

            // Wait until the message is transmitted
            try
            {
                await Task.Delay(-1, notifyToken.Token);
            }
            catch (TaskCanceledException)
            {
            }

            // Remove from notification list
            this.transmissionNotification.Remove(data);
        }
Пример #2
0
        /// <summary>
        /// Asynchronously request for message of type from the device.
        /// </summary>
        /// <typeparam name="T">Type of message that is requested.</typeparam>
        /// <returns>
        /// Task represents the PollMessageAsync execution, which upon completion returns the data
        /// requested from the device, or null if it is aborted by calling <see cref="AbortPollMessageAsync{T}"/>.
        /// </returns>
        public async Task <T> PollMessageAsync <T>() where T : UBXModelBase
        {
            var pollMessage = UBXModelBase.GetPollMessage <T>();

            // Send the data
            TransmitMessage(pollMessage);

            // Wait until expected response comes
            return(await expectingList.ExpectAsync <T>());
        }
Пример #3
0
        /// <summary>
        /// Write configuration message to the device and wait until acknowledge or not-acknowledge message
        /// arrived
        /// </summary>
        /// <param name="data">Communication message to be transmitted </param>
        /// <returns>
        /// Task represents the WriteConfigAsync execution, which upon completion returns boolean where
        /// true means the configuration is acknowledged, and false otherwise.
        /// </returns>
        public async Task <bool> WriteConfigAsync(UBXModelBase data)
        {
            if (!UBXModelBase.IsConfigMessage(data))
            {
                throw new NotSupportedException("WriteConfig only available for config type UBX message");
            }

            TransmitMessage(data);
            var attr = UBXModelBase.GetMessageAttribute(data);

            return(await expectingList.ExpectAcknowledgeAsync(attr.ClassID, attr.MessageID));
        }
Пример #4
0
        public static bool IsConfigMessage(UBXModelBase message)
        {
            var attribute = message.GetType().GetTypeInfo().GetCustomAttribute <UBXConfigAttribute>();

            if (attribute != null)
            {
                return(true);
            }
            else
            {
                return(false);
            }
        }
Пример #5
0
 /// <summary>
 /// Create description key for expecting a message of type.
 /// </summary>
 /// <param name="message">The message</param>
 public ExpectingDescription(UBXModelBase message)
 {
     if (message is AcknowledgeBase)
     {
         var ack = message as AcknowledgeBase;
         this.classId             = ack.ClassID;
         this.messageId           = ack.MessageID;
         this.expectedMessageMode = ExpectingMode.Acknowledge;
     }
     else
     {
         this.expectingType       = message.GetType();
         this.expectedMessageMode = ExpectingMode.Regular;
     }
 }
Пример #6
0
            /// <summary>
            /// Notify any party if waits a message of this type
            /// </summary>
            /// <param name="obj">The message to be notified</param>
            /// <returns>True if there is a party that is waiting for this kind of message, false otherwise.</returns>
            public bool NotifyIfExpected(UBXModelBase obj)
            {
                var expectingDesc = new ExpectingDescription(obj);

                try
                {
                    var expectingContext = expectingList[expectingDesc];
                    expectingContext.NotifyResponseReceived(obj);
                    return(true);
                }
                catch (KeyNotFoundException)
                {
                    return(false);
                }
            }
Пример #7
0
 internal static UBXMessageAttribute GetMessageAttribute(UBXModelBase message)
 {
     return(message.GetType().GetTypeInfo().GetCustomAttribute <UBXMessageAttribute>());
 }
Пример #8
0
        public static UBXModelBase TryParse(byte[] payload)
        {
            if (payload[0] != Header1 || payload[1] != Header2)
            {
                throw new InvalidMessageHeaderException();
            }

            byte classId       = payload[2];
            byte messageId     = payload[3];
            int  messageLength = payload[4] | (payload[5] << 8);

            try
            {
                var ubxType = parsableTypeIndex[new UBXMessageIndex(classId, messageId)];

                ushort expectedChecksum = (ushort)((payload[payload.Length - 2]) | (payload[payload.Length - 1] << 8));
                ushort computedChecksum = GetChecksum(payload, 2, payload.Length - 2);

                if (expectedChecksum != computedChecksum)
                {
                    throw new InvalidChecksumException(String.Format("Checksum expected {0}, computed {1}", expectedChecksum, computedChecksum));
                }

                BinaryReader reader = new BinaryReader(new MemoryStream(payload, 6, messageLength));

                UBXModelBase retVal = (UBXModelBase)Activator.CreateInstance(ubxType.MessageClass);

                foreach (var property in ubxType.PropertyMap)
                {
                    if (!property.ListType)
                    {
                        // If property is not a list type, parse normally using its underlying type
                        property.Property.SetValue(retVal, reader.Read(property.Property.PropertyType));
                    }
                    else
                    {
                        // If property is a list type, infer the type content
                        var typeInfoOfPropertyType = property.Property.PropertyType.GetTypeInfo();
                        var theStructureType       = typeInfoOfPropertyType.GenericTypeArguments[0]; // Get the T of IEnumerable<T>

                        // Get the size of the structure
                        var structureSize = UBXStructureMapper.PayloadSizeOf(theStructureType);

                        // Get the item count
                        var itemCount = Convert.ToInt32(ubxType.PropertyMap[property.ListIndexRef.Value].Property.GetValue(retVal));

                        // Construct list of it
                        var theList = (IList)Activator.CreateInstance(typeof(List <>).MakeGenericType(theStructureType));


                        for (int i = 0; i < itemCount; i++)
                        {
                            var buf = reader.ReadBytes(structureSize);
                            theList.Add(UBXStructureMapper.TryParse(theStructureType, buf));
                        }

                        // Set the value to property
                        property.Property.SetValue(retVal, theList);
                    }
                }

                return(retVal);
            }
            catch (KeyNotFoundException)
            {
                throw new UnknownMessageException(string.Format("Unknown message with Class: {0}, MessageID: {1}", classId, messageId));
            }
            catch (NotSupportedException ex)
            {
                throw new UnknownMessageException(string.Format("Failed to parse Class: {0}, MessageID: {1}", classId, messageId), ex);
            }
        }
Пример #9
0
 /// <summary>
 /// Instantiate MessageReceivedEventArgs.
 /// </summary>
 /// <param name="receivedMessage">The received message object.</param>
 internal MessageReceivedEventArgs(UBXModelBase receivedMessage)
 {
     this.ReceivedMessage = receivedMessage;
 }
Пример #10
0
 /// <summary>
 /// Raise MessageReceived event with the specified message object.
 /// </summary>
 /// <param name="receivedMessage">Message object that is just received.</param>
 protected void OnMessageReceived(UBXModelBase receivedMessage)
 {
     this.MessageReceived?.Invoke(this, new MessageReceivedEventArgs(receivedMessage));
 }
Пример #11
0
 /// <summary>
 /// Transmit any message to the device
 /// </summary>
 /// <param name="messageToTransmit">Message to transmit to the device</param>
 public void TransmitMessage(UBXModelBase messageToTransmit)
 {
     transmitQueue.Enqueue(messageToTransmit);
 }
Пример #12
0
        /// <summary>
        /// Communication loop for GPS serial device
        /// </summary>
        /// <param name="baudRate">Baud rate for this communication loop</param>
        /// <returns>Task that represent the asyncrhonous operation of communication loop</returns>
        private async Task Listen(uint baudRate)
        {
            // If it is already running, just bye
            if (running)
            {
                return;
            }

            // Initialize state and cancellation token to stop this operation
            running     = true;
            cancelToken = new CancellationTokenSource();

            DataReader   dataReader = null;
            DataWriter   dataWriter = null;
            SerialDevice serialPort = null;

#if DEBUG
            Debug.WriteLine("Listening start...");
#endif

            try
            {
                // Get serial device from device info
                serialPort = await InitializeSerialPort(this.deviceInfo, baudRate);

                serialPort.WriteTimeout = TimeSpan.FromMilliseconds(100);
                serialPort.ReadTimeout  = TimeSpan.FromMilliseconds(100);

                dataReader = new DataReader(serialPort.InputStream);
                dataReader.InputStreamOptions = InputStreamOptions.Partial;

                dataWriter = new DataWriter(serialPort.OutputStream);

                // Queue to store current byte processed, in case of data is transmitted
                // intersecting between two loop
                Queue <byte> currentlyProcessed = new Queue <byte>(1024);

                // Current communication state of the loop
                byte   currentState  = 0;
                ushort payloadLength = 0;

                while (true)
                {
                    cancelToken.Token.ThrowIfCancellationRequested();

                    // Write any queued message
                    await WriteQueuedMessages(dataWriter);

                    // Longer timeout to prevent package drop
                    CancellationTokenSource timeoutToken = new CancellationTokenSource(serialPort.ReadTimeout.Milliseconds * 10);

                    // Load asynchronously, while at the same time we process the data that is ready
                    var loadingTask = dataReader.LoadAsync(BufferLength).AsTask(timeoutToken.Token);

                    while (dataReader.UnconsumedBufferLength != 0)
                    {
                        // Consume buffer while waiting for data
                        byte currentByte = dataReader.ReadByte();
                        bool fail        = false;

                        currentlyProcessed.Enqueue(currentByte);

                        // State machine:
                        // 0: Header 1
                        // 1: Header 2
                        // 2: Class ID
                        // 3: Message ID
                        // 4: Least significant byte of size
                        // 5: Most significant byte of size
                        // 6: Payload with 1st byte of checksum
                        // 7: 2nd byte of checksum
                        // 8: Processing
                        switch (currentState)
                        {
                        case 0:     // Start with Header 1
                            if (currentByte != UBXModelBase.Header1)
                            {
                                fail = true;
                            }
                            break;

                        case 1:     // Followed by Header 2, otherwise fail
                            if (currentByte != UBXModelBase.Header2)
                            {
                                fail = true;
                            }
                            break;

                        case 4:     // Retrieve Size
                            payloadLength = currentByte;
                            break;

                        case 5:                                            // Continue retrieve size
                            payloadLength |= ((ushort)(currentByte << 8)); // Second byte of payload length
                            break;
                        }

#if DEBUG && VERBOSE
                        Debug.Write(currentByte.ToString("X") + ' ');
#endif

                        // Reset processing if it encounter invalid header
                        if (fail)
                        {
                            currentState = 0;
                            currentlyProcessed.Clear();
#if DEBUG && VERBOSE
                            Debug.WriteLine("");
#endif
                        }
                        else if (currentState != 6)
                        {
                            // Increment state
                            currentState++;
                        }
                        else if (currentState == 6)
                        {
                            // Loading the payload
                            if (payloadLength > 0)
                            {
                                payloadLength--;
                            }
                            else
                            {
                                currentState++;
                            }
                        }

                        // If the entire message has been received properly
                        // perform processing
                        if (currentState == 8)
                        {
                            try
                            {
                                var arr = currentlyProcessed.ToArray();

#if DEBUG
                                Debug.WriteLine("Package received: " + currentlyProcessed.Count + " bytes");
#if VERBOSE
                                DebugHelper.PrintArray(arr);
#endif
#endif
                                // Parse the byte to UBX models
                                var package = UBXModelBase.TryParse(arr);

                                // Notify if any party is waiting this kind of message
                                if (!expectingList.NotifyIfExpected(package))
                                {
                                    OnMessageReceived(package);
                                }
#if DEBUG
                                Debug.WriteLine(package.ToString());
#endif
                            }
                            catch (UBXException ex)
                            {
#if DEBUG
                                Debug.WriteLine("Failed parsing UBX package: " + ex);
#endif
                            }
                            catch (Exception ex)
                            {
#if DEBUG
                                Debug.WriteLine("Exception occured during parsing: " + ex, ex);
#endif
                            }
                            finally
                            {
                                currentlyProcessed.Clear();
                                currentState = 0;
                            }
                        }
                    }

                    try
                    {
                        uint readedBuffer = await loadingTask;
                    }
                    catch (TaskCanceledException)
                    {
                    }
                    catch (Exception ex)
                    {
#if DEBUG
                        Debug.WriteLine("Unexpected Exception when awaiting loading: " + ex);
#endif
                    }
                }
            }
            catch (OperationCanceledException)
            {
#if DEBUG
                Debug.WriteLine("Listening port stopped!");
#endif
            }
            catch (Exception ex)
            {
#if DEBUG
                Debug.WriteLine("Unexpected Exception happen during the loop: " + ex);
#endif
            }
            finally
            {
                if (dataReader != null)
                {
                    dataReader.DetachStream();
                    dataReader.Dispose();
                    dataReader = null;
                }

                if (serialPort != null)
                {
                    serialPort.Dispose();
                    serialPort = null;
                }

                running     = false;
                cancelToken = null;
            }
        }
Пример #13
0
 /// <summary>
 /// Notify the waiting party that the response is received
 /// </summary>
 /// <param name="obj">The message that is received</param>
 public void NotifyResponseReceived(UBXModelBase obj)
 {
     this.ResponseReceived = obj;
     notifyTokenSource.Cancel();
 }