Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

type 'r' / Little Endian / Big Endian Byte ordering. #158

Open
Anuril opened this issue Dec 29, 2024 · 0 comments
Open

type 'r' / Little Endian / Big Endian Byte ordering. #158

Anuril opened this issue Dec 29, 2024 · 0 comments

Comments

@Anuril
Copy link

Anuril commented Dec 29, 2024

Let me begin by saying that I'm really only a beginner with Arduino / C++ and I'm not sure as to how to best solve this issue.

I'm building a small LED Controller to control some cheapo LED Strips. As a control Surface, I'm using either TouchOSC or Kiosc.
I've been running with Arduino 1.8.19 and OSC 1.3.5 for a while, but now I wanted to use the color wheel functionality recently added in Kiosc which uses the rgba data type in OSC so I started using the master branch.

While controlling each color separately (with float values) works like a charm, the Color wheel gave me issues, because the Arduino didn't didn't correctly create the colors - but instead, I get weird colors which didn't match what the App sent.
While debugging, I've noticed that the RGBA values are actually returned as ABGR by OSCMessage::getRgba .

EthernetUDP Udp;

// Network configuration
byte mac[] = { [...] };
byte ip[] = { 192, 168, 0, 12 };
byte gateway[] = { 192, 168, 0, 1 };
byte subnet[] = { 255, 255, 255, 0 };

// OSC configuration
const unsigned int inPort = 8888;

[...]

void setup() {
    Ethernet.begin(mac, ip, gateway, subnet);
    Udp.begin(inPort);
    Serial.begin(115200);
}
void routeLEDMsg(OSCMessage &msg, int &colorValue) {
    colorValue = static_cast<int>(msg.getFloat(0));
}
void routeRGBMsg(OSCMessage &msg) {
    auto oscd = msg.getRgba(0);
    rValue = oscd.r;
    gValue = oscd.g;
    bValue = oscd.b;
}
void loop() {
    OSCMessage msg;
    if (Udp.parsePacket() > 0) {
        while (Udp.available()) msg.fill(Udp.read());
        if (!msg.hasError()) {
            msg.route("/rgb/red", [](OSCMessage &msg, int) { routeLEDMsg(msg, rValue); });
            msg.route("/rgb/green", [](OSCMessage &msg, int) { routeLEDMsg(msg, gValue); });
            msg.route("/rgb/blue", [](OSCMessage &msg, int) { routeLEDMsg(msg, bValue); });
            msg.route("/rgb/rgb", routeRGBMsg);
            // More stuff, doesn't matter for this [...]
        }
    }
    analogWrite(ledrPin, rValue);
    analogWrite(ledgPin, gValue);
    analogWrite(ledbPin, bValue);
}

Digging deeper, I found out that up until this line oscrgba_t dataVal = BigEndian(u.rgba);, the values are correct in the incomingBuffer, before being reversed by the BigEndian Function.

I'm running this code on an Arduino Uno (Original) which is Little Endian, so it makes sense that BigEndian reverses the byte order.

BUT... That's not necessary here (at least I think...)

While my code adds each incoming UDP byte to the message here: while (Udp.available()) msg.fill(Udp.read());, the bytes of the UDP packet are added to the incoming buffer byte for byte as they come in in the correct order, irrespectively of the Network Byte Order.

So - IMHO - the BigEndian function should not need to be called if the data is filled byte by byte.

The issue is also not there if I'm sending (which I didn't try yet, but I think the code is not complete) an rgba value, although, there's another issue IMHO :

I've not yet verified this part, but to me it looks like if I'm sending an OSCMessage, it would look like this:

//the message wants an OSC address as first argument
  OSCMessage msg("/analog/0");
  oscrgba_t colorToSend = {255,128,0,255};
  msg.add(colorToSend );
  
  Udp.beginPacket(outIp, outPort);
  msg.send(Udp); // send the bytes to the SLIP stream
  Udp.endPacket(); // mark the end of the OSC Packet
  msg.empty(); // free space occupied by message

But what would really be sent out is questionable, as the 'r' type has not been specified. Instead, the else clause would trigger,

uint32_t i = BigEndian(datum->data.i);
uint8_t * ptr = (uint8_t *) &i;
p.write(ptr, datum->bytes);

And what that would basically make the four bytes {255,128,0,255} (FF8000FF)
grafik
into one uint32_t (9811727F or 10011000000100010111001001111111)
grafik
and reverse it to 7F721198 (01111111011100100001000110011000) to "make it big endian".
grafik

So even if the whole LittleEndian/BigEndian thing wouldn't be an issue, I think there needs to be code to handle the type 'r' for sending the data.

I'll update this tomorrow if I find out more. As a workaround for my project, I'm just reversing the order to a,b,g,r here. but that's ugly...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant