1
0
mirror of https://github.com/mainflux/mainflux.git synced 2025-05-14 19:29:11 +08:00
Manuel Imperiale e16a025fba
MF-886 - Add OPC-UA adapter (#878)
* 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>
2019-10-22 17:44:19 +02:00

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()
}