screen.go 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. package lc
  2. import (
  3. "fmt"
  4. "github.com/sirupsen/logrus"
  5. "golang.org/x/text/encoding/simplifiedchinese"
  6. "lc-smartX/bx"
  7. "net"
  8. "strconv"
  9. "time"
  10. )
  11. // Screener 屏接口
  12. type Screener interface {
  13. Display(string)
  14. }
  15. type Screen struct {
  16. Name string
  17. Addr string
  18. conn net.Conn
  19. liveState bool
  20. StateInfo *bx.StateInfo //状态信息
  21. Params *bx.Params //屏参
  22. }
  23. func NewScreen(name string, ip, port string) *Screen {
  24. s := &Screen{
  25. Name: name,
  26. Addr: fmt.Sprintf("%s:%s", ip, port),
  27. StateInfo: &bx.StateInfo{},
  28. Params: &bx.Params{},
  29. }
  30. s.Reconnect()
  31. return s
  32. }
  33. func (s *Screen) Display(str string) {
  34. if !s.getLiveState() {
  35. return
  36. }
  37. s.Lock(1, str)
  38. }
  39. // Correct 校正时间
  40. func (s *Screen) Correct() {
  41. if !s.getLiveState() {
  42. return
  43. }
  44. now := time.Now()
  45. cmd := bx.NewBxCmdSystemClockCorrect(now)
  46. data := bx.NewBxDataPackCmd(cmd)
  47. s.Send(data.Pack())
  48. }
  49. // Reconnect 重连
  50. func (s *Screen) Reconnect() {
  51. if s.getLiveState() {
  52. return
  53. }
  54. conn, err := net.DialTimeout("tcp", s.Addr, 5*time.Second)
  55. if err != nil {
  56. logrus.Error(s.Name, "-", s.Addr, "[屏]重连接失败! error:", err)
  57. return
  58. }
  59. logrus.Info(s.Name, "-", s.Addr, "[屏]连接成功!")
  60. s.setConn(conn)
  61. //读取屏信息
  62. state := s.State()
  63. s.StateInfo.Parse(state.Data)
  64. params := s.Param()
  65. s.Params.Parse(params.Data)
  66. }
  67. func (s *Screen) getLiveState() bool {
  68. return s.liveState
  69. }
  70. func (s *Screen) setConn(conn net.Conn) {
  71. s.conn = conn
  72. s.liveState = true
  73. }
  74. // 给屏发送数据
  75. func (s *Screen) Send(data []byte) {
  76. if !s.getLiveState() {
  77. return
  78. }
  79. _, err := s.conn.Write(data)
  80. if err != nil {
  81. logrus.WithFields(map[string]interface{}{"设备名": s.Name}).Error("tcp write error:", err)
  82. s.liveState = false
  83. }
  84. }
  85. //以下对协议进行封装
  86. //↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
  87. type Color byte
  88. const (
  89. Default Color = iota
  90. Red
  91. Green
  92. Yellow
  93. Blue
  94. LightBlue
  95. LightPurple
  96. White
  97. )
  98. // TextRam 发送动态区节目
  99. func (s *Screen) TextRam(ff FlashFile) {
  100. if !s.getLiveState() {
  101. return
  102. }
  103. var areas []bx.BxArea
  104. encoder := simplifiedchinese.GB18030.NewEncoder()
  105. var bytes []byte
  106. if ff.color == Default {
  107. bytes, _ = encoder.Bytes([]byte(ff.msg))
  108. } else {
  109. bytes, _ = encoder.Bytes([]byte("\\C" + strconv.Itoa(int(ff.color)) + ff.msg))
  110. }
  111. area := bx.NewBxAreaDynamic(s.StateInfo.DynaAreaNum, 0, byte(ff.dispMode), ff.originX, ff.originY, ff.width, ff.height, bytes, false)
  112. areas = append(areas, area)
  113. //
  114. cmd := bx.NewBxCmdSendDynamicArea(areas)
  115. pack := bx.NewBxDataPackCmd(cmd)
  116. pack.SetDisplayType(1) //动态显示模式
  117. d := pack.Pack()
  118. s.Send(d)
  119. s.ReadResp()
  120. s.StateInfo.DynaAreaNum++
  121. }
  122. // DelRamText 删除动态区,不传删除所有
  123. func (s *Screen) DelRamText(numbers ...byte) {
  124. if !s.getLiveState() {
  125. return
  126. }
  127. cmd := bx.NewCmdDelDynamicArea(numbers)
  128. pack := bx.NewBxDataPackCmd(cmd)
  129. s.Send(pack.Pack())
  130. s.ReadResp()
  131. if len(numbers) == 0 {
  132. s.StateInfo.DynaAreaNum = 0
  133. } else {
  134. s.StateInfo.DynaAreaNum--
  135. }
  136. }
  137. type RunMode byte
  138. const (
  139. Loop RunMode = iota //循环
  140. LoopAndStayAtEnd //循环直到最后,停留在最后一个动态区
  141. LoopAndTimeoutOff //循环直到超时,超时后未更新不在显示
  142. LoopAndStayAtLogo //循环完后,停留显示LOGO
  143. LoopAndOff //循环完后不在显示
  144. LoopAndCountOff //循环设定次数后不在显示
  145. DefaultRunMode RunMode = Loop //默认
  146. )
  147. type DisplayMode byte
  148. const (
  149. _ DisplayMode = iota
  150. Static //0x01——静止显示
  151. QuickPunch //0x02——快速打出
  152. MoveLeft //0x03——向左移动
  153. MoveRight //0x04——向右移动
  154. MoveUp //0x05——向上移动
  155. MoveDown //0x06——向下移动
  156. Flicker //0x07——闪烁
  157. DefaultDisplayMode DisplayMode = Static
  158. )
  159. type FlashFile struct {
  160. msg string
  161. color Color
  162. runMode RunMode
  163. dispMode DisplayMode
  164. originX uint16
  165. originY uint16
  166. width uint16
  167. height uint16
  168. }
  169. func (ft *FlashFile) SetMsg(msg string, color Color) {
  170. ft.msg = msg
  171. ft.color = color
  172. }
  173. func (ft *FlashFile) SetMode(runMode RunMode, displayMode DisplayMode) {
  174. ft.runMode = runMode
  175. ft.dispMode = displayMode
  176. }
  177. // SetOrigin xIsPixel=true表示x坐标为像素单位, =false表示以字节(8像素)为单位;y只有像素单位
  178. func (ft *FlashFile) SetOrigin(x uint16, xIsPixel bool, y uint16) {
  179. ft.originY = y
  180. if xIsPixel {
  181. ft.originX = 0x8000 | x
  182. return
  183. }
  184. ft.originX = x
  185. }
  186. // SetArea yIsPixel=true表示像素单位, =false表示以字节(8像素)为单位
  187. func (ft *FlashFile) SetArea(w uint16, yIsPixel bool, h uint16) {
  188. ft.height = h
  189. if yIsPixel {
  190. ft.width = 0x8000 | w
  191. return
  192. }
  193. ft.width = w
  194. }
  195. // TextFlash 发送静态文件节目,掉电保存,文件名格式"P000","P001"
  196. func (s *Screen) TextFlash(ft []FlashFile, isLogo bool) {
  197. if !s.getLiveState() {
  198. return
  199. }
  200. encoder := simplifiedchinese.GB18030.NewEncoder()
  201. name := fmt.Sprintf("P%03d", s.StateInfo.ProgramNum)
  202. if isLogo {
  203. name = "LOGO"
  204. }
  205. var areas []bx.BxArea
  206. for _, i := range ft {
  207. var bytes []byte
  208. if i.color == Default {
  209. bytes, _ = encoder.Bytes([]byte(i.msg))
  210. } else {
  211. bytes, _ = encoder.Bytes([]byte("\\C" + strconv.Itoa(int(i.color)) + i.msg))
  212. }
  213. area := bx.NewBxAreaDynamic(0xff, byte(i.runMode), byte(i.dispMode), i.originX, i.originY, i.width, i.height, bytes, false)
  214. areas = append(areas, area)
  215. }
  216. file := bx.NewBxFile(name, "", areas)
  217. cmd := file.NewCmdWriteFile()
  218. pack := bx.NewBxDataPackCmd(cmd)
  219. data := pack.Pack()
  220. s.Send(data)
  221. resp := s.ReadResp()
  222. if !resp.IsAck() {
  223. logrus.Error("设备拒绝写文件! error:", resp.Error().Description)
  224. return
  225. }
  226. pack1 := bx.NewBxDataPackCmd(cmd)
  227. data1 := pack1.Pack()
  228. s.Send(data1)
  229. resp1 := s.ReadResp()
  230. if resp1.NoError() {
  231. s.StateInfo.ProgramNum++
  232. }
  233. }
  234. // Bitmap 发送自定义位图节目
  235. func (s *Screen) Bitmap(name string, bitmap []byte) {
  236. file := bx.NewBitmapFile(name, bitmap)
  237. cmd := file.NewCmd()
  238. pack := bx.NewBxDataPackCmd(cmd)
  239. data := pack.Pack()
  240. s.Send(data)
  241. resp := s.ReadResp()
  242. if !resp.IsAck() {
  243. logrus.Error("设备拒绝写文件! error:", resp.Error().Description)
  244. return
  245. }
  246. pack1 := bx.NewBxDataPackCmd(cmd)
  247. data1 := pack1.Pack()
  248. s.Send(data1)
  249. fmt.Printf("写图文件数据:% 02x\n", data1)
  250. s.ReadResp()
  251. }
  252. // Lock 锁定状态:0x00——解锁状态,0x01——锁定状态
  253. func (s *Screen) Lock(flag byte, name string) {
  254. cmd := bx.NewCmdLock(flag, name)
  255. pack := bx.NewBxDataPackCmd(&cmd)
  256. s.Send(pack.Pack())
  257. }
  258. // DelFile 删除静态文件节目
  259. func (s *Screen) DelFile(delFiles ...string) {
  260. cmd := bx.NewCmdDeleteFile(delFiles)
  261. pack := bx.NewBxDataPackCmd(cmd)
  262. s.Send(pack.Pack())
  263. s.ReadResp()
  264. if len(delFiles) == 0 {
  265. s.StateInfo.ProgramNum = 0
  266. } else {
  267. s.StateInfo.ProgramNum--
  268. }
  269. }
  270. // DelText 删除动态区域节目
  271. func (s *Screen) DelText(delIds []byte) {
  272. cmd := bx.NewBxCmdSendDynamicArea(nil)
  273. cmd.SetDelAreaIds(delIds)
  274. pack := bx.NewBxDataPackCmd(cmd)
  275. s.Send(pack.Pack())
  276. }
  277. func (s *Screen) TurnOnOff(onOff bool) {
  278. if !s.getLiveState() {
  279. return
  280. }
  281. cmd := bx.NewBxCmdTurnOnOff(onOff)
  282. pack := bx.NewBxDataPackCmd(cmd)
  283. s.Send(pack.Pack())
  284. }
  285. // TimingSwitch 定时开关屏
  286. // 13:49 开, 13:55 关,最多设置3组
  287. //
  288. // onOffSet := [][2]uint64{
  289. // {1349, 1355},
  290. // }
  291. func (s *Screen) TimingSwitch(onOffSet [][2]uint64) {
  292. if !s.getLiveState() {
  293. return
  294. }
  295. cmd := bx.NewCmdTimingSwitch(onOffSet)
  296. pack := bx.NewBxDataPackCmd(cmd)
  297. s.Send(pack.Pack())
  298. }
  299. func (s *Screen) CancelTimingSwitch() {
  300. if !s.getLiveState() {
  301. return
  302. }
  303. cmd := bx.NewCmdCancelTimingSwitch()
  304. pack := bx.NewBxDataPackCmd(cmd)
  305. s.Send(pack.Pack())
  306. }
  307. func (s *Screen) State() *bx.BxResp {
  308. if !s.getLiveState() {
  309. return nil
  310. }
  311. cmd := bx.NewCmdState()
  312. pack := bx.NewBxDataPackCmd(cmd)
  313. s.Send(pack.Pack())
  314. r := s.ReadResp()
  315. return &r
  316. }
  317. func (s *Screen) Param() *bx.BxResp {
  318. if !s.getLiveState() {
  319. return nil
  320. }
  321. cmd := bx.NewCmdReadParams()
  322. pack := bx.NewBxDataPackCmd(cmd)
  323. s.Send(pack.Pack())
  324. r := s.ReadResp()
  325. return &r
  326. }
  327. func (s *Screen) Info() {
  328. s.StateInfo.Print(s.Name)
  329. }
  330. // ReadResp 读取响应
  331. func (s *Screen) ReadResp() bx.BxResp {
  332. var resp = make([]byte, 1024)
  333. read, err := s.conn.Read(resp)
  334. if err != nil {
  335. logrus.Error("读数据错误:", err)
  336. s.liveState = false
  337. return bx.BxResp{}
  338. }
  339. var bxResp = bx.BxResp{}
  340. parse := bxResp.Parse(resp, read)
  341. //if parse.IsAck() {
  342. // fmt.Println("response ACK")
  343. // fmt.Printf("原始响应数据:% 0x\n", resp[:read])
  344. // fmt.Println("解析响应数据:", parse)
  345. //} else if parse.IsInfo() {
  346. // fmt.Println("state ACK")
  347. // fmt.Printf("原始响应数据:% 0x\n", resp[:read])
  348. // fmt.Println("解析响应数据:", parse)
  349. //} else {
  350. // fmt.Println("response")
  351. // fmt.Printf("原始响应数据:% 0x\n", resp[:read])
  352. // fmt.Println("解析响应数据:", parse)
  353. //}
  354. return *parse
  355. }