terry преди 8 месеца
родител
ревизия
1502e9abfa
променени са 14 файла, в които са добавени 189 реда и са изтрити 227 реда
  1. 5 0
      build.bat
  2. 28 4
      bx/BxAreaDynamic.go
  3. 5 5
      bx/BxDataPack.go
  4. 9 8
      config.yaml
  5. 6 10
      lc/IDevice.go
  6. 43 70
      lc/event.go
  7. 0 24
      lc/loudspeaker.go
  8. 2 2
      lc/model/rtu.go
  9. 60 20
      lc/screen.go
  10. 2 9
      lc/server.go
  11. 12 20
      main.go
  12. 12 10
      program_test.go
  13. 5 6
      util/config.go
  14. 0 39
      util/serial.go

+ 5 - 0
build.bat

@@ -0,0 +1,5 @@
+set GOARCH=arm
+set GOARM=6
+set GOOS=linux
+set CGO_ENABLED=0
+go build -o smartX_radio ./

+ 28 - 4
bx/BxAreaDynamic.go

@@ -42,7 +42,7 @@ type BxAreaDynamic struct {
 	soundRepeat byte
 	soundVolume byte //todo 默认值0x05
 	soundSpeed  byte
-	SoundData   []byte
+	soundData   []byte
 	// extend para len
 	extendParaLen byte
 	// type setting
@@ -73,7 +73,31 @@ type BxAreaDynamic struct {
 	data     []byte
 }
 
-func NewBxAreaDynamic(id, runMode, dispMode byte, x uint16, y uint16, w uint16, h uint16, data []byte, is5K bool) *BxAreaDynamic {
+func NewBxAreaDynamic(id, runMode, dispMode byte, x uint16, y uint16, w uint16, h uint16, data []byte,
+	soundData []byte, is5K bool) *BxAreaDynamic {
+	return &BxAreaDynamic{
+		BaseArea:    NewBxArea(0, x, y, w, h),
+		id:          id,
+		data:        data,
+		soundData:   soundData,
+		is5K:        is5K,
+		timeout:     5,
+		runMode:     runMode,
+		soundMode:   0x02,
+		soundPerson: 0x00,
+		soundVolume: 0x01,
+		soundRepeat: 0x00,
+		soundSpeed:  0x05,
+		singleLine:  0x02,
+		autoNewLine: 0x01,
+		dispMode:    dispMode,
+		speed:       0x0a,
+		holdTime:    0x08,
+	}
+}
+
+func NewBxAreaProgram(id, runMode, dispMode byte, x uint16, y uint16, w uint16, h uint16, data []byte,
+	is5K bool) *BxAreaDynamic {
 	return &BxAreaDynamic{
 		BaseArea:    NewBxArea(0, x, y, w, h),
 		id:          id,
@@ -123,9 +147,9 @@ func (b *BxAreaDynamic) Build() []byte {
 		binary.Write(w, binary.LittleEndian, b.soundSpeed)
 	}
 	if b.soundMode == 0x02 {
-		soundDataLen := len(b.SoundData)
+		soundDataLen := len(b.soundData)
 		binary.Write(w, binary.LittleEndian, int32(soundDataLen))
-		binary.Write(w, binary.LittleEndian, b.SoundData)
+		binary.Write(w, binary.LittleEndian, b.soundData)
 	}
 	// extendParaLen
 	binary.Write(w, binary.LittleEndian, b.extendParaLen)

+ 5 - 5
bx/BxDataPack.go

@@ -15,7 +15,7 @@ type BxDataPack struct {
 	r2          byte
 	option      byte
 	crcMode     byte
-	dispMode    byte
+	displayType byte
 	deviceType  byte
 	version     byte
 	dataLen     uint16
@@ -42,7 +42,7 @@ func NewBxDataPackCmd(cmd BxCmd) BxDataPack {
 		dataLen:     uint16(len(b)),
 		WRAP_A5_NUM: 8,
 		WRAP_5A_NUM: 1,
-		dstAddr:     0x0001,
+		dstAddr:     0x0001, //todo 设备id
 		srcAddr:     0x8000,
 		deviceType:  0xfe,
 		version:     0x02,
@@ -53,7 +53,7 @@ func NewBxDataPackCmd(cmd BxCmd) BxDataPack {
 // 0x00:普通模式,动态区与节目可同时显示,但各区域不可重叠。
 // 0x01:动态模式,优先显示动态区,无动态区则显示节目,动态区与节目区可重叠。
 func (dp *BxDataPack) SetDisplayType(typ byte) {
-	dp.dispMode = typ
+	dp.displayType = typ
 }
 
 func (dp *BxDataPack) wrap(src []byte) []byte {
@@ -117,7 +117,7 @@ func (dp *BxDataPack) Pack() []byte {
 	binary.Write(w, binary.LittleEndian, dp.r2)
 	binary.Write(w, binary.LittleEndian, dp.option)
 	binary.Write(w, binary.LittleEndian, dp.crcMode)
-	binary.Write(w, binary.LittleEndian, dp.dispMode)
+	binary.Write(w, binary.LittleEndian, dp.displayType)
 	binary.Write(w, binary.LittleEndian, dp.deviceType)
 	binary.Write(w, binary.LittleEndian, dp.version)
 	binary.Write(w, binary.LittleEndian, dp.dataLen)
@@ -164,7 +164,7 @@ func dpParse(src []byte, length int) *BxDataPack {
 	offset++
 	dp.crcMode = dst[offset]
 	offset++
-	dp.dispMode = dst[offset]
+	dp.displayType = dst[offset]
 	offset++
 	dp.deviceType = dst[offset]
 	offset++

+ 9 - 8
config.yaml

@@ -1,16 +1,17 @@
 hikServer:
   addr : ":8850"
   path : "/event"
-cameras:
+radios:
   -
-    ip: "192.168.1.64"     #192.168.1.64	 e0:ca:3c:6a:26:8c
-    name: "支路1摄像头"
+    port: "/dev/ttymxc4"
+    name: "对向"
+    branch: 1
+  - port: "/dev/ttymxc6"
+    name: "同向"
     branch: 0
-ledServerAddr: ":5005"
 outputDevices:
   -
     name: "主路1输出设备"
-    screen_ip: "192.168.110.200"
-    screen_port: "5000"
-    loudspeaker_ip: "...地址"
-    branch: 1
+    screen_ip: "192.168.1.200"
+    screen_port: "5005"
+    branch: 0

+ 6 - 10
lc/IDevice.go

@@ -37,25 +37,21 @@ type IDevice interface {
 }
 
 type IntersectionDevice struct {
-	Info util.OutputDevice
-	S    Screener
-	L    Loudspeaker
+	Info   util.OutputDevice
+	Screen Screener
 }
 
 func (id *IntersectionDevice) Call() {
-	id.L.Speak()
-	id.S.Display("P001")
+	id.Screen.Display(1)
 }
 func (id *IntersectionDevice) Rollback() {
-	id.S.Display("P002")
+	id.Screen.Display(0)
 }
 
 func (id *IntersectionDevice) Reconnect() {
-	DoReconnect(id.S)
-	DoReconnect(id.L)
+	DoReconnect(id.Screen)
 }
 
 func (id *IntersectionDevice) Correct() {
-	DoCorrectTime(id.S)
-	DoCorrectTime(id.L)
+	DoCorrectTime(id.Screen)
 }

+ 43 - 70
lc/event.go

@@ -1,19 +1,10 @@
 package lc
 
 import (
-	"encoding/xml"
-	"fmt"
+	"github.com/jacobsa/go-serial/serial"
 	"github.com/sirupsen/logrus"
-	"io"
-	"io/ioutil"
 	"lc-smartX/lc/model"
 	"lc-smartX/util"
-	"lc-smartX/util/gopool"
-	"log"
-	"mime/multipart"
-	"net/http"
-	"strings"
-	"time"
 )
 
 type Notifier interface {
@@ -21,93 +12,75 @@ type Notifier interface {
 }
 
 func StartEventServer() {
-	S = &Server{Cameras: util.Config.Cameras, Notifiers: make(map[string]Notifier, 4)}
-	fmt.Println("cameras:", S.Cameras)
+	S = &Server{Radios: util.Config.Radios, Notifiers: make(map[string]Notifier, 4)}
 	S.start()
 }
 
 var S *Server
 
 type Server struct {
-	Cameras   []model.CameraInfo
-	Notifiers map[string]Notifier
+	Radios    []model.RadioInfo
+	Notifiers map[string]Notifier //485通道名
 }
 
 func (s *Server) start() {
-	http.HandleFunc(util.Config.HikServer.Path, handler)
-	logrus.Fatal("事件监听服务启动失败:", util.Config.HikServer.Addr, ", error:", http.ListenAndServe(util.Config.HikServer.Addr, nil))
+	for _, radio := range S.Radios {
+		go OpenSerial(radio.Port)
+	}
 }
 
-func RegisterCallback(branch byte, notifer Notifier) {
-	for _, camera := range S.Cameras {
-		//关联主路led屏和支路摄像头;关联支路led屏和主路摄像头
-		if branch == 0 && camera.Branch == 1 || branch == 1 && camera.Branch == 0 {
-			S.Notifiers[camera.IP] = notifer
+func RegisterCallback(branch byte, notifier Notifier) {
+	for _, radio := range S.Radios {
+		//关联主路led屏和支路雷达;关联支路led屏和主路雷达
+		if branch == 0 && radio.Branch == 1 || branch == 1 && radio.Branch == 0 {
+			S.Notifiers[radio.Port] = notifier
 		}
 	}
 }
 
-func (s *Server) Callback(ip string) {
-	notifier, ok := s.Notifiers[ip]
+func (s *Server) Callback(port string) {
+	notifier, ok := s.Notifiers[port]
 	if !ok {
-		logrus.Errorf("回调函数注册表没有该ip:%s", ip)
+		logrus.Errorf("回调函数注册表没有该ip:%s", port)
 		return
 	}
 	notifier.Notify()
-	logrus.Debugf("camera [%s] Callback", ip)
 }
 
-func handler(w http.ResponseWriter, r *http.Request) {
-	gopool.Go(func() {
-		//监听主机应答固定,直接先应答
-		w.WriteHeader(200)
-		w.Header().Add("Date", time.Now().String())
-		w.Header().Add("Connection", "keep-alive")
-	})
-	//1.
-	contentType := r.Header.Get("Content-Type")
-	if strings.Contains(contentType, "application/xml") {
-		bytes, err := ioutil.ReadAll(r.Body)
-		if err != nil {
-			return
-		}
-		var event model.EventNotificationAlert
-		err = xml.Unmarshal(bytes, &event)
-		if err != nil {
-			return
-		}
-		//发送事件通知
-		S.Callback(event.IpAddress)
-	} else if strings.Contains(contentType, "multipart/form-data") {
-		handleMultipart(r)
+func OpenSerial(portName string) {
+	// 配置串口参数
+	options := serial.OpenOptions{
+		PortName:        portName, // /dev/ttymxc4 6 3
+		BaudRate:        9600,
+		DataBits:        8,
+		StopBits:        1,
+		MinimumReadSize: 4,
 	}
-}
 
-// 处理多文件事件
-func handleMultipart(r *http.Request) {
-	multipartReader := multipart.NewReader(r.Body, "boundary")
-	// 循环读取每个 part
-	var event model.EventNotificationAlert
+	// 打开串口
+	port, err := serial.Open(options)
+	if err != nil {
+		panic(err.Error())
+	}
+
+	// 关闭串口
+	defer port.Close()
 	for {
-		part, err := multipartReader.NextPart()
-		//defer part.Close()
-		if err == io.EOF {
-			break
-		}
+		// 读取数据
+		buf := make([]byte, 128)
+		n, err := port.Read(buf)
 		if err != nil {
-			log.Println("Failed to read part:", err)
-			return
+			break
 		}
-		if part.FormName() != "linedetectionImage" || !strings.Contains(part.FormName(), "Image") {
-			//不含图片的xml部分数据
-			xmlData, err := ioutil.ReadAll(part)
-			if err != nil {
-				return
-			}
-			xml.Unmarshal(xmlData, &event)
+		if n < 8 {
 			continue
 		}
+		result := false
+		if buf[0] == 'x' && (buf[1] > '0' || buf[2] > '0' || buf[3] > '0') {
+			result = true
+		}
+		if result {
+			S.Callback(portName)
+		}
 	}
-	//发送事件通知
-	S.Callback(event.IpAddress)
 }

+ 0 - 24
lc/loudspeaker.go

@@ -1,24 +0,0 @@
-package lc
-
-import (
-	"fmt"
-)
-
-// Loudspeaker 扬声器接口
-type Loudspeaker interface {
-	Speak()
-}
-
-type IpCast struct {
-}
-
-func NewIpCast() *IpCast {
-	return &IpCast{}
-}
-
-func (ip IpCast) Speak() {
-	fmt.Println("来车了来车了!")
-}
-
-//func (ip IpCast) CorrectTime() {}
-//func (ip IpCast)Reconnect(){}

+ 2 - 2
lc/model/rtu.go

@@ -1,7 +1,7 @@
 package model
 
-type RTUInfo struct {
-	Port   string `yaml:"ip"`
+type RadioInfo struct {
+	Port   string `yaml:"port"` //对应哪个485口
 	Name   string `yaml:"name"`
 	Branch byte   `yaml:"branch"`
 }

+ 60 - 20
lc/screen.go

@@ -12,7 +12,7 @@ import (
 
 // Screener 屏接口
 type Screener interface {
-	Display(string)
+	Display(int)
 }
 
 type Screen struct {
@@ -35,11 +35,11 @@ func NewScreen(name string, ip, port string) *Screen {
 	return s
 }
 
-func (s *Screen) Display(str string) {
+func (s *Screen) Display(id int) {
 	if !s.getLiveState() {
 		return
 	}
-	s.Lock(1, str)
+	s.SendRam(id)
 }
 
 // Correct 校正时间
@@ -109,8 +109,32 @@ const (
 	White
 )
 
-// TextRam 发送动态区节目
-func (s *Screen) TextRam(ff FlashFile) {
+const (
+	Normal = 0
+	Warn   = 1
+)
+
+// 发送动态区节目 0正常页面 1红色提醒页面
+func (s *Screen) SendRam(id int) {
+	file := FlashFile{}
+	if id == 0 {
+		file.SetMsg("减速慢行", Yellow)
+		file.SetMode(DefaultRunMode, DefaultDisplayMode)
+		file.SetOrigin(0, true, 0)
+		file.SetArea(64, true, 16)
+		s.TextRam(file, false)
+	} else {
+		file.SetMsg("支路来车", Red)
+		file.SetSoundData("支路来车,请减速")
+		file.SetMode(DefaultRunMode, DefaultDisplayMode)
+		file.SetOrigin(0, true, 0)
+		file.SetArea(64, true, 16)
+		s.TextRam(file, true)
+	}
+}
+
+// TextRam 发送动态区节目实现
+func (s *Screen) TextRam(ff FlashFile, needSpeak bool) {
 	if !s.getLiveState() {
 		return
 	}
@@ -122,16 +146,29 @@ func (s *Screen) TextRam(ff FlashFile) {
 	} else {
 		bytes, _ = encoder.Bytes([]byte("\\C" + strconv.Itoa(int(ff.color)) + ff.msg))
 	}
-	area := bx.NewBxAreaDynamic(s.StateInfo.DynaAreaNum, 0, byte(ff.dispMode), ff.originX, ff.originY, ff.width, ff.height, bytes, false)
-	areas = append(areas, area)
+	if needSpeak {
+		soundData, _ := encoder.Bytes([]byte(ff.soundData))
+		area := bx.NewBxAreaDynamic(0, 1, byte(ff.dispMode), ff.originX, ff.originY, ff.width,
+			ff.height, bytes, soundData, false)
+		areas = append(areas, area)
+	} else {
+		area := bx.NewBxAreaProgram(0, 1, byte(ff.dispMode), ff.originX, ff.originY, ff.width,
+			ff.height, bytes, false)
+		areas = append(areas, area)
+	}
+
 	//
 	cmd := bx.NewBxCmdSendDynamicArea(areas)
 	pack := bx.NewBxDataPackCmd(cmd)
 	pack.SetDisplayType(1) //动态显示模式
 	d := pack.Pack()
 	s.Send(d)
-	s.ReadResp()
-	s.StateInfo.DynaAreaNum++
+	resp := s.ReadResp()
+	if !resp.IsAck() {
+		println("设备拒绝写文件! error:", resp.Error().Description)
+		return
+	}
+	//s.StateInfo.DynaAreaNum++
 }
 
 // DelRamText 删除动态区,不传删除所有
@@ -177,14 +214,15 @@ const (
 )
 
 type FlashFile struct {
-	msg      string
-	color    Color
-	runMode  RunMode
-	dispMode DisplayMode
-	originX  uint16
-	originY  uint16
-	width    uint16
-	height   uint16
+	msg       string
+	soundData string
+	color     Color
+	runMode   RunMode
+	dispMode  DisplayMode
+	originX   uint16
+	originY   uint16
+	width     uint16
+	height    uint16
 }
 
 func (ft *FlashFile) SetMsg(msg string, color Color) {
@@ -195,6 +233,9 @@ func (ft *FlashFile) SetMode(runMode RunMode, displayMode DisplayMode) {
 	ft.runMode = runMode
 	ft.dispMode = displayMode
 }
+func (ft *FlashFile) SetSoundData(soundData string) {
+	ft.soundData = soundData
+}
 
 // SetOrigin xIsPixel=true表示x坐标为像素单位, =false表示以字节(8像素)为单位;y只有像素单位
 func (ft *FlashFile) SetOrigin(x uint16, xIsPixel bool, y uint16) {
@@ -217,12 +258,11 @@ func (ft *FlashFile) SetArea(w uint16, yIsPixel bool, h uint16) {
 }
 
 // TextFlash 发送静态文件节目,掉电保存,文件名格式"P000","P001"
-func (s *Screen) TextFlash(ft []FlashFile, isLogo bool) {
+func (s *Screen) TextFlash(ft []FlashFile, name string, isLogo bool) {
 	if !s.getLiveState() {
 		return
 	}
 	encoder := simplifiedchinese.GB18030.NewEncoder()
-	name := fmt.Sprintf("P%03d", s.StateInfo.ProgramNum)
 	if isLogo {
 		name = "LOGO"
 	}
@@ -234,7 +274,7 @@ func (s *Screen) TextFlash(ft []FlashFile, isLogo bool) {
 		} else {
 			bytes, _ = encoder.Bytes([]byte("\\C" + strconv.Itoa(int(i.color)) + i.msg))
 		}
-		area := bx.NewBxAreaDynamic(0xff, byte(i.runMode), byte(i.dispMode), i.originX, i.originY, i.width, i.height, bytes, false)
+		area := bx.NewBxAreaProgram(0xff, byte(i.runMode), byte(i.dispMode), i.originX, i.originY, i.width, i.height, bytes, false)
 		areas = append(areas, area)
 	}
 

+ 2 - 9
lc/server.go

@@ -56,9 +56,8 @@ func (is *IntersectionServer) Serve() {
 	//先创建响应设备
 	for _, v := range util.Config.OutputDevices {
 		iDevice := &IntersectionDevice{
-			Info: v,
-			S:    NewScreen(v.Name, v.ScreenIp, v.ScreenPort),
-			L:    NewIpCast(),
+			Info:   v,
+			Screen: NewScreen(v.Name, v.ScreenIp, v.ScreenPort),
 		}
 		if iDevice.Info.Branch == 1 {
 			is.MainDevices = append(is.MainDevices, iDevice)
@@ -96,9 +95,3 @@ func (is *IntersectionServer) Serve() {
 		}
 	}
 }
-
-// LServer ###
-// ===
-// ===
-// ===
-// === todo 服务器模式没测通,屏没有连接服务器

+ 12 - 20
main.go

@@ -3,6 +3,8 @@ package main
 import (
 	//"github.com/sirupsen/logrus"
 	"lc-smartX/lc"
+	"lc-smartX/util/gopool"
+
 	//"lc-smartX/util/gopool"
 	//"net"
 	//"time"
@@ -17,24 +19,14 @@ import (
 )
 
 func main() {
-	//gopool.SetCap(64)
-	//gopool.Go(lc.StartEventServer)
-	////等事件服务先启动
-	//time.Sleep(1 * time.Second)
-	//is := &lc.IntersectionServer{
-	//	Main:     time.NewTicker(5 * time.Second),  //主路状态回滚
-	//	Sub:      time.NewTicker(5 * time.Second),  //支路状态回滚
-	//	ReTicker: time.NewTicker(19 * time.Second), //重连
-	//}
-	//lc.StartSmartXServer(is)
-
-	//先用以下示例将静态节目发送至屏,P000为初始节目,P001为来车警示节目,LOGO为开机节目
-	//单个屏设备连接不能并发发送数据,未作实现
-
-	client := lc.NewScreen("支路1屏", "192.168.1.200", "5005")
-	client.Param()
-	time.Sleep(5 * time.Second)
-
-	return
-
+	gopool.SetCap(64)
+	gopool.Go(lc.StartEventServer)
+	//等事件服务先启动
+	time.Sleep(1 * time.Second)
+	is := &lc.IntersectionServer{
+		Main:     time.NewTicker(5 * time.Second),  //主路状态回滚
+		Sub:      time.NewTicker(5 * time.Second),  //支路状态回滚
+		ReTicker: time.NewTicker(19 * time.Second), //重连
+	}
+	lc.StartSmartXServer(is)
 }

+ 12 - 10
program_test.go

@@ -11,11 +11,13 @@ func TestProgram(t *testing.T) {
 	//单个屏设备连接不能并发发送数据,未作实现
 	client := lc.NewScreen("支路1屏", "192.168.1.200", "5005")
 	time.Sleep(2 * time.Second)
-
+	client.SendRam(0)
+	time.Sleep(2 * time.Second)
+	client.SendRam(1)
 	////清除所有文件
-	//client.DelFile("P002")
-	//client.DelFile("P001")
+
 	//time.Sleep(1*time.Second)
+	//client.DelFile()
 
 	//发送flash文件节目 静态Logo
 	//file := lc.FlashFile{}
@@ -27,13 +29,13 @@ func TestProgram(t *testing.T) {
 	//time.Sleep(1 * time.Second)
 
 	//发送flash文件节目 减速慢行
-	file1 := lc.FlashFile{}
-	file1.SetMsg("减速慢行", lc.Yellow)
-	file1.SetMode(lc.DefaultRunMode, lc.DefaultDisplayMode)
-	file1.SetOrigin(0, true, 0)
-	file1.SetArea(64, true, 16)
-	client.TextFlash([]lc.FlashFile{file1}, false)
-	time.Sleep(1 * time.Second)
+	//file1 := lc.FlashFile{}
+	//file1.SetMsg("减速慢行", lc.Yellow)
+	//file1.SetMode(lc.DefaultRunMode, lc.DefaultDisplayMode)
+	//file1.SetOrigin(0, true, 0)
+	//file1.SetArea(64, true, 16)
+	//client.TextFlash([]lc.FlashFile{file1}, "P000",false)
+	//time.Sleep(1 * time.Second)
 
 	//发送flash文件节目 主路来车
 	//file2 := lc.FlashFile{}

+ 5 - 6
util/config.go

@@ -21,9 +21,9 @@ var Config = func() config {
 }()
 
 type config struct {
-	LedServerAddr string             `yaml:"ledServerAddr"`
 	HikServer     hikServer          `yaml:"hikServer"`
 	Cameras       []model.CameraInfo `yaml:"cameras"`
+	Radios        []model.RadioInfo  `yaml:"radios"`
 	OutputDevices []OutputDevice     `yaml:"outputDevices"`
 }
 
@@ -33,9 +33,8 @@ type hikServer struct {
 }
 
 type OutputDevice struct {
-	Name          string `yaml:"name"`
-	ScreenIp      string `yaml:"screen_ip"`
-	ScreenPort    string `yaml:"screen_port"`
-	LoudspeakerIp string `yaml:"loudspeaker_ip"`
-	Branch        byte   `yaml:"branch"`
+	Name       string `yaml:"name"`
+	ScreenIp   string `yaml:"screen_ip"`
+	ScreenPort string `yaml:"screen_port"`
+	Branch     byte   `yaml:"branch"`
 }

+ 0 - 39
util/serial.go

@@ -1,39 +0,0 @@
-package util
-
-import (
-	"fmt"
-	"github.com/jacobsa/go-serial/serial"
-	"log"
-)
-
-func openSerial(portName string) {
-	// 配置串口参数
-	options := serial.OpenOptions{
-		PortName:        portName, // /dev/ttymxc4 6 3
-		BaudRate:        9600,
-		DataBits:        8,
-		StopBits:        1,
-		MinimumReadSize: 4,
-	}
-
-	// 打开串口
-	port, err := serial.Open(options)
-	if err != nil {
-		fmt.Printf("err : %s", err.Error())
-		return
-	}
-
-	// 关闭串口
-	defer port.Close()
-	for {
-		// 读取数据
-		buf := make([]byte, 128)
-		n, err := port.Read(buf)
-		if err != nil {
-			log.Fatal(err)
-		}
-
-		// 输出读取到的数据
-		fmt.Printf("Read %s %d bytes: %s \n", portName, n, string(buf[:n]))
-	}
-}