Use V5 Smart Port as Generic Serial Device [PROS]


Max theoretical baud tate is 921600, however, as baud rates are not derived from a standard oscillator (typically something like 18.432MHz would be used for standard rates) there will be an error between actual baud rate and the requested baud rate, in the case of 921600, perhaps 3%. So your millage will vary depending on how accurate the device you are communicating with is. At lower baud rates the error drops to become largely insignificant.


Ok, thanks for the information.


I’m trying the code right now, and am getting an undefined reference error. Is this the correct function prototype

int vexGenericSerialReceive(int port, char* buffer, int len);

int32_t vexGenericSerialReceive( uint32_t index, uint8_t *buffer, int32_t length );

and define as extern “C”


It’s working!
Thank you @hotel and @jpearman for your help.
For anyone interested, here’s my working code:

#include "main.h"

// Include sstream for serial parsing
#include <sstream>

// Prototypes for hidden vex functions to bypass PROS bug
extern "C" int32_t vexGenericSerialReceive( uint32_t index, uint8_t *buffer, int32_t length );
extern "C" void vexGenericSerialEnable(  uint32_t index, uint32_t nu );
extern "C" void vexGenericSerialBaudrate(  uint32_t index, uint32_t rate );

// Port to use for serial data
#define SERIALPORT 21
// Variable to put the gyro value into
double gyroValue = 0;

// Currently reads serial data & parses for gyro value
// Can be expanded to look for lidar distance, etc.
void serialRead(void* params) {
    // Start serial on desired port
    vexGenericSerialEnable( SERIALPORT - 1, 0 );
    // Set BAUD rate
    vexGenericSerialBaudrate( SERIALPORT - 1, 115200 );
    // Let VEX OS configure port
    // Serial message format:
    // Example Message:
    // D50.2I128A12.32E
    while (true) {
        // Buffer to store serial data
        uint8_t buffer[256];
        int len = 256;
        // Get serial data
        int32_t nRead = vexGenericSerialReceive(SERIALPORT - 1, buffer, len);
        // Now parse the data
        if (nRead >= 9) {
            // Stream to put the characters in
            std::stringstream myStream("");
            bool recordAngle = false;
            // Go through characters
            for (int i = 0; i < nRead; i++) {
                // Get current char
                char thisDigit = (char)buffer[i];
                // If its special, then don't record the value
                if (thisDigit == 'D' || thisDigit == 'I' || thisDigit == 'A')
                    recordAngle = false;
                // Finished recieving angle, so put into variable
                if (thisDigit == 'E') {
                    recordAngle = false;
                    myStream >> gyroValue;
                // If we want the digits, put them into stream
                if (recordAngle)
                    myStream << (char)buffer[i];
                // If the digit is 'A', then the following data is the angle
                if (thisDigit == 'A')
                    recordAngle = true;
        // Delay to let serial data arrive

void opcontrol() {
    // Start serial task
    pros::Task gyroTask (serialRead);
    while (true) {
        // Print value to screen
        pros::lcd::print(4,"%f", gyroValue);


Just for completeness, this is roughly how it works:
The brain keeps a per-port set of memory buffers that the hardware (FPGA fabric used to implement the serial ports) can directly access. When a motor sends an update (which it does on its own every 5ms), the whole 16B message gets stored into one of those buffers. When you issue get_position, the function implementation directly interprets the bytes of the message in the buffer as 32bit encoder ticks, then converts the value to the unit you specify based on the configured gear ratio and so on.
When you issue a command to the motor, it gets stored as a message in an outgoing buffer, where it waits for the next brain transaction. At that point, it gets automatically sent as a reply to the motor status message (if there is no command waiting, yet another, default reply is sent to the motor).