forked from Elara6331/infinitime
		
	Fix issue where DFU responses are missed causing DFU to time out intermittently
This commit is contained in:
		
							
								
								
									
										61
									
								
								dfu.go
									
									
									
									
									
								
							
							
						
						
									
										61
									
								
								dfu.go
									
									
									
									
									
								
							@@ -6,7 +6,6 @@ import (
 | 
			
		||||
	"encoding/binary"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"io"
 | 
			
		||||
	"io/fs"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"os"
 | 
			
		||||
@@ -191,6 +190,23 @@ func (dfu *DFU) sendProgress() {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// bufferPropsCh resends all messages on in to a new channel that is buffered with 5 elements
 | 
			
		||||
func bufferPropsCh(in chan *bluez.PropertyChanged) chan *bluez.PropertyChanged {
 | 
			
		||||
	// Create new buffered channel
 | 
			
		||||
	out := make(chan *bluez.PropertyChanged, 5)
 | 
			
		||||
	go func() {
 | 
			
		||||
		// Close channel when underlying channel closed
 | 
			
		||||
		defer close(out)
 | 
			
		||||
		// For every property change on in
 | 
			
		||||
		for prop := range in {
 | 
			
		||||
			// Write to out
 | 
			
		||||
			out <- prop
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
	// Return new buffered channel
 | 
			
		||||
	return out
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Start DFU process
 | 
			
		||||
func (dfu *DFU) Start() error {
 | 
			
		||||
	if dfu.progress == nil {
 | 
			
		||||
@@ -209,10 +225,12 @@ func (dfu *DFU) Start() error {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Watch for property changes on control point
 | 
			
		||||
	dfu.ctrlRespCh, err = dfu.ctrlPointChar.WatchProperties()
 | 
			
		||||
	unbufferedCh, err := dfu.ctrlPointChar.WatchProperties()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	// Buffer properties channel so no changes are missed
 | 
			
		||||
	dfu.ctrlRespCh = bufferPropsCh(unbufferedCh)
 | 
			
		||||
 | 
			
		||||
	// Run step one
 | 
			
		||||
	err = dfu.stepOne()
 | 
			
		||||
@@ -279,13 +297,30 @@ func (dfu *DFU) Start() error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Reset reverts all values back to default to prepare for
 | 
			
		||||
// the next DFU.
 | 
			
		||||
func (dfu *DFU) Reset() {
 | 
			
		||||
	dfu.bytesRecvd = 0
 | 
			
		||||
	dfu.bytesSent = 0
 | 
			
		||||
	dfu.fwSize = 0
 | 
			
		||||
	dfu.fwSendDone = false
 | 
			
		||||
	dfu.fwImage = nil
 | 
			
		||||
	dfu.initPacket = nil
 | 
			
		||||
	dfu.ctrlRespCh = nil
 | 
			
		||||
	dfu.progress = nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// on waits for the given command to be received on
 | 
			
		||||
// the control point characteristic, then runs the callback.
 | 
			
		||||
func (dfu *DFU) on(cmd []byte, onCmdCb func(data []byte) error) error {
 | 
			
		||||
	// Use for loop in case of invalid property
 | 
			
		||||
	for {
 | 
			
		||||
		select {
 | 
			
		||||
		case propChanged := <-dfu.ctrlRespCh:
 | 
			
		||||
			// If property was invalid
 | 
			
		||||
			if propChanged.Name != "Value" {
 | 
			
		||||
			return ErrDFUInvalidResponse
 | 
			
		||||
				// Keep waiting
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			// Assert propery value as byte slice
 | 
			
		||||
			data := propChanged.Value.([]byte)
 | 
			
		||||
@@ -299,6 +334,7 @@ func (dfu *DFU) on(cmd []byte, onCmdCb func(data []byte) error) error {
 | 
			
		||||
			return ErrDFUTimeout
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (dfu *DFU) stepOne() error {
 | 
			
		||||
	return dfu.ctrlPointChar.WriteValue(DFUCmdStart, nil)
 | 
			
		||||
@@ -346,7 +382,13 @@ func (dfu *DFU) stepSeven() error {
 | 
			
		||||
	// While send is not done
 | 
			
		||||
	for !dfu.fwSendDone {
 | 
			
		||||
		for i := 0; i < DFUPktRecvInterval; i++ {
 | 
			
		||||
			amtLeft := int(dfu.fwSize) - dfu.bytesSent
 | 
			
		||||
			amtLeft := dfu.fwSize - int64(dfu.bytesSent)
 | 
			
		||||
			// If no bytes left to send, end transfer
 | 
			
		||||
			if amtLeft == 0 {
 | 
			
		||||
				dfu.sendProgress()
 | 
			
		||||
				dfu.fwSendDone = true
 | 
			
		||||
				return nil
 | 
			
		||||
			}
 | 
			
		||||
			var segment []byte
 | 
			
		||||
			// If amount left is less than segment size
 | 
			
		||||
			if amtLeft < DFUSegmentSize {
 | 
			
		||||
@@ -357,13 +399,8 @@ func (dfu *DFU) stepSeven() error {
 | 
			
		||||
				segment = make([]byte, DFUSegmentSize)
 | 
			
		||||
			}
 | 
			
		||||
			// Write firmware image into slice
 | 
			
		||||
			n, err := dfu.fwImage.Read(segment)
 | 
			
		||||
			// If EOF, send is done
 | 
			
		||||
			if err == io.EOF {
 | 
			
		||||
				dfu.sendProgress()
 | 
			
		||||
				dfu.fwSendDone = true
 | 
			
		||||
				return nil
 | 
			
		||||
			} else if err != nil {
 | 
			
		||||
			_, err := dfu.fwImage.Read(segment)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			// Write segment to packet characteristic
 | 
			
		||||
@@ -372,7 +409,7 @@ func (dfu *DFU) stepSeven() error {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			// Increment bytes sent by amount read
 | 
			
		||||
			dfu.bytesSent += n
 | 
			
		||||
			dfu.bytesSent += len(segment)
 | 
			
		||||
		}
 | 
			
		||||
		// On 0x11, verify packet receipt size
 | 
			
		||||
		err := dfu.on(DFUNotifPktRecvd, func(data []byte) error {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user