From 1a42ddd18725c5bdcc1acfc92322f910016814c2 Mon Sep 17 00:00:00 2001
From: Julian Leucker <leuckerj@gmail.com>
Date: Mon, 3 Aug 2020 21:25:47 +0200
Subject: [PATCH] Add device address in Config.py and main_window.py

---
 configurations/test_with_addr.json         | 96 ++++++++++++++++++++++
 fpga_device_manager/Config.py              | 40 ++++++++-
 fpga_device_manager/windows/main_window.py |  7 ++
 3 files changed, 140 insertions(+), 3 deletions(-)
 create mode 100644 configurations/test_with_addr.json

diff --git a/configurations/test_with_addr.json b/configurations/test_with_addr.json
new file mode 100644
index 0000000..64fa5c1
--- /dev/null
+++ b/configurations/test_with_addr.json
@@ -0,0 +1,96 @@
+{
+  "devices": {
+    "0": {
+      "name": "RGB Dimmer",
+      "type": 3,
+      "pins": {
+        "red": {
+          "assigned_pin": "1",
+          "active_low": false
+        },
+        "green": {
+          "assigned_pin": "2",
+          "active_low": false
+        },
+        "blue": {
+          "assigned_pin": "3",
+          "active_low": false
+        }
+      },
+      "parameters": {
+        "delay": 10
+      }
+    },
+    "1": {
+      "name": "Shutter",
+      "type": 4,
+      "pins": {
+        "up": {
+          "assigned_pin": "97",
+          "active_low": true
+        },
+        "down": {
+          "assigned_pin": "98",
+          "active_low": true
+        }
+      },
+      "parameters": {
+        "tick_ms": 500,
+        "full_movement_ticks": 30
+      }
+    },
+    "2": {
+      "name": "Generic Binary",
+      "type": 1,
+      "pins": {
+        "signal": {
+          "assigned_pin": "105",
+          "active_low": false
+        }
+      },
+      "parameters": {}
+    }
+  },
+  "inputs": {
+    "0": {
+      "name": "Color cycle button",
+      "type": 4,
+      "associated_device": 0,
+      "pins": {
+        "signal": {
+          "assigned_pin": "34",
+          "active_low": false
+        }
+      },
+      "parameters": {
+        "color_1": 0,
+        "color_2": 16711680,
+        "color_3": 16742144,
+        "color_4": 16776960,
+        "color_5": 65280,
+        "color_6": 30719,
+        "color_7": 255,
+        "color_8": 16711935
+      }
+    },
+    "1": {
+      "name": "Shutter control",
+      "type": 5,
+      "associated_device": 1,
+      "pins": {
+        "up": {
+          "assigned_pin": "35",
+          "active_low": false
+        },
+        "down": {
+          "assigned_pin": "32",
+          "active_low": false
+        }
+      },
+      "parameters": {
+        "full_press_time": 2000
+      }
+    }
+  },
+  "addr": 88
+}
\ No newline at end of file
diff --git a/fpga_device_manager/Config.py b/fpga_device_manager/Config.py
index 83bd711..fa2b7d9 100644
--- a/fpga_device_manager/Config.py
+++ b/fpga_device_manager/Config.py
@@ -1,5 +1,6 @@
 """
-This module maintains a device configuration. It provides a device manager for output and input modules each.
+This module maintains a device configuration. It provides a device manager for output and input modules each,
+as well as the slave address.
 """
 import json
 import os
@@ -16,6 +17,25 @@ from fpga_device_manager.exceptions import DeviceInvalidError, InvalidConfigErro
 
 _output_mgr = DeviceManager(device_class=Output)
 _input_mgr = DeviceManager(device_class=Input)
+_i2c_slave_address = 50
+
+
+def i2c_address(address=None):
+    """Acts as a property function for the i2c_address"""
+    global _i2c_slave_address
+
+    if address:
+        if type(address) != int:
+            try:
+                address = int(address)
+            except ValueError:
+                pass
+
+        if 8 < address < 119:
+            _i2c_slave_address = address
+    else:
+        return _i2c_slave_address
+
 
 
 def clear() -> None:
@@ -66,6 +86,8 @@ def load(cfg_filename: str, max_devices: Optional[int] = None) -> None:
                 device = _output_mgr.get(associated_device_id)
                 dev_input.associate(device)
 
+    i2c_address(device_file_data["addr"])
+
 
 def save(cfg_filename: str) -> None:
     """
@@ -74,7 +96,8 @@ def save(cfg_filename: str) -> None:
     """
     data = {
         "devices": _output_mgr.save(),
-        "inputs": _input_mgr.save()
+        "inputs": _input_mgr.save(),
+        "addr": i2c_address()
     }
 
     with open(cfg_filename, "w") as file:
@@ -104,6 +127,14 @@ def check() -> None:
             except DeviceInvalidError as e:
                 errors.append(str(e))
 
+    try:
+        temp = int(_i2c_slave_address)
+        if not temp or not(8 < temp < 119):
+            errors.append("The I2C-Address has to be between 8 and 119")
+
+    except ValueError:
+        errors.append("The I2C-Address is not numeric")
+
     if len(errors) > 0:
         raise InvalidConfigError(errors)
 
@@ -135,6 +166,9 @@ def export(out_path: str) -> None:
     output_pin_indices = {pin.name: index for index, pin in enumerate(output_pins)}
     input_pin_indices = {pin.name: index for index, pin in enumerate(input_pins)}
 
+    # Get the I2C slave address
+    slave_addr = _i2c_slave_address
+
     # Gather unused pins
     unused_pins = [pin for pin in Pins.all() if not pin.is_assigned()]
 
@@ -146,7 +180,7 @@ def export(out_path: str) -> None:
         "efb.v": tpl_loader.render("efb.v.tpl",
                                    generator=out_generator,
                                    timestamp=out_timestamp,
-                                   address=bin(50)),
+                                   slave_addr=f"0b{slave_addr:07b}"),
         "devices_out.v": tpl_loader.render("devices_out.v.tpl",
                                            generator=out_generator,
                                            timestamp=out_timestamp,
diff --git a/fpga_device_manager/windows/main_window.py b/fpga_device_manager/windows/main_window.py
index 7854b82..ae66edd 100755
--- a/fpga_device_manager/windows/main_window.py
+++ b/fpga_device_manager/windows/main_window.py
@@ -70,12 +70,18 @@ class MainWindow(BaseWindow):
 
     def refresh(self) -> None:
         """Updates all widgets."""
+        self.update_address()
         self.update_labels()
         self.update_buttons()
         self.update_preview()
         self.update_widgets()
         self.update_title()
 
+    def update_address(self) -> None:
+        """Update the I2C-Address."""
+        if self.device_address.value() != Config.i2c_address():
+            Config.i2c_address(self.device_address.value())
+
     def update_labels(self) -> None:
         """Updates the window's labels."""
         self.tabs.setTabText(0, "Appliances (%d)" % (len(Config.outputs().devices)))
@@ -120,6 +126,7 @@ class MainWindow(BaseWindow):
             self.add_all_widgets()
             self.clear_dirty()
             self.update_title()
+            self.device_address.setValue(Config.i2c_address())
 
         except Exception as e:
             Popup.alert(title=f"Failed to load {filename}",
-- 
GitLab