arduino / ArduinoCore-mbed

346 stars 199 forks source link

Arduino MBED "opcode" needed to send data over websockets #599

Closed hpssjellis closed 1 year ago

hpssjellis commented 1 year ago

@facchinm

I got fully connected to an external websocket server using the PortentaH7 and WiFiSSLClient in this issue here https://github.com/arduino/ArduinoCore-mbed/issues/589

The Arduino client can connect and receive data, but sending data over websockets is a bit more complex as the first several bytes determine the type and length of data to send. In a web browser this is all done for you, just send a message as text or blob (binary) but on the Arduino the byte stream needs to be formatted properly.

The first byte would look like

typedef enum {
    WS_CONTINUATION_FRAME = 0,
    WS_TEXT_FRAME = 1,
    WS_BINARY_FRAME = 2,
    WS_CONNECTION_CLOSE_FRAME = 8,
    WS_PING_FRAME = 9,
    WS_PONG_FRAME = 10
} WS_OPCODE;

The above code from this repo here

and then the next bytes are for setting larger sending amounts all based on the total size of the first byte, and then 4 bytes for a mask that gets added to the data bytes. Probably easiest to mask with 0,0,0,0, then follows is the stream of data with I think no end byte.

Just wondering if Arduino or MBED has made this easier to do or does the user have to do all the framing of data?

What I find interesting is the MBED code does mention something about optname here but the code doesn't seem to run from the arduino

nsapi_error_t TLSSocketWrapper::setsockopt(int level, int optname, const void *optval, unsigned optlen)

nsapi_error_t TLSSocketWrapper::getsockopt(int level, int optname, void *optval, unsigned *optlen)

I will try over the winter break to write the framing code for a binary or base64 320x320 PNG and short text messages, but if Arduino or MBED already has the framing done I would like to hear about it.

I can include a pre-setup codesandbox websocket server testing site and Arduino code to connect if anyone is interested.

hpssjellis commented 1 year ago

I might have kind of solved this. See the following explanation and tests that I got working, taken from this site here



/*
     * For example, to send "Hello" to server in binary mode, you do:

    flag: 0x82, "Final packet in frame" and "Binary mode"
    mask bit: 1
   len: 6
   mask: 0x11, 0x22, 0x33, 0x44
   payload: "Hello",
   0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x00
   The masked payload is: 0x48^0x11, 0x65^0x22, 0x6C^0x33, 0x6C^0x44, 0x6F^0x11, 0x00^0x22 => 0x59, 0x47, 0x5F, 0x28, 0x7E, 0x22

   The whole stream is: 0x82, 0x86, 0x11, 0x22, 0x33, 0x44, 0x59, 0x47, 0x5F, 0x28, 0x7E, 0x22
     */

    //   FORMAT:          codes -----------MASK ---------------------DATA-----------------------
    //const char msg[] = {0x82, 0x86,      0x11, 0x22, 0x33, 0x44,   0x59, 0x47, 0x5F, 0x28, 0x7E, 0x22};  // that works!

    // but why the end BYTE on the original. Try without it. but now the length needs to be 5 so 86 to 85

    // Also lets send text not binary so 82 to 81
    // const char msg[] = {0x81, 0x85,    0x11, 0x22, 0x33, 0x44,   0x59, 0x47, 0x5F, 0x28, 0x7E};  // wow that works!

    // const char msg[] = {0x81, 0x05,                              0x48, 0x65, 0x6C, 0x6C, 0x6F};  // This died so a mask is always needed!
    // const char msg[] = {0x81, 0x85,    0x00, 0x00, 0x00, 0x00,   0x48, 0x65, 0x6C, 0x6C, 0x6F};  // Nope, needs a real mask
    // const char msg[] = {0x81, 0x85,    0x01, 0x01, 0x01, 0x01,   0x49, 0x64, 0x6D, 0x6D, 0x6E};  // Easiest mask, strange results, why were some subtracted?
    // const char msg[] = {0x81, 0x85,    0x01, 0x10, 0x02, 0x11,   0x49, 0x75, 0x6E, 0x7D, 0x6E};  // try worked
    // const char msg[] = {0x81, 0x85,    0x01, 0x02, 0x01, 0x02,   0x49, 0x67, 0x6D, 0x6E, 0x6E};  // This might be best, should make it random  
    const char msg[] =    {0x81, 0x85,    0x01, 0x02, 0x03, 0x04,   0x49, 0x67, 0x6F, 0x68, 0x6E};  // Probably best to program this 
    client.write((const uint8_t*)msg, strlen(msg));  

``
hpssjellis commented 1 year ago

I can probably hack my way through this. I am getting send working for under 125 characters and working on sending binary. My final code will be here or on my library

https://github.com/hpssjellis/codesandbox-websocket/blob/main/portenta-socket.ino