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:
SunYF
2026-08-27 10:09:54 +08:00
commit 1f0ee844a4
408 changed files with 102201 additions and 0 deletions
+247
View File
@@ -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 {
//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
},
},
}
+25
View File
@@ -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)
}
+29
View File
@@ -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状态(印字中状态等)时进行操作。