Files
bj_power/bj_power_mes/cs/client.go
T

248 lines
5.5 KiB
Go
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package main
import (
"bytes"
"errors"
"fmt"
"log/slog"
"net"
"strings"
"sync"
"time"
"unicode"
"golang.org/x/text/encoding/japanese"
)
const (
STX = 0x02
ETX = 0x03
ACK = 0x06
NAK = 0x15
)
type Client struct {
host string
conn net.Conn
mtx sync.Mutex
}
func NewClient(host string) *Client {
return &Client{
host: host,
}
}
func main() {
c := NewClient("192.168.2.33:1024")
err := c.SetText(1, "123456789A")
if err != nil {
slog.Error(err.Error())
return
}
slog.Info("OK")
resp, err := c.GetText(1)
if err != nil {
slog.Error(err.Error())
return
}
//0:1:A2001000010:023312332233323342335233623372338:
//0:1:A2001000010:282508251825282538254825582568257:
slog.Info(resp)
}
func (c *Client) sendCommand(cmd string) (string, error) {
c.mtx.Lock()
defer c.mtx.Unlock()
conn, err := net.DialTimeout("tcp", c.host, 3*time.Second)
if err != nil {
return "", fmt.Errorf("喷码机连接失败: %w", err)
}
defer conn.Close()
// 构造完整指令: STX + CMD + parameters + ETX
var buffer bytes.Buffer
buffer.WriteByte(STX)
buffer.WriteString(cmd)
buffer.WriteByte(ETX)
// 计算校验和
checksum := calcChecksum(buffer.Bytes()[1:]) // 排除STX的data部分
// 添加校验和到buffer
buffer.WriteString(fmt.Sprintf("%02X", checksum))
message := buffer.Bytes()
// 发送指令
_, err = conn.Write(message)
if err != nil {
return "", fmt.Errorf("喷码机发送指令失败: %w", err)
}
// 接收响应
resp, err := readResponse(conn)
if err != nil {
return "", fmt.Errorf("喷码机接收响应失败: %w", err)
}
// 解析响应
return parseResponse(resp)
}
func readResponse(conn net.Conn) ([]byte, error) {
_ = conn.SetReadDeadline(time.Now().Add(5 * time.Second))
buffer := make([]byte, 256)
n, err := conn.Read(buffer)
if err != nil {
return nil, err
}
return buffer[:n], nil
}
func parseResponse(resp []byte) (body string, err error) {
if len(resp) == 0 {
return "", errors.New("empty response")
}
switch resp[0] {
case ACK:
// 处理带数据的响应(例如查询命令的响应)
if len(resp) > 3 && resp[1] == STX && resp[len(resp)-1] == ETX {
// 返回有效数据(示例处理)
return string(resp[2 : len(resp)-1]), nil
}
return "", nil
case NAK:
if len(resp) >= 7 && resp[1] == STX && resp[len(resp)-1] == ETX {
errorCode := string(resp[2:6])
msg, exists := errorCodeMap[errorCode]
if !exists {
msg = "Unknown error"
}
return "", fmt.Errorf("NAK error %s: %s", errorCode, msg)
}
return "", errors.New("NAK received without error details")
}
return
}
func calcChecksum(data []byte) byte {
var sum byte
for _, b := range data {
sum += b
}
return sum
}
func (c *Client) SetText(model int, text string) error {
//0JIS、1ASCII、2SHIFT JIS、
//3ASCIISHIFT JIS、4UNICODE、6GB、
//7ASCIIGB、8KS、9ASCIIKS、
//ABIG5、BASCIIBIG5
bb, err := japanese.ShiftJIS.NewEncoder().Bytes([]byte(text))
if err != nil {
return fmt.Errorf("编码失败: %w", err)
}
//纵点数 (1位)
//15点、 27点、 39点、
//410点、 512点、 616点、
//720点、 822点、 924点、
//A26点、 E11点、 F15点
//字体尺寸 (1位)
//224x24、 324x18、 416x16、 516x12、
//612x10、 710x8、 89x9、 99x7、
//A7x8、 B7x5、 C5x5、 D5xN、
//E7xN
//字体底部位置 (2位)
// 00~25:配置于最下行开始0~25点
//倍角 (1位)
// 1818倍
//文字方向 (1位)
// 0:↑、 1:←、 2:→、 3:↓、 4:镜面
//文字间点 (1位)
// 0031031点
//最终文字的文字间 (1位)
// 0:无效、 1:有效
//文字间点的倍角处理 (1位)
// 0:无效、 1:有效
//黑白反转 (1位)
// 0:无效、 1:有效
cmd := fmt.Sprintf("STM:0:%d:A2001000010:3%s:", model, bb)
_, err = c.sendCommand(cmd)
if err != nil {
return err
}
return nil
}
// 0JIS、2shift JIS、3ASCIIshift JIS、
// 4UNICODE、6GB、7ASCIIGB、8KS、
// 9ASCIIKS、ABIG5、BASCIIBIG5
func (c *Client) GetText(model int) (text string, err error) {
conn, err := net.DialTimeout("tcp", "192.168.2.33:1024", 5*time.Second)
if err != nil {
panic(err)
}
defer conn.Close()
cmd := fmt.Sprintf("GTM:0:%d:%d:", model, 3)
response, err := c.sendCommand(cmd)
if err != nil {
return
}
fields := strings.Split(response, ":")
content := fields[3]
//coding, _ := strconv.Atoi(string([]rune(content)[0]))
//var re string
//switch coding {
//case 0, 3:
//case 1:
// re = content[1:]
//case 2:
// re, err = japanese.ShiftJIS.NewDecoder().String(content[1:])
//case 4:
// bb, _ := hex.DecodeString(content[1:])
// re, err = unicodex.UTF16(unicodex.LittleEndian, unicodex.IgnoreBOM).NewDecoder().String(string(bb))
//}
re, err := japanese.ShiftJIS.NewDecoder().String(content[1:])
if err != nil {
return "", fmt.Errorf("解码失败: %w", err)
}
re = strings.ToLowerSpecial(numConv, re)
return re, nil
}
var numConv = unicode.SpecialCase{
{
Lo: 0x3002, // Lo 全角句号
Hi: 0x3002, // Hi 全角句号
Delta: [unicode.MaxCase]rune{
0, // UpperCase
0x002e - 0x3002, // LowerCase 转成半角句号
0, // TitleCase
},
},
{
Lo: 0xff01, // Lo: 全角!
Hi: 0xFF19, // Hi:到全角 9
Delta: [unicode.MaxCase]rune{
0, // UpperCase
0x0021 - 0xff01, // LowerCase 转成半角
0, // TitleCase
},
},
}