init
This commit is contained in:
commit
bd1bb4a03e
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
my_test.cfg
|
||||
*.db
|
97
flow.go
Normal file
97
flow.go
Normal file
|
@ -0,0 +1,97 @@
|
|||
package flow
|
||||
|
||||
import (
|
||||
"log"
|
||||
"time"
|
||||
)
|
||||
|
||||
// FlowContext 流程的上下文, 用于传递每个流程之间的参数
|
||||
type FlowContext struct {
|
||||
RootFlow *Flow
|
||||
CurrentFlow *FlowNode
|
||||
|
||||
CurrentWrite []byte // 8 byte
|
||||
CurrentRead []byte // 14 byte
|
||||
}
|
||||
|
||||
// FlowNode 流程节点
|
||||
type FlowNode struct {
|
||||
Name string
|
||||
Path string
|
||||
|
||||
prev *FlowNode
|
||||
next *FlowNode
|
||||
|
||||
Task func(cxt *FlowContext) int
|
||||
}
|
||||
|
||||
// Write 该写入函数包含了 自动封装日志格式
|
||||
func (cxt *FlowContext) Write(flag OperatorFlag) {
|
||||
|
||||
operator.portWriterLock.Lock()
|
||||
wbuf := OperatorOption(flag)
|
||||
operator.port.Write(wbuf)
|
||||
operator.port.Flush()
|
||||
cxt.CurrentWrite = wbuf
|
||||
operator.portWriterLock.Unlock()
|
||||
|
||||
if len(wbuf) == 8 {
|
||||
flowpath := cxt.CurrentFlow.Path + ">" + cxt.CurrentFlow.Name // 路径
|
||||
_, err := operator.oplog.Exec("insert into operator(ts , rootflow, flowpath, writelog, readlog) values(?,?,?,?,?)", time.Now().Unix(), cxt.RootFlow.Name, flowpath, cxt.CurrentWrite, cxt.CurrentRead)
|
||||
if err != nil {
|
||||
log.Println("日志写入错误: ", err)
|
||||
}
|
||||
} else {
|
||||
log.Println("write buffer len is not equal to 8, now is", len(wbuf), "buf: ", wbuf)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Sensor 返回传感器数值, 每次调用都是最新的.
|
||||
func (cxt *FlowContext) Sensor() *Sensor {
|
||||
buf := make([]byte, 14)
|
||||
|
||||
operator.portReaderLock.Lock()
|
||||
n, err := operator.port.Read(buf)
|
||||
cxt.CurrentRead = buf
|
||||
operator.portReaderLock.Unlock()
|
||||
if err != nil {
|
||||
log.Println("read bufferr is error:", err)
|
||||
} else {
|
||||
|
||||
if n == 14 {
|
||||
return NewSensor(buf)
|
||||
}
|
||||
//TODO: 断包, 沾包 处理
|
||||
log.Println("读取长度不等于14, len = ", n)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Flow 流程
|
||||
type Flow struct {
|
||||
Name string
|
||||
|
||||
Context *FlowContext // 执行流程时候的上下文
|
||||
|
||||
Head *FlowNode
|
||||
Tail *FlowNode
|
||||
}
|
||||
|
||||
// Add 添加
|
||||
func (flow *Flow) Add(node *FlowNode) {
|
||||
|
||||
if flow.Head == nil {
|
||||
flow.Head = node
|
||||
flow.Tail = node
|
||||
return
|
||||
}
|
||||
|
||||
flow.Tail.next = node
|
||||
flow.Tail = node
|
||||
|
||||
if node.next != nil {
|
||||
panic("tail next is not nil")
|
||||
}
|
||||
}
|
11
go.mod
Normal file
11
go.mod
Normal file
|
@ -0,0 +1,11 @@
|
|||
module flow
|
||||
|
||||
go 1.13
|
||||
|
||||
require (
|
||||
github.com/mattn/go-sqlite3 v1.11.0
|
||||
github.com/smartystreets/goconvey v1.6.4 // indirect
|
||||
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07
|
||||
golang.org/x/sys v0.0.0-20191104094858-e8c54fb511f6 // indirect
|
||||
gopkg.in/ini.v1 v1.50.0
|
||||
)
|
21
go.sum
Normal file
21
go.sum
Normal file
|
@ -0,0 +1,21 @@
|
|||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/mattn/go-sqlite3 v1.11.0 h1:LDdKkqtYlom37fkvqs8rMPFKAMe8+SgjbwZ6ex1/A/Q=
|
||||
github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07 h1:UyzmZLoiDWMRywV4DUYb9Fbt8uiOSooupjTq10vpvnU=
|
||||
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20191104094858-e8c54fb511f6 h1:ZJUmhYTp8GbGC0ViZRc2U+MIYQ8xx9MscsdXnclfIhw=
|
||||
golang.org/x/sys v0.0.0-20191104094858-e8c54fb511f6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
gopkg.in/ini.v1 v1.50.0 h1:c/4YI/GUgB7d2yOkxdsQyYDhW67nWrTl6Zyd9vagYmg=
|
||||
gopkg.in/ini.v1 v1.50.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
4
my.cfg
Normal file
4
my.cfg
Normal file
|
@ -0,0 +1,4 @@
|
|||
[config]
|
||||
portid = /dev/pts3
|
||||
baud = 9600
|
||||
readtimeout = 5
|
119
operator.go
Normal file
119
operator.go
Normal file
|
@ -0,0 +1,119 @@
|
|||
package flow
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/binary"
|
||||
"log"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
serial "github.com/tarm/serial"
|
||||
"gopkg.in/ini.v1"
|
||||
)
|
||||
|
||||
// GetOperatorDB 获取 operator 日志
|
||||
func GetOperatorDB() *sql.DB {
|
||||
db, err := sql.Open("sqlite3", "./log.db")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
_, err = db.Exec("create table if not EXISTS operator ( ts INT, rootflow varchar(255), flowpath text, writelog char(8), readlog char(14))")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return db
|
||||
}
|
||||
|
||||
// OperatorFlag 操作位
|
||||
type OperatorFlag uint16
|
||||
|
||||
const (
|
||||
UltrasonicPower OperatorFlag = 0b1000000000000000 // UltrasonicPower bit15 超声波电源开关 1开,0关
|
||||
// CYZ-A-X
|
||||
CirculatingIrrigation OperatorFlag = 0b0100000000000000 // CirculatingIrrigation bit14 循环灌洗水泵 1开,0关
|
||||
UFRecoil OperatorFlag = 0b0010000000000000 // bit13 UF 超滤膜反冲进水阀 1开,0关
|
||||
UFPositive OperatorFlag = 0b0001000000000000 // bit12 UF 超滤膜正冲进水阀 1开,0关
|
||||
// YM-01-X-03
|
||||
UFTreatedWater OperatorFlag = 0b0000100000000000 // bit11 UF 超滤膜净水出水阀 1开,0关
|
||||
UFRawWater OperatorFlag = 0b0000010000000000 // bit10 UF超滤膜原水进水阀 1开,0关
|
||||
// CirculatingTankWashWater YM-01-X-01
|
||||
CirculatingTankWashWater OperatorFlag = 0b0000001000000000 // bit9 循环罐洗进水电动球阀 1开,0关
|
||||
UFPositiveFlushingWaterOutlet OperatorFlag = 0b0000000100000000 // bit8 UF超滤膜正冲浓水出口电磁阀 1开,0关
|
||||
// CleaningTankExhaust YV-02-02-1-X-06
|
||||
CleaningTankExhaust OperatorFlag = 0b0000000010000000 // bit7 清洗罐排气电磁阀 1开,0关
|
||||
DPFCompactCylinderControlB OperatorFlag = 0b0000000001000000 // bit6 DPF压紧气缸控制电磁阀B 1开,0关
|
||||
DPFCompactCylinderControlA OperatorFlag = 0b0000000000100000 // bit5 DPF压紧气缸控制电磁阀A 1开,0关
|
||||
// YV-02-05-1-X-04
|
||||
CleaningTankDrainingWater OperatorFlag = 0b0000000000010000 // bit4 清洗罐放水阀控制电磁阀 1开,0关
|
||||
GasExplosion OperatorFlag = 0b0000000000001000 // bit3 气爆阀控制电磁阀 1开,0关
|
||||
// YV-02-02-1-X-02
|
||||
CleaningTankInflation OperatorFlag = 0b0000000000000100 // bit2 清洗罐充气电磁阀 1开,0关
|
||||
CleaningTankSealB OperatorFlag = 0b0000000000000010 // bit1 清洗罐密封圈充气电磁阀B 1开,0关
|
||||
CleaningTankSealA OperatorFlag = 0b0000000000000001 // bit0 清洗罐密封圈充气电磁阀A 1开,0关
|
||||
)
|
||||
|
||||
// OperatorOption 操作位设置
|
||||
func OperatorOption(flag OperatorFlag) []byte {
|
||||
var buf []byte = make([]byte, 8, 8)
|
||||
buf[0] = byte(0xaa)
|
||||
buf[1] = byte(0x55)
|
||||
binary.BigEndian.PutUint16(buf[2:], uint16(flag))
|
||||
check := byte(0)
|
||||
for _, b := range buf {
|
||||
check += b
|
||||
}
|
||||
buf[7] = check
|
||||
return buf
|
||||
}
|
||||
|
||||
// Operator 日志系统
|
||||
type Operator struct {
|
||||
port *serial.Port
|
||||
|
||||
portReaderLock *sync.Mutex
|
||||
portWriterLock *sync.Mutex
|
||||
|
||||
oplog *sql.DB
|
||||
}
|
||||
|
||||
var operator *Operator
|
||||
|
||||
func init() {
|
||||
op := &Operator{}
|
||||
op.portReaderLock = &sync.Mutex{}
|
||||
op.portWriterLock = &sync.Mutex{}
|
||||
|
||||
op.oplog = GetOperatorDB()
|
||||
|
||||
var portid string
|
||||
var baud int
|
||||
var rtimeout time.Duration
|
||||
|
||||
var cfg *ini.File
|
||||
cfg, err := ini.Load("my_test.cfg")
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
log.Println("加载配置my.cfg失败, 将使用默认值")
|
||||
f, err := os.OpenFile("./my_test.cfg", os.O_CREATE|os.O_WRONLY, 0666)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
f.WriteString("[config]\nportid = COM1\nbaud = 9600\nreadtimeout = 5")
|
||||
cfg, err = ini.Load("my_test.cfg")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
section := cfg.Section("config")
|
||||
portid = section.Key("portid").MustString("COM1")
|
||||
baud = section.Key("baud").MustInt(9600)
|
||||
rtimeout = time.Second * time.Duration(section.Key("readtimeout").MustInt64(5))
|
||||
|
||||
port, err := serial.OpenPort(&serial.Config{Name: portid, Baud: baud, ReadTimeout: rtimeout})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
op.port = port
|
||||
}
|
63
sensor.go
Normal file
63
sensor.go
Normal file
|
@ -0,0 +1,63 @@
|
|||
package flow
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
|
||||
// Sensor 传感器
|
||||
type Sensor struct {
|
||||
SP01 uint16 // 清洗罐气压传感器 SP-01 罐体排空,值≤0.5(暂定)
|
||||
SP02 uint16 // 清洗液水箱水位传感器 SP-02 模拟量传感器
|
||||
LT01 uint16 // 清洗罐满水位传感器 (非接触式水位传感器) LT-01 模拟量传感器
|
||||
LT02 uint16 // 清洗罐排水传感器 (非接触式水位传感器) LT-02 模拟量传感器
|
||||
LT03 uint8 // 清洗液水箱满水位传感器 (浮子式水位传感器) LT-03 值为1,清洗液水箱满水位
|
||||
}
|
||||
|
||||
func (sensor *Sensor) String() string {
|
||||
return fmt.Sprintf("SP01=%d SP02=%d LT01=%d LT02=%d LT03=%d", sensor.SP01, sensor.SP02, sensor.LT01, sensor.LT02, sensor.LT03)
|
||||
}
|
||||
|
||||
func NewSensor(buf []byte) *Sensor {
|
||||
|
||||
if len(buf) == 14 {
|
||||
|
||||
if buf[0] == byte(0xaa) && buf[1] == byte(0x55) {
|
||||
|
||||
sensor := &Sensor{}
|
||||
|
||||
sensor.SP01 = binary.BigEndian.Uint16(buf[2:4])
|
||||
sensor.SP02 = binary.BigEndian.Uint16(buf[4:6])
|
||||
sensor.LT01 = binary.BigEndian.Uint16(buf[6:8])
|
||||
sensor.LT02 = binary.BigEndian.Uint16(buf[8:10])
|
||||
sensor.LT03 = uint8(buf[10])
|
||||
|
||||
return sensor
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
log.Println(buf, "非标准传感器字节流")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// BytesFromSensor 生成Buf从Sensor
|
||||
func BytesFromSensor(sensor *Sensor) []byte {
|
||||
buf := make([]byte, 14)
|
||||
buf[0] = byte(0xaa)
|
||||
buf[1] = byte(0x55)
|
||||
|
||||
binary.BigEndian.PutUint16(buf[2:4], sensor.SP01)
|
||||
binary.BigEndian.PutUint16(buf[4:6], sensor.SP02)
|
||||
binary.BigEndian.PutUint16(buf[6:8], sensor.LT01)
|
||||
binary.BigEndian.PutUint16(buf[8:10], sensor.LT02)
|
||||
buf[10] = sensor.LT03
|
||||
|
||||
for _, b := range buf[0:13] {
|
||||
buf[13] += b
|
||||
}
|
||||
|
||||
return buf
|
||||
}
|
58
tests/cfg_test.go
Normal file
58
tests/cfg_test.go
Normal file
|
@ -0,0 +1,58 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"gopkg.in/ini.v1"
|
||||
)
|
||||
|
||||
func TestIntCreate(t *testing.T) {
|
||||
|
||||
os.Remove("./my_test.cfg")
|
||||
time.Sleep(time.Second * 1)
|
||||
|
||||
for i := 0; i < 3; i++ {
|
||||
|
||||
var portid string
|
||||
var baud int
|
||||
var rtimeout time.Duration
|
||||
|
||||
var cfg *ini.File
|
||||
cfg, err := ini.Load("my_test.cfg")
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
log.Println("加载配置my.cfg失败, 将使用默认值")
|
||||
f, err := os.OpenFile("./my_test.cfg", os.O_CREATE|os.O_WRONLY, 0666)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
f.WriteString("[config]\nportid = COM1\nbaud = 9600\nreadtimeout = 5")
|
||||
cfg, err = ini.Load("my_test.cfg")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
section := cfg.Section("config")
|
||||
portid = section.Key("portid").MustString("COM1")
|
||||
baud = section.Key("baud").MustInt(9600)
|
||||
rtimeout = time.Second * time.Duration(section.Key("readtimeout").MustInt64(5))
|
||||
|
||||
if portid != "COM1" {
|
||||
t.Error(`portid != "COM1"`)
|
||||
}
|
||||
|
||||
if baud != 9600 {
|
||||
t.Error(`baud != 9600`)
|
||||
}
|
||||
|
||||
if rtimeout != time.Second*5 {
|
||||
t.Error(`rtimeout != time.Second * 5`)
|
||||
}
|
||||
}
|
||||
|
||||
os.Remove("./my_test.cfg")
|
||||
}
|
Loading…
Reference in New Issue
Block a user