Exemplo n.º 1
0
class MeshInterface:
    """ Class for Mesh interface,
        all modules that uses Mesh should call only this class methods """

    INTERVAL = const(10)

    def __init__(self, meshaging, lock):
        self.lock = lock  #_thread.allocate_lock()
        self.meshaging = meshaging
        self.mesh = MeshInternal(self.meshaging)
        self.sleep_function = None
        self.single_leader_ts = 0

        self.statistics = Statistics(self.meshaging)
        self._timer = Timer.Alarm(self.periodic_cb,
                                  self.INTERVAL,
                                  periodic=True)

        # just run this ASAP
        self.periodic_cb(None)

        pass

    def periodic_cb(self, alarm):
        # wait lock forever
        if self.lock.acquire():
            print("============ MESH THREAD >>>>>>>>>>> ")
            t0 = time.ticks_ms()

            self.mesh.process()
            if self.mesh.is_connected():
                self.statistics.process()
                self.mesh.process_messages()

            # if Single Leader for 3 mins should reset
            if self.mesh.mesh.state == self.mesh.mesh.STATE_LEADER and self.mesh.mesh.mesh.single(
            ):
                if self.single_leader_ts == 0:
                    # first time Single Leader, record time
                    self.single_leader_ts = time.time()
                print("Single Leader", self.mesh.mesh.state,
                      self.mesh.mesh.mesh.single(),
                      time.time() - self.single_leader_ts)

                if time.time() - self.single_leader_ts > 180:
                    print("Single Leader, just reset")
                    if self.sleep_function:
                        self.sleep_function(1)
            else:
                # print("Not Single Leader", self.mesh.mesh.state, self.mesh.mesh.mesh.single())
                self.single_leader_ts = 0

            self.lock.release()

            print(">>>>>>>>>>> DONE MESH THREAD ============ %d\n" %
                  (time.ticks_ms() - t0))

        pass

    def timer_kill(self):
        # with self.lock:
        self._timer.cancel()

    def get_mesh_mac_list(self):
        mac_list = list()
        if self.lock.acquire():
            # mac_list = list(self.mesh.get_all_macs_set())
            # mac_list.sort()
            mac_list = {0: list(self.mesh.get_all_macs_set())}
            self.lock.release()
        print("get_mesh_mac_list:", str(mac_list))
        return mac_list

    def get_mesh_pairs(self):
        mesh_pairs = []
        if self.lock.acquire():
            mesh_pairs = self.mesh.get_mesh_pairs()
            self.lock.release()
        #print("get_mesh_pairs: %s"%str(mesh_pairs))
        return mesh_pairs

    def set_gps(self, lng, lat):
        with open('/flash/gps', 'w') as fh:
            fh.write('%d;%d'.format(lng, lat))

    def is_connected(self):
        is_connected = None
        if self.lock.acquire():
            is_connected = self.mesh.is_connected()
            self.lock.release()
        return is_connected

    def ip(self):
        ip = None
        if self.lock.acquire():
            ip = self.mesh.mesh.mesh.ipaddr()
            self.lock.release()
        return ip

    def get_node_info(self, mac_id):
        data = {}
        try:
            mac = int(mac_id)
        except:
            mac = self.mesh.MAC
            print("get_node_info own mac")
        if self.lock.acquire():
            data = self.mesh.node_info(mac)
            self.lock.release()
        return data

    def send_message(self, data):
        ## WARNING: is locking required for just adding
        ret = False

        # check input parameters
        try:
            mac = int(data['to'])
            msg_type = data.get('ty', 0)  # text type, by default
            payload = data['b']
            id = int(data['id'])
            ts = int(data['ts'])
        except:
            print('send_message: wrong input params')
            return False

        if self.lock.acquire():
            print("Send message to %d, typ %d, load %s" %
                  (mac, msg_type, payload))
            ret = self.meshaging.send_message(mac, msg_type, payload, id, ts)
            # send messages ASAP
            self.mesh.process_messages()
            self.lock.release()

        return ret

    def mesage_was_ack(self, mac, id):
        ret = False
        if self.lock.acquire():
            ret = self.meshaging.mesage_was_ack(mac, id)
            self.lock.release()
        #print("mesage_was_ack (%X, %d): %d"%(mac, id, ret))
        return ret

    def get_rcv_message(self):
        """ returns a message that was received, {} if none is received """
        message = None
        if self.lock.acquire():
            message = self.meshaging.get_rcv_message()
            self.lock.release()
            if message is not None:
                (mac, id, ts, payload) = message
                return {'from': mac, 'b': payload, 'id': id, 'ts': ts}
        return {}

    def statistics_start(self, data):
        """ starts to do statistics based on message send/ack """
        # data = {'mac':6, 'n':3, 't':30, 's1':10, 's2':30}
        try:
            # validate input params
            mac = int(data['mac'])
            num_mess = int(data['n'])
            timeout = int(data['t'])
        except:
            print("statistics_start failed")
            print(data)
            return 0
        if mac == self.mesh.MAC:
            data['mac'] = 2
        res = self.statistics.add_stat_mess(data)
        return res

    def statistics_get(self, id):
        res = self.statistics.status(id)
        print(res)
        return res
Exemplo n.º 2
0
class MeshInterface:
    """ Class for Mesh interface,
        all modules that uses Mesh should call only this class methods """

    INTERVAL = const(10)

    def __init__(self, config, message_cb):
        self.lock = _thread.allocate_lock()
        self.meshaging = Meshaging(self.lock)
        self.config = config
        self.mesh = MeshInternal(self.meshaging, config, message_cb)
        self.sleep_function = None
        self.single_leader_ts = 0

        # Pybytes debugging
        self.pyb_dbg = False
        self.pyb_ts = 0
        self.pyb_timeout = 1000000
        self.pyb_data = "No data"
        self.br_auto = False
        self.mesh.br_handler = self.br_handler

        self.end_device_m = False

        self.statistics = Statistics(self.meshaging)
        self._timer = Timer.Alarm(self.periodic_cb,
                                  self.INTERVAL,
                                  periodic=True)

        # just run this ASAP
        self.periodic_cb(None)

        pass

    def periodic_cb(self, alarm):
        # wait lock forever
        if self.lock.acquire():
            print_debug(2, "============ MESH THREAD >>>>>>>>>>> ")
            t0 = time.ticks_ms()

            self.mesh.process()
            if self.mesh.is_connected():
                self.statistics.process()
                self.mesh.process_messages()

            # if connected to Pybytes enable/disable BR
            # if self.pyb_dbg:
            #     # self.mesh.border_router(Pybytes_wrap.is_connected())
            #     self.pybytes_process()

            # if Single Leader for 3 mins should reset
            # if self.mesh.mesh.state == self.mesh.mesh.STATE_LEADER and self.mesh.mesh.mesh.single():
            #     if self.single_leader_ts == 0:
            #         # first time Single Leader, record time
            #         self.single_leader_ts = time.time()
            #     print("Single Leader", self.mesh.mesh.state, self.mesh.mesh.mesh.single(),
            #         time.time() - self.single_leader_ts)

            #     if time.time() - self.single_leader_ts > 180:
            #         print("Single Leader, just reset")
            #         if self.sleep_function:
            #             self.sleep_function(1)
            # else:
            #     # print("Not Single Leader", self.mesh.mesh.state, self.mesh.mesh.mesh.single())
            #     self.single_leader_ts = 0

            self.lock.release()

            print_debug(
                2, ">>>>>>>>>>> DONE MESH THREAD ============ %d\n" %
                (time.ticks_ms() - t0))

        pass

    def timer_kill(self):
        # with self.lock:
        self._timer.cancel()

    def get_mesh_mac_list(self):
        mac_list = list()
        if self.lock.acquire():
            # mac_list = list(self.mesh.get_all_macs_set())
            # mac_list.sort()
            mac_list = {0: list(self.mesh.get_all_macs_set())}
            self.lock.release()
        print("get_mesh_mac_list:", str(mac_list))
        return mac_list

    def get_mesh_pairs(self):
        mesh_pairs = []
        if self.lock.acquire():
            mesh_pairs = self.mesh.get_mesh_pairs()
            self.lock.release()
        #print("get_mesh_pairs: %s"%str(mesh_pairs))
        return mesh_pairs

    def set_gps(self, lng, lat):
        with open('/flash/gps', 'w') as fh:
            fh.write('%d;%d'.format(lng, lat))

    def is_connected(self):
        is_connected = None
        if self.lock.acquire():
            is_connected = self.mesh.is_connected()
            self.lock.release()
        return is_connected

    def ip(self):
        ip = None
        if self.lock.acquire():
            ip = self.mesh.mesh.mesh.ipaddr()
            self.lock.release()
        return ip

    def get_node_info(self, mac_id=""):
        data = {}
        try:
            mac = int(mac_id)
        except:
            mac = self.mesh.MAC
            print("get_node_info own mac")
        if self.lock.acquire():
            data = self.mesh.node_info(mac)
            self.lock.release()
        return data

    def send_message(self, data):
        ## WARNING: is locking required for just adding
        ret = False

        # check if message is for BR
        if len(data.get('ip', '')) > 0:
            with self.lock:
                self.mesh.br_send(data)
            return
        # check input parameters
        try:
            mac = int(data['to'])
            msg_type = data.get('ty', 0)  # text type, by default
            payload = data['b']
            id = int(data['id'])
            ts = int(data['ts'])
        except:
            print('send_message: wrong input params')
            return False

        if self.lock.acquire():
            print("Send message to %d, typ %d, load %s" %
                  (mac, msg_type, payload))
            ret = self.meshaging.send_message(mac, msg_type, payload, id, ts)
            # send messages ASAP
            self.mesh.process_messages()
            self.lock.release()

        return ret

    def mesage_was_ack(self, mac, id):
        ret = False
        if self.lock.acquire():
            ret = self.meshaging.mesage_was_ack(mac, id)
            self.lock.release()
        #print("mesage_was_ack (%X, %d): %d"%(mac, id, ret))
        return ret

    def get_rcv_message(self):
        """ returns a message that was received, {} if none is received """
        message = None
        if self.lock.acquire():
            message = self.meshaging.get_rcv_message()
            self.lock.release()
            if message is not None:
                (mac, id, ts, payload) = message
                return {'from': mac, 'b': payload, 'id': id, 'ts': ts}
        return {}

    def statistics_start(self, data):
        """ starts to do statistics based on message send/ack """
        # data = {'mac':6, 'n':3, 't':30, 's1':10, 's2':30}
        try:
            # validate input params
            mac = int(data['mac'])
            num_mess = int(data['n'])
            timeout = int(data['t'])
        except:
            print("statistics_start failed")
            print(data)
            return 0
        if mac == self.mesh.MAC:
            data['mac'] = 2
        res = self.statistics.add_stat_mess(data)
        return res

    def statistics_get(self, id):
        res = self.statistics.status(id)
        print(res)
        return res

    def pybytes_process(self):
        """ Send data to Pybytes periodically, called from Mesh Task """
        # if not self.pyb_dbg:
        #     return
        if time.time() - self.pyb_ts > self.pyb_timeout:
            # with self.lock:
            self.pyb_data = self.mesh.debug_data()

            # send data to Pybytes
            # res = Pybytes_wrap.send_signal(self.mesh.MAC, self.pyb_data)
            self.pyb_ts = time.time()
        pass

    def pybytes_config(self, state, timeout=60):
        """ Configure sending data to Pybytes """
        self.pyb_dbg = state
        self.pyb_timeout = timeout

        # just set timestamp back, to make sure we're sending first call
        if self.pyb_dbg:
            self.pyb_ts = time.time() - self.pyb_timeout

        print("Sending Pybytes packets %s, every %s sec" %
              (self.pyb_dbg, self.pyb_timeout))
        pass

    def br_handler(self, id, data):
        """ sending data NOW to Pybytes """
        if not self.pyb_dbg:
            return
        print("Sending BR data to Pybytes")
        # res = Pybytes_wrap.send_signal(self.mesh.MAC, id + ": " + str(data))
        pass

    def br_set(self, enable, prio=0, br_mess_cb=None):
        with self.lock:
            self.mesh.border_router(enable, prio, br_mess_cb)

    def ot_cli(self, command):
        """ Executes commands in Openthread CLI,
        see https://github.com/openthread/openthread/tree/master/src/cli """
        return self.mesh.mesh.mesh.cli(command)

    def end_device(self, state=None):
        if state is None:
            # read status of end_device
            state = self.ot_cli('routerrole')
            return state == 'Disabled'
        self.end_device_m = False
        state_str = 'enable'
        if state == True:
            self.end_device_m = True
            state_str = 'disable'
        ret = self.ot_cli('routerrole ' + state_str)
        return ret == ''

    def leader_priority(self, weight=None):
        if weight is None:
            # read status of end_device
            ret = self.ot_cli('leaderweight')
            try:
                weight = int(ret)
            except:
                weight = -1
            return weight
        try:
            x = int(weight)
        except:
            return False
        # weight should be uint8, positive and <256
        if weight > 0xFF:
            weight = 0xFF
        elif weight < 0:
            weight = 0
        ret = self.ot_cli('leaderweight ' + str(weight))
        return ret == ''

    def debug_level(self, level=None):
        if level is None:
            try:
                ret = pycom.nvs_get('pymesh_debug')
            except:
                ret = None
            return ret
        try:
            ret = int(level)
        except:
            ret = self.debug_level
        debug_level(ret)

    def parent(self):
        """ Returns the Parent MAC for the current Child node
        Returns 0 if node is not Child """

        if self.mesh.mesh.mesh.state() != self.mesh.mesh.STATE_CHILD:
            print("Not Child, no Parent")
            return 0
        # try:
        parent_mac = int(
            self.mesh.mesh.mesh.cli('parent').split('\r\n')[0].split(
                'Ext Addr: ')[1], 16)
        # except:
        # parent_mac = 0
        print('Parent mac is:', parent_mac)
        return parent_mac