From 3ce16ce158a7f13a914c3ae233c79f6179c9514d Mon Sep 17 00:00:00 2001 From: lihua <531456470@qq.com> Date: Tue, 24 Dec 2019 16:39:55 +0800 Subject: [PATCH] init --- .gitignore | 2 +- build.bat | 3 + config.json | 12 + deviceIDCS.go | 594 ++++++++++++++++++++++++++++++++++++++++++++ deviceIDCS.ico | Bin 0 -> 67646 bytes deviceIDCS.manifest | 15 ++ go.mod | 13 + go.sum | 19 ++ rsrc.syso | Bin 0 -> 68863 bytes syso.bat | 1 + 10 files changed, 658 insertions(+), 1 deletion(-) create mode 100644 build.bat create mode 100644 config.json create mode 100644 deviceIDCS.go create mode 100644 deviceIDCS.ico create mode 100644 deviceIDCS.manifest create mode 100644 go.mod create mode 100644 go.sum create mode 100644 rsrc.syso create mode 100644 syso.bat diff --git a/.gitignore b/.gitignore index f3aa750..f32cc05 100644 --- a/.gitignore +++ b/.gitignore @@ -65,4 +65,4 @@ fabric.properties # Android studio 3.1+ serialized cache file .idea/caches/build_file_checksums.ser - +.idea diff --git a/build.bat b/build.bat new file mode 100644 index 0000000..1828dd9 --- /dev/null +++ b/build.bat @@ -0,0 +1,3 @@ +rem set GOARCH=386 +set CGO_ENABLED=0 +go build -ldflags "-H windowsgui" \ No newline at end of file diff --git a/config.json b/config.json new file mode 100644 index 0000000..c3d31cf --- /dev/null +++ b/config.json @@ -0,0 +1,12 @@ +{ + "MQTT": { + "host": "39.98.253.192", + "port": 1885, + "username": "", + "password": "", + "ssl": false, + "ca_cert": "", + "tls_cert": "", + "tls_key": "" + } +} \ No newline at end of file diff --git a/deviceIDCS.go b/deviceIDCS.go new file mode 100644 index 0000000..70b6de5 --- /dev/null +++ b/deviceIDCS.go @@ -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 + } + } +} \ No newline at end of file diff --git a/deviceIDCS.ico b/deviceIDCS.ico new file mode 100644 index 0000000000000000000000000000000000000000..a914feeb8bdd0d82da9bbd520acee0dd11f49119 GIT binary patch literal 67646 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 literal 0 HcmV?d00001 diff --git a/deviceIDCS.manifest b/deviceIDCS.manifest new file mode 100644 index 0000000..1492a19 --- /dev/null +++ b/deviceIDCS.manifest @@ -0,0 +1,15 @@ + + + + + + + + + + + PerMonitorV2, PerMonitor + True + + + \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..97ee7b7 --- /dev/null +++ b/go.mod @@ -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 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..ab851be --- /dev/null +++ b/go.sum @@ -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= diff --git a/rsrc.syso b/rsrc.syso new file mode 100644 index 0000000000000000000000000000000000000000..b5fe3a0b6784ac3feb299b3739e54d0f22670b8b GIT binary patch literal 68863 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 NC<)w2rd#3f{{i6IA9(-( literal 0 HcmV?d00001 diff --git a/syso.bat b/syso.bat new file mode 100644 index 0000000..b14004d --- /dev/null +++ b/syso.bat @@ -0,0 +1 @@ +rsrc -manifest deviceIDCS.manifest -ico deviceIDCS.ico -o rsrc.syso \ No newline at end of file