248 lines
5.5 KiB
Go
248 lines
5.5 KiB
Go
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 {
|
|||
|
|
|
|||
|
|
//0:JIS、1:ASCII、2:SHIFT JIS、
|
|||
|
|
//3:ASCII+SHIFT JIS、4:UNICODE、6:GB、
|
|||
|
|
//7:ASCII+GB、8:KS、9:ASCII+KS、
|
|||
|
|
//A:BIG5、B:ASCII+BIG5
|
|||
|
|
bb, err := japanese.ShiftJIS.NewEncoder().Bytes([]byte(text))
|
|||
|
|
if err != nil {
|
|||
|
|
return fmt.Errorf("编码失败: %w", err)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//纵点数 (1位)
|
|||
|
|
//1:5点、 2:7点、 3:9点、
|
|||
|
|
//4:10点、 5:12点、 6:16点、
|
|||
|
|
//7:20点、 8:22点、 9:24点、
|
|||
|
|
//A:26点、 E:11点、 F:15点
|
|||
|
|
//字体尺寸 (1位)
|
|||
|
|
//2:24x24、 3:24x18、 4:16x16、 5:16x12、
|
|||
|
|
//6:12x10、 7:10x8、 8:9x9、 9:9x7、
|
|||
|
|
//A:7x8、 B:7x5、 C:5x5、 D:5xN、
|
|||
|
|
//E:7xN
|
|||
|
|
//字体底部位置 (2位)
|
|||
|
|
// 00~25:配置于最下行开始0~25点
|
|||
|
|
//倍角 (1位)
|
|||
|
|
// 1~8:1~8倍
|
|||
|
|
//文字方向 (1位)
|
|||
|
|
// 0:↑、 1:←、 2:→、 3:↓、 4:镜面
|
|||
|
|
//文字间点 (1位)
|
|||
|
|
// 00~31:0~31点
|
|||
|
|
//最终文字的文字间 (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
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 0:JIS、2:shift JIS、3:ASCII+shift JIS、
|
|||
|
|
// 4:UNICODE、6:GB、7:ASCII+GB、8:KS、
|
|||
|
|
// 9:ASCII+KS、A:BIG5、B:ASCII+BIG5
|
|||
|
|
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
|
|||
|
|
},
|
|||
|
|
},
|
|||
|
|
}
|