We made a few tweaks to the protocol today, in an effort to make things easier to implement on the client side, with fewer special cases. In addition, we created a client.h file in lib/universal_controller/client.h, which provides various #defines to simplify implementing the client side code.
The new protocol is as follows:
Sending button / stick events (from controller to client): Bit order: [TAAVVVVV] (analog stick event) [TN0SBBBB] (button event) Bit 8 (T, MSB): 0 == analog stick message, 1 == digital button message Analog stick message: Bit 7 (A) : 0 == Left stick, 1 == Right Stick Bit 6 (A) : 0 == X axis, 1 == Y axis Bit 5::1(V): Analog stick value: For the Y axis, 0x00 is all the way forward and 0x1F is all the way back; for the X axis, 0x00 is all the way left and 0x1F is all the way right. Digital button message: Bit 7 (N) : 0 == Normal button press / release event, 1 == No Buttons Pressed event. When bit 7 is 1, the remainder of the message is ignored. By convention we fill buts 6::1 with zeros in this state, meaning that the 'No button pressed' message will always be 0xC0. Bit 6 : Unused, set to 0 Bit 5 (S) : 0 = Released, 1 = Pressed Bit 4::1(B): Button number. Use lib/universal_controller/client.h for defines. Receiving client commands (from client to controller): Bit order: [CCXXXXXX] C: Command (see below) X: Command-specific message, left padded with zeros Commands: 00: Enable / Disable Buttons [000AAAAX] A: Button address. Specify a button to modify (0x00 - 0x0F). X: New value. 1 = enabled, 0 = disabled 01: Enable / Disable Analog Sticks [0100000X] X: New value. 1 = enabled, 0 = disabled 10: Set poll frequency (non-changes will be re-sent after this time) [10XXXXXX] X: New poll value, to be shifted 8 bits left and set in OCR1A. For instance, to set OCR1A = 0x0F00 (the default value), you would send the value 001111 (0x0F) as shifting this 8 bits gives 0x0F00. 0x0F (expanded to 0x0F00) results in an idle poll time of about 500ms. 0x3F (expanded to 0x3F00) results in an idle poll time of about 2s. 0x01 (expanded to 0x0100) results in an idle poll time of about 10ms. 0x00 results in completely disabling idle polling (only send change events). 11: Set maximum analog repeat frequency (you can't send analog stick changes faster than this). [11XXXXXX] X: New poll value, to be shifted 2 bits left and set in OCR0A. Analog values cannot be sent until this compare ISR fires. Set this high enough to not be sending un-needed data constantly, but low enough that you can get good response times from the controller. 0x3F (expanded to 0xFC) is the maximum, and results in an analog repeat time of about 32ms. 0x10 (expanded to 0x40) is the default, and results in an analog repeat time of about 8ms. 0x00 results in completely disabling the timer and sends all analog events, no matter how fast.
The client.h file includes the following defines:
//Bit 8: 0 == analog stick message, 1 == digital button message #define CONTROLLER_MESSAGE_TYPE_MASK 0x80 #define CONTROLLER_MESSAGE_TYPE_ANALOG 0x00 #define CONTROLLER_MESSAGE_TYPE_BUTTON 0x80 //Bit 7 (Analog): Left / Right stick #define CONTROLLER_ANALOG_STICK 0x40 #define CONTROLLER_ANALOG_STICK_LEFT 0x00 #define CONTROLLER_ANALOG_STICK_RIGHT 0x40 //Bit 6 (Analog): X / Y axis #define CONTROLLER_ANALOG_AXIS 0x20 #define CONTROLLER_ANALOG_AXIS_X 0x00 #define CONTROLLER_ANALOG_AXIS_Y 0x20 //Bit 5::1 (Analog): Value #define CONTROLLER_ANALOG_VALUE_MASK 0x1F //No Buttons Pressed message #define CONTROLLER_BUTTON_NONE 0xC0 //Bit 5 (Button): Press / Release #define CONTROLLER_BUTTON_PRESS_MASK 0x10 #define CONTROLLER_BUTTON_RELEASE 0x00 #define CONTROLLER_BUTTON_PRESS 0x10 //Bit 4::1 (Button): Button address #define CONTROLLER_BUTTON_VALUE_MASK 0x0F #define CONTROLLER_BUTTON_VALUE_SELECT 0x00 #define CONTROLLER_BUTTON_VALUE_LEFT3 0x01 #define CONTROLLER_BUTTON_VALUE_RIGHT3 0x02 #define CONTROLLER_BUTTON_VALUE_START 0x03 #define CONTROLLER_BUTTON_VALUE_PADUP 0x04 #define CONTROLLER_BUTTON_VALUE_PADRIGHT 0x05 #define CONTROLLER_BUTTON_VALUE_PADDOWN 0x06 #define CONTROLLER_BUTTON_VALUE_PADLEFT 0x07 #define CONTROLLER_BUTTON_VALUE_LEFT2 0x08 #define CONTROLLER_BUTTON_VALUE_RIGHT2 0x09 #define CONTROLLER_BUTTON_VALUE_LEFT1 0x0A #define CONTROLLER_BUTTON_VALUE_RIGHT1 0x0B #define CONTROLLER_BUTTON_VALUE_TRIANGLE 0x0C #define CONTROLLER_BUTTON_VALUE_CIRCLE 0x0D #define CONTROLLER_BUTTON_VALUE_CROSS 0x0E #define CONTROLLER_BUTTON_VALUE_SQUARE 0x0F
This simplifies (at least makes more clear) implementing code. For instance, this is a slightly simplified version of what is currently in use for Stubby, to read the left stick and the X button (assume 'b' is a uint8_t, and is the incoming message over the serial port):
if ((b & CONTROLLER_MESSAGE_TYPE_MASK) == CONTROLLER_MESSAGE_TYPE_ANALOG){ if ((b & CONTROLLER_ANALOG_STICK) == CONTROLLER_ANALOG_STICK_LEFT){ uint8_t value = b & CONTROLLER_ANALOG_VALUE_MASK; if ((b & CONTROLLER_ANALOG_AXIS) == CONTROLLER_ANALOG_AXIS_X){ x_value = value; } else if ((b & CONTROLLER_ANALOG_AXIS) == CONTROLLER_ANALOG_AXIS_Y){ y_value = value; } } } else if ((b & CONTROLLER_MESSAGE_TYPE_MASK) == CONTROLLER_MESSAGE_TYPE_BUTTON){ if ((b & CONTROLLER_BUTTON_PRESS_MASK) == CONTROLLER_BUTTON_PRESS){ cross_button_pressed = 0x01; } }
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.