mirror of
https://github.com/mainflux/mainflux.git
synced 2025-05-14 19:29:11 +08:00

* NOISSUE- Add OPC-UA adapter Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * NOISSUE - Add opc-adapter PoC, docker and vendor Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Convert OPC messages to SenML Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Add gopcua package Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * lora-adapter typo Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Add OPC Reader Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Typo fix Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Typo fix Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Update copyright headers Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Fix reviews Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Fix reviews Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Add opc config Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Add all opc envars in the config Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Config typo Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Add route map Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Use opcua package instead of opc Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Fix OPCUA typo Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Rm MQTT sub Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Move interefaces to root Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Fix revieews and typo Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Update Gopkg.toml Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Add all envars into .env Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>
139 lines
3.2 KiB
Go
139 lines
3.2 KiB
Go
// Copyright 2018-2019 opcua authors. All rights reserved.
|
|
// Use of this source code is governed by a MIT-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
package ua
|
|
|
|
import (
|
|
"fmt"
|
|
"math"
|
|
"reflect"
|
|
"time"
|
|
|
|
"github.com/gopcua/opcua/debug"
|
|
"github.com/gopcua/opcua/errors"
|
|
)
|
|
|
|
// debugCodec enables printing of debug messages in the opcua codec.
|
|
var debugCodec = debug.FlagSet("codec")
|
|
|
|
// BinaryEncoder is the interface implemented by an object that can
|
|
// marshal itself into a binary OPC/UA representation.
|
|
type BinaryEncoder interface {
|
|
Encode() ([]byte, error)
|
|
}
|
|
|
|
var binaryEncoder = reflect.TypeOf((*BinaryEncoder)(nil)).Elem()
|
|
|
|
func isBinaryEncoder(val reflect.Value) bool {
|
|
return val.Type().Implements(binaryEncoder)
|
|
}
|
|
|
|
func Encode(v interface{}) ([]byte, error) {
|
|
val := reflect.ValueOf(v)
|
|
return encode(val, val.Type().String())
|
|
}
|
|
|
|
func encode(val reflect.Value, name string) ([]byte, error) {
|
|
if debugCodec {
|
|
fmt.Printf("encode: %s has type %s and is a %s\n", name, val.Type(), val.Type().Kind())
|
|
}
|
|
|
|
buf := NewBuffer(nil)
|
|
switch {
|
|
case isBinaryEncoder(val):
|
|
v := val.Interface().(BinaryEncoder)
|
|
return v.Encode()
|
|
|
|
case isTime(val):
|
|
buf.WriteTime(val.Interface().(time.Time))
|
|
|
|
default:
|
|
switch val.Kind() {
|
|
case reflect.Bool:
|
|
buf.WriteBool(val.Bool())
|
|
case reflect.Int8:
|
|
buf.WriteInt8(int8(val.Int()))
|
|
case reflect.Uint8:
|
|
buf.WriteUint8(uint8(val.Uint()))
|
|
case reflect.Int16:
|
|
buf.WriteInt16(int16(val.Int()))
|
|
case reflect.Uint16:
|
|
buf.WriteUint16(uint16(val.Uint()))
|
|
case reflect.Int32:
|
|
buf.WriteInt32(int32(val.Int()))
|
|
case reflect.Uint32:
|
|
buf.WriteUint32(uint32(val.Uint()))
|
|
case reflect.Int64:
|
|
buf.WriteInt64(int64(val.Int()))
|
|
case reflect.Uint64:
|
|
buf.WriteUint64(uint64(val.Uint()))
|
|
case reflect.Float32:
|
|
buf.WriteFloat32(float32(val.Float()))
|
|
case reflect.Float64:
|
|
buf.WriteFloat64(float64(val.Float()))
|
|
case reflect.String:
|
|
buf.WriteString(val.String())
|
|
case reflect.Ptr:
|
|
if val.IsNil() {
|
|
return nil, nil
|
|
}
|
|
return encode(val.Elem(), name)
|
|
case reflect.Struct:
|
|
return writeStruct(val, name)
|
|
case reflect.Slice:
|
|
return writeSlice(val, name)
|
|
default:
|
|
return nil, errors.Errorf("unsupported type: %s", val.Type())
|
|
}
|
|
}
|
|
return buf.Bytes(), buf.Error()
|
|
}
|
|
|
|
func writeStruct(val reflect.Value, name string) ([]byte, error) {
|
|
var buf []byte
|
|
valt := val.Type()
|
|
for i := 0; i < val.NumField(); i++ {
|
|
ft := valt.Field(i)
|
|
fname := name + "." + ft.Name
|
|
b, err := encode(val.Field(i), fname)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
buf = append(buf, b...)
|
|
}
|
|
return buf, nil
|
|
}
|
|
|
|
func writeSlice(val reflect.Value, name string) ([]byte, error) {
|
|
buf := NewBuffer(nil)
|
|
if val.IsNil() {
|
|
buf.WriteUint32(null)
|
|
return buf.Bytes(), buf.Error()
|
|
}
|
|
|
|
if val.Len() > math.MaxInt32 {
|
|
return nil, errors.Errorf("array too large")
|
|
}
|
|
|
|
buf.WriteUint32(uint32(val.Len()))
|
|
|
|
// fast path for []byte
|
|
if val.Type().Elem().Kind() == reflect.Uint8 {
|
|
// fmt.Println("[]byte fast path")
|
|
buf.Write(val.Bytes())
|
|
return buf.Bytes(), buf.Error()
|
|
}
|
|
|
|
// loop over elements
|
|
for i := 0; i < val.Len(); i++ {
|
|
ename := fmt.Sprintf("%s[%d]", name, i)
|
|
b, err := encode(val.Index(i), ename)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
buf.Write(b)
|
|
}
|
|
return buf.Bytes(), buf.Error()
|
|
}
|