KUKAVARPROXY 在 KRC4 中接收和发送消息的格式 (1)

目录 Content
[hide]

一、目的

在前面的一篇博文中《JOpenShowVarCMD : 命令行版本的 JOpenShowVar》提到过KUKAVARPROXY 这个第三方软件。它运行在 KUKA 的 KRC4 控制器中作为服务器,监听 7000 端口,通过 TCP/IP 接收客户端的读写变量的消息请求,与控制器交互,返回结果给客户端。如果我们获取到它的消息格式,就可以开发自己专属的客户端软件!

KUKAVARPROXY

二、方法

通过阅读源代码,可以了解作者设计的消息格式,不过呢,一是不够直观,二是kukavarproxy是VB编写的,作者并没有开放源代码,只开放了客户端 openshowvar 的源代码。所以最直观的就是监听通讯过程中的字节流,从而可以分析出消息的格式。

使用 SmartSniff 监听到通信过程如下:

kukavarproxy_read_write_msg_format

三、分析

第一行为kukavarproxy接收的消息,第二行为kukavarproxy返回的消息。

1. 请求读变量

a. 接收消息流格式

  • 第1个byte和第2个byte:消息的编号
  • 第3个byte和第4个byte:后面消息流的byte个数。如后面的byte为 00 00 07 24 4F 56 5F 50 52 4F 共10个byte,所以此处值为 000A
  • 第5个byte:0 表示读变量,1表示写变量
  • 第6个byte和第7个byte: 后面变量名的byte个数。如后面的byte为 24 4F 56 5F 50 52 4F 共7个byte,所以此处值为 0007
  • 第8个byte: 变量名,如 $OV_PRO 的ANSI码为244F565F50524F

b. 返回消息流格式

  • 第1个byte和第2个byte:返回接受到的消息编号,,以便客户端程序识别
  • 第3个byte和第4个byte:后面消息流中的byte个数。如后面的byte为 00 00 03 31 30 30 00 01 01 共9个byte,所以此处值为 0009
  • 第5个byte:返回接受到消息中的值。0 表示读变量,1表示写变量
  • 第6个byte和第7个byte:返回变量内容的byte个数。如返回值为100,则ANSI为313030,共3个byte,所以此处值为0003
  • 第8个byte:返回变量的内容。如100的ANSI为 313030
  • 最后3个字节:常为 000101

2. 请求写变量

  • 前面与读变量类似
  • 第8个byte:变量名的ANSI + 后面变量内容的byte个数 (这里是0002)+ 变量内容的ANSI

四、代码实现

抽取作者  OpenShowVar 的代码片段,并修改以实现最基本的读写功能。下面是 Qt5 的代码实现:

#include <QDebug>
#include <QTcpSocket>

QByteArray formatMsg(QByteArray msg, unsigned short idMsg){

    const char READVARIABLE=0;

    QByteArray header, block;
    int lunghezza,varNameLen;
    unsigned char hByte, lByte;
    unsigned char hByteMsg,lByteMsg;

    varNameLen=msg.size();
    hByte=(varNameLen & 0xff00) >> 8;
    lByte=(varNameLen & 0x00ff);

    block.append(READVARIABLE).append(hByte).append(lByte).append(msg);
    lunghezza=block.size();

    hByte=(lunghezza & 0xff00) >> 8;
    lByte=(lunghezza & 0x00ff);

    hByteMsg=(idMsg & 0xff00) >> 8;
    lByteMsg=(idMsg & 0x00ff);

    header.append(hByteMsg).append(lByteMsg).append(hByte).append(lByte);
    block.prepend(header);

    qDebug()<<"Message send:"<<block.toHex();

    return block;
}

QByteArray formatMsg(QByteArray msg, QByteArray value, unsigned short idMsg){

    const char WRITEVARIABLE=1;

    QByteArray header, block;
    short lunghezza,varNameLen,varValueLen;
    unsigned char hByte, lByte;
    unsigned char hByteMsg,lByteMsg;

    varNameLen=msg.size();
    hByte=(varNameLen & 0xff00) >> 8;
    lByte=(varNameLen & 0x00ff);

    block.append(WRITEVARIABLE).append(hByte).append(lByte).append(msg);

    varValueLen=value.size();
    hByte=(varValueLen & 0xff00) >> 8;
    lByte=(varValueLen & 0x00ff);

    block.append(hByte).append(lByte).append(value);

    lunghezza=block.size();

    hByte=(lunghezza & 0xff00) >> 8;
    lByte=(lunghezza & 0x00ff);

    hByteMsg=(idMsg & 0xff00) >> 8;
    lByteMsg=(idMsg & 0x00ff);

    header.append(hByteMsg).append(lByteMsg).append(hByte).append(lByte);
    block.prepend(header);

    qDebug()<<"Message send:"<<block.toHex();

    return block;
}

unsigned short clearMsg(QByteArray msg, QByteArray &value){

    short lenMsg,func,lenValue;
    unsigned short idReadMsg;

    if(msg.length() > 0){
        //Message ID
        idReadMsg=((unsigned char)msg[0])<<8 | ((unsigned char)msg[1]);
        qDebug() << "Message ID: " << idReadMsg;

        //Message Length
        lenMsg=((unsigned char)msg[2])<<8 | ((unsigned char)msg[3]);
        qDebug() << "Message Length:" << lenMsg;

        //Function(read/Write)
        func=((int)msg[4]);
        qDebug() << "Function(read:0/Write:1) " << func;

        //Value Length
        lenValue=((unsigned char)msg[5])<<8 | ((unsigned char)msg[6]);
        qDebug() << "Value Length:" << lenValue;

        qDebug() << "Message return:" << msg.toHex();

        // the byte7 begin the value
        value = msg.mid(7,lenValue);
        return idReadMsg;

    }
    else{
        value = QByteArray("");
        return 0;
    }
}

int main()
{
    const int Timeout = 5 * 1000;

    QTcpSocket socketClient;
    socketClient.connectToHost("192.168.40.128", 7000);
    if (!socketClient.waitForConnected(Timeout)) {
        qDebug() << "Timeout connection!";
        return -1;
    }

    socketClient.write(formatMsg("$OV_PRO",0));
    if(!socketClient.waitForBytesWritten(Timeout))
    {
        qDebug() << "Timeout message sent!";
        return -1;
    }

    if (!socketClient.waitForReadyRead(Timeout)) {
        qDebug() << "Timeout message return!";
        return -1;
    }
    QByteArray returnMsg = socketClient.read(socketClient.bytesAvailable());

    qDebug()<<"-----------return message-----------";
    unsigned char ok = returnMsg.right(1).at(0);

    QByteArray value;
    unsigned short idMsg = clearMsg(returnMsg,value);
    qDebug()<<"Value:"<<value;

    socketClient.disconnectFromHost();

    return 0;
}

测试正常

kukavarproxy_read_write_msg_format_Qt5_debug代码下载

五、总结

通过以上的研究,可以有以下结论:

  1. 编写自己的客户端软件,读写KRC4的变量。
  2. 可以借鉴openvarshow作者的通讯消息的组织和解析格式,将来在自己的软件中使用

六、扩展阅读

关键字:KUKAVARPROXY, KRC4

Leave a Reply

Your email address will not be published. Required fields are marked *