Files
bj_power/bj_power_mes/cs/client.go
T

248 lines
5.5 KiB
Go
Raw Normal View History

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