Example #1
0
        /// <summary>
        /// Request and read DFU checksum from control point after data have been sent
        /// </summary>
        /// <param name="device"></param>
        /// <returns></returns>
        private async Task <ObjectChecksum> ReadChecksum(IGattCharacteristic controlPoint)
        {
            Debug.WriteLineIf(LogLevelDebug, String.Format("Begin read checksum"));
            ObjectChecksum checksum = new ObjectChecksum();

            CharacteristicGattResult result = null;

            for (var retry = 0; retry < MaxRetries; retry++)
            {
                try
                {
                    // Request checksum
                    var notif = GetTimedNotification(controlPoint);

                    var re = await controlPoint.Write(CCalculateCRC).Timeout(OperationTimeout);

                    Debug.WriteLine(re);
                    result = await notif.Task;
                    break;
                }
                catch (Exception)
                {
                    await Task.Delay(100);
                }
                finally
                {
                    if (retry == MaxRetries)
                    {
                        throw new DFUTimeout();
                    }
                }
            }

            Debug.WriteLineIf(LogLevelDebug, String.Format("Check Sum Response {0}", BitConverter.ToString(result.Data)));

            AssertSuccess(result);

            SetChecksum(checksum, result.Data);

            Debug.WriteLineIf(LogLevelDebug, String.Format("End read checksum"));
            return(checksum);
        }
Example #2
0
        /// <summary>
        /// Upload Init package (*.dat)
        /// </summary>
        /// <param name="device">Device in DFU mode</param>
        /// <param name="InitFilePath">Init package path (*.dat)</param>
        /// <param name="controlPoint">Secure DFU control point characteristic [Commands / Notifications]</param>
        /// <param name="packetPoint">Secure DFU packet point characteristic [Data of images]</param>
        /// <returns></returns>
        private async Task SendInitPacket(IDevice device, Stream InitPacket, IGattCharacteristic controlPoint, IGattCharacteristic packetPoint)
        {
            Debug.WriteLineIf(LogLevelDebug, "Start of init packet send");
            //FileStream file = new FileStream(InitFilePath, FileMode.Open, FileAccess.Read);
            var   file      = InitPacket;
            int   imageSize = (int)file.Length;// Around ?~ 130bytes
            var   MTU       = Math.Min(device.MtuSize, DFUMaximumMTU);
            CRC32 crc       = new CRC32();

            ObjectInfo info = await SelectCommand(controlPoint, SecureDFUSelectCommandType.CommmandObject);

            bool resumeSendingInitPacket = false;

            if (info.offset > 0 && info.offset <= imageSize)
            {
                // Check if remote sent content is valid
                byte[] buffer = new byte[info.offset];

                file.Seek(0, SeekOrigin.Begin);
                file.Read(buffer, 0, (int)info.offset);

                crc.Update(buffer);

                if (crc.Value == (uint)info.CRC32)
                {
                    if (info.offset == imageSize)
                    {
                        Debug.WriteLineIf(LogLevelDebug, "Init packet already sent and valid");
                        await ExecuteCommand(controlPoint);

                        Debug.WriteLineIf(LogLevelDebug, "End of init packet send");
                        return;
                    }
                    else
                    {
                        Debug.WriteLineIf(LogLevelDebug, String.Format("-> " + info.offset + " bytes of Init packet were sent before"));
                        resumeSendingInitPacket = true;
                        Debug.WriteLineIf(LogLevelDebug, String.Format("Resuming sending Init packet..."));
                    }
                }
                else
                {
                    crc.Reset();
                    info.offset = 0;
                }
            }
            await SetPRN(controlPoint, 0);

            for (int attempt = 1; attempt <= MaxRetries;)
            {
                if (!resumeSendingInitPacket)
                {
                    // Allocate new object
                    await CreateCommand(controlPoint, SecureDFUCreateCommandType.CommmandObject, imageSize);
                }
                await TransferData(packetPoint, crc, file, offsetStart : info.offset, MTU : MTU, offsetEnd : imageSize);

                ObjectChecksum check = await ReadChecksum(controlPoint);

                info.offset = check.offset;
                info.CRC32  = check.offset;
                Debug.WriteLineIf(LogLevelDebug, String.Format("Checksum received (Offset = {0}, CRC = {1})", check.offset, check.CRC32));

                uint localcrc  = (uint)crc.Value;
                uint remotecrc = (uint)check.CRC32;
                if (localcrc == remotecrc)
                {
                    // Everything is OK, we can proceed
                    break;
                }
                else
                {
                    if (attempt < MaxRetries)
                    {
                        attempt++;
                        Debug.WriteLineIf(LogLevelDebug, String.Format("CRC does not match! Retrying...(" + attempt + "/" + MaxRetries + ")"));

                        // Restart
                        resumeSendingInitPacket = false;
                        info.offset             = 0;
                        info.CRC32 = 0;
                        file.Seek(0, SeekOrigin.Begin);
                        crc.Reset();
                    }
                    else
                    {
                        Debug.WriteLineIf(LogLevelDebug, String.Format("CRC does not match!"));
                        device.CancelConnection();
                        return;
                    }
                }
            }
            await ExecuteCommand(controlPoint);

            Debug.WriteLineIf(LogLevelDebug, "End of init packet send");
        }
Example #3
0
        /// <summary>
        /// Upload Firmware image (*.bin)
        /// </summary>
        /// <param name="device">Device in DFU mode</param>
        /// <param name="FirmwareFilePath">Fimware path (.bin)</param>
        /// <param name="controlPoint">Secure DFU control point characteristic [Commands / Notifications]</param>
        /// <param name="packetPoint">Secure DFU packet point characteristic [Data of images]</param>
        /// <returns></returns>
        private async Task SendFirmware(IDevice device, Stream FirmwarePacket, IGattCharacteristic controlPoint, IGattCharacteristic packetPoint)
        {
            //FileStream file = new FileStream(FirmwareFilePath, FileMode.Open, FileAccess.Read);
            var       file         = FirmwarePacket;
            long      firmwareSize = file.Length;
            var       MTU          = Math.Min(device.MtuSize, DFUMaximumMTU);
            const int prn          = 0;

            ObjectInfo info = await SelectCommand(controlPoint, SecureDFUSelectCommandType.DataObject);

            int objectSize = info.maxSize;// Use maximum available object size

            Debug.WriteLineIf(LogLevelDebug, String.Format("Data object info received (Max size = {0}, Offset = {1}, CRC = {2})", objectSize, info.offset, info.CRC32));

            CRC32 crc = new CRC32();

            await SetPRN(controlPoint, prn);

            // Try to allocate first object
            int startAllocatedSize = (int)(firmwareSize - info.offset);

            startAllocatedSize = Math.Min(startAllocatedSize, objectSize);
            if (startAllocatedSize > 0)
            {
                await CreateCommand(controlPoint, SecureDFUCreateCommandType.DataObject, startAllocatedSize);
            }

            IDisposable dispose             = null;
            var         LastOffsetFailed    = 0;
            var         LastOffsetFailCount = 0;

            // Run till all objects are transferred, object sizes must be page aligned
            while (true)
            {
                byte[] lastData;
                dispose = controlPoint.WhenNotificationReceived().Subscribe(
                    result =>
                {
                    lastData = result.Data;
                    Debug.WriteLineIf(LogLevelDebug, String.Format("Notification {0}", BitConverter.ToString(result.Data)));
                    if (result.Data.Length == 11)
                    {
                        ObjectChecksum checks = new ObjectChecksum();
                        SetChecksum(checks, result.Data);
                        info.offset = checks.offset;
                        info.CRC32  = checks.CRC32;
                        Debug.WriteLineIf(LogLevelDebug, String.Format("{0} ::: PRN response check: {1}, offset: {2}", DateTime.Now.ToString("HH:mm:ss.ffffff"), checks.CRC32, checks.offset));
                    }
                }
                    );

                int endOffset    = GetCurrentObjectEnd(info.offset, objectSize, firmwareSize);
                int objectOffset = info.offset;

                // Send single current object
                for (int startoffset = objectOffset; ;)
                {
                    if (startoffset < objectOffset)
                    {
                        if (objectOffset % objectSize == 0 || objectOffset == firmwareSize)
                        {
                            break;
                        }
                    }
                    int bytesWritten = await TransferData(packetPoint, crc, file, offsetStart : objectOffset, offsetEnd : endOffset, MTU : MTU);

                    objectOffset += bytesWritten;
                    DFUEvents.OnFimwareProgressChanged?.Invoke(objectOffset / (float)firmwareSize, DateTime.Now - DFUStartTime);

                    Debug.WriteLineIf(LogLevelDebug, String.Format("{0} ::: Written bytes {1}, progress: {2}, elapsed: {3}", DateTime.Now.ToString("HH:mm:ss.ffffff"), bytesWritten, objectOffset / (float)firmwareSize, DateTime.Now - DFUStartTime));
                }
                // if PRN with correct offset not received, force to calculate CRC and offset
                if (info.offset != objectOffset)
                {
                    Debug.WriteLineIf(LogLevelDebug, String.Format("{0} ::: Force chekcsum calc", DateTime.Now.ToString("HH:mm:ss.ffffff")));
                    ObjectChecksum check = await ReadChecksum(controlPoint);

                    info.CRC32  = check.CRC32;
                    info.offset = check.offset;
                }
                dispose?.Dispose();

                uint localcrc  = (uint)crc.Value;
                uint remotecrc = (uint)info.CRC32;
                if (localcrc == remotecrc)
                {
                    await ExecuteCommand(controlPoint, skipRegistring : true);

                    if (firmwareSize == info.offset)
                    {
                        // Firmware upload finished
                        break;
                    }

                    // Allocate next object
                    int allocateSize = objectSize;
                    if (info.offset + objectSize > firmwareSize)
                    {
                        allocateSize = (int)(firmwareSize - info.offset);
                    }
                    await CreateCommand(controlPoint, SecureDFUCreateCommandType.DataObject, allocateSize);
                }
                else
                {
                    await Task.Delay(1000);

                    // Get current object start offset
                    int allocateSize       = objectSize;
                    int currentObject      = info.offset / objectSize;
                    int currentStartOffset = currentObject * objectSize;
                    if (currentStartOffset + objectSize > firmwareSize)
                    {
                        allocateSize = (int)(firmwareSize - currentStartOffset);
                    }
                    info.offset = currentStartOffset;

                    // Calculate crc of already sent data
                    file.Seek(0, SeekOrigin.Begin);
                    byte[] crcBuffer = new byte[currentStartOffset];
                    crc.Reset();
                    if (currentStartOffset > 0)
                    {
                        file.Read(crcBuffer, 0, crcBuffer.Length);

                        crc.Update(crcBuffer);
                    }
                    if (LastOffsetFailed != currentStartOffset)
                    {
                        LastOffsetFailed    = currentStartOffset;
                        LastOffsetFailCount = 0;
                    }
                    LastOffsetFailCount++;
                    if (LastOffsetFailCount == MaxRetries)
                    {
                        throw new Exception("Too much retries for one object");
                    }
                    // Allocate memory from current object start position
                    await CreateCommand(controlPoint, SecureDFUCreateCommandType.DataObject, allocateSize);
                }
            }
        }
Example #4
0
 /// <summary>
 /// Sets checksum from (Response PRN) or (Response Calculate CRC) responses
 /// </summary>
 /// <param name="checksum"></param>
 /// <param name="data"></param>
 private void SetChecksum(ObjectChecksum checksum, byte[] data)
 {
     checksum.offset = (int)BitConverter.ToUInt32(data, 3);
     checksum.CRC32  = (int)BitConverter.ToUInt32(data, 3 + 4);
 }