import os import struct import _thread from abc import ABCMeta, abstractmethod import logging from message import HydroBotMessage import module import protocol from canard import can from canard.hw import socketcan from canard.utils import queue class NetworkInterface(metaclass=ABCMeta): def __init__(self, network): self.logger = logging.getLogger('hydrobot') self.network = network @abstractmethod def start(self): self.logger.info("Network: start") @abstractmethod def send_message(self, message): pass def process_message(self, message): self.logger.debug("Network Interface: process message") class CanBusNetworkInterface(NetworkInterface): def __init__(self, network, interface_name): super(CanBusNetworkInterface, self).__init__(network) try: # 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.queue = None self.dev = socketcan.SocketCanDev(interface_name) self.queue = queue.CanQueue(self.dev) except: self.logger.error("Can Bus failed to initilize") #bidirectional address <==> uuid lookup self.address_lookup = {} self.uuid_lookup = {} def start(self): super(CanBusNetworkInterface, self).start() self.logger.info("CanBusNetworkInterface: start") if self.queue != None: self.queue.start() _thread.start_new_thread(self.process_message, ()) else: self.logger.error("Can Bus failed to start") 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)) if self.queue != None: self.queue.send(can_frame) else: self.logger.error("Can Bus is not initilized") def process_message(self): while True: if self.queue != None: frame = self.queue.recv() if frame != None: base_id = frame.id & 0x7fe if not base_id in self.address_lookup: self.logger.debug("Uknown module address: " + hex(base_id)) device_id = frame.data[0] & 0x7f new_module = self.network.module_list.new_module(device_id, base_id, self) self.address_lookup[base_id] = new_module.uuid self.uuid_lookup[new_module.uuid] = base_id self.logger.debug("Received CAN message! ID: " + hex(frame.id)) data = [frame.data[7], frame.data[6], frame.data[5], frame.data[4]] b = struct.pack('4B', *data) f_data = struct.unpack('>f', b)[0] message = HydroBotMessage(self.address_lookup[base_id], frame.data[0], ((frame.data[1] << 8) + frame.data[2]), frame.data[3], f_data) self.logger.debug("Process message: " + str(message)) self.network.process_message(message) else: self.logger.error("Can Bus is not initilized") class WifiNetworkInterface(NetworkInterface): def __init__(self, network): super(WifiNetworkInterface, self).__init__(network) def start(self): pass def send_message(self, message): pass def process_message(self, message): pass