Skip to content

Commit 94af0dd

Browse files
committed
feat: point accessors
Comprehensive re-write of the `Point` interface implementations to simplify the numerous different implementations to only a few based on their data types, and then add Get/Set functions for each of the fields that a Point _may_ have.
1 parent e3e751b commit 94af0dd

File tree

8 files changed

+1346
-800
lines changed

8 files changed

+1346
-800
lines changed

dnp3/data.go

Lines changed: 108 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ type DataObject struct {
9090
Points []Point `json:"points"`
9191
Extra []byte `json:"extra,omitempty"`
9292
totalSize int
93+
indexes []int
9394
}
9495

9596
func (do *DataObject) FromBytes(data []byte) error {
@@ -114,16 +115,26 @@ func (do *DataObject) FromBytes(data []byte) error {
114115
return nil
115116
}
116117

117-
var sizeAllPoints int
118+
var size int
118119

119-
do.Points, sizeAllPoints, err = do.Header.objectType.Constructor(
120+
do.Points, size, err = do.Header.objectType.Constructor(
120121
data[headSize:],
121122
numPoints,
122123
do.Header.PointPrefixCode.GetPointPrefixSize(),
124+
do.Header.PointPrefixCode,
123125
)
124-
do.totalSize += sizeAllPoints
126+
if err != nil {
127+
return fmt.Errorf("can't create points: %w", err)
128+
}
129+
130+
do.totalSize += size
131+
132+
err = do.updateIndexes()
133+
if err != nil {
134+
return fmt.Errorf("failed to update indexes: %w", err)
135+
}
125136

126-
return err
137+
return nil
127138
}
128139

129140
func (do *DataObject) ToBytes() ([]byte, error) {
@@ -201,6 +212,95 @@ func (do *DataObject) SizeOf() int {
201212
return do.totalSize
202213
}
203214

215+
func (do *DataObject) Indexes() []int {
216+
return do.indexes
217+
}
218+
219+
//nolint:cyclop // straightforward switches
220+
func (do *DataObject) updateIndexes() error {
221+
switch rangeField := do.Header.RangeField.(type) {
222+
// If the RangeField has start and stop indexes, we can pull those (0 - 5)
223+
case *RangeField0:
224+
for i := rangeField.Start; i <= rangeField.Stop; i++ {
225+
do.indexes = append(do.indexes, int(i))
226+
}
227+
228+
return nil
229+
case *RangeField1:
230+
for i := rangeField.Start; i <= rangeField.Stop; i++ {
231+
do.indexes = append(do.indexes, int(i))
232+
}
233+
234+
return nil
235+
case *RangeField2:
236+
for i := rangeField.Start; i <= rangeField.Stop; i++ {
237+
do.indexes = append(do.indexes, int(i))
238+
}
239+
240+
return nil
241+
case *RangeField3:
242+
for i := rangeField.Start; i <= rangeField.Stop; i++ {
243+
do.indexes = append(do.indexes, int(i))
244+
}
245+
246+
return nil
247+
case *RangeField4:
248+
for i := rangeField.Start; i <= rangeField.Stop; i++ {
249+
do.indexes = append(do.indexes, int(i))
250+
}
251+
252+
return nil
253+
case *RangeField5:
254+
for i := rangeField.Start; i <= rangeField.Stop; i++ {
255+
do.indexes = append(do.indexes, int(i))
256+
}
257+
258+
return nil
259+
// TODO - assumption
260+
// If the RangeField is all, we expect the points start at 0
261+
case *RangeField6:
262+
for i := range len(do.Points) {
263+
do.indexes = append(do.indexes, i)
264+
}
265+
266+
return nil
267+
// If the RangeField is count-based, we need to pull the indexes from the points themselves
268+
case *RangeField7, *RangeField8, *RangeField9, *RangeFieldB:
269+
return do.updateIndexesFromPrefix()
270+
default:
271+
return fmt.Errorf("unexpected range field type %T", do.Header.RangeField)
272+
}
273+
}
274+
275+
// updateIndexesFromPrefix resolves point indexes for count-based range
276+
// fields by inspecting the object header's PointPrefixCode.
277+
func (do *DataObject) updateIndexesFromPrefix() error {
278+
switch do.Header.PointPrefixCode {
279+
case OctetIndex1, OctetIndex2, OctetIndex4:
280+
for _, point := range do.Points {
281+
index, err := point.GetIndex()
282+
if err != nil {
283+
return fmt.Errorf("failed to get index from point: %w", err)
284+
}
285+
286+
do.indexes = append(do.indexes, index)
287+
}
288+
289+
return nil
290+
case NoPrefix:
291+
for i := range do.Points {
292+
do.indexes = append(do.indexes, i)
293+
}
294+
295+
return nil
296+
default:
297+
return fmt.Errorf(
298+
"cannot determine point indexes for prefix code %s",
299+
do.Header.PointPrefixCode,
300+
)
301+
}
302+
}
303+
204304
// ObjectHeader is used to describe the structure of application data.
205305
type ObjectHeader struct {
206306
// Object Type Field
@@ -219,16 +319,16 @@ type rangeFieldConstructor func() RangeField
219319

220320
var rangeFieldConstructors = map[RangeSpecCode]rangeFieldConstructor{
221321
StartStop1: func() RangeField { return &RangeField0{} },
222-
VirtualStartStop1: func() RangeField { return &RangeField0{} },
223322
StartStop2: func() RangeField { return &RangeField1{} },
224-
VirtualStartStop2: func() RangeField { return &RangeField1{} },
225323
StartStop4: func() RangeField { return &RangeField2{} },
226-
VirtualStartStop4: func() RangeField { return &RangeField2{} },
324+
VirtualStartStop1: func() RangeField { return &RangeField3{} },
325+
VirtualStartStop2: func() RangeField { return &RangeField4{} },
326+
VirtualStartStop4: func() RangeField { return &RangeField5{} },
227327
NoRangeField: func() RangeField { return &RangeField6{} },
228328
Count1: func() RangeField { return &RangeField7{} },
229-
Count1Variable: func() RangeField { return &RangeField7{} },
230329
Count2: func() RangeField { return &RangeField8{} },
231330
Count4: func() RangeField { return &RangeField9{} },
331+
Count1Variable: func() RangeField { return &RangeFieldB{} },
232332
}
233333

234334
var reservedRangeSpecifiers = map[RangeSpecCode]struct{}{

0 commit comments

Comments
 (0)