272 lines
7.7 KiB
Go
272 lines
7.7 KiB
Go
|
// -*- Mode: Go; indent-tabs-mode: t -*-
|
|||
|
//
|
|||
|
// Copyright (C) 2018 Canonical Ltd
|
|||
|
// Copyright (C) 2018-2019 IOTech Ltd
|
|||
|
// Copyright (C) 2021 Jiangxing Intelligence Ltd
|
|||
|
// Copyright (C) 2022 HCL Technologies Ltd
|
|||
|
//
|
|||
|
// SPDX-License-Identifier: Apache-2.0
|
|||
|
|
|||
|
// Package driver this package provides an UART implementation of
|
|||
|
// ProtocolDriver interface.
|
|||
|
//
|
|||
|
// CONTRIBUTORS COMPANY
|
|||
|
//===============================================================
|
|||
|
// 1. Sathya Durai HCL Technologies
|
|||
|
// 2. Sudhamani Bijivemula HCL Technologies
|
|||
|
// 3. Vediyappan Villali HCL Technologies
|
|||
|
// 4. Vijay Annamalaisamy HCL Technologies
|
|||
|
//
|
|||
|
//
|
|||
|
|
|||
|
package driver
|
|||
|
|
|||
|
import (
|
|||
|
"device-ble/cmd/config"
|
|||
|
internalif "device-ble/internal/interfaces"
|
|||
|
"log"
|
|||
|
|
|||
|
"device-ble/pkg/ble"
|
|||
|
"device-ble/pkg/dataparse"
|
|||
|
"device-ble/pkg/mqttbus"
|
|||
|
"device-ble/pkg/uart"
|
|||
|
errorDefault "errors"
|
|||
|
"fmt"
|
|||
|
"sync"
|
|||
|
"time"
|
|||
|
|
|||
|
"github.com/spf13/cast"
|
|||
|
|
|||
|
edgexif "github.com/edgexfoundry/device-sdk-go/v4/pkg/interfaces"
|
|||
|
dsModels "github.com/edgexfoundry/device-sdk-go/v4/pkg/models"
|
|||
|
"github.com/edgexfoundry/go-mod-core-contracts/v4/clients/logger"
|
|||
|
"github.com/edgexfoundry/go-mod-core-contracts/v4/models"
|
|||
|
"github.com/edgexfoundry/go-mod-messaging/v4/pkg/types"
|
|||
|
"github.com/tarm/serial"
|
|||
|
)
|
|||
|
|
|||
|
// Driver BLE代理服务驱动程序,协调各组件初始化和生命周期管理。
|
|||
|
type Driver struct {
|
|||
|
// EdgeX SDK相关
|
|||
|
sdk edgexif.DeviceServiceSDK
|
|||
|
logger logger.LoggingClient
|
|||
|
asyncCh chan<- *dsModels.AsyncValues
|
|||
|
deviceCh chan<- []dsModels.DiscoveredDevice
|
|||
|
|
|||
|
// 核心组件
|
|||
|
BleController internalif.BLEController
|
|||
|
MessageBusClient internalif.MessageBusClient
|
|||
|
|
|||
|
// 业务服务
|
|||
|
CommandService *CommandService
|
|||
|
AgentService *AgentService
|
|||
|
|
|||
|
// 内部状态
|
|||
|
commandResponses sync.Map
|
|||
|
}
|
|||
|
|
|||
|
// Initialize 初始化设备服务
|
|||
|
/*
|
|||
|
在 Initialize 方法执行时:
|
|||
|
设备配置文件(如 devices.yaml)尚未加载,设备实例还未添加到 EdgeX 中,只能访问服务级别的配置,不能访问具体的设备配置
|
|||
|
*/
|
|||
|
func (d *Driver) Initialize(sdk edgexif.DeviceServiceSDK) error {
|
|||
|
d.sdk = sdk
|
|||
|
d.logger = sdk.LoggingClient()
|
|||
|
d.asyncCh = sdk.AsyncValuesChannel()
|
|||
|
d.deviceCh = sdk.DiscoveredDeviceChannel()
|
|||
|
return nil
|
|||
|
}
|
|||
|
|
|||
|
// HandleUpAgentCallback 处理上行透明代理数据回调。
|
|||
|
func (d *Driver) HandleUpAgentCallback(data string) {
|
|||
|
if d.AgentService != nil {
|
|||
|
d.AgentService.HandleAgentData(data)
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// HandleUpCommandCallback 处理上行命令回调。
|
|||
|
func (d *Driver) HandleUpCommandCallback(cmd string) {
|
|||
|
if d.CommandService != nil {
|
|||
|
d.CommandService.HandleCommand(cmd)
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Start 启动设备服务。
|
|||
|
func (d *Driver) Start() error {
|
|||
|
return nil
|
|||
|
}
|
|||
|
|
|||
|
// agentDown 处理蓝牙透明代理下行数据。
|
|||
|
func (d *Driver) agentDown(topic string, envelope types.MessageEnvelope) error {
|
|||
|
if err := dataparse.SendToBlE(d.BleController, envelope); err != nil {
|
|||
|
d.logger.Infof("【透明代理(↓)】下行数据发送失败 ❌, err: %v", err) // 记录成功日志
|
|||
|
}
|
|||
|
d.logger.Infof("【透明代理(↓)】下行数据发送成功 ✔, err: %v") // 记录成功日志
|
|||
|
return nil
|
|||
|
}
|
|||
|
|
|||
|
// Discover 触发协议特定的设备发现。
|
|||
|
func (s *Driver) Discover() error {
|
|||
|
return fmt.Errorf("Discover function is yet to be implemented!")
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
// ValidateDevice 校验设备协议属性。
|
|||
|
func (s *Driver) ValidateDevice(device models.Device) error {
|
|||
|
|
|||
|
protocol, ok := device.Protocols["UART"]
|
|||
|
if !ok {
|
|||
|
return errorDefault.New("Missing 'UART' protocols")
|
|||
|
}
|
|||
|
|
|||
|
deviceLocation, ok := protocol["deviceLocation"]
|
|||
|
if !ok {
|
|||
|
return errorDefault.New("Missing 'deviceLocation' information")
|
|||
|
} else if deviceLocation == "" {
|
|||
|
return errorDefault.New("deviceLocation must not empty")
|
|||
|
}
|
|||
|
|
|||
|
baudRate, ok := protocol["baudRate"]
|
|||
|
if !ok {
|
|||
|
return errorDefault.New("Missing 'baudRate' information")
|
|||
|
} else if baudRate == "" {
|
|||
|
return errorDefault.New("baudRate must not empty")
|
|||
|
}
|
|||
|
|
|||
|
return nil
|
|||
|
}
|
|||
|
|
|||
|
// Stop 停止设备服务,释放资源。
|
|||
|
func (d *Driver) Stop(force bool) error {
|
|||
|
if d.logger != nil {
|
|||
|
d.logger.Infof("正在停止BLE代理服务 (force=%v)", force)
|
|||
|
}
|
|||
|
|
|||
|
// 关闭MessageBus客户端
|
|||
|
if d.MessageBusClient != nil {
|
|||
|
if closer, ok := d.MessageBusClient.(interface{ Disconnect() error }); ok {
|
|||
|
err := closer.Disconnect()
|
|||
|
if err != nil {
|
|||
|
d.logger.Errorf("MessageBus客户端关闭失败: %v", err)
|
|||
|
} else {
|
|||
|
d.logger.Debug("MessageBus客户端已断开连接")
|
|||
|
}
|
|||
|
} else {
|
|||
|
d.logger.Debug("MessageBus客户端不支持关闭操作")
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// 关闭BLE控制器和串口
|
|||
|
if d.BleController != nil {
|
|||
|
if closer, ok := d.BleController.(interface{ Close() error }); ok {
|
|||
|
err := closer.Close()
|
|||
|
if err != nil {
|
|||
|
d.logger.Errorf("BLE控制器关闭失败: %v", err)
|
|||
|
} else {
|
|||
|
d.logger.Debug("BLE控制器已关闭")
|
|||
|
}
|
|||
|
} else {
|
|||
|
d.logger.Debug("BLE控制器不支持关闭操作")
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if d.logger != nil {
|
|||
|
d.logger.Info("BLE代理服务已停止")
|
|||
|
}
|
|||
|
|
|||
|
return nil
|
|||
|
}
|
|||
|
|
|||
|
// AddDevice 添加设备回调函数。
|
|||
|
func (d *Driver) AddDevice(deviceName string, protocols map[string]models.ProtocolProperties, adminState models.AdminState) error {
|
|||
|
d.logger.Debugf("新设备已添加: %s", deviceName)
|
|||
|
|
|||
|
// 获取 UART 配置信息
|
|||
|
// 通过结构体字段访问 Protocols
|
|||
|
var deviceLocation string
|
|||
|
var baudRate int
|
|||
|
|
|||
|
for i, protocol := range protocols {
|
|||
|
deviceLocation = fmt.Sprintf("%v", protocol["deviceLocation"])
|
|||
|
baudRate, _ = cast.ToIntE(protocol["baudRate"])
|
|||
|
d.logger.Debugf("Driver.HandleReadCommands(): protocol = %v, device location = %v, baud rate = %v timeout=%v", i, deviceLocation, baudRate)
|
|||
|
}
|
|||
|
|
|||
|
serialPort, err := uart.NewSerialPort(serial.Config{
|
|||
|
Name: deviceLocation,
|
|||
|
Baud: baudRate,
|
|||
|
ReadTimeout: time.Duration(10) * time.Millisecond,
|
|||
|
}, d.logger)
|
|||
|
if err != nil {
|
|||
|
log.Fatal("创建串口实例失败:", err)
|
|||
|
}
|
|||
|
// 初始化串口队列,注册Driver回调
|
|||
|
serialQueue := uart.NewSerialQueue(
|
|||
|
serialPort,
|
|||
|
d.logger,
|
|||
|
func(cmd string) { d.HandleUpCommandCallback(cmd) },
|
|||
|
func(data string) { d.HandleUpAgentCallback(data) },
|
|||
|
5,
|
|||
|
)
|
|||
|
|
|||
|
// 初始化BLE控制器
|
|||
|
bleController := ble.NewBLEController(serialPort, serialQueue, d.logger)
|
|||
|
|
|||
|
// 初始化BLE设备为外围设备模式
|
|||
|
if err := bleController.InitializeAsPeripheral(); err != nil {
|
|||
|
log.Fatal("BLE设备初始化失败:", err)
|
|||
|
}
|
|||
|
|
|||
|
// 加载自定义MQTT配置
|
|||
|
cfg, err := config.LoadConfig("./res/configuration.yaml")
|
|||
|
if err != nil {
|
|||
|
log.Fatal("MessageBusClient 获取自定义配置失败:", err)
|
|||
|
}
|
|||
|
d.logger.Debugf("自定义Mqtt服务配置: %v\n", cfg)
|
|||
|
// 初始化消息总线
|
|||
|
mqttClient, err := mqttbus.NewEdgexMessageBusClient(cfg, d.logger)
|
|||
|
if err != nil {
|
|||
|
log.Fatal("MessageBusClient 创建失败:", err)
|
|||
|
}
|
|||
|
|
|||
|
// 初始化业务服务
|
|||
|
commandService := &CommandService{
|
|||
|
Logger: d.logger,
|
|||
|
MessageBusClient: mqttClient,
|
|||
|
BleController: bleController,
|
|||
|
}
|
|||
|
agentService := &AgentService{
|
|||
|
Logger: d.logger,
|
|||
|
MessageBusClient: mqttClient,
|
|||
|
}
|
|||
|
|
|||
|
// 注入依赖到Driver
|
|||
|
d.BleController = bleController
|
|||
|
d.MessageBusClient = mqttClient
|
|||
|
d.CommandService = commandService
|
|||
|
d.AgentService = agentService
|
|||
|
|
|||
|
if d.BleController == nil || d.MessageBusClient == nil {
|
|||
|
return fmt.Errorf("依赖未注入")
|
|||
|
}
|
|||
|
if err := d.MessageBusClient.Subscribe(TopicBLEDown, d.agentDown); err != nil { // 转发下行数据
|
|||
|
d.logger.Errorf("【透明代理(↓)】 订阅下行总线失败 err: %v", err)
|
|||
|
}
|
|||
|
return nil
|
|||
|
}
|
|||
|
|
|||
|
// UpdateDevice 更新设备回调函数。
|
|||
|
func (d *Driver) UpdateDevice(deviceName string, protocols map[string]models.ProtocolProperties, adminState models.AdminState) error {
|
|||
|
d.logger.Debugf("设备 %s 已更新", deviceName)
|
|||
|
|
|||
|
return nil
|
|||
|
}
|
|||
|
|
|||
|
// RemoveDevice 移除设备回调函数。
|
|||
|
func (d *Driver) RemoveDevice(deviceName string, protocols map[string]models.ProtocolProperties) error {
|
|||
|
d.logger.Debugf("设备 %s 已移除", deviceName)
|
|||
|
|
|||
|
return nil
|
|||
|
}
|