visca协议及其实现的简单认识

转载自:https://latelee.blog.csdn.net/article/details/35811777

visca协议及其实现的简单认识

李迟 2014-06-30 14:09:01 7064 收藏 12

分类专栏: 程序编程 代码生活 打工人的知识库

版权

最近在搞visca协议,在这里写写,算是个记录。

visca是索尼公司搞出来的,用来控制相机的协议,一般通过rs232来通信(看了些资料,也有用rs485的)。

一、命令格式

命令通信的基本单元称为包(Packet)。一个包的长度为3到16字节,由头部、消息体和结束符三部分组成。命令包的第一个字节称为命令头(Header)。高半字节由1 (最高位,固定为1)和发送方(控制者)地址(地址一般为0)组成,低半字节由0和设备(相机)地址(或称“编号”)组成,从组成格式看,可以外接的相机最多有7台,如向1号相机发送命令,则命令头为0x81。命令包最后一个字节为终结符号,固定为0xff。中间部分字节称为消息体。协议说明文档中将命令头写成“8x”,其中x表示相机地址。

命令共2类:普通命令(Command)及查询命令(Inquiry)。前者是直接发送命令到相机,后者是从相机获取到数据。
具体的命令包格式如下:
8X QQ RR … FF
其中QQ为命令分类,01表示普通命令,09表示查询命令。RR为类别码(Category code)。X表示相机地址。范围1~7。

二、响应

每个命令均有响应包,格式如下:
X0 … … FF
其中X范围为9~F,数值为相机编号+8。以FF结束。发送普通命令时,相机会返回ACK响应,但查询命令不会返回ACK。

ACK响应包格式:X0 41 FF
普通命令响应包格式:X0 51 FF
查询命令响应包格式:X0 51 ... FF
其中,X范围为9~F,是相机地址值+8。查询命令的响应包中带有数据,每种数据均不相同,可以询查协议文档。

错误信息格式如下:
语法错误:X0 61 02 FF
命令取消:X0 61 04 FF
没有socket:X0 61 05 FF
命令没有执行:X0 61 41 FF
其中X的值和上面的一样。“socket”的范围暂时还不太了解。这些值就是代码做出判断的依据。

三、协议文档备注
对于协议文档中qprs这类的描述方式,直接将其放到16位的十六进制数据的各项(十六进制格式为0xAAAA)中即可。比如一个命令的响应包格式为“y0  50  0p 0q  0r  0s  FF”,则实际得到的数据是0xpqrs。如“01 02 03 04”,对应数据为0x1234。反之亦然。在代码中用移位来实现即可。下面看几个经典的命令格式。

1、不带参数的命令
相机上电CAM_Power命令格式: 8x  01  04  00  02  FF
“8x”中的“x”表示相机编号。此类命令,直接按命令字段来组装即可。

2、带参数的命令
变焦CAM_Zoom命令格式为:8x  01  04  47  0p 0q  0r  0s  FF。
“0p 0q 0r 0s”中的pqrs组成focus position参数。组装命令时,要将这个参数依次移位到对应的字段。假设参数值为0x1234,则对应的字段为“01 02 03 04”。
CAM_AFMode命令可以设置Active/Interval Time两个值,格式为:8x  01  04  27  0p 0q  0r  0s  FF
“0p 0q”对应于movement time,“0r 0s”对应于Interval,组装命令时,要分别进行组装。方式见上。

3、查询类命令,不带参数
像CAM_PowerInq查询命令,发送8x  09  04  00  FF,直接返回y0  50  02  FF或y0  50  03  FF
其中“y0  50  02  FF”是返回的数据,y值为相机编号+8。对于此类命令,直接读取第3个字节即可得到对应的状态。

4、查询类命令,带参数
像CAM_ZoomPosInq命令,发送8x  09  04  47  FF,返回y0  50  0p 0q  0r  0s  FF
在查询命令中,有大部分的命令是带有可变数据的,“y0  50  0p 0q  0r  0s  FF”中的“0p 0q 0r 0s”需要移位后才能知道确切的值,对应的值为0xpqrs。

四、实现

很庆幸,关于visca,已经有libvisca开源项目了(见参考资源)。下面参考这个项目,做了一些小修改,写一下关键的实现代码。

关于串口的打开、读写、关闭,在此不再多说。下面说一下命令的封装:

void _visca_append_byte(VISCAPacket_t *packet, unsigned char byte)
{
    packet->bytes[packet->length]=byte;
    (packet->length)++;
}

void _visca_init_packet(VISCAPacket_t *packet)
{
    // set it to null
    memset(packet->bytes, '\0', sizeof(packet->bytes));
    // we start writing at byte 1, the first byte will be filled by the
    // packet sending function(_visca_send_packet). This function will also append a terminator.
    packet->length=1;
}

这两个函数是命令的填充,每次调用_visca_append_byte就填充一个字符,在未填充前,要调用_visca_init_packet来初始化包的长度。当然,实现上也可以直接用数组形式把每个命令合到一起发送出去。_visca_send_packet是填充头部和尾部数据,无须调用者进行考虑,调用者只需关注实际的命令数据即可。这也是使用了VISCAInterface_t的好处(后面写pelco实现的将会看到)。

int32_t _visca_send_packet(VISCAInterface_t *iface, VISCACamera_t *camera, VISCAPacket_t *packet)
{
    // check data:
    if ((iface->address>7)||(camera->address>7)||(iface->broadcast>1))
    {
        com_print("(%s): Invalid header parameters\n",__FILE__);
        com_print("addr: %d %d broadcast: %d(0x%x)\n",iface->address,camera->address,
                    iface->broadcast,iface->broadcast);
        return VISCA_FAILURE;
    }

    // build header:
    packet->bytes[0]=0x80;
    packet->bytes[0]|=(iface->address << 4);
    if (iface->broadcast>0)
    {
        packet->bytes[0]|=(iface->broadcast << 3);
        packet->bytes[0]&=0xF8;
    }
    else
    {
        packet->bytes[0]|=camera->address;
    }

    // append footer(0xff)
    _visca_append_byte(packet,VISCA_TERMINATOR);

    return _visca_write_packet_data(iface,packet);
}

命令响应包函数如下:

int32_t _visca_get_reply(VISCAInterface_t *iface, VISCACamera_t *camera)
{
    // first message: -------------------
    if (_visca_get_packet(iface)!= VISCA_SUCCESS)
        return VISCA_FAILURE;

    iface->type=iface->ibuf[1]&0xF0;

    // skip ack messages
    while (iface->type==VISCA_RESPONSE_ACK)
    {
        if (_visca_get_packet(iface)!=VISCA_SUCCESS)
            return VISCA_FAILURE;
        iface->type=iface->ibuf[1]&0xF0;
    }

    switch (iface->type)
    {
    case VISCA_RESPONSE_CLEAR:
        return VISCA_SUCCESS;
        break;
    case VISCA_RESPONSE_ADDRESS:
        return VISCA_SUCCESS;
        break;
    case VISCA_RESPONSE_COMPLETED:
        return VISCA_SUCCESS;
        break;
    case VISCA_RESPONSE_ERROR:
        return VISCA_CMDERROR;
        break;
    }

    return VISCA_FAILURE;
}

里面一些宏定义如下:

/* response types */
#define VISCA_RESPONSE_CLEAR             0x40
#define VISCA_RESPONSE_ADDRESS           0x30
#define VISCA_RESPONSE_ACK               0x40
#define VISCA_RESPONSE_COMPLETED         0x50
#define VISCA_RESPONSE_ERROR             0x60

其实判断也十分简单,就是根据协议给出的错误码来一一判断。
其它的代码,直接参考libvisca即可,不在这里列出。

 

参考资源:

1、开源的visca协议库:libvisca: http://damien.douxchamps.net/libvisca/
2、visca协议的wiki介绍:http://en.wikipedia.org/wiki/VISCA_Protocol

 

后记:截止本文编写时,手上还没有得到硬件资源,文章是根据libvisca和visca协议文档中的描述来写的,应该不具有实践价值。

李迟记于2014年6月30日

下面是一个简单的C语言实现Sony VISCA协议的例子,可以通过串口控制Sony的高清摄像机和摄影机。这个例子实现了一些基本的VISCA命令,如对焦、变焦、光圈等控制。需要注意的是,具体的VISCA命令码和参数设置需要参考设备的VISCA协议文档。 ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <termios.h> #define VISCA_BAUDRATE B9600 #define VISCA_DEVICE "/dev/ttyS1" int fd; void visca_init() { struct termios newtio; fd = open(VISCA_DEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK); if (fd < 0) { perror("open"); exit(EXIT_FAILURE); } tcgetattr(fd, &newtio); newtio.c_cflag = VISCA_BAUDRATE | CS8 | CLOCAL | CREAD; newtio.c_iflag = IGNPAR; newtio.c_oflag = 0; newtio.c_lflag = 0; newtio.c_cc[VTIME] = 0; newtio.c_cc[VMIN] = 1; tcflush(fd, TCIFLUSH); tcsetattr(fd, TCSANOW, &newtio); } void visca_command(char *cmd) { int len = strlen(cmd); if (write(fd, cmd, len) != len) { perror("write"); exit(EXIT_FAILURE); } usleep(10000); } void visca_zoom(int dir, int speed) { char cmd[8]; sprintf(cmd, "%02X%02X%02X%02X%02X%02X%02X", 0x81, 0x01, 0x04, 0x07, 0x02, dir, speed); visca_command(cmd); } void visca_focus(int dir, int speed) { char cmd[8]; sprintf(cmd, "%02X%02X%02X%02X%02X%02X%02X", 0x81, 0x01, 0x04, 0x08, 0x02, dir, speed); visca_command(cmd); } void visca_aperture(int dir, int speed) { char cmd[8]; sprintf(cmd, "%02X%02X%02X%02X%02X%02X%02X", 0x81, 0x01, 0x04, 0x47, 0x02, dir, speed); visca_command(cmd); } int main(int argc, char *argv[]) { visca_init(); visca_zoom(1, 10); visca_focus(1, 10); visca_aperture(1, 10); close(fd); return 0; } ``` 上面的例子实现了对摄像机的变焦、对焦和光圈的控制。使用方法是编译程序,并通过串口连接到摄像机。需要注意的是,在使用VISCA命令时,需要根据具体的设备和命令码进行设置和修改。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值