252 lines
7.2 KiB
Go
252 lines
7.2 KiB
Go
// Package model define model struct of model runtime service
|
||
package model
|
||
|
||
import (
|
||
"encoding/json"
|
||
"fmt"
|
||
"strconv"
|
||
"strings"
|
||
|
||
"modelRT/constants"
|
||
)
|
||
|
||
// MeasurementDataSource define measurement data source struct
|
||
type MeasurementDataSource struct {
|
||
Type int `json:"type"`
|
||
IOAddress IOAddress `json:"io_address"`
|
||
}
|
||
|
||
// IOAddress define interface of IO address
|
||
type IOAddress any
|
||
|
||
// CL3611Address define CL3611 protol struct
|
||
type CL3611Address struct {
|
||
Station string `json:"station"`
|
||
Device string `json:"device"`
|
||
Channel string `json:"channel"`
|
||
}
|
||
|
||
// Power104Address define electricity 104 protol struct
|
||
type Power104Address struct {
|
||
Station string `json:"station"`
|
||
Packet int `json:"packet"`
|
||
Offset int `json:"offset"`
|
||
}
|
||
|
||
// NewCL3611DataSource define func of create CL3611 data source
|
||
func NewCL3611DataSource(station, device, channel string) (*MeasurementDataSource, error) {
|
||
return &MeasurementDataSource{
|
||
Type: constants.DataSourceTypeCL3611,
|
||
IOAddress: CL3611Address{
|
||
Station: station,
|
||
Device: device,
|
||
Channel: channel,
|
||
},
|
||
}, nil
|
||
}
|
||
|
||
// NewPower104DataSource define func of create Power104 data source
|
||
func NewPower104DataSource(station string, packet, offset int) (*MeasurementDataSource, error) {
|
||
return &MeasurementDataSource{
|
||
Type: constants.DataSourceTypePower104,
|
||
IOAddress: Power104Address{
|
||
Station: station,
|
||
Packet: packet,
|
||
Offset: offset,
|
||
},
|
||
}, nil
|
||
}
|
||
|
||
func generateChannelName(prefix string, number int, suffix string) (string, error) {
|
||
switch prefix {
|
||
case constants.ChannelPrefixTelemetry:
|
||
if number > 10 {
|
||
return "", constants.ErrExceedsLimitType
|
||
}
|
||
var builder strings.Builder
|
||
numberStr := strconv.Itoa(number)
|
||
builder.Grow(len(prefix) + len(numberStr) + len(suffix))
|
||
builder.WriteString(prefix)
|
||
builder.WriteString(numberStr)
|
||
builder.WriteString(suffix)
|
||
channelName := builder.String()
|
||
return channelName, nil
|
||
case constants.ChannelPrefixTelesignal:
|
||
var numberStr string
|
||
if number < 10 {
|
||
numberStr = "0" + strconv.Itoa(number)
|
||
}
|
||
numberStr = strconv.Itoa(number)
|
||
|
||
var builder strings.Builder
|
||
builder.Grow(len(prefix) + len(numberStr) + len(suffix))
|
||
builder.WriteString(prefix)
|
||
builder.WriteString(numberStr)
|
||
builder.WriteString(suffix)
|
||
channelName := builder.String()
|
||
return channelName, nil
|
||
default:
|
||
return "", constants.ErrUnsupportedChannelPrefixType
|
||
}
|
||
}
|
||
|
||
// NewTelemetryChannel define func of generate telemetry channel CL3611 data source
|
||
func NewTelemetryChannel(station, device, channelNameSuffix string, channelNumber int) (*MeasurementDataSource, error) {
|
||
channelName, err := generateChannelName(constants.ChannelPrefixTelemetry, channelNumber, channelNameSuffix)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to generate channel name: %w", err)
|
||
}
|
||
return NewCL3611DataSource(station, device, channelName)
|
||
}
|
||
|
||
// NewTelesignalChannel define func of generate telesignal channel CL3611 data source
|
||
func NewTelesignalChannel(station, device, channelNameSuffix string, channelNumber int) (*MeasurementDataSource, error) {
|
||
channelName, err := generateChannelName(constants.ChannelPrefixTelesignal, channelNumber, channelNameSuffix)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to generate channel name: %w", err)
|
||
}
|
||
return NewCL3611DataSource(station, device, channelName)
|
||
}
|
||
|
||
// NewStandardChannel define func of generate standard channel CL3611 data source
|
||
func NewStandardChannel(station, device, channelType string) (*MeasurementDataSource, error) {
|
||
return NewCL3611DataSource(station, device, channelType)
|
||
}
|
||
|
||
// ParseDataSourceFromJSON define func of parse data source from json string
|
||
func ParseDataSourceFromJSON(jsonStr string) (MeasurementDataSource, error) {
|
||
var data struct {
|
||
Type int `json:"type"`
|
||
IOAddress json.RawMessage `json:"io_address"`
|
||
}
|
||
|
||
if err := json.Unmarshal([]byte(jsonStr), &data); err != nil {
|
||
return MeasurementDataSource{}, err
|
||
}
|
||
|
||
var source MeasurementDataSource
|
||
source.Type = data.Type
|
||
|
||
switch data.Type {
|
||
case constants.DataSourceTypeCL3611:
|
||
var addr CL3611Address
|
||
if err := json.Unmarshal(data.IOAddress, &addr); err != nil {
|
||
return MeasurementDataSource{}, err
|
||
}
|
||
source.IOAddress = addr
|
||
case constants.DataSourceTypePower104:
|
||
var addr Power104Address
|
||
if err := json.Unmarshal(data.IOAddress, &addr); err != nil {
|
||
return MeasurementDataSource{}, err
|
||
}
|
||
source.IOAddress = addr
|
||
default:
|
||
// 对于未知类型,保持原始JSON数据
|
||
source.IOAddress = data.IOAddress
|
||
}
|
||
|
||
return source, nil
|
||
}
|
||
|
||
// ToJSON define func of convert data source to json string
|
||
func (m MeasurementDataSource) ToJSON() (string, error) {
|
||
bytes, err := json.Marshal(m)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
return string(bytes), nil
|
||
}
|
||
|
||
// GetIOAddress define func of get IO address with correct type
|
||
func (m MeasurementDataSource) GetIOAddress() (IOAddress, error) {
|
||
switch m.Type {
|
||
case constants.DataSourceTypeCL3611:
|
||
if addr, ok := m.IOAddress.(CL3611Address); ok {
|
||
return addr, nil
|
||
}
|
||
return nil, constants.ErrInvalidAddressType
|
||
case constants.DataSourceTypePower104:
|
||
if addr, ok := m.IOAddress.(Power104Address); ok {
|
||
return addr, nil
|
||
}
|
||
return nil, constants.ErrInvalidAddressType
|
||
default:
|
||
return nil, constants.ErrUnknownDataType
|
||
}
|
||
}
|
||
|
||
// GenerateMeasureIdentifier define func of generate measurement identifier
|
||
func GenerateMeasureIdentifier(source map[string]any) (string, error) {
|
||
regTypeVal, ok := source["type"]
|
||
if !ok {
|
||
return "", fmt.Errorf("can not find type in datasource field")
|
||
}
|
||
|
||
var regType int
|
||
switch v := regTypeVal.(type) {
|
||
case int:
|
||
regType = v
|
||
default:
|
||
return "", fmt.Errorf("invalid type format in datasource field")
|
||
}
|
||
|
||
ioAddrVal, ok := source["io_address"]
|
||
if !ok {
|
||
return "", fmt.Errorf("can not find io_address from datasource field")
|
||
}
|
||
|
||
ioAddress, ok := ioAddrVal.(map[string]any)
|
||
if !ok {
|
||
return "", fmt.Errorf("io_address field is not a valid map")
|
||
}
|
||
|
||
switch regType {
|
||
case constants.DataSourceTypeCL3611:
|
||
station, ok := ioAddress["station"].(string)
|
||
if !ok {
|
||
return "", fmt.Errorf("CL3611:invalid or missing station field")
|
||
}
|
||
device, ok := ioAddress["device"].(string)
|
||
if !ok {
|
||
return "", fmt.Errorf("CL3611:invalid or missing device field")
|
||
}
|
||
// 提取 channel (string)
|
||
channel, ok := ioAddress["channel"].(string)
|
||
if !ok {
|
||
return "", fmt.Errorf("CL3611:invalid or missing channel field")
|
||
}
|
||
return fmt.Sprintf("%s.%s.%s", station, device, channel), nil
|
||
case constants.DataSourceTypePower104:
|
||
station, ok := ioAddress["station"].(string)
|
||
if !ok {
|
||
return "", fmt.Errorf("Power104:invalid or missing station field")
|
||
}
|
||
packetVal, ok := ioAddress["packet"]
|
||
if !ok {
|
||
return "", fmt.Errorf("Power104: missing packet field")
|
||
}
|
||
var packet int
|
||
switch v := packetVal.(type) {
|
||
case int:
|
||
packet = v
|
||
default:
|
||
return "", fmt.Errorf("Power104:invalid packet format")
|
||
}
|
||
|
||
offsetVal, ok := ioAddress["offset"]
|
||
if !ok {
|
||
return "", fmt.Errorf("Power104:missing offset field")
|
||
}
|
||
var offset int
|
||
switch v := offsetVal.(type) {
|
||
case int:
|
||
offset = v
|
||
default:
|
||
return "", fmt.Errorf("Power104:invalid offset format")
|
||
}
|
||
return fmt.Sprintf("%s.%d.%d", station, packet, offset), nil
|
||
default:
|
||
return "", fmt.Errorf("unsupport regulation type %d into datasource field", regType)
|
||
}
|
||
}
|