2

I have created a gui in python that allows an arduino controlled mecanum wheel cart to move around.

The cart allows for 8 different move directions and can rotate left and right. Commands are sent over a serial connection between the laptop(w10, python) and the arduino.

I have an Enum class in python representing the different move directions.

I have a corresponding enum in the arduino to interprete the commands from the python task.

What is an easy way to share a single common enum definition for both coding environments?

juerg
  • 479
  • 5
  • 16

3 Answers3

3

No. Enums in C/C++ and enum.Enum in python are two very different things. However, there is a powerful solution. I suggest writing the C/C++/Arduino header from your python code. With python's powerful introspection, it's easy to scan through your python enum/class with __dict__ and write a .h file that your Arduino code can use. This is how I generate Verilog and SystemVerilog headers that match the enums and constants in related python projects. Running the python applications produces a new header file, always in sync.

EDIT: A MORE EXPLICIT EXAMPLE

I've built an assembler for an FPGA-based microprocessor. The assembler is in python, while the processor is programmed in Verilog. So I create a Verilog header file like this:

# Compute the 'after' content.
content = '// opcodes.vh\n'
content += '`ifndef _opcodes_vh\n'
content += '`define _opcodes_vh\n'
content += '// DO NOT EDIT -- FILE GENERATED BY ASSEMBLER\n'
content += '// ------------------------------------\n'
content += '// OPCODES\n'
content += '// ------------------------------------\n'
A = Arch
for i in A.__dict__:
    if i.startswith('OPC_'):
        o = i.replace('OPC_', 'OPCODE_')
        s = '`define ' + o
        while len(s) < 40:
            s = s + ' '
        hexval = str(hex(A.__dict__[i])).replace('0x', '')
        decval = str(A.__dict__[i])
        s = s + "7'h" + hexval + '\t\t// ' + str(decval) + '\n'
        content += s
content += '// END OF GENERATED FILE.\n'
content += '`endif'

# Write to very specific location for Vivado to see it.
file = open(self.opcodes_filename, 'w', encoding='utf-8')
file.write(content)
file.close()

The final output looks like this:

// opcodes.vh
`ifndef _opcodes_vh
`define _opcodes_vh
// DO NOT EDIT -- FILE GENERATED BY ASSEMBLER
// ------------------------------------
// OPCODES
// ------------------------------------
`define OPCODE_LD_GPR_EXPR              7'h0        // 0
`define OPCODE_LD_GPR_GPTR              7'h1        // 1
`define OPCODE_SV_EXPR_GPR              7'h2        // 2
...
`define OPCODE_IO_T                     7'h4a       // 74
`define OPCODE_TX_T                     7'h4b       // 75
// END OF GENERATED FILE.
`endif
TomServo
  • 7,248
  • 5
  • 30
  • 47
1

As @TomServo said, have your Python code write the Arduino header. Here's an example using either aenum 3.01 or Python 3.10 2:

from aenum import Enum   # or "from enum import Enum"

class CHeader(Enum):
    def __init_subclass__(cls, **kwds):
        # write Enums to C header file
        cls_name = cls.__name__
        header_path = getattr(cls, '_%s__header' % cls_name)
        with open(header_path, 'w') as fh:
            fh.write('initial header stuff here\n')
            for enum in cls:
                fh.write('#define %s %r\n' % (enum.name, enum.value))

class Arduino(CHeader):
    #
    _order_ = 'ONE TWO'  # only if using Python 2
    #
    __header = './arduino.h'
    #
    ONE = 1
    TWO = 2

Which would result in:

initial header stuff here
#define ONE 1
#define TWO 2

1 Disclosure: I am the author of the Python stdlib Enum, the enum34 backport, and the Advanced Enumeration (aenum) library.

2 In aenum 3.0 and Python 3.10 __init_subclass__ will be called after the enum members are added to the Enum class (in prior versions __init_subclass__ is called before the members are added).

Ethan Furman
  • 63,992
  • 20
  • 159
  • 237
  • One could also read the arduino file in Python to [generate the Python Enum](https://stackoverflow.com/a/66037988/208880). – Ethan Furman Sep 24 '21 at 05:41
  • Is it possible first write a definition file for the enum, and run a script to generated all the enum definition for both C, C++ and Python. I have coded C in micro processor, C++ in the GUI and Python GUI running on PC. But I would like to share the enum const value for all those 3 kinds of languages. Thanks. – ollydbg23 Jul 26 '22 at 01:58
  • https://arduino.stackexchange.com/a/79700/86014 Something like this answer, but need tweaks, I'm not sure such tool exists. Thanks. – ollydbg23 Jul 26 '22 at 02:21
1

Optional solution is to have the enum in *.py file, which C file can include and python can import.

The file will look like:

#if 0
"""
#endif
typedef enum my_enum{
#if 0
"""
from enum import IntEnum, unique
@unique
class MyEnum(IntEnum):
#endif
    FIRST = 0,
    SECOND = 1,
    THIRD = 2,
#if 0
"""
#endif
}my_enum_e;

#if 0
"""
#endif

The idea behind it is that Python ignores all the C preprocessor commands, as they are in Python triple-quoted strings, which is where I put the C only code.

In the other hand, C ignores everything inside #if 0 - where I put the python code.

The disadvantage in this structure is it bit confusing and I didn't find way to make the numbering automatic.

arye
  • 458
  • 3
  • 15
  • Great! as you mention a bit ugly to look at but once understood a nice way to avoid maintaining the code in 2 environments – juerg Mar 02 '23 at 08:19
  • If you liked this answer, maybe you will also like https://stackoverflow.com/a/75570512/8913338 which based on similar ideas – arye Mar 02 '23 at 10:50