You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by cc...@apache.org on 2017/08/04 21:41:13 UTC
[mynewt-newtmgr] 04/05: MYNEWT-821 recover during image upload
This is an automated email from the ASF dual-hosted git repository.
ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-newtmgr.git
commit 03fd1a5ea35c89894fa48d04ca0823c0d19fcaea
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Mon Jul 31 13:03:52 2017 -0700
MYNEWT-821 recover during image upload
An image upgrade consists of two phases:
1. Erase slot
2. Upload image
On nRF boards, both phases cause the processor to stall while flash is
being accessed. Such stalls can cause any established BLE connections to
terminate due to "supervision timeout."
Currently, the newtmgr tool automatically recovers from a disconnect
during the first phase (erase). However, it does not recover from such a
disconnect during the upload phase.
Newtmgr should be improved to use the same reconnect logic during the
second phase that it already uses during the first phase.
---
nmxact/xact/image.go | 98 ++++++++++++++++++++++++++++++++++++++--------------
1 file changed, 72 insertions(+), 26 deletions(-)
diff --git a/nmxact/xact/image.go b/nmxact/xact/image.go
index 3787560..2fd2d9c 100644
--- a/nmxact/xact/image.go
+++ b/nmxact/xact/image.go
@@ -34,6 +34,7 @@ type ImageUploadProgressFn func(c *ImageUploadCmd, r *nmp.ImageUploadRsp)
type ImageUploadCmd struct {
CmdBase
Data []byte
+ StartOff int
ProgressCb ImageUploadProgressFn
}
@@ -117,7 +118,7 @@ func nextImageUploadReq(s sesn.Sesn, data []byte, off int) (
func (c *ImageUploadCmd) Run(s sesn.Sesn) (Result, error) {
res := newImageUploadResult()
- for off := 0; off < len(c.Data); {
+ for off := c.StartOff; off < len(c.Data); {
r, err := nextImageUploadReq(s, c.Data, off)
if err != nil {
return nil, err
@@ -150,8 +151,8 @@ func (c *ImageUploadCmd) Run(s sesn.Sesn) (Result, error) {
// Image upgrade combines the image erase and image upload commands into a
// single command. Some hardware and / or BLE connection settings cause the
-// connection to drop during the initial erase. The image upgrade command
-// addresses this issue with the following sequence:
+// connection to drop while flash is being erased or written to. The image
+// upgrade command addresses this issue with the following sequence:
// 1. Send image erase command.
// 2. If the image erase command succeeded, proceed to step 5.
// 3. Else if the peer is disconnected, attempt to reconnect to the peer. If
@@ -159,7 +160,8 @@ func (c *ImageUploadCmd) Run(s sesn.Sesn) (Result, error) {
// the reconnect attempt succeeded, proceed to step 5.
// 4. Else (the erase command failed and the peer is still connected), proceed
// to step 5.
-// 5. Execute the upload command.
+// 5. Execute the upload command. If the connection drops before the final
+// part is uploaded, reconnect and retry the previous part.
type ImageUpgradeCmd struct {
CmdBase
@@ -192,36 +194,80 @@ func (r *ImageUpgradeResult) Status() int {
}
}
-func (c *ImageUpgradeCmd) Run(s sesn.Sesn) (Result, error) {
- upgradeRes := newImageUpgradeResult()
+// Attempts to recover from a disconnect.
+func (c *ImageUpgradeCmd) rescue(s sesn.Sesn, err error) error {
+ if err != nil {
+ if !s.IsOpen() {
+ if err := s.Open(); err == nil {
+ return nil
+ }
+ }
+ }
+
+ return err
+}
- eraseCmd := NewImageEraseCmd()
- res, err := eraseCmd.Run(s)
+func (c *ImageUpgradeCmd) runErase(s sesn.Sesn) (*ImageEraseResult, error) {
+ cmd := NewImageEraseCmd()
+ res, err := cmd.Run(s)
- if res != nil {
- upgradeRes.EraseRes = res.(*ImageEraseResult)
+ if err := c.rescue(s, err); err != nil {
+ return nil, err
}
- if err != nil || res.Status() != 0 {
- // If the erase command failed and the peer is no longer connected, the
- // disconnect could have been caused by a stall in the destination
- // device's processor. In this case, the erase command succeeded. Try
- // to recover by reconnecting.
- if !s.IsOpen() {
- if err := s.Open(); err != nil {
- return upgradeRes, err
- }
+
+ if res == nil {
+ // We didn't get a response back but we rescued ourselves from the
+ // disconnect.
+ res = newImageEraseResult()
+ }
+
+ return res.(*ImageEraseResult), nil
+}
+
+func (c *ImageUpgradeCmd) runUpload(s sesn.Sesn) (*ImageUploadResult, error) {
+ startOff := 0
+ progressCb := func(uc *ImageUploadCmd, r *nmp.ImageUploadRsp) {
+ if r.Rc == 0 {
+ startOff = int(r.Off)
}
+ c.ProgressCb(uc, r)
}
- uploadCmd := NewImageUploadCmd()
- uploadCmd.Data = c.Data
- uploadCmd.ProgressCb = c.ProgressCb
- res, err = uploadCmd.Run(s)
+ for {
+ cmd := NewImageUploadCmd()
+ cmd.Data = c.Data
+ cmd.StartOff = startOff
+ cmd.ProgressCb = progressCb
+
+ res, err := cmd.Run(s)
+ if err == nil {
+ return res.(*ImageUploadResult), nil
+ }
+
+ if err := c.rescue(s, err); err != nil {
+ // Disconnected and couldn't recover.
+ return nil, err
+ }
- if res != nil {
- upgradeRes.UploadRes = res.(*ImageUploadResult)
+ // Disconnected but recovered; retry last part.
}
- return upgradeRes, err
+}
+
+func (c *ImageUpgradeCmd) Run(s sesn.Sesn) (Result, error) {
+ eres, err := c.runErase(s)
+ if err != nil {
+ return nil, err
+ }
+
+ ures, err := c.runUpload(s)
+ if err != nil {
+ return nil, err
+ }
+
+ upgradeRes := newImageUpgradeResult()
+ upgradeRes.EraseRes = eres
+ upgradeRes.UploadRes = ures
+ return upgradeRes, nil
}
//////////////////////////////////////////////////////////////////////////////
--
To stop receiving notification emails like this one, please contact
"commits@mynewt.apache.org" <co...@mynewt.apache.org>.