Skip to content

Commit

Permalink
Add support for Memfault commands
Browse files Browse the repository at this point in the history
https://memfault.com/

Adds support for pulling coredump data, events and traces from
the device.
  • Loading branch information
Michał Narajowski committed May 25, 2020
1 parent 4f3783e commit 732b88d
Show file tree
Hide file tree
Showing 6 changed files with 257 additions and 0 deletions.
1 change: 1 addition & 0 deletions newtmgr/cli/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ func Commands() *cobra.Command {
nmCmd.AddCommand(resCmd())
nmCmd.AddCommand(interactiveCmd())
nmCmd.AddCommand(shellCmd())
nmCmd.AddCommand(memfaultCmd())

return nmCmd
}
110 changes: 110 additions & 0 deletions newtmgr/cli/memfault.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package cli

import (
"fmt"
"os"

"github.com/spf13/cobra"

"mynewt.apache.org/newt/util"
"mynewt.apache.org/newtmgr/newtmgr/nmutil"
"mynewt.apache.org/newtmgr/nmxact/nmp"
"mynewt.apache.org/newtmgr/nmxact/xact"
)

func memfaultDownloadCmd(cmd *cobra.Command, args []string) {
if len(args) < 1 {
nmUsage(cmd, nil)
}

tmpName := args[0] + ".tmp"
progressBytes := 0
file, err := os.OpenFile(tmpName, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0660)
if err != nil {
nmUsage(cmd, util.NewNewtError(fmt.Sprintf(
"Cannot open file %s - %s", tmpName, err.Error())))
}
defer os.Remove(tmpName)
defer file.Close()

s, err := GetSesn()
if err != nil {
nmUsage(nil, err)
}

c := xact.NewMemfaultPullCmd()
c.SetTxOptions(nmutil.TxOptions())
c.ProgressCb = func(c *xact.MemfaultPullCmd, rsp *nmp.MemfaultPullRsp) {
progressBytes += len(rsp.Data)
fmt.Printf("Pulled %d bytes\n", progressBytes)
if _, err := file.Write(rsp.Data); err != nil {
nmUsage(nil, util.ChildNewtError(err))
}
}

res, err := c.Run(s)
if err != nil {
nmUsage(nil, util.ChildNewtError(err))
}

sres := res.(*xact.MemfaultPullResult)
if sres.Status() != 0 {
fmt.Printf("Error: %d\n", sres.Status())
return
}

err = file.Sync()
if err != nil {
nmUsage(nil, util.ChildNewtError(err))
}

err = file.Close()
if err != nil {
nmUsage(nil, util.ChildNewtError(err))
}

os.Rename(tmpName, args[0])
fmt.Printf("Done writing memfault file to %s\n", args[0])
}

func memfaultCmd() *cobra.Command {
memfaultCmd := &cobra.Command{
Use: "memfault",
Short: "Manage Memfault data on a device",
Run: func(cmd *cobra.Command, args []string) {
cmd.HelpFunc()(cmd, args)
},
}

memfaultEx := " " + nmutil.ToolInfo.ExeName +
" -c olimex memfault pull\n"

memfaultDownloadCmd := &cobra.Command{
Use: "pull <memfault-file> -c <conn_profile>",
Short: "Pull memfault data from a device",
Example: memfaultEx,
Run: memfaultDownloadCmd,
}
memfaultCmd.AddCommand(memfaultDownloadCmd)

return memfaultCmd
}
3 changes: 3 additions & 0 deletions nmxact/nmp/decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ const gr_cra = NMP_GROUP_CRASH
const gr_run = NMP_GROUP_RUN
const gr_fil = NMP_GROUP_FS
const gr_she = NMP_GROUP_SHELL
const gr_mft = NMP_GROUP_MEMFAULT

// Op-Group-Id
type Ogi struct {
Expand Down Expand Up @@ -74,6 +75,7 @@ func fsUploadRspCtor() NmpRsp { return NewFsUploadRsp() }
func configReadRspCtor() NmpRsp { return NewConfigReadRsp() }
func configWriteRspCtor() NmpRsp { return NewConfigWriteRsp() }
func shellExecRspCtor() NmpRsp { return NewShellExecRsp() }
func memfaultPullRspCtor() NmpRsp { return NewMemfaultPullRsp() }

var rspCtorMap = map[Ogi]rspCtor{
{op_wr, gr_def, NMP_ID_DEF_ECHO}: echoRspCtor,
Expand Down Expand Up @@ -104,6 +106,7 @@ var rspCtorMap = map[Ogi]rspCtor{
{op_rr, gr_cfg, NMP_ID_CONFIG_VAL}: configReadRspCtor,
{op_wr, gr_cfg, NMP_ID_CONFIG_VAL}: configWriteRspCtor,
{op_wr, gr_she, NMP_ID_SHELL_EXEC}: shellExecRspCtor,
{op_rr, gr_mft, NMP_ID_MEMFAULT_PULL}: memfaultPullRspCtor,
}

func DecodeRspBody(hdr *NmpHdr, body []byte) (NmpRsp, error) {
Expand Down
6 changes: 6 additions & 0 deletions nmxact/nmp/defs.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ const (
NMP_GROUP_RUN = 7
NMP_GROUP_FS = 8
NMP_GROUP_SHELL = 9
NMP_GROUP_MEMFAULT= 10
NMP_GROUP_PERUSER = 64
)

Expand Down Expand Up @@ -112,3 +113,8 @@ const (
const (
NMP_ID_SHELL_EXEC = 0
)

// Memfault group (8).
const (
NMP_ID_MEMFAULT_PULL = 0
)
49 changes: 49 additions & 0 deletions nmxact/nmp/memfault.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package nmp

//////////////////////////////////////////////////////////////////////////////
// $memfaultpull //
//////////////////////////////////////////////////////////////////////////////

type MemfaultPullReq struct {
NmpBase `codec:"-"`
}

type MemfaultPullRsp struct {
NmpBase
Status int `codec:"status"`
Data []byte `codec:"data"`
}

func NewMemfaultPullReq() *MemfaultPullReq {
r := &MemfaultPullReq{}
fillNmpReq(r, NMP_OP_READ, NMP_GROUP_MEMFAULT, NMP_ID_MEMFAULT_PULL)
return r
}

func (r *MemfaultPullReq) Msg() *NmpMsg { return MsgFromReq(r) }

func NewMemfaultPullRsp() *MemfaultPullRsp {
return &MemfaultPullRsp{}
}

func (r *MemfaultPullRsp) Msg() *NmpMsg { return MsgFromReq(r) }

88 changes: 88 additions & 0 deletions nmxact/xact/memfault.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package xact

import (
"mynewt.apache.org/newtmgr/nmxact/nmp"
"mynewt.apache.org/newtmgr/nmxact/sesn"
)

//////////////////////////////////////////////////////////////////////////////
// $memfaultpull //
//////////////////////////////////////////////////////////////////////////////

const (
MEMFAULT_PACKETIZER_STATUS_NO_MORE_DATA = 0
MEMFAULT_PACKETIZER_STATUS_END_OF_CHUNK = 1
MEMFAULT_PACKETIZER_STATUS_MORE_DATA_FOR_CHUNK = 2
)

type MemfaultPullProgressFn func(c *MemfaultPullCmd, r *nmp.MemfaultPullRsp)
type MemfaultPullCmd struct {
CmdBase
ProgressCb MemfaultPullProgressFn
}

type MemfaultPullResult struct {
Rsps []*nmp.MemfaultPullRsp
}

func NewMemfaultPullCmd() *MemfaultPullCmd {
return &MemfaultPullCmd{
CmdBase: NewCmdBase(),
}
}

func newMemfaultPullResult() *MemfaultPullResult {
return &MemfaultPullResult{}
}

func (r *MemfaultPullResult) Status() int {
return 0
}

func (c *MemfaultPullCmd) Run(s sesn.Sesn) (Result, error) {
res := newMemfaultPullResult()

for {
r := nmp.NewMemfaultPullReq()

rsp, err := txReq(s, r.Msg(), &c.CmdBase)
if err != nil {
return nil, err
}
irsp := rsp.(*nmp.MemfaultPullRsp)

if c.ProgressCb != nil {
c.ProgressCb(c, irsp)
}

res.Rsps = append(res.Rsps, irsp)
if irsp.Status == MEMFAULT_PACKETIZER_STATUS_NO_MORE_DATA ||
irsp.Status == MEMFAULT_PACKETIZER_STATUS_END_OF_CHUNK ||
len(irsp.Data) == 0 {
// Download complete.
break
}
}

return res, nil
}

0 comments on commit 732b88d

Please sign in to comment.