|
2 | 2 | import json |
3 | 3 | import math |
4 | 4 | import coloredlogs, logging |
| 5 | +from os import linesep |
5 | 6 | from quine_mccluskey import qm |
6 | 7 | from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter, BooleanOptionalAction |
7 | 8 |
|
|
38 | 39 | help='dump wokwi connections list only', |
39 | 40 | default=0) |
40 | 41 |
|
| 42 | + parser.add_argument('-t', '--test', |
| 43 | + action=BooleanOptionalAction, |
| 44 | + help='add an Arduino MEGA as test framework and generate Arduino verification code', |
| 45 | + default=0) |
| 46 | + |
41 | 47 | args = parser.parse_args() |
42 | 48 |
|
43 | 49 | # Create and configure logger object |
|
97 | 103 | "attrs": {} |
98 | 104 | } |
99 | 105 |
|
| 106 | + wokwi_arduino_mega = { |
| 107 | + "type": "wokwi-arduino-mega", |
| 108 | + "id": "mega", |
| 109 | + "top": -400, |
| 110 | + "left": -500, |
| 111 | + "rotate": 90, |
| 112 | + "attrs": {} |
| 113 | + } |
| 114 | + |
100 | 115 | # ------------------------------------------------------------------------------ |
101 | 116 | # user specific output style and laoyut definition |
102 | 117 |
|
|
122 | 137 | con_color_or_or_interconnect = "green" |
123 | 138 | con_color_or_output = "cyan" |
124 | 139 | con_color_termination = "black" |
| 140 | + con_color_arduino_interconnect = "black" |
| 141 | + |
| 142 | + arduino_sketch_template_file = "sketch.ino.template" |
125 | 143 |
|
126 | 144 | global global_and_gate_idx |
127 | 145 | global_and_gate_idx = -1 |
@@ -237,6 +255,18 @@ def allocate_next_free_or_gate_inport(): |
237 | 255 |
|
238 | 256 | return retval |
239 | 257 |
|
| 258 | + def get_expected_bin_out_vals(output_names, output_data, num_inputs): |
| 259 | + # create binary based expectation values for Arduino verification code |
| 260 | + # see also: https://www.arduino.cc/reference/en/language/variables/constants/integerconstants/ |
| 261 | + expected_bin_val = "" |
| 262 | + for k in range(2**num_inputs): |
| 263 | + expected_bin_val += linesep + " 0b" |
| 264 | + for output in output_names: |
| 265 | + expected_bin_val += str(output_data[output][k]) |
| 266 | + expected_bin_val += "," |
| 267 | + |
| 268 | + return expected_bin_val |
| 269 | + |
240 | 270 |
|
241 | 271 | log.info(f"Log level: {log_level}") |
242 | 272 |
|
@@ -277,6 +307,7 @@ def allocate_next_free_or_gate_inport(): |
277 | 307 | log.info(f"Outputs: {num_outputs:2} {output_names}") |
278 | 308 |
|
279 | 309 | for output in output_names: |
| 310 | + # make sure that we have 2^num_inputs output values! |
280 | 311 | assert len(in_data["outputs"][output]) == 2**num_inputs |
281 | 312 | ones = [i for i in range(2**num_inputs) if in_data["outputs"][output][i] == 1] |
282 | 313 | log.info(f" Output {output}: {in_data['outputs'][output]}; ones: {ones}") |
@@ -708,6 +739,64 @@ def allocate_next_free_or_gate_inport(): |
708 | 739 |
|
709 | 740 | log.info(f"Finished the wokwi design!") |
710 | 741 |
|
| 742 | + |
| 743 | + if args.test: |
| 744 | + log.info("Generating verification code and test framework") |
| 745 | + arduino_sketch_template = None |
| 746 | + with open(arduino_sketch_template_file, 'r') as f: |
| 747 | + arduino_sketch = f.read() |
| 748 | + if arduino_sketch: |
| 749 | + # generate the code, then add parts and connections to the wokwi schematic |
| 750 | + |
| 751 | + # replace the placeholders with actual values |
| 752 | + arduino_sketch = arduino_sketch.replace("{DESIGN_NUM_USED_INPUTS_PH}", f"{num_inputs}u") |
| 753 | + arduino_sketch = arduino_sketch.replace("{DESIGN_NUM_USED_OUTPUTS_PH}", f"{num_outputs}u") |
| 754 | + expected_bin_out_vals = get_expected_bin_out_vals(output_names, in_data["outputs"], num_inputs) |
| 755 | + arduino_sketch = arduino_sketch.replace("{VERIFICATION_EXPECTED_OUT_VALS_PH}", expected_bin_out_vals) |
| 756 | + |
| 757 | + # TODO: allow to use non-constant values for placeholders by controlling the from the |
| 758 | + # Python generator (e.g. by adding command line arguments) |
| 759 | + arduino_sketch = arduino_sketch.replace("{VERIFICATION_STOP_ON_ERROR}", "true") |
| 760 | + arduino_sketch = arduino_sketch.replace("{SERIAL_BAUDRATE_PH}", "230400u") |
| 761 | + arduino_sketch = arduino_sketch.replace("{VERIFICATION_SETUP_TIME_MS_PH}", "50u") |
| 762 | + arduino_sketch = arduino_sketch.replace("{VERIFICATION_HOLD_TIME_MS_PH}", "350u") |
| 763 | + |
| 764 | + # save the generated Arduino sketch |
| 765 | + with open("sketch.ino", 'w') as f: |
| 766 | + f.write(arduino_sketch) |
| 767 | + |
| 768 | + # add the Arduino MEGA to the wokwi schematic's parts list |
| 769 | + wokwi_design["parts"].append(wokwi_arduino_mega) |
| 770 | + |
| 771 | + # add the serial monitor to the wokwi schematic |
| 772 | + wokwi_design["serialMonitor"] = { |
| 773 | + "display": "always", |
| 774 | + "newline": "lf" |
| 775 | + } |
| 776 | + |
| 777 | + # connect design inputs to Arduino outputs |
| 778 | + arduino_mega_outputs = range(2, 11+1) |
| 779 | + out_idx = 0 |
| 780 | + for input in input_names: |
| 781 | + con = [ f"mega:{arduino_mega_outputs[out_idx]}", f"input_{input}:IN", |
| 782 | + con_color_arduino_interconnect, default_con_instr ] |
| 783 | + log.debug(" Connection: "+str(con)) |
| 784 | + wokwi_design["connections"].append(con) |
| 785 | + out_idx += 1 |
| 786 | + |
| 787 | + # connect design outputs to Arduino outputs |
| 788 | + arduino_mega_inputs = range(12, 21+1) |
| 789 | + in_idx = 0 |
| 790 | + for output in output_names: |
| 791 | + con = [ f"mega:{arduino_mega_inputs[in_idx]}", f"output_{output}:OUT", |
| 792 | + con_color_arduino_interconnect, default_con_instr ] |
| 793 | + log.debug(" Connection: "+str(con)) |
| 794 | + wokwi_design["connections"].append(con) |
| 795 | + in_idx += 1 |
| 796 | + |
| 797 | + else: |
| 798 | + log.error("Unable to open Arduino sketch template file.") |
| 799 | + |
711 | 800 | #log.debug( json.dumps(logic_meta, indent=4) ) |
712 | 801 |
|
713 | 802 | wokwi_design_dump = wokwi_design |
|
0 commit comments