Skip to content

Commit

Permalink
Add support for reading from the NVRAM to support #13.
Browse files Browse the repository at this point in the history
  • Loading branch information
pwood committed Apr 16, 2020
1 parent 0d7a4de commit bdd8340
Show file tree
Hide file tree
Showing 4 changed files with 176 additions and 8 deletions.
3 changes: 3 additions & 0 deletions messages.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ func registerMessages(l *Library) {
l.Add(AREQ, SYS, SysResetReqID, SysResetReq{})
l.Add(AREQ, SYS, SysResetIndID, SysResetInd{})

l.Add(SREQ, SYS, SysOSALNVReadID, SysOSALNVRead{})
l.Add(SRSP, SYS, SysOSALNVReadReplyID, SysOSALNVReadReply{})

l.Add(SREQ, SYS, SysOSALNVWriteID, SysOSALNVWrite{})
l.Add(SRSP, SYS, SysOSALNVWriteReplyID, SysOSALNVWriteReply{})

Expand Down
28 changes: 28 additions & 0 deletions messages_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,34 @@ func Test_registerMessages(t *testing.T) {
assert.Equal(t, reflect.TypeOf(SysResetInd{}), ty)
})

t.Run("SysOSALNVRead", func(t *testing.T) {
identity, found := ml.GetByObject(&SysOSALNVRead{})

assert.True(t, found)
assert.Equal(t, SREQ, identity.MessageType)
assert.Equal(t, SYS, identity.Subsystem)
assert.Equal(t, uint8(0x08), identity.CommandID)

ty, found := ml.GetByIdentifier(SREQ, SYS, 0x08)

assert.True(t, found)
assert.Equal(t, reflect.TypeOf(SysOSALNVRead{}), ty)
})

t.Run("SysOSALNVReadReply", func(t *testing.T) {
identity, found := ml.GetByObject(&SysOSALNVReadReply{})

assert.True(t, found)
assert.Equal(t, SRSP, identity.MessageType)
assert.Equal(t, SYS, identity.Subsystem)
assert.Equal(t, uint8(0x08), identity.CommandID)

ty, found := ml.GetByIdentifier(SRSP, SYS, 0x08)

assert.True(t, found)
assert.Equal(t, reflect.TypeOf(SysOSALNVReadReply{}), ty)
})

t.Run("SysOSALNVWrite", func(t *testing.T) {
identity, found := ml.GetByObject(&SysOSALNVWrite{})

Expand Down
55 changes: 50 additions & 5 deletions nvram_write.go → nvram.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ import (
"reflect"
)

var NVRAMWriteUnsuccessful = errors.New("nvram write unsuccessful")
var NVRAMUnrecognised = errors.New("nvram write structure unrecognised")
var NVRAMUnsuccessful = errors.New("nvram operation unsuccessful")
var NVRAMUnrecognised = errors.New("nvram structure unrecognised")

func (z *ZStack) writeNVRAM(ctx context.Context, v interface{}) error {
configId, found := nvMapping[reflect.TypeOf(v)]
configId, found := nvramStructToID[reflect.TypeOf(v)]

if !found {
return NVRAMUnrecognised
Expand All @@ -37,12 +37,43 @@ func (z *ZStack) writeNVRAM(ctx context.Context, v interface{}) error {
}

if writeResponse.Status != ZSuccess {
return fmt.Errorf("%w: status = %v", NVRAMWriteUnsuccessful, writeResponse.Status)
return fmt.Errorf("%w: status = %v", NVRAMUnsuccessful, writeResponse.Status)
}

return nil
}

func (z *ZStack) readNVRAM(ctx context.Context, v interface{}) error {
vType := reflect.TypeOf(v)

if vType.Kind() == reflect.Ptr {
vType = vType.Elem()
}

configId, found := nvramStructToID[vType]

if !found {
return NVRAMUnrecognised
}

readRequest := SysOSALNVRead{
NVItemID: configId,
Offset: 0,
}

readResponse := SysOSALNVReadReply{}

if err := z.requestResponder.RequestResponse(ctx, readRequest, &readResponse); err != nil {
return err
}

if readResponse.Status != ZSuccess {
return fmt.Errorf("%w: status = %v", NVRAMUnsuccessful, readResponse.Status)
}

return bytecodec.Unmarshal(readResponse.Value, v)
}

type SysOSALNVWrite struct {
NVItemID uint16
Offset uint8
Expand All @@ -55,7 +86,21 @@ type SysOSALNVWriteReply GenericZStackStatus

const SysOSALNVWriteReplyID uint8 = 0x09

var nvMapping = map[reflect.Type]uint16{
type SysOSALNVRead struct {
NVItemID uint16
Offset uint8
}

const SysOSALNVReadID uint8 = 0x08

type SysOSALNVReadReply struct {
Status ZStackStatus
Value []byte `bcsliceprefix:"8"`
}

const SysOSALNVReadReplyID uint8 = 0x08

var nvramStructToID = map[reflect.Type]uint16{
reflect.TypeOf(ZCDNVStartUpOption{}): ZCDNVStartUpOptionID,
reflect.TypeOf(ZCDNVLogicalType{}): ZCDNVLogicalTypeID,
reflect.TypeOf(ZCDNVSecurityMode{}): ZCDNVSecurityModeID,
Expand Down
98 changes: 95 additions & 3 deletions nvram_write_test.go → nvram_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,69 @@ import (
"time"
)

func Test_readNVRAM(t *testing.T) {
t.Run("verifies that a request response is made to unpi", func(t *testing.T) {
mrr := &ReturningMockRequestResponse{}

z := ZStack{requestResponder: mrr}

ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
defer cancel()

val := &ZCDNVLogicalType{}
err := z.readNVRAM(ctx, val)

assert.NoError(t, err)
assert.Equal(t, zigbee.EndDevice, val.LogicalType)
})

t.Run("verifies that read requests that fail raise an error", func(t *testing.T) {
mrr := &ReadFailingMockRequestResponse{}

z := ZStack{requestResponder: mrr}

ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
defer cancel()

err := z.readNVRAM(ctx, &ZCDNVLogicalType{})

assert.Error(t, err)
})

t.Run("verifies that a request response with errors is raised", func(t *testing.T) {
mrr := new(MockRequestResponder)

mrr.On("RequestResponse", mock.Anything, SysOSALNVRead{
NVItemID: ZCDNVLogicalTypeID,
Offset: 0,
}, &SysOSALNVReadReply{}).Return(errors.New("context expired"))

z := ZStack{requestResponder: mrr}

ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
defer cancel()

err := z.readNVRAM(ctx, &ZCDNVLogicalType{})

mrr.AssertExpectations(t)
assert.Error(t, err)
})

t.Run("verifies that unknown structure raises an error", func(t *testing.T) {
mrr := new(MockRequestResponder)

z := ZStack{requestResponder: mrr}

ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
defer cancel()

err := z.readNVRAM(ctx, struct{}{})

mrr.AssertExpectations(t)
assert.Error(t, err)
})
}

func Test_writeNVRAM(t *testing.T) {
t.Run("verifies that a request response is made to unpi", func(t *testing.T) {
mrr := new(MockRequestResponder)
Expand All @@ -33,7 +96,7 @@ func Test_writeNVRAM(t *testing.T) {
})

t.Run("verifies that write requests that fail raise an error", func(t *testing.T) {
mrr := &FailingMockRequestResponse{}
mrr := &WriteFailingMockRequestResponse{}

z := ZStack{requestResponder: mrr}

Expand Down Expand Up @@ -80,9 +143,9 @@ func Test_writeNVRAM(t *testing.T) {
})
}

type FailingMockRequestResponse struct{}
type WriteFailingMockRequestResponse struct{}

func (m *FailingMockRequestResponse) RequestResponse(ctx context.Context, req interface{}, resp interface{}) error {
func (m *WriteFailingMockRequestResponse) RequestResponse(ctx context.Context, req interface{}, resp interface{}) error {
response, ok := resp.(*SysOSALNVWriteReply)

if !ok {
Expand All @@ -94,6 +157,35 @@ func (m *FailingMockRequestResponse) RequestResponse(ctx context.Context, req in
return nil
}

type ReadFailingMockRequestResponse struct{}

func (m *ReadFailingMockRequestResponse) RequestResponse(ctx context.Context, req interface{}, resp interface{}) error {
response, ok := resp.(*SysOSALNVReadReply)

if !ok {
panic("incorrect type passed to mock")
}

response.Status = 0x01

return nil
}

type ReturningMockRequestResponse struct{}

func (m *ReturningMockRequestResponse) RequestResponse(ctx context.Context, req interface{}, resp interface{}) error {
response, ok := resp.(*SysOSALNVReadReply)

if !ok {
panic("incorrect type passed to mock")
}

response.Status = ZSuccess
response.Value = []byte{0x02}

return nil
}

func Test_NVRAMStructs(t *testing.T) {
t.Run("ZCDNVStartUpOption", func(t *testing.T) {
s := ZCDNVStartUpOption{
Expand Down

0 comments on commit bdd8340

Please sign in to comment.