123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391 |
- package lc
- import (
- "fmt"
- "github.com/sirupsen/logrus"
- "golang.org/x/text/encoding/simplifiedchinese"
- "lc-smartX/bx"
- "net"
- "strconv"
- "time"
- )
- // Screener 屏接口
- type Screener interface {
- Display(string)
- }
- type Screen struct {
- Name string
- Addr string
- conn net.Conn
- liveState bool
- StateInfo *bx.StateInfo //状态信息
- Params *bx.Params //屏参
- }
- func NewScreen(name string, ip, port string) *Screen {
- s := &Screen{
- Name: name,
- Addr: fmt.Sprintf("%s:%s", ip, port),
- StateInfo: &bx.StateInfo{},
- Params: &bx.Params{},
- }
- s.Reconnect()
- return s
- }
- func (s *Screen) Display(str string) {
- if !s.getLiveState() {
- return
- }
- s.Lock(1, str)
- }
- // Correct 校正时间
- func (s *Screen) Correct() {
- if !s.getLiveState() {
- return
- }
- now := time.Now()
- cmd := bx.NewBxCmdSystemClockCorrect(now)
- data := bx.NewBxDataPackCmd(cmd)
- s.Send(data.Pack())
- }
- // Reconnect 重连
- func (s *Screen) Reconnect() {
- if s.getLiveState() {
- return
- }
- conn, err := net.DialTimeout("tcp", s.Addr, 5*time.Second)
- if err != nil {
- logrus.Error(s.Name, "-", s.Addr, "[屏]重连接失败! error:", err)
- return
- }
- logrus.Info(s.Name, "-", s.Addr, "[屏]连接成功!")
- s.setConn(conn)
- //读取屏信息
- state := s.State()
- s.StateInfo.Parse(state.Data)
- params := s.Param()
- s.Params.Parse(params.Data)
- }
- func (s *Screen) getLiveState() bool {
- return s.liveState
- }
- func (s *Screen) setConn(conn net.Conn) {
- s.conn = conn
- s.liveState = true
- }
- // 给屏发送数据
- func (s *Screen) Send(data []byte) {
- if !s.getLiveState() {
- return
- }
- _, err := s.conn.Write(data)
- if err != nil {
- logrus.WithFields(map[string]interface{}{"设备名": s.Name}).Error("tcp write error:", err)
- s.liveState = false
- }
- }
- //以下对协议进行封装
- //↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
- type Color byte
- const (
- Default Color = iota
- Red
- Green
- Yellow
- Blue
- LightBlue
- LightPurple
- White
- )
- // TextRam 发送动态区节目
- func (s *Screen) TextRam(ff FlashFile) {
- if !s.getLiveState() {
- return
- }
- var areas []bx.BxArea
- encoder := simplifiedchinese.GB18030.NewEncoder()
- var bytes []byte
- if ff.color == Default {
- bytes, _ = encoder.Bytes([]byte(ff.msg))
- } 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)
- //
- cmd := bx.NewBxCmdSendDynamicArea(areas)
- pack := bx.NewBxDataPackCmd(cmd)
- pack.SetDisplayType(1) //动态显示模式
- d := pack.Pack()
- s.Send(d)
- s.ReadResp()
- s.StateInfo.DynaAreaNum++
- }
- // DelRamText 删除动态区,不传删除所有
- func (s *Screen) DelRamText(numbers ...byte) {
- if !s.getLiveState() {
- return
- }
- cmd := bx.NewCmdDelDynamicArea(numbers)
- pack := bx.NewBxDataPackCmd(cmd)
- s.Send(pack.Pack())
- s.ReadResp()
- if len(numbers) == 0 {
- s.StateInfo.DynaAreaNum = 0
- } else {
- s.StateInfo.DynaAreaNum--
- }
- }
- type RunMode byte
- const (
- Loop RunMode = iota //循环
- LoopAndStayAtEnd //循环直到最后,停留在最后一个动态区
- LoopAndTimeoutOff //循环直到超时,超时后未更新不在显示
- LoopAndStayAtLogo //循环完后,停留显示LOGO
- LoopAndOff //循环完后不在显示
- LoopAndCountOff //循环设定次数后不在显示
- DefaultRunMode RunMode = Loop //默认
- )
- type DisplayMode byte
- const (
- _ DisplayMode = iota
- Static //0x01——静止显示
- QuickPunch //0x02——快速打出
- MoveLeft //0x03——向左移动
- MoveRight //0x04——向右移动
- MoveUp //0x05——向上移动
- MoveDown //0x06——向下移动
- Flicker //0x07——闪烁
- DefaultDisplayMode DisplayMode = Static
- )
- type FlashFile struct {
- msg string
- color Color
- runMode RunMode
- dispMode DisplayMode
- originX uint16
- originY uint16
- width uint16
- height uint16
- }
- func (ft *FlashFile) SetMsg(msg string, color Color) {
- ft.msg = msg
- ft.color = color
- }
- func (ft *FlashFile) SetMode(runMode RunMode, displayMode DisplayMode) {
- ft.runMode = runMode
- ft.dispMode = displayMode
- }
- // SetOrigin xIsPixel=true表示x坐标为像素单位, =false表示以字节(8像素)为单位;y只有像素单位
- func (ft *FlashFile) SetOrigin(x uint16, xIsPixel bool, y uint16) {
- ft.originY = y
- if xIsPixel {
- ft.originX = 0x8000 | x
- return
- }
- ft.originX = x
- }
- // SetArea yIsPixel=true表示像素单位, =false表示以字节(8像素)为单位
- func (ft *FlashFile) SetArea(w uint16, yIsPixel bool, h uint16) {
- ft.height = h
- if yIsPixel {
- ft.width = 0x8000 | w
- return
- }
- ft.width = w
- }
- // TextFlash 发送静态文件节目,掉电保存,文件名格式"P000","P001"
- func (s *Screen) TextFlash(ft []FlashFile, isLogo bool) {
- if !s.getLiveState() {
- return
- }
- encoder := simplifiedchinese.GB18030.NewEncoder()
- name := fmt.Sprintf("P%03d", s.StateInfo.ProgramNum)
- if isLogo {
- name = "LOGO"
- }
- var areas []bx.BxArea
- for _, i := range ft {
- var bytes []byte
- if i.color == Default {
- bytes, _ = encoder.Bytes([]byte(i.msg))
- } 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)
- areas = append(areas, area)
- }
- file := bx.NewBxFile(name, "", areas)
- cmd := file.NewCmdWriteFile()
- pack := bx.NewBxDataPackCmd(cmd)
- data := pack.Pack()
- s.Send(data)
- resp := s.ReadResp()
- if !resp.IsAck() {
- logrus.Error("设备拒绝写文件! error:", resp.Error().Description)
- return
- }
- pack1 := bx.NewBxDataPackCmd(cmd)
- data1 := pack1.Pack()
- s.Send(data1)
- resp1 := s.ReadResp()
- if resp1.NoError() {
- s.StateInfo.ProgramNum++
- }
- }
- // Bitmap 发送自定义位图节目
- func (s *Screen) Bitmap(name string, bitmap []byte) {
- file := bx.NewBitmapFile(name, bitmap)
- cmd := file.NewCmd()
- pack := bx.NewBxDataPackCmd(cmd)
- data := pack.Pack()
- s.Send(data)
- resp := s.ReadResp()
- if !resp.IsAck() {
- logrus.Error("设备拒绝写文件! error:", resp.Error().Description)
- return
- }
- pack1 := bx.NewBxDataPackCmd(cmd)
- data1 := pack1.Pack()
- s.Send(data1)
- fmt.Printf("写图文件数据:% 02x\n", data1)
- s.ReadResp()
- }
- // Lock 锁定状态:0x00——解锁状态,0x01——锁定状态
- func (s *Screen) Lock(flag byte, name string) {
- cmd := bx.NewCmdLock(flag, name)
- pack := bx.NewBxDataPackCmd(&cmd)
- s.Send(pack.Pack())
- }
- // DelFile 删除静态文件节目
- func (s *Screen) DelFile(delFiles ...string) {
- cmd := bx.NewCmdDeleteFile(delFiles)
- pack := bx.NewBxDataPackCmd(cmd)
- s.Send(pack.Pack())
- s.ReadResp()
- if len(delFiles) == 0 {
- s.StateInfo.ProgramNum = 0
- } else {
- s.StateInfo.ProgramNum--
- }
- }
- // DelText 删除动态区域节目
- func (s *Screen) DelText(delIds []byte) {
- cmd := bx.NewBxCmdSendDynamicArea(nil)
- cmd.SetDelAreaIds(delIds)
- pack := bx.NewBxDataPackCmd(cmd)
- s.Send(pack.Pack())
- }
- func (s *Screen) TurnOnOff(onOff bool) {
- if !s.getLiveState() {
- return
- }
- cmd := bx.NewBxCmdTurnOnOff(onOff)
- pack := bx.NewBxDataPackCmd(cmd)
- s.Send(pack.Pack())
- }
- // TimingSwitch 定时开关屏
- // 13:49 开, 13:55 关,最多设置3组
- //
- // onOffSet := [][2]uint64{
- // {1349, 1355},
- // }
- func (s *Screen) TimingSwitch(onOffSet [][2]uint64) {
- if !s.getLiveState() {
- return
- }
- cmd := bx.NewCmdTimingSwitch(onOffSet)
- pack := bx.NewBxDataPackCmd(cmd)
- s.Send(pack.Pack())
- }
- func (s *Screen) CancelTimingSwitch() {
- if !s.getLiveState() {
- return
- }
- cmd := bx.NewCmdCancelTimingSwitch()
- pack := bx.NewBxDataPackCmd(cmd)
- s.Send(pack.Pack())
- }
- func (s *Screen) State() *bx.BxResp {
- if !s.getLiveState() {
- return nil
- }
- cmd := bx.NewCmdState()
- pack := bx.NewBxDataPackCmd(cmd)
- s.Send(pack.Pack())
- r := s.ReadResp()
- return &r
- }
- func (s *Screen) Param() *bx.BxResp {
- if !s.getLiveState() {
- return nil
- }
- cmd := bx.NewCmdReadParams()
- pack := bx.NewBxDataPackCmd(cmd)
- s.Send(pack.Pack())
- r := s.ReadResp()
- return &r
- }
- func (s *Screen) Info() {
- s.StateInfo.Print(s.Name)
- }
- // ReadResp 读取响应
- func (s *Screen) ReadResp() bx.BxResp {
- var resp = make([]byte, 1024)
- read, err := s.conn.Read(resp)
- if err != nil {
- logrus.Error("读数据错误:", err)
- s.liveState = false
- return bx.BxResp{}
- }
- var bxResp = bx.BxResp{}
- parse := bxResp.Parse(resp, read)
- //if parse.IsAck() {
- // fmt.Println("response ACK")
- // fmt.Printf("原始响应数据:% 0x\n", resp[:read])
- // fmt.Println("解析响应数据:", parse)
- //} else if parse.IsInfo() {
- // fmt.Println("state ACK")
- // fmt.Printf("原始响应数据:% 0x\n", resp[:read])
- // fmt.Println("解析响应数据:", parse)
- //} else {
- // fmt.Println("response")
- // fmt.Printf("原始响应数据:% 0x\n", resp[:read])
- // fmt.Println("解析响应数据:", parse)
- //}
- return *parse
- }
|