chore: init bj_power monorepo (dashboard/mes/wms/wms_client/workstation), clear subproject git metadata and align naming to folder names
This commit is contained in:
@@ -0,0 +1,247 @@
|
||||
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
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/text/encoding/japanese"
|
||||
unicodex "golang.org/x/text/encoding/unicode"
|
||||
)
|
||||
|
||||
func TestEncoding(t *testing.T) {
|
||||
bb := []byte{130, 80, 130, 81, 130, 82, 130, 83, 130, 84, 130, 85, 130, 86, 130, 87}
|
||||
re, _ := japanese.ShiftJIS.NewDecoder().Bytes(bb)
|
||||
res := strings.ToLowerSpecial(numConv, string(re))
|
||||
t.Logf("%s", res)
|
||||
}
|
||||
func TestEncoding1(t *testing.T) {
|
||||
bb, _ := hex.DecodeString("FF11FF12FF13FF14FF15FF16FF17FF18")
|
||||
re, _ := unicodex.UTF16(unicodex.BigEndian, unicodex.IgnoreBOM).NewDecoder().Bytes(bb)
|
||||
|
||||
res := strings.ToLowerSpecial(numConv, string(re))
|
||||
|
||||
t.Logf("%s", res)
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package main
|
||||
|
||||
var errorCodeMap = map[string]string{
|
||||
"1500": "通讯超出错误",
|
||||
"1510": "通讯构架错误",
|
||||
"1520": "通讯对等错误",
|
||||
"1530": "通讯接收缓存已满",
|
||||
"1540": "通讯接收超时",
|
||||
"1560": "通讯指令错误",
|
||||
"1570": "通讯指令格式错误",
|
||||
"1581": "运行停止",
|
||||
"1582": "喷头加热中",
|
||||
"1584": "印字中",
|
||||
"1588": "图形化未执行",
|
||||
"1590": "通讯信息类型错误",
|
||||
"15A0": "通讯其它错误",
|
||||
"15B3": "通讯指令不可执行",
|
||||
"15B4": "通讯校验和错误",
|
||||
}
|
||||
|
||||
//15D0H
|
||||
//〜
|
||||
//15DFH
|
||||
//从机控制通讯错误
|
||||
//无法和从机控制器进行通讯。
|
||||
//下1位(0〜F)表示发生错误的控制器(No.1〜16)。
|
||||
//⇒请重新确认通讯条件和通讯线缆及其连接。
|
||||
//⇒请确认主机侧和从机侧的功能选择设定是否相同。
|
||||
//⇒请不要在从机侧Busy状态(印字中状态等)时进行操作。
|
||||
Reference in New Issue
Block a user