예제 #1
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);
                }
            }
        }
예제 #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");
        }
예제 #3
0
        /// <summary>
        /// Write data to data point characteristic
        /// </summary>
        /// <param name="crc32"></param>
        /// <param name="file"></param>
        /// <param name="device"></param>
        /// <param name="MTU"></param>
        /// <param name="transferBytes"></param>
        /// <param name="remoteOffset"></param>
        /// <returns></returns>
        private async Task <int> TransferData(IGattCharacteristic packetPoint, CRC32 crc, Stream file, /*int prn = -1,*/ int offsetStart = 0, int offsetEnd = -1, int MTU = 20)
        {
            const int RESERVED_BYTES = 3;
            int       bytesWritten   = 0;

            try
            {
                int MAX_READ_BYTES = MTU - RESERVED_BYTES;
                Debug.WriteLineIf(LogLevelDebug, String.Format("Start of data transfer flen: {0}", file.Length));
                file.Seek(offsetStart, SeekOrigin.Begin);

                byte[] data = new byte[MAX_READ_BYTES];

                for (int packetsSent = 0, offset = offsetStart; ;)
                {
                    int bytesToRead = MAX_READ_BYTES;
                    if (offsetEnd > -1)
                    {
                        int endOffsetDiff = offsetEnd - offset;
                        if (endOffsetDiff <= 0)
                        {
                            break;
                        }
                        bytesToRead = Math.Min(bytesToRead, endOffsetDiff);
                    }
                    Debug.WriteLineIf(LogLevelDebug, String.Format("Reading {0} bytes from file stream", bytesToRead));
                    int size = file.Read(data, 0, bytesToRead);
                    if (size <= 0)
                    {
                        break;
                    }
                    offset += size;
                    byte[] pending;

                    if (size < MAX_READ_BYTES)
                    {
                        pending = new byte[size];
                        Array.Copy(data, pending, size);
                    }
                    else
                    {
                        pending = data;
                    }

                    // Specific for iOS, if no timeout, then sending happens to be blocked
                    await Task.Delay(1);

                    await packetPoint.WriteWithoutResponse(pending).Timeout(OperationTimeout);

                    packetsSent++;
                    bytesWritten += pending.Length;

                    crc.Update(pending);
                    Debug.WriteLineIf(LogLevelDebug, String.Format("### CRC32 Step value, crc: {0} offset:{2} size: {1} packetLocalNo:{3}", crc.Value, pending.Length, offset, packetsSent));
                }
                Debug.WriteLineIf(LogLevelDebug, String.Format("End of data transfer"));
            }
            catch (Exception ex)
            {
                Debug.WriteLineIf(LogLevelDebug, String.Format("Error while transfering data"));
                Debug.Write(ex);
            }
            return(bytesWritten);
        }