Skip to content

Commit

Permalink
error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
Jan Klaban committed Jan 24, 2025
1 parent accfeca commit 3b8d21e
Show file tree
Hide file tree
Showing 11 changed files with 114 additions and 100 deletions.
52 changes: 30 additions & 22 deletions dlmsal/data.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,21 @@ type DlmsData struct {
}

func NewDlmsDataError(err AccessResultTag) DlmsData {
return DlmsData{Tag: TagError, Value: DlmsError{Result: err}}
return DlmsData{Tag: TagError, Value: NewDlmsError(err)}
}

type DlmsError struct {
Result AccessResultTag
}

func (e *DlmsError) Error() string {
return fmt.Sprintf("dlms error: %s", e.Result)
}

func NewDlmsError(result AccessResultTag) error {
return &DlmsError{Result: result}
}

type DlmsCompactArray struct {
tag dataTag
tags []dataTag
Expand Down Expand Up @@ -100,7 +108,7 @@ func decodeData(src io.Reader, tag dataTag, tmpbuffer *tmpbuffer) (data DlmsData
{
_, err = io.ReadFull(src, tmpbuffer[:1])
if err != nil {
return data, 0, fmt.Errorf("too short data for boolean, %v", err)
return data, 0, fmt.Errorf("too short data for boolean, %w", err)
}
return DlmsData{Tag: tag, Value: tmpbuffer[0] != 0}, 1, nil
}
Expand All @@ -119,7 +127,7 @@ func decodeData(src io.Reader, tag dataTag, tmpbuffer *tmpbuffer) (data DlmsData
}
_, err = io.ReadFull(src, tmp)
if err != nil {
return data, 0, fmt.Errorf("too short data for bitstring %v", err)
return data, 0, fmt.Errorf("too short data for bitstring %w", err)
}
val := make([]bool, l)
off := uint(0)
Expand All @@ -139,7 +147,7 @@ func decodeData(src io.Reader, tag dataTag, tmpbuffer *tmpbuffer) (data DlmsData
{
_, err = io.ReadFull(src, tmpbuffer[:4])
if err != nil {
return data, 0, fmt.Errorf("too short data for double long %v", err)
return data, 0, fmt.Errorf("too short data for double long %w", err)
}
v := int32(tmpbuffer[0])<<24 | int32(tmpbuffer[1])<<16 | int32(tmpbuffer[2])<<8 | int32(tmpbuffer[3])
return DlmsData{Tag: tag, Value: v}, 4, nil
Expand All @@ -148,7 +156,7 @@ func decodeData(src io.Reader, tag dataTag, tmpbuffer *tmpbuffer) (data DlmsData
{
_, err = io.ReadFull(src, tmpbuffer[:4])
if err != nil {
return data, 0, fmt.Errorf("too short data for double long unsigned %v", err)
return data, 0, fmt.Errorf("too short data for double long unsigned %w", err)
}
v := uint32(tmpbuffer[0])<<24 | uint32(tmpbuffer[1])<<16 | uint32(tmpbuffer[2])<<8 | uint32(tmpbuffer[3])
return DlmsData{Tag: tag, Value: v}, 4, nil
Expand All @@ -162,7 +170,7 @@ func decodeData(src io.Reader, tag dataTag, tmpbuffer *tmpbuffer) (data DlmsData
v := make([]byte, l)
_, err = io.ReadFull(src, v)
if err != nil {
return data, 0, fmt.Errorf("too short data for octet string %v", err)
return data, 0, fmt.Errorf("too short data for octet string %w", err)
}
return DlmsData{Tag: tag, Value: v}, c + int(l), nil
}
Expand All @@ -175,7 +183,7 @@ func decodeData(src io.Reader, tag dataTag, tmpbuffer *tmpbuffer) (data DlmsData
v := make([]byte, l)
_, err = io.ReadFull(src, v)
if err != nil {
return data, 0, fmt.Errorf("too short data for visible string %v", err)
return data, 0, fmt.Errorf("too short data for visible string %w", err)
}
return DlmsData{Tag: tag, Value: string(v)}, c + int(l), nil // double copy
}
Expand All @@ -201,7 +209,7 @@ func decodeData(src io.Reader, tag dataTag, tmpbuffer *tmpbuffer) (data DlmsData
{
_, err = io.ReadFull(src, tmpbuffer[:1])
if err != nil {
return data, 0, fmt.Errorf("too short data for bcd %v", err)
return data, 0, fmt.Errorf("too short data for bcd %w", err)
}
v := int(tmpbuffer[0]&0xf) + 10*(int(tmpbuffer[0]>>4)&7)
if (tmpbuffer[0] & 0x80) != 0 {
Expand All @@ -213,7 +221,7 @@ func decodeData(src io.Reader, tag dataTag, tmpbuffer *tmpbuffer) (data DlmsData
{
_, err = io.ReadFull(src, tmpbuffer[:1])
if err != nil {
return data, 0, fmt.Errorf("too short data for integer %v", err)
return data, 0, fmt.Errorf("too short data for integer %w", err)
}
v := int8(tmpbuffer[0])
return DlmsData{Tag: tag, Value: v}, 1, nil
Expand All @@ -222,7 +230,7 @@ func decodeData(src io.Reader, tag dataTag, tmpbuffer *tmpbuffer) (data DlmsData
{
_, err = io.ReadFull(src, tmpbuffer[:2])
if err != nil {
return data, 0, fmt.Errorf("too short data for long %v", err)
return data, 0, fmt.Errorf("too short data for long %w", err)
}
v := int16(tmpbuffer[0])<<8 | int16(tmpbuffer[1])
return DlmsData{Tag: tag, Value: v}, 2, nil
Expand All @@ -231,7 +239,7 @@ func decodeData(src io.Reader, tag dataTag, tmpbuffer *tmpbuffer) (data DlmsData
{
_, err = io.ReadFull(src, tmpbuffer[:1])
if err != nil {
return data, 0, fmt.Errorf("too short data for unsigned/enum %v", err)
return data, 0, fmt.Errorf("too short data for unsigned/enum %w", err)
}
v := uint8(tmpbuffer[0])
return DlmsData{Tag: tag, Value: v}, 1, nil
Expand All @@ -240,7 +248,7 @@ func decodeData(src io.Reader, tag dataTag, tmpbuffer *tmpbuffer) (data DlmsData
{
_, err = io.ReadFull(src, tmpbuffer[:2])
if err != nil {
return data, 0, fmt.Errorf("too short data for long unsigned %v", err)
return data, 0, fmt.Errorf("too short data for long unsigned %w", err)
}
v := uint16(tmpbuffer[0])<<8 | uint16(tmpbuffer[1])
return DlmsData{Tag: tag, Value: v}, 2, nil
Expand All @@ -249,7 +257,7 @@ func decodeData(src io.Reader, tag dataTag, tmpbuffer *tmpbuffer) (data DlmsData
{
n, err := io.ReadFull(src, tmpbuffer[:1])
if err != nil {
return data, 0, fmt.Errorf("too short data for compact array %v", err)
return data, 0, fmt.Errorf("too short data for compact array %w", err)
}
ctag := dataTag(tmpbuffer[0])
var types []dataTag
Expand All @@ -267,7 +275,7 @@ func decodeData(src io.Reader, tag dataTag, tmpbuffer *tmpbuffer) (data DlmsData
}
_, err = io.ReadFull(src, tmp)
if err != nil {
return data, 0, fmt.Errorf("too short data for compact array (number of structure items), %v", err)
return data, 0, fmt.Errorf("too short data for compact array (number of structure items), %w", err)
}
types = make([]dataTag, l)
for i := 0; i < int(l); i++ {
Expand All @@ -285,7 +293,7 @@ func decodeData(src io.Reader, tag dataTag, tmpbuffer *tmpbuffer) (data DlmsData
// length in bytes, then slice it and traverse through slice till there is something left
l, c, err := decodelength(src, tmpbuffer)
if err != nil {
return data, 0, fmt.Errorf("too short data for compact array (length) %v", err)
return data, 0, fmt.Errorf("too short data for compact array (length) %w", err)
}
n += c

Expand Down Expand Up @@ -342,7 +350,7 @@ func decodeData(src io.Reader, tag dataTag, tmpbuffer *tmpbuffer) (data DlmsData
{
_, err = io.ReadFull(src, tmpbuffer[:8])
if err != nil {
return data, 0, fmt.Errorf("too short data for long64 %v", err)
return data, 0, fmt.Errorf("too short data for long64 %w", err)
}
v := int64(tmpbuffer[0])<<56 | int64(tmpbuffer[1])<<48 | int64(tmpbuffer[2])<<40 | int64(tmpbuffer[3])<<32 | int64(tmpbuffer[4])<<24 | int64(tmpbuffer[5])<<16 | int64(tmpbuffer[6])<<8 | int64(tmpbuffer[7])
return DlmsData{Tag: tag, Value: v}, 8, nil
Expand All @@ -351,7 +359,7 @@ func decodeData(src io.Reader, tag dataTag, tmpbuffer *tmpbuffer) (data DlmsData
{
_, err = io.ReadFull(src, tmpbuffer[:8])
if err != nil {
return data, 0, fmt.Errorf("too short data for long64 unsigned %v", err)
return data, 0, fmt.Errorf("too short data for long64 unsigned %w", err)
}
v := uint64(tmpbuffer[0])<<56 | uint64(tmpbuffer[1])<<48 | uint64(tmpbuffer[2])<<40 | uint64(tmpbuffer[3])<<32 | uint64(tmpbuffer[4])<<24 | uint64(tmpbuffer[5])<<16 | uint64(tmpbuffer[6])<<8 | uint64(tmpbuffer[7])
return DlmsData{Tag: tag, Value: v}, 8, nil
Expand All @@ -360,23 +368,23 @@ func decodeData(src io.Reader, tag dataTag, tmpbuffer *tmpbuffer) (data DlmsData
{
_, err = io.ReadFull(src, tmpbuffer[:4])
if err != nil {
return data, 0, fmt.Errorf("too short data for float32 %v", err)
return data, 0, fmt.Errorf("too short data for float32 %w", err)
}
return DlmsData{Tag: tag, Value: math.Float32frombits(binary.BigEndian.Uint32(tmpbuffer[:4]))}, 4, nil
}
case TagFloat64:
{
_, err = io.ReadFull(src, tmpbuffer[:8])
if err != nil {
return data, 0, fmt.Errorf("too short data for float64 %v", err)
return data, 0, fmt.Errorf("too short data for float64 %w", err)
}
return DlmsData{Tag: tag, Value: math.Float64frombits(binary.BigEndian.Uint64(tmpbuffer[:8]))}, 8, nil
}
case TagDateTime:
{
_, err = io.ReadFull(src, tmpbuffer[:12])
if err != nil {
return data, 0, fmt.Errorf("too short data for datetime %v", err)
return data, 0, fmt.Errorf("too short data for datetime %w", err)
}
v := DlmsDateTime{
Date: DlmsDate{
Expand All @@ -400,7 +408,7 @@ func decodeData(src io.Reader, tag dataTag, tmpbuffer *tmpbuffer) (data DlmsData
{
_, err = io.ReadFull(src, tmpbuffer[:5])
if err != nil {
return data, 0, fmt.Errorf("too short data for date %v", err)
return data, 0, fmt.Errorf("too short data for date %w", err)
}
v := DlmsDate{
Year: uint16(tmpbuffer[0])<<8 | uint16(tmpbuffer[1]),
Expand All @@ -414,7 +422,7 @@ func decodeData(src io.Reader, tag dataTag, tmpbuffer *tmpbuffer) (data DlmsData
{
_, err = io.ReadFull(src, tmpbuffer[:4])
if err != nil {
return data, 0, fmt.Errorf("too short data for time %v", err)
return data, 0, fmt.Errorf("too short data for time %w", err)
}
v := DlmsTime{
Hour: tmpbuffer[0],
Expand Down
7 changes: 4 additions & 3 deletions dlmsal/datastream.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package dlmsal

import (
"errors"
"fmt"
"io"

Expand Down Expand Up @@ -101,8 +102,8 @@ func (d *datastream) NextElement() (*DlmsDataStreamItem, error) {
_, err := io.ReadFull(d.src, d.buffer[:1])
if err != nil {
d.inerror = true
if err == io.EOF {
return nil, fmt.Errorf("unexpected EOF")
if errors.Is(err, io.EOF) {
return nil, io.ErrUnexpectedEOF
}
return nil, err
}
Expand Down Expand Up @@ -142,7 +143,7 @@ func (d *datastream) Close() error { // artifically read out the rest
n, err := d.src.Read(rb)
cnt += n
if err != nil {
if err == io.EOF {
if errors.Is(err, io.EOF) {
if d.logger != nil {
d.logger.Debugf("data stream readout %v bytes", cnt)
}
Expand Down
17 changes: 9 additions & 8 deletions dlmsal/dlmsal.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package dlmsal

import (
"bytes"
"errors"
"fmt"
"io"

Expand Down Expand Up @@ -66,9 +67,9 @@ type DlmsClient interface {
Open() error
SetLogger(logger *zap.SugaredLogger)
Get(items []DlmsLNRequestItem) ([]DlmsData, error)
GetStream(item DlmsLNRequestItem, inmem bool) (DlmsDataStream, *DlmsError, error)
GetStream(item DlmsLNRequestItem, inmem bool) (DlmsDataStream, error)
Read(items []DlmsSNRequestItem) ([]DlmsData, error)
ReadStream(item DlmsSNRequestItem, inmem bool) (DlmsDataStream, *DlmsError, error) // only for big single item queries
ReadStream(item DlmsSNRequestItem, inmem bool) (DlmsDataStream, error) // only for big single item queries
Write(items []DlmsSNRequestItem) ([]AccessResultTag, error)
Action(item DlmsLNRequestItem) (*DlmsData, error)
Set(items []DlmsLNRequestItem) ([]AccessResultTag, error)
Expand Down Expand Up @@ -266,10 +267,10 @@ func (d *dlmsal) smallreadout() ([]byte, error) {

n, err := d.transport.Read(ret[total:])
total += n
if err == io.EOF {
return ret[:total], nil
}
if err != nil {
if errors.Is(err, io.EOF) {
return ret[:total], nil
}
return nil, err
}
}
Expand All @@ -293,19 +294,19 @@ func (d *dlmsal) Open() error { // login and shits
}
aare, err := d.smallreadout()
if err != nil {
return fmt.Errorf("unable to receive snrm: %v", err)
return fmt.Errorf("unable to receive snrm: %w", err)
}
// parse aare
tag, _, data, err := decodetag(aare, &d.tmpbuffer)
if err != nil {
return fmt.Errorf("unable to parse aare: %v", err)
return fmt.Errorf("unable to parse aare: %w", err)
}
if tag != byte(TagAARE) {
return fmt.Errorf("unexpected tag: %x", tag)
}
tags, err := decodeaare(data, &d.tmpbuffer)
if err != nil {
return fmt.Errorf("unable to parse aare: %v", err)
return fmt.Errorf("unable to parse aare: %w", err)
}
for _, dt := range tags {
switch dt.tag {
Expand Down
16 changes: 8 additions & 8 deletions dlmsal/dlmsexception.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package dlmsal

import (
"fmt"
"errors"
"io"
)

Expand All @@ -11,15 +11,15 @@ func decodeException(src io.Reader, tmp *tmpbuffer) (e DlmsData, err error) {
switch n {
case 0:
e = NewDlmsDataError(TagAccOtherReason)
case 1:
e = NewDlmsDataError(TagAccOtherReason) // not decoding state-error
case 2:
e = NewDlmsDataError(TagAccOtherReason) // not decoding service error
case 1, 2:
e = NewDlmsDataError(TagAccOtherReason) // not decoding state-error or service-error
default:
err = fmt.Errorf("programatic error, unexpected read bytes count")
panic("programatic error, unexpected read bytes count")
}
if err == io.EOF || err == io.ErrUnexpectedEOF {
err = nil
if err != nil {
if errors.Is(err, io.EOF) || errors.Is(err, io.ErrUnexpectedEOF) {
err = nil
}
}
return
}
5 changes: 3 additions & 2 deletions dlmsal/dlmslnaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package dlmsal

import (
"bytes"
"errors"
"fmt"
"io"

Expand Down Expand Up @@ -30,7 +31,7 @@ func encodelnactionitem(dst *bytes.Buffer, item *DlmsLNRequestItem) error {
dst.WriteByte(1)
err := encodeData(dst, item.SetData)
if err != nil {
return fmt.Errorf("unable to encode data: %v", err)
return fmt.Errorf("unable to encode data: %w", err)
}
} else {
dst.WriteByte(0)
Expand Down Expand Up @@ -100,7 +101,7 @@ func (ln *dlmsalaction) actiondata(tag CosemTag) (data *DlmsData, err error) {

_, err = io.ReadFull(ln.transport, master.tmpbuffer[:1])
if err != nil {
if err == io.EOF || err == io.ErrUnexpectedEOF {
if errors.Is(err, io.EOF) || errors.Is(err, io.ErrUnexpectedEOF) {
return nil, nil
}
return
Expand Down
Loading

0 comments on commit 3b8d21e

Please sign in to comment.