lihua
5 years ago
10 changed files with 658 additions and 1 deletions
@ -0,0 +1,3 @@ |
|||||
|
rem set GOARCH=386 |
||||
|
set CGO_ENABLED=0 |
||||
|
go build -ldflags "-H windowsgui" |
@ -0,0 +1,12 @@ |
|||||
|
{ |
||||
|
"MQTT": { |
||||
|
"host": "39.98.253.192", |
||||
|
"port": 1885, |
||||
|
"username": "", |
||||
|
"password": "", |
||||
|
"ssl": false, |
||||
|
"ca_cert": "", |
||||
|
"tls_cert": "", |
||||
|
"tls_key": "" |
||||
|
} |
||||
|
} |
@ -0,0 +1,594 @@ |
|||||
|
package main |
||||
|
|
||||
|
import ( |
||||
|
"bytes" |
||||
|
"crypto/tls" |
||||
|
"crypto/x509" |
||||
|
"encoding/json" |
||||
|
"fmt" |
||||
|
mqtt "github.com/eclipse/paho.mqtt.golang" |
||||
|
"github.com/lxn/walk" |
||||
|
. "github.com/lxn/walk/declarative" |
||||
|
"github.com/lxn/win" |
||||
|
"go.bug.st/serial.v1" |
||||
|
"io/ioutil" |
||||
|
"log" |
||||
|
"os" |
||||
|
"sort" |
||||
|
"strconv" |
||||
|
"strings" |
||||
|
"time" |
||||
|
) |
||||
|
|
||||
|
type DeviceInfo struct { |
||||
|
ID int64 `json:"id"` |
||||
|
DevEui string `json:"devEUI"` |
||||
|
DevAddr string `json:"devAddr"` |
||||
|
Username string `json:"username"` |
||||
|
CreateAt string `json:"createAt"` |
||||
|
} |
||||
|
|
||||
|
type Config struct { |
||||
|
MQTT struct { |
||||
|
Host string `json:"host"` |
||||
|
Port int `json:"port"` |
||||
|
Username string `json:"username"` |
||||
|
Password string `json:"password"` |
||||
|
SSL bool `json:"ssl"` |
||||
|
CACert string `json:"ca_cert"` |
||||
|
TLSCert string `json:"tls_cert"` |
||||
|
TLSKey string `json:"tls_key"` |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
type CSModel struct { |
||||
|
walk.TableModelBase |
||||
|
walk.SorterBase |
||||
|
sortColumn int |
||||
|
sortOrder walk.SortOrder |
||||
|
items []*DeviceInfo |
||||
|
} |
||||
|
|
||||
|
func (m *CSModel) RowCount() int { |
||||
|
return len(m.items) |
||||
|
} |
||||
|
|
||||
|
func (m *CSModel) Value(row, col int) interface{} { |
||||
|
item := m.items[row] |
||||
|
|
||||
|
switch col { |
||||
|
case 0: |
||||
|
return item.ID |
||||
|
case 1: |
||||
|
return item.DevEui |
||||
|
case 2: |
||||
|
return item.DevAddr |
||||
|
case 3: |
||||
|
return item.Username |
||||
|
case 4: |
||||
|
return item.CreateAt |
||||
|
} |
||||
|
panic("unexpected col") |
||||
|
} |
||||
|
|
||||
|
func (m *CSModel) Sort(col int, order walk.SortOrder) error { |
||||
|
m.sortColumn, m.sortOrder = col, order |
||||
|
sort.Stable(m) |
||||
|
return m.SorterBase.Sort(col, order) |
||||
|
} |
||||
|
|
||||
|
func (m *CSModel) Len() int { |
||||
|
return len(m.items) |
||||
|
} |
||||
|
|
||||
|
func (m *CSModel) Less(i, j int) bool { |
||||
|
a, b := m.items[i], m.items[j] |
||||
|
c := func(ls bool) bool { |
||||
|
if m.sortOrder == walk.SortAscending { |
||||
|
return ls |
||||
|
} |
||||
|
return !ls |
||||
|
} |
||||
|
|
||||
|
switch m.sortColumn { |
||||
|
case 0: |
||||
|
return c(a.ID < b.ID) |
||||
|
case 1: |
||||
|
return c(a.DevEui < b.DevEui) |
||||
|
case 2: |
||||
|
return c(a.DevAddr < b.DevAddr) |
||||
|
case 3: |
||||
|
return c(a.Username < b.Username) |
||||
|
default: |
||||
|
return false |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (m *CSModel) Swap(i, j int) { |
||||
|
m.items[i], m.items[j] = m.items[j], m.items[i] |
||||
|
} |
||||
|
|
||||
|
func NewCSModel() *CSModel { |
||||
|
return new(CSModel) |
||||
|
} |
||||
|
|
||||
|
type CSMainWindow struct { |
||||
|
*walk.MainWindow |
||||
|
mqttClient mqtt.Client |
||||
|
serialPort serial.Port |
||||
|
model *CSModel |
||||
|
tv *walk.TableView |
||||
|
host,username,password*walk.LineEdit |
||||
|
port *walk.NumberEdit |
||||
|
connect, disconnect,caConf,send,open,close *walk.PushButton |
||||
|
ssl *walk.CheckBox |
||||
|
msg,recvData,sendData *walk.TextEdit |
||||
|
commPort,baudRate,dataBits,stopBits,parity *walk.ComboBox |
||||
|
confFileName string |
||||
|
conf Config |
||||
|
icon *walk.Icon |
||||
|
recvDatas,sendDatas string |
||||
|
ch chan string |
||||
|
serialOpen bool |
||||
|
} |
||||
|
|
||||
|
func main() { |
||||
|
mw := &CSMainWindow{model: NewCSModel(),ch:make(chan string,100),serialOpen:false} |
||||
|
mw.icon,_ = walk.NewIconFromResourceId(3) |
||||
|
maxWidth := int(win.GetSystemMetrics(win.SM_CXSCREEN)) - 200 |
||||
|
maxHeight := int(win.GetSystemMetrics(win.SM_CYSCREEN)) - 100 |
||||
|
err := MainWindow{ |
||||
|
AssignTo: &mw.MainWindow, |
||||
|
Title: "DeviceIDCS", |
||||
|
Icon: mw.icon, |
||||
|
Size: Size{maxWidth,maxHeight }, |
||||
|
Layout: VBox{}, |
||||
|
Children: []Widget{ |
||||
|
Composite{ |
||||
|
Layout: HBox{MarginsZero: true}, |
||||
|
Children: []Widget{ |
||||
|
Label{Text:"主机/IP:"}, |
||||
|
LineEdit{AssignTo:&mw.host}, |
||||
|
Label{Text:"端口:"}, |
||||
|
NumberEdit{AssignTo:&mw.port,MinSize:Size{Width:50}}, |
||||
|
Label{Text:"用户名:"}, |
||||
|
LineEdit{AssignTo:&mw.username}, |
||||
|
Label{Text:"密码:"}, |
||||
|
LineEdit{AssignTo:&mw.password,PasswordMode:true}, |
||||
|
PushButton{Text:"连接", AssignTo: &mw.connect,OnClicked:mw.Connect}, |
||||
|
PushButton{Text:"断开连接", AssignTo:&mw.disconnect, Enabled:false, OnClicked: mw.Disconnect}, |
||||
|
CheckBox{Text:"开启SSL/TLS",AssignTo:&mw.ssl,OnClicked:mw.SSL}, |
||||
|
PushButton{Text:"证书配置",Enabled:false,AssignTo:&mw.caConf,OnClicked: mw.Config}, |
||||
|
PushButton{Text:"清空数据", OnClicked: mw.Clean}, |
||||
|
}, |
||||
|
}, |
||||
|
Composite{ |
||||
|
Layout: HBox{}, |
||||
|
Children: []Widget{ |
||||
|
TableView{ |
||||
|
AssignTo: &mw.tv, |
||||
|
MinSize:Size{Width:maxWidth*3/5}, |
||||
|
CheckBoxes: true, |
||||
|
ColumnsOrderable: true, |
||||
|
MultiSelection: true, |
||||
|
Columns: []TableViewColumn{ |
||||
|
{Title: "序号"}, |
||||
|
{Title: "终端EUI"}, |
||||
|
{Title: "终端Addr"}, |
||||
|
{Title: "用户名"}, |
||||
|
{Title: "创建时间"}, |
||||
|
}, |
||||
|
Model: mw.model, |
||||
|
}, |
||||
|
Composite{ |
||||
|
Layout:VBox{}, |
||||
|
Children:[]Widget{ |
||||
|
GroupBox{ |
||||
|
Title:"串口设置", |
||||
|
Layout:VBox{SpacingZero:true}, |
||||
|
Children:[]Widget{ |
||||
|
Composite{ |
||||
|
Layout: Grid{Columns:4}, |
||||
|
Children: []Widget{ |
||||
|
Label{Text:"端口号:"}, |
||||
|
ComboBox{AssignTo:&mw.commPort}, |
||||
|
Label{Text:"波特率:"}, |
||||
|
ComboBox{AssignTo:&mw.baudRate,Model:[]string{"115200","57600","56000","38400","19200","14400","9600"}}, |
||||
|
Label{Text:"数据位:"}, |
||||
|
ComboBox{AssignTo:&mw.dataBits,Model:[]string{"8","7","6","5"}}, |
||||
|
Label{Text:"停止位:"}, |
||||
|
ComboBox{AssignTo:&mw.stopBits,Model:[]string{"1","1.5","2"}}, |
||||
|
Label{Text:"奇偶校验:"}, |
||||
|
ComboBox{AssignTo:&mw.parity,Model:[]string{"None","Odd","Even","Mark","Space"}}, |
||||
|
HSpacer{}, |
||||
|
HSpacer{}, |
||||
|
HSpacer{}, |
||||
|
HSpacer{}, |
||||
|
PushButton{Text:"打开串口", AssignTo: &mw.open,OnClicked:mw.Open}, |
||||
|
PushButton{Text:"关闭串口", AssignTo: &mw.close,Enabled:false,OnClicked:mw.Close1}, |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
GroupBox{ |
||||
|
Title:"串口发送", |
||||
|
Layout:VBox{SpacingZero:true}, |
||||
|
Children:[]Widget{ |
||||
|
Composite{ |
||||
|
Layout:VBox{}, |
||||
|
Children:[]Widget{ |
||||
|
Label{Text:"消息"}, |
||||
|
TextEdit{AssignTo:&mw.msg}, |
||||
|
}, |
||||
|
}, |
||||
|
Composite{ |
||||
|
Layout:HBox{}, |
||||
|
Children:[]Widget{ |
||||
|
HSpacer{}, |
||||
|
PushButton{Text:"手动发送",AssignTo:&mw.send,OnClicked: mw.SendMsg}, |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
Composite{ |
||||
|
Layout: HBox{}, |
||||
|
Children: []Widget{ |
||||
|
TextEdit{AssignTo:&mw.recvData,ReadOnly:true,HScroll:true,VScroll:true}, |
||||
|
TextEdit{AssignTo:&mw.sendData,ReadOnly:true,HScroll:true,VScroll:true}, |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
}.Create() |
||||
|
if err != nil { |
||||
|
panic("DeviceIDCS窗口创建失败") |
||||
|
} |
||||
|
_ = mw.port.SetValue(1883) |
||||
|
_ = mw.baudRate.SetCurrentIndex(0) |
||||
|
_ = mw.dataBits.SetCurrentIndex(0) |
||||
|
_ = mw.stopBits.SetCurrentIndex(0) |
||||
|
_ = mw.parity.SetCurrentIndex(0) |
||||
|
|
||||
|
go func(mw *CSMainWindow) { |
||||
|
for{ |
||||
|
ports, _ := serial.GetPortsList() |
||||
|
if (len(ports) > 0 && mw.commPort.Model() == nil) || |
||||
|
(mw.commPort.Model() != nil && len(ports) != len(mw.commPort.Model().([]string))) { |
||||
|
_ = mw.commPort.SetModel(ports) |
||||
|
} |
||||
|
time.Sleep(time.Second) |
||||
|
} |
||||
|
}(mw) |
||||
|
|
||||
|
dir,_ := os.Getwd() |
||||
|
mw.confFileName = dir + "/config.json" |
||||
|
data, err := ioutil.ReadFile(mw.confFileName) |
||||
|
if err == nil { |
||||
|
err = json.Unmarshal(data, &mw.conf) |
||||
|
if err != nil { |
||||
|
msg := "配置文件格式错误:" + err.Error() |
||||
|
walk.MsgBox(mw, "错误", msg, walk.MsgBoxIconError) |
||||
|
} else { |
||||
|
_ = mw.host.SetText(mw.conf.MQTT.Host) |
||||
|
_ = mw.port.SetValue(float64(mw.conf.MQTT.Port)) |
||||
|
_ = mw.username.SetText(mw.conf.MQTT.Username) |
||||
|
_ = mw.password.SetText(mw.conf.MQTT.Password) |
||||
|
mw.ssl.SetChecked(mw.conf.MQTT.SSL) |
||||
|
} |
||||
|
} |
||||
|
mw.Run() |
||||
|
} |
||||
|
|
||||
|
func newTLSConfig(cafile, certFile, certKeyFile string) (*tls.Config, error) { |
||||
|
if cafile == "" && certFile == "" && certKeyFile == "" { |
||||
|
return nil, nil |
||||
|
} |
||||
|
tlsConfig := &tls.Config{} |
||||
|
// Import trusted certificates from CAfile.pem.
|
||||
|
if cafile != "" { |
||||
|
cacert, err := ioutil.ReadFile(cafile) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
certpool := x509.NewCertPool() |
||||
|
certpool.AppendCertsFromPEM(cacert) |
||||
|
|
||||
|
tlsConfig.RootCAs = certpool // RootCAs = certs used to verify server cert.
|
||||
|
} |
||||
|
|
||||
|
// Import certificate and the key
|
||||
|
if certFile != "" && certKeyFile != "" { |
||||
|
kp, err := tls.LoadX509KeyPair(certFile, certKeyFile) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
tlsConfig.Certificates = []tls.Certificate{kp} |
||||
|
} |
||||
|
|
||||
|
return tlsConfig, nil |
||||
|
} |
||||
|
|
||||
|
func (mw *CSMainWindow) Connect() { |
||||
|
if !mw.serialOpen { |
||||
|
msg := "串口未打开,请先打开串口" |
||||
|
walk.MsgBox(mw, "错误", msg, walk.MsgBoxIconError) |
||||
|
return |
||||
|
} |
||||
|
go func() { |
||||
|
if mw.host.Text() != "" && mw.port.Value() > 0 { |
||||
|
opts := mqtt.NewClientOptions() |
||||
|
serverAddr := fmt.Sprintf("%s:%d",mw.host.Text(),int(mw.port.Value())) |
||||
|
if mw.ssl.Checked() { |
||||
|
if mw.conf.MQTT.CACert != "" { |
||||
|
serverAddr = fmt.Sprintf("ssl://%s:%d",mw.host.Text(),int(mw.port.Value())) |
||||
|
tlsconfig, err := newTLSConfig(mw.conf.MQTT.CACert, mw.conf.MQTT.TLSCert, mw.conf.MQTT.TLSKey) |
||||
|
if err != nil { |
||||
|
msg := "证书加载错误:" + err.Error() |
||||
|
walk.MsgBox(mw, "错误", msg, walk.MsgBoxIconError) |
||||
|
} |
||||
|
if tlsconfig != nil { |
||||
|
opts.SetTLSConfig(tlsconfig) |
||||
|
} |
||||
|
}else{ |
||||
|
msg := "证书未配置,服务端单向认证只需配置CA证书,双向认证还需配置客户端证书及秘钥" |
||||
|
walk.MsgBox(mw, "错误", msg, walk.MsgBoxIconError) |
||||
|
return |
||||
|
} |
||||
|
} |
||||
|
opts.AddBroker(serverAddr) |
||||
|
opts.SetUsername(mw.username.Text()) |
||||
|
opts.SetPassword(mw.password.Text()) |
||||
|
opts.SetConnectTimeout(5 * time.Second) |
||||
|
mw.mqttClient = mqtt.NewClient(opts) |
||||
|
token := mw.mqttClient.Connect() |
||||
|
if token.Wait() && token.Error() == nil { |
||||
|
mw.conf.MQTT.Host = mw.host.Text() |
||||
|
mw.conf.MQTT.Port = int(mw.port.Value()) |
||||
|
mw.conf.MQTT.Username = mw.username.Text() |
||||
|
mw.conf.MQTT.Password = mw.password.Text() |
||||
|
var confData bytes.Buffer |
||||
|
d,_ := json.Marshal(&mw.conf) |
||||
|
_ = json.Indent(&confData, d, "", "\t") |
||||
|
_ = ioutil.WriteFile(mw.confFileName,confData.Bytes(),0644) |
||||
|
mw.host.SetEnabled(false) |
||||
|
mw.port.SetEnabled(false) |
||||
|
mw.username.SetEnabled(false) |
||||
|
mw.password.SetEnabled(false) |
||||
|
mw.disconnect.SetEnabled(true) |
||||
|
mw.connect.SetEnabled(false) |
||||
|
mw.ssl.SetEnabled(false) |
||||
|
mw.caConf.SetEnabled(false) |
||||
|
mw.send.SetEnabled(false) |
||||
|
mw.msg.SetEnabled(false) |
||||
|
topic := "device/id" |
||||
|
token := mw.mqttClient.Subscribe(topic,0, func(client mqtt.Client, message mqtt.Message) { |
||||
|
var dev DeviceInfo |
||||
|
_ = json.Unmarshal(message.Payload(), &dev) |
||||
|
const TIME_LAYOUT = "2006-01-02 15:04:05" |
||||
|
if lt, err := time.ParseInLocation(time.RFC3339Nano, dev.CreateAt, time.UTC);err == nil { |
||||
|
dev.CreateAt = lt.Local().Format(TIME_LAYOUT) |
||||
|
} |
||||
|
cmds := []string{"AT+DEUI=" + dev.DevEui + "\r\n","AT+DADDR=" + dev.DevAddr + "\r\n"} |
||||
|
for _,cmd := range cmds{ |
||||
|
_, err := mw.serialPort.Write([]byte(cmd)) |
||||
|
if err != nil { |
||||
|
mw.sendDatas += err.Error() + "\r\n" |
||||
|
_ = mw.sendData.SetText(mw.sendDatas) |
||||
|
continue |
||||
|
} |
||||
|
mw.sendDatas += cmd |
||||
|
_ = mw.sendData.SetText(mw.sendDatas) |
||||
|
mw.ch <- cmd |
||||
|
} |
||||
|
|
||||
|
mw.model.items = append(mw.model.items, &dev) |
||||
|
mw.model.PublishRowsReset() |
||||
|
_ = mw.tv.SetSelectedIndexes([]int{}) |
||||
|
}) |
||||
|
if token.Wait() && token.Error() != nil { |
||||
|
msg := "订阅失败:" + token.Error().Error() |
||||
|
walk.MsgBox(mw, "错误", msg, walk.MsgBoxIconError) |
||||
|
} |
||||
|
}else{ |
||||
|
msg := "连接失败:" + token.Error().Error() |
||||
|
walk.MsgBox(mw, "错误", msg, walk.MsgBoxIconError) |
||||
|
} |
||||
|
}else{ |
||||
|
msg := "主机/IP不能为空,端口不能为0" |
||||
|
walk.MsgBox(mw, "错误", msg, walk.MsgBoxIconError) |
||||
|
} |
||||
|
}() |
||||
|
} |
||||
|
|
||||
|
func (mw *CSMainWindow) Disconnect() { |
||||
|
mw.connect.SetEnabled(true) |
||||
|
mw.host.SetEnabled(true) |
||||
|
mw.port.SetEnabled(true) |
||||
|
mw.username.SetEnabled(true) |
||||
|
mw.password.SetEnabled(true) |
||||
|
mw.disconnect.SetEnabled(false) |
||||
|
mw.ssl.SetEnabled(true) |
||||
|
mw.caConf.SetEnabled(true) |
||||
|
mw.mqttClient.Disconnect(0) |
||||
|
mw.send.SetEnabled(true) |
||||
|
mw.msg.SetEnabled(true) |
||||
|
} |
||||
|
|
||||
|
|
||||
|
func (mw *CSMainWindow) Clean() { |
||||
|
mw.model.items = []*DeviceInfo{} |
||||
|
mw.model.PublishRowsReset() |
||||
|
_ = mw.tv.SetSelectedIndexes([]int{}) |
||||
|
} |
||||
|
func (mw *CSMainWindow) SSL() { |
||||
|
mw.conf.MQTT.SSL = mw.ssl.Checked() |
||||
|
if mw.ssl.Checked() { |
||||
|
mw.caConf.SetEnabled(true) |
||||
|
}else{ |
||||
|
mw.caConf.SetEnabled(false) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (mw *CSMainWindow) Config() { |
||||
|
var dlg *walk.Dialog |
||||
|
var caCert,tlsCert,tlsKey *walk.LineEdit |
||||
|
var acceptPB, cancelPB *walk.PushButton |
||||
|
_ = Dialog{ |
||||
|
Title: "配置", |
||||
|
Layout: VBox{}, |
||||
|
Icon: mw.icon, |
||||
|
AssignTo: &dlg, |
||||
|
DefaultButton: &acceptPB, |
||||
|
CancelButton: &cancelPB, |
||||
|
MinSize: Size{400, 200}, |
||||
|
Children: []Widget{ |
||||
|
Composite{ |
||||
|
Layout:Grid{Columns: 3}, |
||||
|
Children:[]Widget{ |
||||
|
Label{Text:"CA证书:"}, |
||||
|
LineEdit{Text:Bind("CACert"),AssignTo:&caCert}, |
||||
|
PushButton{Text:"打开",OnClicked: func() { |
||||
|
dlg := new(walk.FileDialog) |
||||
|
dlg.Title = "请选择CA证书" |
||||
|
dlg.Filter = "CA证书 (*.crt)|*.crt|所有文件 (*.*)|*.*" |
||||
|
if ok, err := dlg.ShowOpen(mw); err != nil { |
||||
|
return |
||||
|
} else if !ok { |
||||
|
return |
||||
|
} |
||||
|
_ = caCert.SetText(dlg.FilePath) |
||||
|
}}, |
||||
|
Label{Text:"客户端证书:"}, |
||||
|
LineEdit{Text:Bind("TLSCert"),AssignTo:&tlsCert}, |
||||
|
PushButton{Text:"打开",OnClicked: func() { |
||||
|
dlg := new(walk.FileDialog) |
||||
|
dlg.Title = "请选择客户端证书" |
||||
|
dlg.Filter = "客户端证书 (*.crt)|*.crt|所有文件 (*.*)|*.*" |
||||
|
if ok, err := dlg.ShowOpen(mw); err != nil { |
||||
|
return |
||||
|
} else if !ok { |
||||
|
return |
||||
|
} |
||||
|
_ = tlsCert.SetText(dlg.FilePath) |
||||
|
}}, |
||||
|
Label{Text:"客户端证书秘钥:"}, |
||||
|
LineEdit{Text:Bind("TLSKey"),AssignTo:&tlsKey}, |
||||
|
PushButton{Text:"打开",OnClicked: func() { |
||||
|
dlg := new(walk.FileDialog) |
||||
|
dlg.Title = "请选择客户端证书秘钥" |
||||
|
dlg.Filter = "客户端证书秘钥 (*.key)|*.key|所有文件 (*.*)|*.*" |
||||
|
if ok, err := dlg.ShowOpen(mw); err != nil { |
||||
|
return |
||||
|
} else if !ok { |
||||
|
return |
||||
|
} |
||||
|
_ = tlsKey.SetText(dlg.FilePath) |
||||
|
}}, |
||||
|
}, |
||||
|
}, |
||||
|
Composite{ |
||||
|
Layout: HBox{}, |
||||
|
Children: []Widget{ |
||||
|
HSpacer{}, |
||||
|
PushButton{ |
||||
|
AssignTo: &acceptPB, |
||||
|
Text: "确定", |
||||
|
OnClicked: func() { |
||||
|
mw.conf.MQTT.CACert = caCert.Text() |
||||
|
mw.conf.MQTT.TLSCert = tlsCert.Text() |
||||
|
mw.conf.MQTT.TLSKey = tlsKey.Text() |
||||
|
dlg.Accept() |
||||
|
}, |
||||
|
}, |
||||
|
PushButton{ |
||||
|
AssignTo: &cancelPB, |
||||
|
Text: "取消", |
||||
|
OnClicked: func() { dlg.Cancel() }, |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
}.Create(mw) |
||||
|
_ = caCert.SetText(mw.conf.MQTT.CACert) |
||||
|
_ = tlsCert.SetText(mw.conf.MQTT.TLSCert) |
||||
|
_ = tlsKey.SetText(mw.conf.MQTT.TLSKey) |
||||
|
dlg.Run() |
||||
|
} |
||||
|
func (mw *CSMainWindow) Open() { |
||||
|
baudRate,err := strconv.Atoi(mw.baudRate.Text()) |
||||
|
if err != nil { |
||||
|
return |
||||
|
} |
||||
|
dataBits,err := strconv.Atoi(mw.dataBits.Text()) |
||||
|
if err != nil { |
||||
|
return |
||||
|
} |
||||
|
mode := &serial.Mode{ |
||||
|
BaudRate: baudRate, |
||||
|
DataBits: dataBits, |
||||
|
StopBits: serial.StopBits(mw.stopBits.CurrentIndex()), |
||||
|
Parity: serial.Parity(mw.parity.CurrentIndex()), |
||||
|
} |
||||
|
mw.serialPort,err = serial.Open(mw.commPort.Text(),mode) |
||||
|
if err != nil { |
||||
|
msg := "打开串口失败:" + err.Error() |
||||
|
walk.MsgBox(mw, "错误", msg, walk.MsgBoxIconError) |
||||
|
return |
||||
|
} |
||||
|
mw.open.SetEnabled(false) |
||||
|
mw.close.SetEnabled(true) |
||||
|
mw.serialOpen = true |
||||
|
go RecvMsg(mw) |
||||
|
} |
||||
|
func (mw *CSMainWindow) Close1() { |
||||
|
mw.open.SetEnabled(true) |
||||
|
mw.close.SetEnabled(false) |
||||
|
_ = mw.serialPort.Close() |
||||
|
} |
||||
|
func (mw *CSMainWindow) SendMsg() { |
||||
|
if mw.serialPort == nil { |
||||
|
msg := "请先打开串口" |
||||
|
walk.MsgBox(mw, "错误", msg, walk.MsgBoxIconError) |
||||
|
return |
||||
|
} |
||||
|
msg := mw.msg.Text() + "\r\n" |
||||
|
_, err := mw.serialPort.Write([]byte(msg)) |
||||
|
if err != nil { |
||||
|
msg := "串口写入失败:" + err.Error() |
||||
|
walk.MsgBox(mw, "错误", msg, walk.MsgBoxIconError) |
||||
|
return |
||||
|
} |
||||
|
mw.ch <- msg |
||||
|
mw.sendDatas += msg |
||||
|
_ = mw.sendData.SetText(mw.sendDatas) |
||||
|
} |
||||
|
|
||||
|
func RecvMsg(mw *CSMainWindow) { |
||||
|
buff := make([]byte, 100) |
||||
|
for { |
||||
|
n, err := mw.serialPort.Read(buff) |
||||
|
if err != nil { |
||||
|
log.Println("读串口错误",err) |
||||
|
break |
||||
|
} |
||||
|
msg := string(buff[:n]) |
||||
|
dim := " ---- " |
||||
|
cmd := <- mw.ch |
||||
|
if strings.Contains(msg,"\r\n") { |
||||
|
msg = strings.Trim(msg,"\r\n") |
||||
|
} |
||||
|
if !strings.Contains(cmd,"\r\n") { |
||||
|
cmd += "\r\n" |
||||
|
} |
||||
|
mw.recvDatas += msg + dim + cmd |
||||
|
_ = mw.recvData.SetText(mw.recvDatas) |
||||
|
cmd = "" |
||||
|
if n == 0 { |
||||
|
fmt.Println("\nEOF") |
||||
|
break |
||||
|
} |
||||
|
} |
||||
|
} |
After Width: | Height: | Size: 66 KiB |
@ -0,0 +1,15 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> |
||||
|
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> |
||||
|
<assemblyIdentity version="1.0.0.0" processorArchitecture="*" name="SomeFunkyNameHere" type="win32"/> |
||||
|
<dependency> |
||||
|
<dependentAssembly> |
||||
|
<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"/> |
||||
|
</dependentAssembly> |
||||
|
</dependency> |
||||
|
<application xmlns="urn:schemas-microsoft-com:asm.v3"> |
||||
|
<windowsSettings> |
||||
|
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2, PerMonitor</dpiAwareness> |
||||
|
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">True</dpiAware> |
||||
|
</windowsSettings> |
||||
|
</application> |
||||
|
</assembly> |
@ -0,0 +1,13 @@ |
|||||
|
module deviceIDCS |
||||
|
|
||||
|
go 1.12 |
||||
|
|
||||
|
require ( |
||||
|
github.com/creack/goselect v0.1.1 // indirect |
||||
|
github.com/eclipse/paho.mqtt.golang v1.2.0 |
||||
|
github.com/lxn/walk v0.0.0-20191106172653-8c6cb582c05e |
||||
|
github.com/lxn/win v0.0.0-20191106123917-121afc750dd3 |
||||
|
go.bug.st/serial.v1 v0.0.0-20191202182710-24a6610f0541 |
||||
|
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 // indirect |
||||
|
gopkg.in/Knetic/govaluate.v3 v3.0.0 // indirect |
||||
|
) |
@ -0,0 +1,19 @@ |
|||||
|
github.com/creack/goselect v0.1.1 h1:tiSSgKE1eJtxs1h/VgGQWuXUP0YS4CDIFMp6vaI1ls0= |
||||
|
github.com/creack/goselect v0.1.1/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY= |
||||
|
github.com/eclipse/paho.mqtt.golang v1.2.0 h1:1F8mhG9+aO5/xpdtFkW4SxOJB67ukuDC3t2y2qayIX0= |
||||
|
github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts= |
||||
|
github.com/lxn/walk v0.0.0-20191106172653-8c6cb582c05e h1:dv4IlLUbRVtjwFx464cMbPrgs+c3WYp1YDkBYADgTaQ= |
||||
|
github.com/lxn/walk v0.0.0-20191106172653-8c6cb582c05e/go.mod h1:E23UucZGqpuUANJooIbHWCufXvOcT6E7Stq81gU+CSQ= |
||||
|
github.com/lxn/win v0.0.0-20191106123917-121afc750dd3 h1:DvGEvKK/Qnhph/EgdBN9zXA7pEosgJ0k57ojII51JAo= |
||||
|
github.com/lxn/win v0.0.0-20191106123917-121afc750dd3/go.mod h1:ouWl4wViUNh8tPSIwxTVMuS014WakR1hqvBc2I0bMoA= |
||||
|
go.bug.st/serial.v1 v0.0.0-20191202182710-24a6610f0541 h1:eQfoPfT+gNSh63t/oKanQlZyKgblRa/LMZRPIT+MHzA= |
||||
|
go.bug.st/serial.v1 v0.0.0-20191202182710-24a6610f0541/go.mod h1:dRSl/CVCTf56CkXgJMDOdSwNfo2g1orOGE/gBGdvjZw= |
||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= |
||||
|
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8= |
||||
|
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= |
||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
||||
|
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd h1:DBH9mDw0zluJT/R+nGuV3jWFWLFaHyYZWD4tOT+cjn0= |
||||
|
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= |
||||
|
gopkg.in/Knetic/govaluate.v3 v3.0.0 h1:18mUyIt4ZlRlFZAAfVetz4/rzlJs9yhN+U02F4u1AOc= |
||||
|
gopkg.in/Knetic/govaluate.v3 v3.0.0/go.mod h1:csKLBORsPbafmSCGTEh3U7Ozmsuq8ZSIlKk1bcqph0E= |
Binary file not shown.
@ -0,0 +1 @@ |
|||||
|
rsrc -manifest deviceIDCS.manifest -ico deviceIDCS.ico -o rsrc.syso |
Loading…
Reference in new issue