# HG changeset patch # User matthewreed # Date 2017-04-04 20:54:23 # Node ID 72dd61ca5365148ce7b0a507e8e8c1682162abf1 # Parent ce32edfd2399f2ee6e94b89a6b7f0f9b36f33d34 Started refactoring with the networking and modules diff --git a/message.py b/message.py new file mode 100644 --- /dev/null +++ b/message.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python + +class HydroBotMessage: + + def __init__(self, module_uuid, message_type, data_key, sensor_num, data): + + self.module_uuid = module_uuid + self.message_type = message_type + self.data_key = data_key + self.sensor_num = sensor_num + self.data = data + + def __str__(self): + return "Module UUID: " + str(self.module_uuid) + " Message Type: " + hex(self.message_type) + " Data Key: " + hex(self.data_key) + " Sensor Num: " + str(self.sensor_num) + " Data: " + str(self.data) + diff --git a/module.py b/module.py new file mode 100644 --- /dev/null +++ b/module.py @@ -0,0 +1,92 @@ +from abc import ABCMeta, abstractmethod +import uuid + +class ModuleList(): + + def __init__(self): + self._modules = [] + + def add_module(self, module): + assert isinstance(module, Module), 'invalid module' + if module in self._modules: + raise ValueError('Module %s already in database' % module) + else: + self._modules.append(module) + + def remove_module(self, module): + assert isinstance(Module, module), 'invalid module' + try: + self._module.remove(module) + except ValueError: + raise ValueError('Module %s is not in database' % module) + + def lookup_module(self, uuid): + for module in self._modules: + if module.uuid == uuid: + return module + + def new_module(self, device_type, address, interface): + + if device_type == 0x01: + module = AirSenseModule(device_type, address, interface) + elif device_type == 0x02: + module = RelayDriveModule(device_type, address, interface) + else: + module = UnknownModule(device_type, address, interface) + + self.add_module(module) + + return module + +class Module(metaclass=ABCMeta): + + def __init__(self, device_type, address, interface): + self.device_type = device_type + self.address = address + self.interface = interface + + self.uuid = uuid.uuid1() + print("Created new module! " + str(self.uuid)) + + @abstractmethod + def send_message(self): + pass + + @abstractmethod + def receive_message(self): + pass + +class AirSenseModule(Module): + + def __init__(self, device_type, address, interface): + super(AirSenseModule, self).__init__(device_type, address, interface) + + def send_message(self): + message = None + self.interface.network.send_message(message) + + def receive_message(self): + print("AirSenseModule receive message!") + +class RelayDriveModule(Module): + + def __init__(self, device_type, address, interface): + super(RelayDriveModule, self).__init__(device_type, address, interface) + + def send_message(self): + pass + + def receive_message(self): + print("RelayDriveModule receive message!") + +class UnknownModule(Module): + + def __init__(self, device_type, address, interface): + super(UnknownModule, self).__init__(device_type, address, interface) + + def send_message(self): + pass + + def receive_message(self): + print("UnknownModule receive message!") + diff --git a/network.py b/network.py new file mode 100644 --- /dev/null +++ b/network.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python + +import network_interface +import module + +class Network(): + + def __init__(self, logger): + self.interfaces = [] + self.module_list = module.ModuleList() + self.logger = logger + + def add_interface(self, interface): + self.interfaces.append(interface) + + def load_interfaces(self): + #TODO: Load interfaces from config file + pass + + def get_interface(self, interface_name): + for interface in self.interfaces: + if interface.interface_name == interface_name: + return interface + + def start_interface(self, interface_name): + print("Network: start interface " + interface_name) + #TODO: Start interface + for interface in self.interfaces: + if interface.interface_name == interface_name: + interface.start() + + def start_all_interfaces(self): + print("Network: start all interfaces") + for interface in self.interfaces: + interface.start() + + def send_message(self, message): + module = self.module_list.lookup_module(message.module_uuid) + if not module == None: + module.interface.send_message(message) + else: + print("Could not find module " + str(message.module_uuid)) + + def process_message(self, message): + print("Network: process message") + self.module_list.lookup_module(message.module_uuid).receive_message() + diff --git a/network_interface.py b/network_interface.py new file mode 100644 --- /dev/null +++ b/network_interface.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python + +import os +import struct +import _thread +from abc import ABCMeta, abstractmethod + +from message import HydroBotMessage +import module + +from canard import can +from canard.hw import socketcan +from canard.utils import queue + +class NetworkInterface(metaclass=ABCMeta): + + def __init__(self, network, logger): + self.network = network + self.logger = logger + + @abstractmethod + def start(self): + print("Network: start") + + @abstractmethod + def send_message(self, message): + pass + + def process_message(self, message): + print("Network Interface: process message") + + + +class CanBusNetworkInterface(NetworkInterface): + + def __init__(self, network, interface_name, logger): + super(CanBusNetworkInterface, self).__init__(network, logger) + + # Bring up CAN interface (maybe do this in a systemd service file) + # Passing random arguments to sudo is super dangerous + os.system("sudo ip link set " + interface_name + " up type can bitrate 500000") + + self.interface_name = interface_name + self.dev = socketcan.SocketCanDev(interface_name) + self.queue = queue.CanQueue(self.dev) + + self.address_lookup = {} + self.uuid_lookup = {} + + def start(self): + super(CanBusNetworkInterface, self).start() + print("CanBusNetworkInterface: start") + self.queue.start() + _thread.start_new_thread(self.process_message, ()) + + def send_message(self, message): + address = self.uuid_lookup[message.module_uuid] + can_frame = can.Frame(address, 8, [message.message_type, (message.data_key>>8) & 0xff, (message.data_key>>0) & 0xff, message.sensor_num] + list(struct.pack("f", message.data))) + self.logger.debug("Send CAN message! CAN ID: " + hex(can_frame.id) + " Data: " + str(can_frame.data)) + self.queue.send(can_frame) + + def process_message(self): + while True: + frame = self.queue.recv() + if frame != None: + print("CanBusNetworkInterface: process message") + + if not frame.id in self.address_lookup: + new_module = self.network.module_list.new_module(frame.data[0] & 0x7f, frame.id, self) + self.address_lookup[frame.id] = new_module.uuid + self.uuid_lookup[new_module.uuid] = frame.id + + self.logger.debug("Received CAN message! ID: " + hex(frame.id)) + message = HydroBotMessage(self.address_lookup[frame.id], frame.data[0], ((frame.data[1] << 8) + frame.data[2]), frame.data[3], ((frame.data[4] << 24) + (frame.data[5] << 16) + (frame.data[6] << 8) + frame.data[7])) + print(message) + self.network.process_message(message) + + +class WifiNetworkInterface(NetworkInterface): + + def __init__(self, network, logger): + super(WifiNetworkInterface, self).__init__(network, logger) + + def start(self): + pass + + def send_message(self, message): + pass + + def process_message(self, message): + pass + + + +#module knows how to send and recieve messages +