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 run(self): t_next = skibase.get_time_millis() + KFNET_PACKET_TIMEOUT_MS while not self._got_stop_event(): # Send to network (from queue) while self._queue.empty() is False: packet = self._queue.get() self._send(packet) # relay back the task that was sent. # The main program will wait for the task to be relayed # back before acting. # Add delay before relaying self._main_queue.put(skibase.TASK_DELAY_MS + 12) self._main_queue.put(packet.task) self._queue.task_done() # Receive from network (to queue) packet = self._receive() # blocking if packet is not None: self._main_queue.put(packet.task) # Check if p_to for p_id is timed out (once every X ms) t_now = skibase.get_time_millis() if t_now > t_next: for [p_to, p_id] in self._known_packet_ids[:]: if p_to < t_now: skibase.log_debug( ("Removing packet ID '%s' with timeout %d.") \ % (p_id.decode(), p_to)) self._known_packet_ids.remove([p_to, p_id]) t_next = t_next + 1000 # Empty queue and stop while self._queue.empty() is False: self._queue.get() self._queue.task_done()
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 mcast_check_receive(self): ready = select.select([self], [], [], 0.100) # Non-blocking, 100 ms if ready[0]: data, addr = self.recvfrom(MCAST_PACKET_LEN) if data: skibase.log_debug(("Received %d bytes: \n%s") \ % (len(data), bytes_to_hex_str(data))) return data return None
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 wd_kick(): if wd_enabled: try: with open(WD_DEVICE, 'w') as wd_fd: wd_fd.write('1') except: skibase.die_err("Cannot kick watchdog. Ensure that the you " \ "execute as root (permissions) and that the watchdog device " \ "is free.") skibase.log_debug("!", end='')
def run(self): led = gpiozero.LED(self.ledpin) last_program = self.program while not self._got_stop_event(): if self.program == 0xff: led.off() elif last_program != self.program: last_program = self.program if last_program & 0x1: led.on() else: led.off() skibase.log_debug("LED state: %d" % (last_program & 0x1)) time.sleep(25 / 1000)
def run(self): button = gpiozero.Button(BUTT_PIN, pull_up=True) while not self._got_stop_event(): button.wait_for_press(timeout=0.500) if not button.is_pressed: continue t_press = skibase.get_time_millis() button.wait_for_release(timeout=(LONG_PRESS_TIME+10)/1000) t_release = skibase.get_time_millis() press_time = t_release - t_press if press_time >= LONG_PRESS_TIME: skibase.log_debug("Button Long press") self._main_queue.put(skibase.TASK_BUTTON_LONG_1) if button.is_pressed: button.wait_for_release(timeout=None) self._main_queue.put(skibase.TASK_BUTTON_LONG_2) else: self._main_queue.put(skibase.TASK_BUTTON_PRESS) skibase.log_debug("Button Press")
def wd_set_handle(handle): global wd_enabled wd_enabled = handle skibase.log_debug("Set watchdog handle to: %s" % handle)
def mcast_send(self, data): self.sendto(data, (self.mcast_grp, self.to_port)) skibase.log_debug("Sent %d bytes: \n%s" % (len(data), bytes_to_hex_str(data)))