Browse Source

init

master
lihua 5 years ago
parent
commit
3ce16ce158
  1. 2
      .gitignore
  2. 3
      build.bat
  3. 12
      config.json
  4. 594
      deviceIDCS.go
  5. BIN
      deviceIDCS.ico
  6. 15
      deviceIDCS.manifest
  7. 13
      go.mod
  8. 19
      go.sum
  9. BIN
      rsrc.syso
  10. 1
      syso.bat

2
.gitignore

@ -65,4 +65,4 @@ fabric.properties
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
.idea

3
build.bat

@ -0,0 +1,3 @@
rem set GOARCH=386
set CGO_ENABLED=0
go build -ldflags "-H windowsgui"

12
config.json

@ -0,0 +1,12 @@
{
"MQTT": {
"host": "39.98.253.192",
"port": 1885,
"username": "",
"password": "",
"ssl": false,
"ca_cert": "",
"tls_cert": "",
"tls_key": ""
}
}

594
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
}
}
}

BIN
deviceIDCS.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

15
deviceIDCS.manifest

@ -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>

13
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
)

19
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=

BIN
rsrc.syso

Binary file not shown.

1
syso.bat

@ -0,0 +1 @@
rsrc -manifest deviceIDCS.manifest -ico deviceIDCS.ico -o rsrc.syso
Loading…
Cancel
Save