# 喷码机 通信对接 **Repository Path**: inkprinter/network ## Basic Information - **Project Name**: 喷码机 通信对接 - **Description**: 智能喷码机网络串口通信对接开发 - **Primary Language**: Unknown - **License**: AFL-3.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 2 - **Forks**: 2 - **Created**: 2023-04-11 - **Last Updated**: 2026-02-05 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 喷码机 通信软件 目录介绍: | 目录 | 介绍 | |--------|---| | bin | 通信测试软件 exe文件,支持串口、网口连接,可直接运行 | | code | 通信测试软件 源码,可以下载参考开发 | | pmjdev | 通信发码软件 安装包,支持串口、网口、蓝牙连接 | # 喷码机 通信对接 智能喷码机网络串口通信对接开发 喷码机支持网络连接与串口连接。支持传输文字与图片。 通信方式 1. 串口连接 2. 网络连接 使用说明 **1. 串口连接** 喷码机串口可以与电脑等其他任何设备的串口相连接。串口传输格式为N,8,1。波特率支持4800-256000可设置。 **2. 网络连接** 网络连接使用TCP/IP协议,可靠连接。 **3. 通信协议** 支持传输文字与图片,图片有协议要求。我们提供对接协议和二次开发库。开发者可以选择使用二次开发库开发或者使用协议对接。开发者只需要调用库函数即可实现与喷码机通信。我们提供库函数和示例源代码,示例源代码实现了文字传输与图片传输,参考示例源代码可以快速开发出与喷码机通信的专用软件。 # 协议对接开发 ## 串口对接 **1. 串口连接** 串口连接支持传输文字与图片和指令,协议只提供文字和指令传输协议,暂时不开放图片传输协议,需要传输图片请采用二次开发库开发。 串口传输文本支持带协议传输和不带协议传输,喷码机收到串口数据如果在数据中检测不到协议头,那么就将数据按文本处理。如果有协议头,根据协议解析数据是文本、指令还是图片,按对应协议处理。 不带协议传输文本只需要通过串口按照设定的波特率把文字按照UTF8或者GBK/ANSI编码格式发送到喷码机即可。喷码机收到文本数据可以按照设置的格式截取特定内容喷印。 喷码机串口可以与电脑等其他任何设备的串口相连接,可以不需要任何协议,只要其他设备发送UTF8或者GBK/ANSI编码格式的文本到喷码机即可。串口传输格式为N,8,1。波特率支持4800-256000可设置。 C语言示例: 串口不带协议发送文本 “Send Example” 示例: ``` char str = "Send Example"; int len = strlen(str); DWORD dwwrittenLen = 0; WriteFile(hCom, str, len, &dwwrittenLen, NULL); ``` 如果上位机同时有发送指令和文本的需求,那么建议发送文本的时候也带上协议 带协议的文本发送格式为: [0x4B][0x54][0x01][0x00][0x00][0x00][数据长度高8位][数据长度低8位][数据][数据][数据][数据].... 前6个字节固定为4B 54 01 00 00 00,第7和8个字节为文本的字节长度,后面为文本数据。 串口带协议发送文本 “Send Example” 示例: ``` char str = "Send Example"; uint8_t data[128]; int len = strlen(str); data[0] = 0x4B; data[1] = 0x54; data[2] = 1; data[3] = 0; data[4] = 0; data[5] = 0; data[6] = len >> 8; data[7] = len & 0xff; strcpy(&data[8], str, len); DWORD dwwrittenLen = 0; WriteFile(hCom, data, 8 + len, &dwwrittenLen, NULL); ``` 可以在喷码机上设置收到数据后是否回复,在喷码机设置里面找到接收响应,打开或者关闭。打开的情况下喷码机收到数据会回复"OK\r\n"。关闭的情况下收到数据不会回复。 注:关闭接收响应不影响指令回复,无论如何发送指令都会有回复的,如果没有回复可能是指令格式有误或者硬件层不通。 ## 网络对接 **2. 网络连接** 喷码机网络连接采用TCPIP协议,喷码机作为服务端,电脑或者其他设备作为客户端与喷码机连接。网络连接支持传输文字与图片,协议只提供文字传输协议,需要传输图片请采用二次开发库开发。 1.将喷码机通过有线网络或者无线网络连接到路由器或者直连电脑、其他设备。 2.设置好通讯端口号。 3.客户端通过喷码机的IP地址和端口号采用TCPIP连接到喷码机。 4.发送数据到喷码机。 5.网络连接数据发送格式与串口一样,也支持带协议和不带协议传输。喷码机收到TCP/IP数据如果在数据中检测不到协议头,那么就将数据按文本处理。如果有协议头,根据协议解析数据是文本、指令还是图片,按对应协议处理。 C语言示例: TCP/IP不带协议发送文本 “Send Example” 示例: ``` char str = "Send Example"; int len = strlen(str); send(sockfd, str, len, 0); ``` 如果上位机同时有发送指令和文本的需求,那么建议发送文本的时候也带上协议 带协议的文本发送格式为: [0x4B][0x54][0x01][0x00][0x00][0x00][数据长度高8位][数据长度低8位][数据][数据][数据][数据].... 前6个字节固定为4B 54 01 00 00 00,第7和8个字节为文本的字节长度,后面为文本数据。 TCP/IP带协议发送文本 “Send Example” 示例: ``` char str = "Send Example"; uint8_t data[128]; int len = strlen(str); data[0] = 0x4B; data[1] = 0x54; data[2] = 1; data[3] = 0; data[4] = 0; data[5] = 0; data[6] = len >> 8; data[7] = len & 0xff; strcpy(&data[8], str, len); send(sockfd, data, 8 + len, 0); ``` 可以在喷码机上设置收到数据后是否回复,在喷码机设置里面找到接收响应,打开或者关闭。打开的情况下喷码机收到数据会回复"OK\r\n"。关闭的情况下收到数据不会回复。 注:关闭接收响应不影响指令回复,无论如何发送指令都会有回复的,如果没有回复可能是指令格式有误或者硬件层不通。 ## 控制指令 无论使用串口还是网络都支持发送控制指令,关于控制指令格式请参考库函数开发第5节(控制指令)。 函数开发第5节中使用到的库函数devlib_sent_data和devlib_read_data均为透传函数,不使用库函数开发的时候用串口收发函数或者TCP/IP收发函数替换即可。 # 库函数开发 ## 1. 库文件 kpnpmjdevlib.dll ## 2. 库函数 ``` int devlib_init(void); int devlib_connect(int way, uint32_t ip, int port, int com, int baudrate); int devlib_disconnect(void); int devlib_get_connect_status(void); int devlib_sent_str(uint8_t *data, uint32_t len); int devlib_sent_str_img(uint8_t *str, uint32_t len, uint8_t *img, int width, int height); int devlib_read_data(uint8_t *data, uint32_t len); int devlib_sent_data(uint8_t *data, uint32_t len); ``` ## 3. 库函数简介 ### 3.1.库初始化 int devlib_init(void); 说明:程序启动时调用一次初始化即可。不可重复调用。 参数:无 返回值:0x221118表示成功。 ### 3.2.连接设备 int devlib_connect(int way, uint32_t ip, int port, int com, int baudrate); 说明:连接到设备。如果设备已经连接,则会先断开连接,然后再连接。 参数: way:连接方式。0表示网络连接,1表示串口连接。 ip:IP地址,采用串口连接时无效。 port:网络通讯端口号,采用串口连接时无效。 com:串口端口号,采用网络连接时无效。 baudrate:串口通信波特率,采用网络连接时无效。 返回值:0表示连接成功。 ### 3.3.断开连接 int devlib_disconnect(void); 说明:断开与设备的连接。 参数:无 返回值:0表示本身就没有连接。1表示已经断开网络连接。2表示已经关闭串口连接。 ### 3.4.获取连接状态 int devlib_get_connect_status(void); 说明:获取与设备的连接状态。 参数:无 返回值:0表示没有连接。1表示已经建立网络连接。2表示串口连接。 注:老版本状态检测有BUG,TCP连接时网络意外断开无法检测到。当前版本库文件增加心跳机制,采用心跳判断连接是否正常。 采用网络连接时,心跳时间为2秒,心跳重发时间为500毫秒,心跳重发次数为5次或者10次(与系统有关)。 网络意外断开以后大概需要5~10秒的时间才能检测到。 采用网络连接时,也可以通过devlib_read_data来判断连接状态,返回值0表示未连接或者连接已断开。大于零表示读取到的数据长度。 ### 3.5.发送字符串 int devlib_sent_str(uint8_t *data, uint32_t len); 说明:向设备发送文本。具体调用参看示例 参数: data:文本数据指针。 len:文本长度。(最大1024) 返回值:0表示发送成功。 注:文本长度最大不得超过1024。否则返回错误(-1)。 ### 3.6.发送字符串和图片 int devlib_sent_str_img(uint8_t *str, uint32_t len, uint8_t *img, int width, int height); 说明:向设备发送文本和图片。具体调用参看示例 参数: str:文本数据指针。当只发送图片时,str设为NULL。 len:文本长度(最大1024)。当只发送图片时,len设为0。 img:图片数据指针。 width:图片宽度(单位像素)。 height:图片高度(单位像素)。 返回值:0表示发送成功。 注:图片宽度乘以图片高度最大不得超过1048576。否则返回错误(-3)。 ### 3.7.读取返回数据 int devlib_read_data(uint8_t *data, uint32_t len); 说明:读取喷码机返回的数据。如果不需要读取,可以不使用。如果需要读取喷码机返回的数据,则要创建一个新的线程,在新的线程里轮训该函数。 参数: data:数据存放缓存。需要用户开辟缓存并传入。 len:缓存大小。最大1024即可。 返回值:0表示未连接或者连接已断开。大于零表示读取到的数据长度。小于零表示无数据。 ### 3.8.发送数据 int devlib_sent_data(uint8_t *data, uint32_t len); 说明:发送数据到喷码机,不对数据做打包处理,直接透传数据到喷码机。 参数: data:要发送的数据指针 len:数据长度,字节为单位。最大不得超过1024。 返回值:0表示发送成功。 ## 4. 示例 ### 4.1.动态库加载 ``` HINSTANCE g_hInstDll = NULL; typedef int (WINAPI*dll_init)(void); typedef int (WINAPI*dll_connect)(int way, UINT32 ip, int port, int com, int baudrate); typedef int (WINAPI*dll_disconnect)(void); typedef int (WINAPI*dll_get_connect_status)(void); typedef int (WINAPI*dll_sent_str)(UINT8 *data, UINT32 len); typedef int (WINAPI*dll_sent_str_img)(UINT8 *str, UINT32 len, UINT8 *img, int width, int height); typedef int (WINAPI*dll_read_data)(UINT8 *data, UINT32 len); typedef int (WINAPI*dll_sent_data)(UINT8 *data, UINT32 len); dll_init devlib_init; dll_connect devlib_connect; dll_disconnect devlib_disconnect; dll_get_connect_status devlib_get_connect_status; dll_sent_str devlib_sent_str; dll_sent_str_img devlib_sent_str_img; dll_read_data devlib_read_data; dll_sent_data devlib_sent_data; g_hInstDll = LoadLibrary(_T("kpnpmjdevlib.dll")); if (g_hInstDll != NULL) { devlib_init = (dll_init)::GetProcAddress(g_hInstDll, "devlib_init"); devlib_connect = (dll_connect)::GetProcAddress(g_hInstDll, "devlib_connect"); devlib_disconnect = (dll_disconnect)::GetProcAddress(g_hInstDll, "devlib_disconnect"); devlib_get_connect_status = (dll_get_connect_status)::GetProcAddress(g_hInstDll, "devlib_get_connect_status"); devlib_sent_str = (dll_sent_str)::GetProcAddress(g_hInstDll, "devlib_sent_str"); devlib_sent_str_img = (dll_sent_str_img)::GetProcAddress(g_hInstDll, "devlib_sent_str_img"); devlib_read_data = (dll_read_data)::GetProcAddress(g_hInstDll, "devlib_read_data"); devlib_sent_data = (dll_sent_data)::GetProcAddress(g_hInstDll, "devlib_sent_data"); if(devlib_init == NULL) MessageBox(_T("加载库失败!")); else if (devlib_connect == NULL) MessageBox(_T("加载库失败!")); else if (devlib_disconnect == NULL) MessageBox(_T("加载库失败!")); else if (devlib_get_connect_status == NULL) MessageBox(_T("加载库失败!")); else if (devlib_sent_str == NULL) MessageBox(_T("加载库失败!")); else if (devlib_sent_str_img == NULL) MessageBox(_T("加载库失败!")); else if (devlib_read_data == NULL) MessageBox(_T("加载库失败!")); else if (devlib_sent_data == NULL) MessageBox(_T("加载库失败!请更新库到最新版本")); if (devlib_init) devlib_init(); } else MessageBox(_T("加载库失败!")); ``` ### 4.2.连接喷码机 ``` int ret = devlib_connect(0, ip, port, 1, 115200); if(ret == 0) MessageBox(_T("连接成功!")); else MessageBox(_T("连接失败!")); ``` ### 4.3.发送文字 ``` int len = strlen(str_utf8); if (len <= 1024 && len > 0) { int ret = devlib_sent_str((UINT8 *)str_utf8, len); if (ret == 0) MessageBox(_T("发送成功!")); else MessageBox(_T("发送失败!")); } else { MessageBox(_T("文本长度不符合要求!")); } ``` ### 4.4.发送图片 发送图片主要分为以下5个步骤,具体算法实现参看示例源码。 - 1. 获取图片的RGB数据 - 1. RGB图片转灰度图片 - 1. 计算图片的平均亮度 - 1. 灰度图片转单色图片 - 1. 发送单色图片数据 ## 5. 控制指令 发送指令主要使用devlib_sent_data函数。devlib_sent_data函数是一个透传函数,不会对数据做任何处理。如果使用的是网络会直接通过TCPIP协议发送出去,如果使用的是串口会直接通过串口协议发送出去,所以如果不使用库函数开发也是可以实现发送控制指令的。 发送两条指令之间的间隔建议大于50ms。 ### 5.1.指令介绍 目前只支持11条指令,更多指令正在开发中。指令列表如下 | 指令 | 值 | 描述 | 指令长度 | 响应长度 | |----------------------|------|--------|--------|--------| | REMOTE_CMD_GETPAGE | 0x01 | 获取当前页面 | 12 | 8 | | REMOTE_CMD_PRESSKEY | 0x02 | 发送按钮 | 12 | 8 | | REMOTE_CMD_TRIGGERPR | 0x03 | 触发一次喷印 | 12 | 8 | | REMOTE_CMD_SPRAY | 0x04 | 发送一次闪喷 | 12 | 8 | | REMOTE_CMD_SETPDELAY | 0x05 | 设置喷头延迟 | 48 | 8 | | REMOTE_CMD_SETHERT | 0x06 | 设置通信心跳 | 12 | 12 | | REMOTE_CMD_GETFFIRST | 0x07 | 获取第一个文件 | 12 | 12 + 数据长度 | | REMOTE_CMD_GETFNEXT | 0x08 | 获取下一个文件 | 12 | 12 + 数据长度 | | REMOTE_CMD_GETFCLOSE | 0x09 | 关闭获取文件 | 12 | 8 | | REMOTE_CMD_SELFILE | 0x0A | 选择喷印文件 | 12 + 数据长度 | 8 | | REMOTE_CMD_GETCFILE | 0x0B | 获取当前文件名 | 12 | 12 + 数据长度 | 发送指令 指令数据包为12个字节,每个字节含义如下表 | Byte0 | Byte1 | Byte2 | Byte3 | |---------|-------|-------|-------| | 固定为0x10 | 固定为0x01 | 固定为0x55 | 固定为0xAA | | Byte4 | Byte5 | Byte6 | Byte7 | |-------|---------|-------|---------| | 指令 | 固定为0x00 | 指令取反 | 固定为0xff | | Byte8 | Byte9 | Byte10 | Byte11 | |-------|-------|--------|--------| | 参数 | 参数 | 参数 | 参数 | 其中Byte8~Byte9为参数,如果指令没有参数,固定为0x00即可。 指令返回值 喷码机收到指令以后会返回一个数据包,数据包长度根据不同指令有所不同,大部分指令数据包长度为8字节。 | Byte0 | Byte1 | Byte2 | Byte3 | Byte4 | Byte5 | Byte6 | Byte7 | |---------|---------|---------|---------|-------|---------|-------|-------| | 固定为0x01 | 固定为0x10 | 固定为0x55 | 固定为0xAA | 响应指令 | 固定为0x00 | 值 | 值 | 其中Byte4指示当前回应是对应哪条指令,Byte6和Byte7为响应值。对于指令REMOTE_CMD_GETPAGE,Byte6表示当前页面。 ### 5.2.获取当前页面 获取当前页面用于判断当前喷码机处于什么状态,示例程序如下: ``` //发送指令 UINT8 DataPack[12] = {0x10, 0x01, 0x55, 0xAA, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00}; DataPack[4] = REMOTE_CMD_GETPAGE; DataPack[6] = ~DataPack[4]; ret = devlib_sent_data(DataPack, 12); if (ret != 0) { MessageBox(_T("发送失败!")); return; } //读取喷码机返回值 UINT8 rdata[512]; for (int i = 0; i < 50; i++) { Sleep(100); ret = devlib_read_data(rdata, 512); if (ret > 0 && rdata[0] == 0x01 && rdata[1] == 0x10 && rdata[2] == 0x55 && rdata[3] == 0xAA && rdata[4] == REMOTE_CMD_GETPAGE) { //获取当前页面的值 int page = rdata[6]; break; } } ``` 注:目前只支持以下页面,其他页面获取到的值不具有参考意义。 | 页面 | 值 | 描述 | |------------------|---|----------| | PAGE_UNDEFINE | 0 | 未定义页面 | | PAGE_EDIT | 1 | 编辑页面 | | PAGE_EDIT_FULL | 2 | 全屏编辑页面 | | PAGE_PRINT_PAUSE | 3 | 喷印页面(暂停) | | PAGE_PRINT | 4 | 喷印页面(启动) | | PAGE_HOME | 5 | 主页 | | PAGE_SYSSETTING | 6 | 系统设置页面 | | PAGE_PRSETTING | 7 | 喷印设置页面 | | PAGE_FILEMANAGE | 8 | 文件管理页面 | ### 5.3.发送按钮 发送按钮用于操作喷码机。喷码机每个页面都有许多按钮,每个按钮都有一个唯一ID,通过远程软件发送按钮可以用来操作喷码机。比如开机后需要让喷码机进入喷印页面,那么发送打印按钮即可。 示例程序如下: ``` //发送指令 UINT8 DataPack[12] = {0x10, 0x01, 0x55, 0xAA, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00}; DataPack[4] = REMOTE_CMD_PRESSKEY; DataPack[6] = ~DataPack[4]; DataPack[8] = KEY_PRINT; //按钮ID ret = devlib_sent_data(DataPack, 12); if (ret != 0) { MessageBox(_T("发送失败!")); return; } //读取喷码机返回值 UINT8 rdata[512]; for (int i = 0; i < 50; i++) { Sleep(100); ret = devlib_read_data(rdata, 512); if (ret > 0 && rdata[0] == 0x01 && rdata[1] == 0x10 && rdata[2] == 0x55 && rdata[3] == 0xAA && rdata[4] == REMOTE_CMD_PRESSKEY) { //有返回值表示喷码机已经收到按钮ID,如果当前页面有对应的ID就会执行,如果没有就会忽略。 break; } } ``` 常用按钮的ID如下表所示。参考例程中给出了更多按钮的ID值,可以查看例程获取更多。如果需要明确知道具体页面的某个按钮的ID,请联系我们。 | 按钮 | ID值 | 描述 | |--------------|-----|-------| | KEY_ESC | 144 | 返回 | | KEY_ENTER | 135 | 确定 | | KEY_PRINT | 147 | 喷印/启动 | | KEY_PAUSE | 178 | 暂停 | | KEY_SETTING | 153 | 设置 | | KEY_PSETTING | 154 | 参数设置 | | KEY_BACKWARD | 229 | 上一条 | | KEY_FORWARD | 230 | 下一条 | ### 5.4.触发一次喷印 在喷印启动状态下,如果没有接传感器也没有接打印按键,那么可以通过发送REMOTE_CMD_TRIGGERPR指令来触发一次打印。发送REMOTE_CMD_TRIGGERPR指令就相当于传感器感应到物体一次或者相当于按一次手持机的打印按键。因此该指令只有再喷印启动的状态下才有效。示例代码如下: ``` //发送指令 UINT8 DataPack[12] = {0x10, 0x01, 0x55, 0xAA, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00}; DataPack[4] = REMOTE_CMD_TRIGGERPR; DataPack[6] = ~DataPack[4]; ret = devlib_sent_data(DataPack, 12); if (ret != 0) { MessageBox(_T("发送失败!")); return; } //读取喷码机返回值 UINT8 rdata[512]; for (int i = 0; i < 50; i++) { Sleep(100); ret = devlib_read_data(rdata, 512); if (ret > 0 && rdata[0] == 0x01 && rdata[1] == 0x10 && rdata[2] == 0x55 && rdata[3] == 0xAA && rdata[4] == REMOTE_CMD_TRIGGERPR) { //有返回值表示喷码机已经收到指令 break; } } ``` 注:只有在喷印启动状态下且喷码机没有喷印的时候才会响应该指令。如果喷码机正在喷印一条内容且还没有喷印完成,此时收到该指令会忽略。 ### 5.5.发送一次闪喷 在喷印启动状态下,如果想要喷码机闪喷一下,发送REMOTE_CMD_SPRAY指令即可。该指令带有一个参数,用于指定闪喷墨水量。需要特别注意的是喷码机在开启多帧缓存的时候是不支持闪喷功能的。如果需要闪喷功能请先在喷码机上关闭多帧缓存功能。示例代码如下: ``` //发送指令 UINT8 DataPack[12] = {0x10, 0x01, 0x55, 0xAA, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00}; DataPack[4] = REMOTE_CMD_SPRAY; DataPack[6] = ~DataPack[4]; DataPack[8] = 32; //墨水量等级 ret = devlib_sent_data(DataPack, 12); if (ret != 0) { MessageBox(_T("发送失败!")); return; } //读取喷码机返回值 UINT8 rdata[512]; for (int i = 0; i < 50; i++) { Sleep(100); ret = devlib_read_data(rdata, 512); if (ret > 0 && rdata[0] == 0x01 && rdata[1] == 0x10 && rdata[2] == 0x55 && rdata[3] == 0xAA && rdata[4] == REMOTE_CMD_SPRAY) { //有返回值表示喷码机已经接收该指令。 break; } } ``` 注:只有在喷印启动状态下且喷码机没有喷印的时候才会响应该指令。如果喷码机正在喷印一条内容且还没有喷印完成,此时收到该指令会忽略。 ### 5.6.设置喷头延迟 设置喷头延迟只针对多喷头喷码机有效,单喷头喷码机无效。多喷头的喷码机可以针对每个喷头单独设置喷头延迟。设置喷头延迟指令为REMOTE_CMD_SETPDELAY,该指令带有10个参数,分别表示10个喷头的延迟值,每个参数占4字节,数据类型为uint32_t。示例代码如下: ``` uint32_t PrinterDelay[10] = {0, 100, 200, 300, 400, 500, 600, 700, 800, 900}; //发送指令 UINT8 DataPack[48] = { 0x10, 0x01, 0x55, 0xAA, 0x00, 0x00, 0x00, 0xff}; DataPack[4] = REMOTE_CMD_SETPDELAY; DataPack[6] = ~DataPack[4]; memcpy(&DataPack[8], PrinterDelay, 40); ret = devlib_sent_data(DataPack, 48); if (ret != 0) { MessageBox(_T("发送失败!")); return; } //读取喷码机返回值 UINT8 rdata[512]; for (int i = 0; i < 50; i++) { Sleep(100); ret = devlib_read_data(rdata, 512); if (ret > 0 && rdata[0] == 0x01 && rdata[1] == 0x10 && rdata[2] == 0x55 && rdata[3] == 0xAA && rdata[4] == REMOTE_CMD_SETPDELAY) { //有返回值表示喷码机已经接收该指令。 break; } } ``` 注:如果接收的喷码机没有10个喷头,只有2个或者4个、6个,那么多余的喷头延迟数据将会自动忽略。 ### 5.7.设置通信心跳 喷码机通信支持心跳功能。开机后心跳默认关闭,可以通过发送指令开启和关闭心跳,并设置心跳间隔时间。 心跳内容可设置,支持小数计数、总数计数、墨水余量(需要在喷码机上设置返回数据,勾选需要的内容)。 心跳内容解析参考第6节(心跳数据和喷印完成返回数据格式)。 心跳时间有效范围100-500000(毫秒),设为0表示关闭。 ``` //发送指令 uint32_t Hert_time = 1000;//心跳时间(毫秒) UINT8 DataPack[12] = {0x10, 0x01, 0x55, 0xAA, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00}; DataPack[4] = REMOTE_CMD_SETHERT; DataPack[6] = ~DataPack[4]; memcpy(&DataPack[8], &Hert_time, 4); ret = devlib_sent_data(DataPack, 12); if (ret != 0) { MessageBox(_T("发送失败!")); return; } //读取喷码机返回值 UINT8 rdata[512]; for (int i = 0; i < 50; i++) { Sleep(100); ret = devlib_read_data(rdata, 512); if (ret > 0 && rdata[0] == 0x01 && rdata[1] == 0x10 && rdata[2] == 0x55 && rdata[3] == 0xAA && rdata[4] == REMOTE_CMD_SETHERT) { //有返回值表示喷码机已经接收该指令。设置心跳指令返回12个字节,其中第8-11字节表示设置后的心跳值。 uint32_t d32; memcpy(&d32, &rdata[8], 4); if(d32 == Hert_time) ;//成功 else ;//失败 break; } } ``` ### 5.8.获取喷码机内部喷印文件列表 获取喷码机内部的喷印文件列表需要用到REMOTE_CMD_GETFFIRST、REMOTE_CMD_GETFNEXT和REMOTE_CMD_GETFCLOSE指令。 REMOTE_CMD_GETFFIRST指令用于获取第一个文件的文件名。REMOTE_CMD_GETFNEXT用于获取下一个文件的文件名。如果获取了几个文件之后不想要继续获取下一个文件名了就需要调用REMOTE_CMD_GETFCLOSE以释放内存。如果所有文件都获取完了喷码机会自动释放内存,就可以不用再调用REMOTE_CMD_GETFCLOSE指令了。 REMOTE_CMD_GETFFIRST和REMOTE_CMD_GETFNEXT的指令长度都是12字节,指令响应的长度是不固定的,但是至少是12字节。指令响应数据中Byte6表示返回值,含义见下表,Byte8~Byte11表示数据长度,0表示没有数据。Byte11后面的数据为unicode编码的文件名称。 | Byte6 | 描述 | |--------|---| | 0x00 | 指令执行成功 | | 0x01 | 喷码机内存不足 | | 0x02 | 喷码机内存不足 | | 0x03 | 喷码机内存不足 | | 0x04 | 打开磁盘目录失败 | | 0x05 | 需要先执行REMOTE_CMD_GETFFIRST指令 | | 0x06 | 文件列表访问完成 | | 其他 | 未定义 | 获取喷码机内部喷印文件列表功能的使用参考示例Demo。 ### 5.9.选择喷印文件 想要远程切换喷码机的喷印文件,可以使用REMOTE_CMD_SELFILE指令。 该指令的指令长度为12 + 文件名长度。 其中指令前12个字节与普通指令一样,其中参数(Byte8~Byte11)表示文件名的字节长度。文件名使用unicode编码方式。 发送REMOTE_CMD_SELFILE指令的时候把文件名和12个字节的指令一起发送即可。 该指令的指令响应为8字节,其中Byte6表示执行结果,含义见下表。 | Byte6 | 描述 | |--------|---| | 0x00 | 指令执行成功 | | 0x01 | 文件名长度错误(最大256个字符,512字节) | | 0x02 | 喷印启动界面和未定义界面不支持切换 | | 0x03 | 文件不存在 | | 0x04 | 打开文件失败 | | 其他 | 未定义 | 远程切换喷码机的喷印文件功能的使用参考示例Demo。 注:喷印启动界面和未定义界面不支持切换。如正在喷印需要先发送暂停指令,然后再发送切换文件指令,最后再发送启动喷印指令。 ### 5.10.获取当前喷印文件名 获取当前正在喷印或者编辑区已经打开的文件的文件名可以使用REMOTE_CMD_GETCFILE指令。 该指令的指令长度为12字节,指令响应与REMOTE_CMD_GETFFIRST、REMOTE_CMD_GETFNEXT类似,长度是不固定的,但是至少是12字节。指令响应数据中Byte6表示返回值,含义见下表,Byte8~Byte11表示数据长度,0表示没有数据。Byte11后面的数据为unicode编码的文件名称。 | Byte6 | 描述 | |--------|---| | 0x00 | 指令执行成功 | | 0x01 | 喷码机内存不足 | | 0x02 | 文件名过长(最大256个字符,512字节) | | 其他 | 未定义 | 获取当前喷印文件名功能的使用参考示例Demo。 ## 6. 心跳数据和喷印完成返回数据格式 数据格式包含数据头,数据包长度,数据内容标志,数据内容。其中数据内容在喷码机上可设置,可以包含小计计数、总数计数、墨水量,也可能不包含。可以根据数据内容标志来判断。 | | 字节数 | 描述 | |--------|---|---| | 数据头 | 4 | 根据数据头判断是心跳数据还是喷印完成的返回数据 | | 包长度 | 4 | 表示此数据包的总长度 | | 数据标志 | 4 | 32位整数,根据每一位来判断包含哪些数据 | | 小数计数 | 4 | 32位整数,表示喷印小计计数 | | 总数计数 | 4 | 32位整数,表示喷印总数计数 | | 墨水余量 | 16 | 墨水余量 | 数据头 0x54524148表示心跳数据; 0x4B4F5250表示喷印完成返回数据; 数据标志 32位整数,其中每一位表示的含义如下 | 位 | 0 | 1 | |---|---|---| | bit31~bit3 | 未定义 | 未定义 | | bit2 | 不包含墨水余量 | 包含墨水余量 | | bit1 | 不包含总数计数 | 包含总数计数 | | bit0 | 不包含小计计数 | 包含小计计数 | 墨水余量 总共16个字节。每个字节含义如下 | 字节 | 字节数 | 描述 | |--------------|------|----| | Byte0~Byte1 | 2 | 喷头有效标志位,每一位表示一个喷头,0表示无效,1表示有效 | | Byte2~Byte3 | 2 | 未定义 | | Byte4~Byte15 | 12 | 喷头1~喷头12的墨水量,具体是否有效要看标志位。0表示0%,255表示100% | 数据解析参考C语言代码 ``` #pragma pack(4) typedef struct { uint32_t dataType; uint32_t dataLen; uint32_t dataOpt; }DT_HEAT; typedef struct { uint16_t validSign; //Byte0~Byte1,喷头有效标志位 uint16_t reserve1; //Byte2~Byte3,未定义 uint8_t ink[12]; //Byte4~Byte15,喷头1~喷头12的墨水量 }DT_HEAT_INK; #pragma pack() int offset; uint8_t data[512]; uint32_t *d32; DT_HEAT *Hert; DT_HEAT_INK *Ink; uint32_t Count; int ret = devlib_read_data(data, 1024); if(ret > 0) { Hert = (DT_HEAT *)data; if(Hert->dataType == 0x54524148) printf("心跳数据\r\n"); else if(Hert->dataType == 0x4B4F5250) printf("喷印完成数据\r\n"); else return; offset = sizeof(DT_HEAT); if (Hert->dataOpt & 0x01) { d32 = (uint32_t *)&data[offset]; offset += 4; Count = *d32; printf("文件计数%d\r\n", Count); } if (Hert->dataOpt & 0x02) { d32 = (uint32_t *)&data[offset]; offset += 4; Count = *d32; printf("总数计数%d\r\n", Count); } if (Hert->dataOpt & 0x04) { Ink = (DT_HEAT_INK *)&data[offset]; offset += sizeof(DT_HEAT_INK); printf("墨水余量\r\n"); if(Ink->validSign == 0) printf("非喷印状态无法获取\r\n"); else { for (int i = 0; i < 12; i++) { if (Ink->validSign & (1 << i)) printf("喷头%d:%d%%\r\n", i + 1, (uint32_t)Ink->ink[i] * 100 / 255); else printf("喷头%d无效\r\n", i + 1); } } } } ``` ## 7. 示例程序运行效果 ![输入图片说明](image/devdemo.png) ### 功能介绍: ### 数据 发送文本:将文本框里的文字发送到喷码机 发送图片:将选好的图片发送到喷码机 发送文本和图片:将文本框里的文字和选好的图片一起发送到喷码机 ### 指令 获取当前页面:获取喷码机当前页面(状态) 喷印/启动:发送启动/喷印按钮(主页,编辑界面,喷印界面有效) 暂停:发送暂停按钮(喷印启动状态有效) 确定:发送确定按钮 返回:发送返回按钮 设置:发送设置按钮 参数设置:发送参数设置按钮 上一条:发送上一条按钮(喷印暂停状态有效) 下一条:发送下一条按钮(喷印暂停状态有效) 触发一次喷印:通过该指令触发一次喷印(喷印启动状态有效) 心跳设置:设置喷码机通信的心跳时间 获取文件列表:获取喷码机内部文件列表 切换喷印文件:切换喷码机的喷印文件(喷印启动状态无效) 获取当前文件名:获取当前正在喷印或者编辑区已经打开的文件的文件名