Skip to content

Commit

Permalink
新增镜像设备特性
Browse files Browse the repository at this point in the history
  • Loading branch information
smthing committed May 30, 2024
1 parent d10dc6a commit e891c22
Show file tree
Hide file tree
Showing 5 changed files with 299 additions and 0 deletions.
45 changes: 45 additions & 0 deletions driverbox/export/mirror/export.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package mirror

import (
"github.com/ibuilding-x/driver-box/driverbox"
"github.com/ibuilding-x/driver-box/driverbox/plugin"
"github.com/ibuilding-x/driver-box/driverbox/plugin/callback"
"github.com/ibuilding-x/driver-box/internal/plugins/mirror"
"sync"
)

var driverInstance *Export
var once = &sync.Once{}

type Export struct {
ready bool
plugin *mirror.Plugin
}

func (export *Export) Init() error {
//注册镜像插件
export.plugin = new(mirror.Plugin)
driverbox.RegisterPlugin("mirror", export.plugin)
export.ready = true
return nil
}
func NewExport() *Export {
once.Do(func() {
driverInstance = &Export{}
})
return driverInstance
}

// 点位变化触发场景联动
func (export *Export) ExportTo(deviceData plugin.DeviceData) {
callback.OnReceiveHandler(export.plugin.VirtualConnector, deviceData)
}

// 继承Export OnEvent接口
func (export *Export) OnEvent(eventCode string, key string, eventValue interface{}) error {
return nil
}

func (export *Export) IsReady() bool {
return export.ready
}
80 changes: 80 additions & 0 deletions internal/plugins/mirror/adapter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package mirror

import (
"errors"
"github.com/ibuilding-x/driver-box/driverbox/plugin"
)

// Encode 编码数据
func (c *connector) Encode(deviceId string, mode plugin.EncodeMode, values ...plugin.PointData) (res interface{}, err error) {
//本次操作的点位可能涉及到多个通讯设备,要先进行归类
group := make(map[string]EncodeModel)
for _, point := range values {
//匹配镜像设备
mirrorDevice, ok := c.mirrors[deviceId]
if !ok {
return nil, errors.New("mirror device not found")
}
//匹配原始设备
rawDevice, ok := mirrorDevice[point.PointName]
if !ok {
return nil, errors.New("mirror pointName not found")
}
if _, ok := group[rawDevice.deviceId]; !ok {
group[rawDevice.deviceId] = EncodeModel{
deviceId: rawDevice.deviceId,
points: make([]plugin.PointData, 0),
mode: mode,
}
}
model := group[rawDevice.deviceId]
model.points = append(model.points, point)
}
//group转数组
models := make([]EncodeModel, 0)
for _, model := range group {
models = append(models, model)
}
return models, err
}

// Decode 数据来源于ExportTo
func (c *connector) Decode(raw interface{}) (res []plugin.DeviceData, err error) {
//真实通讯设备的数据
rawDeviceData := raw.(plugin.DeviceData)
//镜像设备数据不支持二次镜像,否则配置失误时存在死循环风险
if _, ok := c.mirrors[rawDeviceData.ID]; ok {
return []plugin.DeviceData{}, err
}
pointMapping, ok := c.rawMapping[rawDeviceData.ID]
//当前通讯设备不存在镜像设备
if !ok {
return []plugin.DeviceData{}, err
}
//镜像设备分组
group := make(map[string]plugin.DeviceData)
for _, point := range rawDeviceData.Values {
mirrors, ok := pointMapping[point.PointName]
if !ok {
continue
}
for _, mirror := range mirrors {
//镜像设备分组以存在,填充点位
if mirrorData, ok := group[mirror.ID]; ok {
mirrorData.Values = append(mirrorData.Values, point)
continue
}
//创建镜像设备数据
group[mirror.ID] = plugin.DeviceData{
ID: mirror.ID,
Values: []plugin.PointData{
point,
},
}
}
}
for _, data := range group {
res = append(res, data)
}
return res, err
}
53 changes: 53 additions & 0 deletions internal/plugins/mirror/connector.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package mirror

import (
"errors"
"github.com/ibuilding-x/driver-box/driverbox/plugin"
"github.com/ibuilding-x/driver-box/internal/core"
)

type connector struct {
plugin *Plugin
//镜像设备与真实设备的映射关系,镜像设备ID:{镜像点位:原始设备点位}
//镜像设备的点位只会指向唯一的原始设备点位
mirrors map[string]map[string]Device
//真实设备点位与镜像设备的映射关系, rawDeviceId:{rawPointName:{mirrorDevice:[mirrorPoint]}}
//原始设备点位可能指向多个镜像设备和多个点位
//------------原始设备ID 原始点位 镜像点位------------
rawMapping map[string]map[string][]plugin.DeviceData
}

// Release 虚拟链接,无需释放
func (c *connector) Release() (err error) {
return
}

// ProtocolAdapter 协议适配器
func (p *connector) ProtocolAdapter() plugin.ProtocolAdapter {
return p
}

// Send 发送请求
func (c *connector) Send(raw interface{}) (err error) {
var e error
models := raw.([]EncodeModel)
for _, encodeModel := range models {
switch encodeModel.mode {
case plugin.WriteMode:
e = core.SendBatchWrite(encodeModel.deviceId, encodeModel.points)
case plugin.ReadMode:
e = core.SendBatchRead(encodeModel.deviceId, encodeModel.points)
default:
return errors.New("unknown mode")
}
if e != nil {
err = e
}
}
return err

}

func getMirrorKey(deviceId, pointName string) string {
return deviceId + "_" + pointName
}
15 changes: 15 additions & 0 deletions internal/plugins/mirror/model.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package mirror

import "github.com/ibuilding-x/driver-box/driverbox/plugin"

type EncodeModel struct {
deviceId string
points []plugin.PointData
mode plugin.EncodeMode
}

// Device 原始设备
type Device struct {
deviceId string
pointName string
}
106 changes: 106 additions & 0 deletions internal/plugins/mirror/plugin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package mirror

import (
"errors"
"github.com/ibuilding-x/driver-box/driverbox/config"
"github.com/ibuilding-x/driver-box/driverbox/helper"
"github.com/ibuilding-x/driver-box/driverbox/plugin"
lua "github.com/yuin/gopher-lua"
"go.uber.org/zap"
)

type Plugin struct {
logger *zap.Logger // 日志记录器
config config.Config // 核心配置
ls *lua.LState // lua 虚拟机
VirtualConnector plugin.Connector //虚拟链接
}

func (p *Plugin) Initialize(logger *zap.Logger, c config.Config, ls *lua.LState) (err error) {
p.logger = logger
p.config = c
p.ls = ls

mirrors := make(map[string]map[string]Device)
rawDeviceMappings := make(map[string]map[string][]plugin.DeviceData)
//生成镜像设备映射关系
for _, model := range p.config.DeviceModels {
deviceCount := len(model.Devices)
if deviceCount == 0 {
continue
}
if deviceCount > 1 {
return errors.New("mirror only support one device")
}
device := model.Devices[0]
if _, ok := mirrors[device.ID]; ok {
return errors.New("mirror device id must be unique")
}

mirrors[device.ID] = make(map[string]Device)
for _, point := range model.DevicePoints {
pointModel := point.ToPoint()
if pointModel.Extends["rawDevice"] == nil || pointModel.Extends["rawPoint"] == nil {
return errors.New("mirror point must have rawDevice and rawPoint")
}
//原始设备
rawDevice := pointModel.Extends["rawDevice"].(string)
//原始设备点位
rawPoint := pointModel.Extends["rawPoint"].(string)
//创建镜像设备与原始设备的映射关系
mirrors[device.ID][pointModel.Name] = Device{
deviceId: rawDevice,
pointName: rawPoint,
}

//真实设备点位与镜像设备的映射关系
if _, ok := rawDeviceMappings[rawDevice]; !ok {
//初始化设备映射
rawDeviceMappings[rawDevice] = make(map[string][]plugin.DeviceData)
}
rawPointMapping := rawDeviceMappings[rawDevice]
if _, ok := rawPointMapping[rawPoint]; !ok {
//初始化点位映射
rawPointMapping[rawPoint] = make([]plugin.DeviceData, 0)
}
ok := false
for _, deviceData := range rawPointMapping[rawPoint] {
if deviceData.ID != device.ID {
continue
}
deviceData.Values = append(deviceData.Values, plugin.PointData{
PointName: pointModel.Name,
})
ok = true
break
}
if !ok {
rawPointMapping[rawPoint] = append(rawPointMapping[rawPoint], plugin.DeviceData{
ID: device.ID,
Values: []plugin.PointData{
{
PointName: pointModel.Name,
},
},
})
}
}
}
p.VirtualConnector = &connector{
plugin: p,
mirrors: mirrors,
rawMapping: rawDeviceMappings,
}
return nil
}

func (p *Plugin) Connector(deviceSn, pointName string) (connector plugin.Connector, err error) {
return p.VirtualConnector, nil
}

func (p *Plugin) Destroy() error {
if p.ls != nil {
helper.Close(p.ls)
}
return nil
}

0 comments on commit e891c22

Please sign in to comment.