Problems compiling a function for arduino R4 minima, Type conversion error

Hi! I'm working on a serial library for a robotics project. We wrote the code and tested it in an Arduino uno for simplicity and we are now moving all the code to the final project that is run and compiled for an Arduino R4 minima. The code was tested and worked fine in the Arduino uno.
here is the code that's giving us problems:

enum Order : uint8_t {
    UNKNOWN = 0,
    HELLO = 1,
    VAR1 = 2,
    VAR2 = 3,
    ALREADY_CONNECTED = 4,
    ERROR = 5,
    RECEIVED = 6,
    STOP = 7
  };
template<typename T>  //specialize uint8 for speed
T SerialProtocolManager::Read() {
  constexpr size_t SIZE = sizeof(T) / sizeof(uint8_t);
  int8_t buffer[SIZE];
  WaitForBytes(SIZE, 200);
  ReadSignedBytes(buffer, SIZE);
  T result = NULL;
  T mask = 0xff;
  for (size_t i = 0; i < SIZE; ++i) {
    result |= ((T)buffer[i]) << 8 * i & mask;
    mask <<= 8;
  }
  return result;
}

And here are the errors:

In file included from C:\Users\Anna\Desktop\Arnau\Projects\ODrive\sketch_jun23a\SerialProtocolManager.cpp:2:0:
C:\Users\Anna\Desktop\Arnau\Projects\ODrive\sketch_jun23a\SerialProtocolManager.h: In instantiation of 'T SerialProtocolManager::Read() [with T = SerialProtocolManager::Order]':
C:\Users\Anna\Desktop\Arnau\Projects\ODrive\sketch_jun23a\SerialProtocolManager.cpp:7:38:   required from here
C:\Users\Anna\Desktop\Arnau\Projects\ODrive\sketch_jun23a\SerialProtocolManager.h:53:5: error: invalid conversion from 'int' to 'SerialProtocolManager::Order' [-fpermissive]
   T result = NULL;
     ^~~~~~
C:\Users\Anna\Desktop\Arnau\Projects\ODrive\sketch_jun23a\SerialProtocolManager.h:54:5: error: invalid conversion from 'int' to 'SerialProtocolManager::Order' [-fpermissive]
   T mask = 0xff;
     ^~~~
C:\Users\Anna\Desktop\Arnau\Projects\ODrive\sketch_jun23a\SerialProtocolManager.h:56:12: error: invalid conversion from 'int' to 'SerialProtocolManager::Order' [-fpermissive]
     result |= ((T)buffer[i]) << 8 * i & mask;
     ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
C:\Users\Anna\Desktop\Arnau\Projects\ODrive\sketch_jun23a\SerialProtocolManager.h:57:10: error: invalid conversion from 'int' to 'SerialProtocolManager::Order' [-fpermissive]
     mask <<= 8;
     ~~~~~^~~~~

exit status 1

Compilation error: invalid conversion from 'int' to 'SerialProtocolManager::Order' [-fpermissive]

We've read that the processor of the arduino uno and R4 don't share the same architecture, so we expect differences, but i'ts been quite hard to find exactly what is different, and why we are now having issues converting from Int to uint8_t (Order enum)

Thanks a lot in advance for all your help <3

Welcome to the forum

Please post the full sketch so that the problem can be seen in context and to allow others to compile it

Sure thing, its several files:
SerialProtocolManager.h

// If DEBUG is set to true, the arduino will send back all the received messages
#define DEBUG false
#define SERIAL_BUFFER_SIZE 64  // OLED display height, in pixels

#include <Arduino.h>

class SerialProtocolManager {
public:

  void GetMessagesFromSerial(float& var1, float& var2);
  void ReadSignedBytes(int8_t* buffer, size_t n);
  void WaitForBytes(uint8_t num_bytes, unsigned long timeout);

  template<typename T = uint8_t>
  void Write(T val);
  template<typename T>
  T Read();



  // Define the orders that can be sent and received
  enum Order : uint8_t {
    UNKNOWN = 0,
    HELLO = 1,
    VAR1 = 2,
    VAR2 = 3,
    ALREADY_CONNECTED = 4,
    ERROR = 5,
    RECEIVED = 6,
    STOP = 7
  };

  bool is_connected = false;  ///< True if the connection with the master is available
  //Order Order;
};

template<typename T = uint8_t>
void SerialProtocolManager::Write(T val) {
  constexpr size_t SIZE = sizeof(T) / sizeof(uint8_t);
  int8_t buffer[SIZE];
  for (size_t i = 0; i < SIZE; ++i) {
    buffer[i] = (int8_t)(val >> 8 * i & 0xff);
  }
  Serial.write((uint8_t*)&buffer, SIZE);
}


template<typename T>  //specialize uint8 for speed
T SerialProtocolManager::Read() {
  constexpr size_t SIZE = sizeof(T) / sizeof(uint8_t);
  int8_t buffer[SIZE];
  WaitForBytes(SIZE, 200);
  ReadSignedBytes(buffer, SIZE);
  T result = NULL;
  T mask = 0xff;
  for (size_t i = 0; i < SIZE; ++i) {
    result |= ((T)buffer[i]) << 8 * i & mask;
    mask <<= uint8_t(8);
  }
  return result;
}

and SerialProtocolManager.cpp

#pragma once
#include "SerialProtocolManager.h"

void SerialProtocolManager::GetMessagesFromSerial(float& var1,float& var2) {

  // The first byte received is the instruction
  Order order_received = Read<Order>();

  if (order_received == HELLO) {
    // If the cards haven't say hello, check the connection
    if (!is_connected) {
      is_connected = true;
      Write(HELLO);
    } else {
      // If we are already connected do not send "hello" to avoid infinite loop
      Write(ALREADY_CONNECTED);
    }
  } else if (order_received == ALREADY_CONNECTED) {
    is_connected = true;
  } else {
    switch (order_received) {
      case STOP:
        {
          if (DEBUG) {
            Write(STOP);
          }
          break;
        }
      case VAR1:
        {
          var1 = float(Read<int32_t>())/1000.0f;
          if (DEBUG) {
            Write(VAR1);
            Write<int32_t>(var1*1000);
          }
          break;
        }
      case VAR2:
        {
          var2 = float(Read<int32_t>())/1000.0f;
          if (DEBUG) {
            Write(VAR2);
            Write<int32_t>(var2*1000);
          }
          break;
        }
      // Unknown order
      default:
        Write(ERROR);
        Write<int16_t>(404);
        return;
    }
  }
  Write(RECEIVED);  // Confirm the reception
}


void SerialProtocolManager::ReadSignedBytes(int8_t* buffer, size_t n) {
  size_t i = 0;
  int c;
  while (i < n) {
    c = Serial.read();
    if (c < 0) break;
    *buffer++ = (int8_t)c;  // buffer[i] = (int8_t)c;
    i++;
  }
}

void SerialProtocolManager::WaitForBytes(uint8_t num_bytes, unsigned long timeout) {
  unsigned long startTime = millis();
  //Wait for incoming bytes or exit if timeout
  while ((Serial.available() < num_bytes) && (millis() - startTime < timeout)) {}
}

There is no ino file since the library is still unused because it does not compile.

Lastly, I just saw this that I think could be the problem
image
I'm defining the enum as a uint8_t but the tooltip says its compiling as an int type, why should this be? in the uno compiled code it shows as uint8 in both the tooltip and code.

If you set compiler warnings to all in file/preferences and compile for the Uno, you get the below warnings.

/home/wim/Downloads/1_arduino_ide_1.x/arduino-1.8.19-UnoR4/portable/sketchbook/1276871/SerialProtocolManager.cpp:1:9: warning: #pragma once in main file
 #pragma once
         ^~~~
In file included from /home/wim/Downloads/1_arduino_ide_1.x/arduino-1.8.19-UnoR4/portable/sketchbook/1276871/SerialProtocolManager.cpp:2:0:
/home/wim/Downloads/1_arduino_ide_1.x/arduino-1.8.19-UnoR4/portable/sketchbook/1276871/SerialProtocolManager.h: In instantiation of 'T SerialProtocolManager::Read() [with T = SerialProtocolManager::Order]':
/home/wim/Downloads/1_arduino_ide_1.x/arduino-1.8.19-UnoR4/portable/sketchbook/1276871/SerialProtocolManager.cpp:7:38:   required from here
/home/wim/Downloads/1_arduino_ide_1.x/arduino-1.8.19-UnoR4/portable/sketchbook/1276871/SerialProtocolManager.h:54:5: warning: invalid conversion from 'int' to 'SerialProtocolManager::Order' [-fpermissive]
   T result = NULL;
     ^~~~~~
/home/wim/Downloads/1_arduino_ide_1.x/arduino-1.8.19-UnoR4/portable/sketchbook/1276871/SerialProtocolManager.h:55:5: warning: invalid conversion from 'int' to 'SerialProtocolManager::Order' [-fpermissive]
   T mask = 0xff;
     ^~~~
/home/wim/Downloads/1_arduino_ide_1.x/arduino-1.8.19-UnoR4/portable/sketchbook/1276871/SerialProtocolManager.h:57:12: warning: invalid conversion from 'int' to 'SerialProtocolManager::Order' [-fpermissive]
     result |= ((T)buffer[i]) << 8 * i & mask;
     ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/wim/Downloads/1_arduino_ide_1.x/arduino-1.8.19-UnoR4/portable/sketchbook/1276871/SerialProtocolManager.h:58:10: warning: invalid conversion from 'int' to 'SerialProtocolManager::Order' [-fpermissive]
     mask <<= uint8_t(8);
     ~~~~~^~~~~~~~~~~~~~
/home/wim/Downloads/1_arduino_ide_1.x/arduino-1.8.19-UnoR4/portable/sketchbook/1276871/SerialProtocolManager.h: In instantiation of 'T SerialProtocolManager::Read() [with T = long int]':
/home/wim/Downloads/1_arduino_ide_1.x/arduino-1.8.19-UnoR4/portable/sketchbook/1276871/SerialProtocolManager.cpp:31:38:   required from here
/home/wim/Downloads/1_arduino_ide_1.x/arduino-1.8.19-UnoR4/portable/sketchbook/1276871/SerialProtocolManager.h:54:5: warning: converting to non-pointer type 'long int' from NULL [-Wconversion-null]
   T result = NULL;
     ^~~~~~

When you compile the same code for the Uno R4 Minima, those warnings are treated as errors due to compiler configuration.

This is not so much about the different architecture but about the compiler settings. You should have fixed the warning while compiling for the Uno :smiley:

I do not know enough about this stuff to be able to advise further.

1 Like

You should be casting the uint8_t or int values to Order. uint8_t tells the compiler that the enum Order is to be stored as an unsigned 8-bit integer, but the type of the enum itself is Order.

Also, does not appear that the compiler likes |= or <<=, need to do the operation on the right of the = then cast the result to Order to store back in the original variable.

I have no idea what the code does when given an Order of 0xff, since there is no corresponding value in the enum.

Thanks a lot, didn't know about that! I guess that's right since we treat data types as just containers with the right byte size. We'll have to comply with the compiler now hahaha

Thanks for your reply, but casting the uint8 to Order would defeat the whole purpose of the type of the function since it's a generic template and we don't know what the incoming type is, just its size.

Can you cast to T instead of Order?