visca_parser_web_logo

ViscaParser C++ library

v3.0.8

Table of contents

Overview

The ViscaParser is a C++ library for encoding control commands and checking responses for VISCA protocol messages. The command set was made and checked with the camera Sony FCB-EV7520A. The library can also control other cameras that support the VISCA protocol; such a camera may support only a part of the commands, so check that a command works with your camera before using it. The library includes basic methods for preparing commands (encoding) and interpreting the camera responses (checking command arguments). It uses C++17 standard. The library provides simple interface and doesn’t have third party dependencies. Also, the library includes test application to test communication with cameras. Test application depends on SerialPort library (provides methods to work with serial ports).

ViscaParser is general-purpose software: it is not tied to any sector or application, and the developer of a program decides what the program does with it.

The library code was developed by reverse engineering the serial port communication protocol of VISCA compatible cameras.

Versions

Table 1 - Library versions.

Version Release date What’s new
1.0.0 20.01.2022 - First version.
2.0.0 02.06.2022 - New commands added.
- Bugs fixed.
3.0.0 03.04.2023 - Class name changed from ViscaProtocolParser to ViscaParser.
- ViscaProtocolParserDataStructures.h file excluded.
- Documentation updated.
3.0.1 11.02.2024 - Documentation updated.
3.0.2 24.04.2024 - Documentation updated.
- Code reviewed.
3.0.3 24.05.2024 - Documentation updated.
3.0.5 15.07.2024 - Fix focus near limit decoding.
3.0.6 25.10.2025 - SerialPort submodule update.
3.0.7 25.10.2025 - Fix documentation for COMMAND_CAM_ChromaSuppress.
3.0.8 18.10.2026 - Git submodules removed: the SerialPort library used by the test application is expected next to the library repository.
- Code reviewed: compiler warnings fixed, documentation of the class and of the ViscaPackets enum corrected and completed.
- encodeCommand(…) method returns FALSE if the pointer to the packet buffer is nullptr.
- Compiler warning and hardening options added to CMake files.
- Test application checks the entered values and the result of command encoding.

Library files

The library supplied by source code only. The user would be given a set of files in the form of a CMake project (repository). The repository structure is shown below:

CMakeLists.txt --------------- Main CMake file.
src -------------------------- Folder with library source code.
    CMakeLists.txt ----------- CMake file of the library.
    ViscaParser.h ------------ Main library header file.
    ViscaParser.cpp ---------- C++ implementation file.
    ViscaParserVersion.h ----- Header file with library version.
    ViscaParserVersion.h.in -- CMake file to generate version header.
test ------------------------- Folder for test application files.
    CMakeLists.txt ----------- CMake file for test application.
    main.cpp ----------------- Source C++ file of test application.
static ----------------------- Folder with pictures for this document.

ViscaParser class description

Class declaration

ViscaParser.h contains main class ViscaParser declaration and ViscaPackets enum that contains list commands and messages supported by VISCA protocol. Class declaration:

class ViscaParser
{
public:

    /// Get library version.
    static std::string getVersion();

    /// Encode COMMAND or INQUIRY command.
    bool encodeCommand(
        rapidpixel::ViscaPackets commandId, uint8_t* packet,
        uint32_t& packetSize, uint8_t cameraAddress,
        uint32_t param1 = 0, uint32_t param2 = 0,
        uint32_t param3 = 0, uint32_t param4 = 0,
        uint32_t param5 = 0, uint32_t param6 = 0,
        uint32_t param7 = 0, uint32_t param8 = 0,
        uint32_t param9 = 0, uint32_t param10 = 0);

    /// Decode input data byte-by-byte.
    rapidpixel::ViscaPackets decodeData(
        uint8_t nextByte, uint8_t cameraAddress,
        uint32_t& param1, uint32_t& param2,
        uint32_t& param3, uint32_t& param4,
        uint32_t& param5, uint32_t& param6,
        uint32_t& param7, uint32_t& param8,
        uint32_t& param9, uint32_t& param10);
};

getVersion method

The getVersion() method returns string of current version of ViscaParser class. Method declaration:

static std::string getVersion();

Method can be used without ViscaParser class instance:

std::cout << "ViscaParser class version: " << rapidpixel::ViscaParser::getVersion() << std::endl;

Console output:

ViscaParser class version: 3.0.8

encodeCommand method

encodeCommand(…) method intended to encode VISCA command or inquiry to send to camera. Only COMMAND_… and INQUIRY_… values of ViscaPackets enum can be encoded. The method remembers the command: decodeData(…) uses it to decode replies to inquiries. The method is not thread-safe: methods of one object must not be called from several threads at the same time without external synchronization. Method declaration:

bool encodeCommand(
        rapidpixel::ViscaPackets commandId, uint8_t* packet,
        uint32_t& packetSize, uint8_t cameraAddress,
        uint32_t param1 = 0, uint32_t param2 = 0,
        uint32_t param3 = 0, uint32_t param4 = 0,
        uint32_t param5 = 0, uint32_t param6 = 0,
        uint32_t param7 = 0, uint32_t param8 = 0,
        uint32_t param9 = 0, uint32_t param10 = 0);
Parameter Value
commandId ID of VISCA command according to ViscaPackets enum (declared in ViscaParser.h file). ViscaPackets enum lists the VISCA commands that the library supports.
packet Pointer to the packet buffer to be filled by the method. Must not be nullptr. The size of the buffer must be at least 16 bytes (the longest packet).
packetSize Output packet size, bytes (from 3 to 16).
cameraAddress Camera address. Usually equals 1 or can be reassigned with the command rapidpixel::ViscaPackets::COMMAND_AddressSet. The camera address can be in the range from 1 to 7.
param1 Parameter 1. The value of each parameter depends on the commandId (see ViscaPackets enum).
param2 Parameter 2. The value of each parameter depends on the commandId (see ViscaPackets enum).
param3 Parameter 3. The value of each parameter depends on the commandId (see ViscaPackets enum).
param4 Parameter 4. The value of each parameter depends on the commandId (see ViscaPackets enum).
param5 Parameter 5. The value of each parameter depends on the commandId (see ViscaPackets enum).
param6 Parameter 6. The value of each parameter depends on the commandId (see ViscaPackets enum).
param7 Parameter 7. The value of each parameter depends on the commandId (see ViscaPackets enum).
param8 Parameter 8. The value of each parameter depends on the commandId (see ViscaPackets enum).
param9 Parameter 9. The value of each parameter depends on the commandId (see ViscaPackets enum).
param10 Parameter 10. The value of each parameter depends on the commandId (see ViscaPackets enum).

A parameter that is not used by the command is ignored. The method checks the range of a parameter (the valid values are described for each command in ViscaPackets enum). The parameters of the following commands are not range checked, only the low bits of the value are encoded: COMMAND_CAM_AFMode_Active_or_Interval_Time, COMMAND_CAM_Gain_Limit, COMMAND_CAM_ExpComp_Direct, COMMAND_CAM_SpotAE_Position, COMMAND_CAM_AE_Response_Direct, COMMAND_CAM_AutoICR_Threshold and param5 of COMMAND_CAM_PrivacyZone_Non_InterlockMask.

Returns: TRUE if the command encoded or FALSE if the pointer to the packet buffer is nullptr, the camera address is not in the range from 1 to 7, the command is not supported or a parameter is out of range. If the method returns FALSE, the packet buffer and packetSize are not changed (if packet is nullptr, packetSize is set to 0). The exception is COMMAND_CAM_PrivacyZone_SetPTZMask: the method fills the packet buffer and packetSize, but returns FALSE. The command is remembered for decoding also if the method returns FALSE because of a parameter value (it is not remembered if packet is nullptr or the camera address is not valid).

decodeData method

decodeData(…) method intended for decoding input data received from the camera, processing it byte by byte. This process is essential for identifying connected packets within the data stream obtained from the serial port. A byte that can not start or continue a message is skipped. The method returns the ID of a message when its last byte is received. A reply to an inquiry is decoded according to the last command passed to encodeCommand(…) method, so the user should send the inquiry first: if the reply does not match the last encoded inquiry the method returns UNDEFINED_PACKET. Acknowledge, completion, error and alarm messages are decoded independently of the last command. The method is not thread-safe: methods of one object must not be called from several threads at the same time without external synchronization. Method declaration:

rapidpixel::ViscaPackets decodeData(
            uint8_t nextByte, uint8_t cameraAddress,
            uint32_t& param1, uint32_t& param2,
            uint32_t& param3, uint32_t& param4,
            uint32_t& param5, uint32_t& param6,
            uint32_t& param7, uint32_t& param8,
            uint32_t& param9, uint32_t& param10);
Parameter Value
nextByte Next byte in data to decode.
cameraAddress Camera address. Usually equals 1 or can be reassigned with the command rapidpixel::ViscaPackets::COMMAND_AddressSet. The camera address can be in the range from 1 to 7. If the address is not valid the method returns UNDEFINED_PACKET and does not change the decoder state.
param1 Output parameter 1. The value of each parameter depends on the decoded message (see ViscaPackets enum). The method sets all output parameters to 0 and then sets the parameters of the decoded message.
param2 Output parameter 2. The value of each parameter depends on the decoded message (see ViscaPackets enum). The method sets all output parameters to 0 and then sets the parameters of the decoded message.
param3 Output parameter 3. The value of each parameter depends on the decoded message (see ViscaPackets enum). The method sets all output parameters to 0 and then sets the parameters of the decoded message.
param4 Output parameter 4. The value of each parameter depends on the decoded message (see ViscaPackets enum). The method sets all output parameters to 0 and then sets the parameters of the decoded message.
param5 Output parameter 5. The value of each parameter depends on the decoded message (see ViscaPackets enum). The method sets all output parameters to 0 and then sets the parameters of the decoded message.
param6 Output parameter 6. The value of each parameter depends on the decoded message (see ViscaPackets enum). The method sets all output parameters to 0 and then sets the parameters of the decoded message.
param7 Output parameter 7. The value of each parameter depends on the decoded message (see ViscaPackets enum). The method sets all output parameters to 0 and then sets the parameters of the decoded message.
param8 Output parameter 8. The value of each parameter depends on the decoded message (see ViscaPackets enum). The method sets all output parameters to 0 and then sets the parameters of the decoded message.
param9 Output parameter 9. The value of each parameter depends on the decoded message (see ViscaPackets enum). The method sets all output parameters to 0 and then sets the parameters of the decoded message.
param10 Output parameter 10. The value of each parameter depends on the decoded message (see ViscaPackets enum). The method sets all output parameters to 0 and then sets the parameters of the decoded message.

Returns: ID of message according to enumeration ViscaPackets enum: ACKNOWLEDGE, COMPLETION_COMMANDS, ERROR_… or REPLY_…. If the method decoded a message, it returns the message identifier. If no message is completed by the byte, the method returns the identifier rapidpixel::ViscaPackets::UNDEFINED_PACKET.

Data Structures

ViscaPackets enum

ViscaPackets enum declared in ViscaParser.h file. Enum represents all commands and replies described in VISCA protocol. The enum declaration:

enum class ViscaPackets
{
    /// No message was decoded: the input bytes do not form a complete
    /// message that the library decodes.
    UNDEFINED_PACKET,

    // ERROR MESSAGES.

    /// Error message: the message length is wrong.
    ERROR_Message_Length,
    /// Error message: the command is not known or its parameters are wrong
    /// (syntax error).
    ERROR_Syntax,
    /// Error message: the camera can not accept the command because both
    /// command buffers are full.
    ERROR_Command_Buffer_Full,
    /// Error message: the command was canceled.
    ERROR_Command_Canceled,
    /// Error message: the command to cancel is not executing (no such socket).
    ERROR_No_Socket,
    /// Error message: the camera can not execute the command in the current
    /// state.
    ERROR_Command_Not_Executable,

    // COMMAND MESSAGES.

    /// Set address value. Parameters:
    /// camera address.
    COMMAND_AddressSet,

    /// Clears the command buffers in the camera and cancels the command
    /// currently being executed. No parameters.
    COMMAND_IF_Clear_Broadcast,
    /// Clears the command buffers in the camera and cancels the command
    /// currently being executed. Parameters: camera address.
    COMMAND_IF_Clear,

    /// Cancels the command currently being executed. Parameters:
    /// camera address
    /// param_1 - socket number (1 or 2).
    COMMAND_CommandCancel,

    /// Camera power On. Parameters:
    /// camera address.
    COMMAND_CAM_Power_On,
    /// Camera power Off (Standby). Parameters:
    /// camera address.
    COMMAND_CAM_Power_Off,

    /// ...... other commands ...... ///
}

The enum values that start with COMMAND_ and INQUIRY_ are encoded by encodeCommand(…) method. The values ACKNOWLEDGE, COMPLETION_COMMANDS and the values that start with ERROR_ and REPLY_ are returned by decodeData(…) method. The comment of each value in ViscaParser.h describes the meaning of the parameters. The values NETWORK_CHANGE, COMPLETION_INQUIRY, REPLY and REPLY_CAM_ExAperture are not returned by the library.

Examples

Command encoding example

Below is an example of encoding command.

rapidpixel::ViscaParser parser;
rapidpixel::SerialPort serialPort;

// Open the serial port: name, baudrate, timeout of waiting for data (msec).
if (serialPort.open("/dev/ttyUSB0", 9600, 500))
{
    // Encode the zoom position inquiry for the camera with address 1.
    uint8_t packetData[16];
    uint32_t packetSize = 0;
    if (!parser.encodeCommand(rapidpixel::ViscaPackets::INQUIRY_CAM_ZoomPosInq,
                              packetData, packetSize, 1))
    {
        std::cout << "Command not encoded" << std::endl;
    }
    // Send the packet to the serial port.
    else if (serialPort.write(packetData, packetSize) != static_cast<int>(packetSize))
    {
        std::cout << "Command not sent" << std::endl;
    }
}
else
{
    std::cout << "Serial port not open" << std::endl;
}

Command decoding example

Below is an example of decoding cameras response. The inquiry is sent first: the parser remembers it to decode the reply.

rapidpixel::ViscaParser parser;
rapidpixel::SerialPort serialPort;

if (serialPort.open("/dev/ttyUSB0", 9600, 500))
{
    // Send the zoom position inquiry to the camera with address 1.
    uint8_t packetData[16];
    uint32_t packetSize = 0;
    if (parser.encodeCommand(rapidpixel::ViscaPackets::INQUIRY_CAM_ZoomPosInq,
                             packetData, packetSize, 1) &&
        serialPort.write(packetData, packetSize) == static_cast<int>(packetSize))
    {
        // Read data from serial port.
        uint8_t buffer[1024];
        int numberOfBytes = serialPort.read(buffer, static_cast<uint32_t>(sizeof(buffer)));
        if (numberOfBytes <= 0)
        {
            std::cout << "No response" << std::endl;
        }
        else
        {
            // Decode data byte by byte.
            for (int i = 0; i < numberOfBytes; ++i)
            {
                uint32_t param1 = 0, param2 = 0, param3 = 0, param4 = 0, param5 = 0;
                uint32_t param6 = 0, param7 = 0, param8 = 0, param9 = 0, param10 = 0;
                switch (parser.decodeData(buffer[i], 1, param1, param2, param3, param4, param5,
                                          param6, param7, param8, param9, param10))
                {
                case rapidpixel::ViscaPackets::ACKNOWLEDGE:
                    std::cout << "ACKNOWLEDGE" << std::endl;
                    break;
                case rapidpixel::ViscaPackets::COMPLETION_COMMANDS:
                    std::cout << "COMPLETION_COMMANDS" << std::endl;
                    break;
                case rapidpixel::ViscaPackets::REPLY_CAM_ZoomPos:
                    std::cout << "ZOOM POSITION: " << param1 << std::endl;
                    break;
                default:
                    break;
                }
            }
        }
    }
}

Build and connect to your project

Build stand alone

The repository does not contain sub-repositories. The SerialPort library used by the test application must be cloned into the same folder as ViscaParser. The library itself has no dependencies. The folder structure must be:

<work folder>
    ViscaParser
    SerialPort

Typical commands to build the library and the test application (use the URLs of the repositories provided to you):

git clone <ViscaParser repository URL>
git clone <SerialPort repository URL>
cd ViscaParser
mkdir build
cd build
cmake ..
make

On Windows use cmake --build . --config Release instead of make. If ViscaParser is the top-level CMake project, the main CMakeLists.txt file adds the folder ../SerialPort before the test application. If the folder does not exist CMake stops with an error. To build the library only (without the test application and without the SerialPort library) disable the test application and the forced rewriting of the options:

cmake -D_SUBMODULE_CACHE_OVERWRITE=OFF -D_VISCA_PARSER_EXAMPLES=OFF ..

CMake options

Table 2 - CMake options of the repository. In the options below ${PARENT} is the prefix defined by the top-level project (empty if ViscaParser is the top-level project).

Option Default Description
${PARENT}_VISCA_PARSER ON Build the library.
${PARENT}_VISCA_PARSER_EXAMPLES ON (stand alone), OFF (included in other project) Build the test application.
${PARENT}_SUBMODULE_CACHE_OVERWRITE ON Forced rewriting of the options above in the CMake cache. The top-level project sets it to OFF when it includes ViscaParser as a sub-repository.
CMAKE_BUILD_TYPE Release (if not specified) Build type.

Connect to your project

If you want connect ViscaParser library to your CMake project as source code you can make follow. The library does not add other libraries to your project. The test application is excluded from compiling if ViscaParser is included in another project. If you enable the test application, your project must add the SerialPort library before ViscaParser. For example, if your repository has structure:

CMakeLists.txt
src
    CMakeList.txt
    yourLib.h
    yourLib.cpp

Create folder 3rdparty and copy folder of ViscaParser repository there. New structure of your repository:

CMakeLists.txt
src
    CMakeList.txt
    yourLib.h
    yourLib.cpp
3rdparty
    ViscaParser

Create CMakeLists.txt file in 3rdparty folder. CMakeLists.txt should contain:

cmake_minimum_required(VERSION 3.13)

################################################################################
## 3RD-PARTY
## dependencies for the project
################################################################################
project(3rdparty LANGUAGES CXX)

################################################################################
## SETTINGS
## basic 3rd-party settings before use
################################################################################
# To inherit the top-level architecture when the project is used as a submodule.
SET(PARENT ${PARENT}_YOUR_PROJECT_3RDPARTY)
# Disable self-overwriting of parameters inside included subdirectories.
SET(${PARENT}_SUBMODULE_CACHE_OVERWRITE OFF CACHE BOOL "" FORCE)

################################################################################
## CONFIGURATION
## 3rd-party submodules configuration
################################################################################
SET(${PARENT}_SUBMODULE_VISCA_PARSER                 ON  CACHE BOOL "" FORCE)
if (${PARENT}_SUBMODULE_VISCA_PARSER)
    SET(${PARENT}_VISCA_PARSER                       ON  CACHE BOOL "" FORCE)
    SET(${PARENT}_VISCA_PARSER_EXAMPLES              OFF CACHE BOOL "" FORCE)
endif()

################################################################################
## INCLUDING SUBDIRECTORIES
## Adding subdirectories according to the 3rd-party configuration
################################################################################
if (${PARENT}_SUBMODULE_VISCA_PARSER)
    add_subdirectory(ViscaParser)
endif()

File 3rdparty/CMakeLists.txt adds folder ViscaParser to your project and excludes the test application from compiling (by default the test application is excluded from compiling if ViscaParser is included as sub-repository). The new structure of your repository:

CMakeLists.txt
src
    CMakeList.txt
    yourLib.h
    yourLib.cpp
3rdparty
    CMakeLists.txt
    ViscaParser

Next you need include folder 3rdparty in main CMakeLists.txt file of your repository. Add string at the end of your main CMakeLists.txt:

add_subdirectory(3rdparty)

Next you have to include ViscaParser library in your src/CMakeLists.txt file:

target_link_libraries(${PROJECT_NAME} ViscaParser)

Done!

Test application

Folder ViscaParser/test contains the test application files. The test application allows you to generate some commands, send it to the camera over the serial port, receive and decode the response. Once started, the user must enter the full serial port name (for example /dev/ttyUSB0 for Linux or COM3 for Windows), baudrate and camera address.

================================================
VISCA protocol parser v3.0.8 test
================================================

Enter serial port name: 
Enter serial port baudrate (bps): 
Enter camera address [1:7], 1 - default: 
Serial port /dev/serial/by-id/usb-FTDI_TTL232R_Sony-if00-port0 open. Wait response timeout by default 500 msec

After user can choose command (enter command ID). Test application supports the following commands:

Type of command:
1 - Zoom tele.
2 - Zoom wide.
3 - Zoom stop.
4 - Focus far.
5 - Focus near.
6 - Focus stop.
7 - Inquiry zoom position.
8 - Inquiry focus position.
9 - Enable autofocus mode.
0 - Disable autofocus mode.
10 - Inquiry lens control system.
Command type: 

Portability

The library is written in standard C++17 and uses only the standard library. It contains no SIMD code, no inline assembly and no platform specific code. Packets are built and parsed byte by byte with shifts and masks: the code does not read or write multi-byte values through pointers, so the results do not depend on the byte order of the CPU. The library was built and tested with GCC 9, 11 and 12 on x86-64 and with GCC 11 on aarch64 (Linux): the encoded packets and the decoded messages are identical on all of them.


Table of contents