def _receive(self): data = self.mcast_listener_obj.mcast_check_receive() if data is not None: # On an ad-hoc mesh network we will probably receive the # same packet multiple times. We will only store each # packet (packet ID) for a short time, and then discard # it in case of an "rereceived" packet. packet = KesselfallHeader.from_buffer_copy(data) # Check if packet was sent by ourselves if packet.src == self.source_id: return None # Check packet is valid if packet.stx != KFNET_STX or packet.etx != KFNET_ETX: skibase.log_warning(("Invalid packet: \n%s") \ %(bytes_to_hex_str(data))) return None t_timeout = skibase.get_time_millis() + KFNET_PACKET_TIMEOUT_MS for i, [p_to, p_id] in enumerate(self._known_packet_ids[:]): # Check if this packet was already received. if packet.id == p_id: # Renew timeout skibase.log_debug( "Renewing timout of packet ID '%s' from %d to %d." \ % (packet.id.decode(), p_to, t_timeout)) self._known_packet_ids[i] = [t_timeout, p_id] return None # We have identified a new packet # Send packet and add it to the list of _known_packet_ids self._send(packet) # Prioritize send skibase.log_info( "Received packet '%s' with timeout: %d." \ % (packet.id.decode(), t_timeout)) self._known_packet_ids.append([t_timeout, packet.id]) return packet return None
def _send(self, packet): # Check STX and ETX if packet.stx != KFNET_STX or packet.etx != KFNET_ETX: skibase.log_warning(("Invalid packet: \n%s") \ %(bytes_to_hex_str(bytes(packet)))) return # Verify length if len(bytes(packet)) != MCAST_PACKET_LEN: skibase.log_warning(("Packet ID '%s'. Packet is %d/%d bytes long") \ %(packet.id.decode(), len(bytes(packet)), MCAST_PACKET_LEN)) return # Check if we will resend packet (if not new packet) number = random.randint(0x00, 0xFF) if packet.rp < number and packet.ttl != KFNET_TTL_RETRANS: skibase.log_debug(("Discard resend of packet ID '%s' (%d < %d)") \ %(packet.id.decode(), packet.rp, number)) return # Decrease TTL if packet.ttl < 1: skibase.log_debug(("Discard packet ID '%s'. TTL is %d") \ %(packet.id.decode(), packet.ttl)) return packet.ttl -= 1 # Send self.mcast_sender_obj.mcast_send(bytes(packet)) skibase.log_info(("Sent packet ID '%s'. TTL is %d") \ %(packet.id.decode(), packet.ttl+1))
def do_delay_task(task): if task > skibase.TASK_DELAY_MS and \ ((task & skibase.MAJOR_TASK) == skibase.TASK_DELAY_MS): delay = task & skibase.MINOR_TASK skibase.log_debug("Delay: %d ms" % delay) time.sleep(delay / 1000) else: skibase.log_warning("Delay: task %04x not within limits" % task)
def get_program_from_task(task): if task >= skibase.TASK_PROGRAM and \ ((task & skibase.MAJOR_TASK) == skibase.TASK_PROGRAM): program = task & skibase.MINOR_TASK skibase.log_debug("Program from task: %s" % \ program_id_to_str(program)) return program else: skibase.log_warning("Program: task %s not within limits" % \ skibase.task_to_str(task)) return 0
def test(): skibase.set_time_start() # Arguments parser = argparse.ArgumentParser(description=__doc__) parser = skibase.args_add_log(parser) parser = args_add_kfnet(parser) args = parser.parse_args() # Parse skibase.log_config(args.loglevel.upper(), args.syslog) # Signal skibase.signal_setup([signal.SIGINT, signal.SIGTERM]) # Start queue main_queue = queue.Queue() # Start kfnet kfnet_obj = kfnet_start(main_queue, args.interface, MCAST_GRP, args.ip_addr, args.mcast_port) # Loop (main) skibase.log_notice("Running Kesselfall network unittest") counter = random.randint(0, 0xFF) t_next_send = skibase.get_time_millis() while not skibase.signal_counter and kfnet_obj.status(): try: task = main_queue.get(block=True, timeout=0.25) except queue.Empty: task = None if task: try: skibase.log_notice("-> task: %s" % skibase.task_to_str(task)) except: skibase.log_warning("kfnet got unknown task") main_queue.task_done() if t_next_send < skibase.get_time_millis(): # Send packet to kfnet task # otherwise use kfnet_obj.queue_task(task) packet = kfnet_obj.create_packet() packet.task = skibase.TASK_PROGRAM + \ (counter & skibase.MINOR_TASK) kfnet_obj.queue_packet(packet) skibase.log_notice("<- Packet: %s :: task: %s" %\ (packet.id.decode(), task_to_str(packet.task))) t_next_send = t_next_send \ + random.randint(CHANGE_RATE_MIN, CHANGE_RATE_MAX) counter += 1 kfnet_obj = kfnet_stop(kfnet_obj) skibase.log_notice("Kesselfall network unittest ended")
def run(self): while not self._got_stop_event(): this_program = self.program skibase.log_info("sphat: %02x" % this_program) try: scrollphathd.clear() if this_program == 0x00: self.show_string(this_program, "Kesselfall 2019 ") elif this_program == 0x01: self.do_storm(this_program) elif this_program == 0x02: self.do_graph(this_program) elif this_program == 0x03: self.do_forest_fire(this_program) elif this_program == 0x04: self.do_storm(this_program) elif this_program == 0x05: self.do_cells(this_program) elif this_program == 0x06: self.show_string(this_program, "Kesselfall 2019 ") elif this_program == 0x07: self.do_forest_fire(this_program) elif this_program == 0x08: self.do_swirl(this_program) elif this_program == 0x09: self.do_plasma(this_program) elif this_program == 0x0A: self.do_swirl(this_program) elif this_program == 0x0B: self.do_plasma(this_program) elif this_program == 0xff: while self.program == this_program and not self._got_stop_event( ): scrollphathd.show() else: scroll_string = "ERROR%d" % this_program except: skibase.log_warning("sphat does not work") for i in range(int(60000 / SCROLL_TEXT_RATE_MS)): if self.program == this_program and not self._got_stop_event( ): time.sleep(SCROLL_TEXT_RATE_MS / 1000) else: break
def test(): # Arguments parser = argparse.ArgumentParser(description=__doc__) parser = skibase.args_add_log(parser) parser = args_add_butt(parser) args = parser.parse_args() # Parse skibase.log_config(args.loglevel.upper(), args.syslog) # Signal skibase.signal_setup([signal.SIGINT, signal.SIGTERM]) # Start queue main_queue = queue.Queue() # Start Butt butt_obj = butt_start(main_queue) # Loop skibase.log_notice("Running butt unittest") while not skibase.signal_counter and butt_obj.status(): try: task = main_queue.get(block=True, timeout=0.25) except queue.Empty: task = None if task is not None: if task == skibase.TASK_BUTTON_PRESS: skibase.log_notice("butt press") elif task == skibase.TASK_BUTTON_LONG: skibase.log_notice("butt long press") else: skibase.log_warning("butt got unknown task") # Stop Butt butt_stop(butt_obj) skibase.log_notice("butt unittest ended")
def loop(main_queue, program_id, kfnet_obj, butt_obj, sphat_obj, ws281x_obj, dbgled_obj): next_kick = 0 program_can_change_again = 0 while not skibase.signal_counter \ and kfnet_obj.status() \ and butt_obj.status() \ and sphat_obj.status() \ and ws281x_obj.status() \ and dbgled_obj.status(): next_kick = wd.wd_check(next_kick) try: task = main_queue.get(block=True, timeout=LOOP_SPEED) except queue.Empty: task = None if task: if task == skibase.TASK_BUTTON_PRESS: now = skibase.get_time_millis() if now >= program_can_change_again: program_id = get_next_program(program_id) # Add program_id to kfnet as a task that is transmitted # Do not execute task yet, but wait for kfnet to relay # the task back when it is sent. This should make the # network appear more "in sync". kfnet_obj.queue_task(skibase.TASK_PROGRAM + program_id) skibase.log_info("task: press: %s" % \ program_id_to_str(program_id)) program_can_change_again = now + PROGRAM_CHANGE_BLOCK_MS else: skibase.log_info("Ignoring program change.") elif task == skibase.TASK_BUTTON_LONG_1: skibase.log_info("task: long press") ws281x_obj.program = 0xff sphat_obj.program = 0xff dbgled_obj.program = 0xff elif task == skibase.TASK_BUTTON_LONG_2: do_shutdown() main_queue.task_done() break elif (task & skibase.MAJOR_TASK) == skibase.TASK_DELAY_MS: skibase.log_info("task: delay") do_delay_task(task) elif (task & skibase.MAJOR_TASK) == skibase.TASK_PROGRAM: program_id = get_program_from_task(task) ws281x_obj.program = program_id sphat_obj.program = program_id dbgled_obj.program = program_id skibase.log_notice("task: program: %s" % \ program_id_to_str(program_id)) else: skibase.log_warning("skipi got unknown task!") try: skibase.log_warning("task: %s" % task_to_str(task)) except: skibase.log_warning("log task failed...") print(task) main_queue.task_done()