From ae9b468be74c69e420bf2bbfb1dbdda8e5e2202e Mon Sep 17 00:00:00 2001 From: Smims Date: Thu, 11 Sep 2025 17:08:33 +0200 Subject: [PATCH] feat: implement handler for distance and led --- distance.py | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++++ led.py | 36 +++++++++++++++++++++++ 2 files changed, 120 insertions(+) create mode 100644 distance.py create mode 100644 led.py diff --git a/distance.py b/distance.py new file mode 100644 index 0000000..ee712c2 --- /dev/null +++ b/distance.py @@ -0,0 +1,84 @@ +import machine +import time +from i2c_handler import I2CSlaveHandler, Packet + +class DistanceHandler(I2CSlaveHandler): + """ + I2C handler that responds to master requests by sending distance values + from an HC-SR04 ultrasonic sensor. + """ + + def __init__(self, i2c_id, sda, scl, slave_addr, trig_pin, echo_pin): + super().__init__(i2c_id, sda, scl, slave_addr) + self.trig = machine.Pin(trig_pin, machine.Pin.OUT) + self.echo = machine.Pin(echo_pin, machine.Pin.IN) + + def read_distance_mm(self): + """ + Measure distance using the HC-SR04 sensor. + Returns distance in millimeters as an integer. + """ + # Send a 10us pulse to trigger + self.trig.low() + time.sleep_us(2) + self.trig.high() + time.sleep_us(10) + self.trig.low() + + # Wait for echo high (timeout after 25ms) + timeout = 25000 + start = time.ticks_us() + while not self.echo.value(): + if time.ticks_diff(time.ticks_us(), start) > timeout: + return 0 # sensor error + t1 = time.ticks_us() + while self.echo.value(): + if time.ticks_diff(time.ticks_us(), t1) > timeout: + return 0 # sensor error + t2 = time.ticks_us() + + # Calculate duration and distance + duration = time.ticks_diff(t2, t1) + distance_mm = (duration * 100) // 582 + # HC-SR04: distance (mm) = duration (us) / 5.82 + + # Clamp to 0..65535 + return max(0, min(distance_mm, 65535)) + + def process_request(self): + """ + Called when master requests data. Responds with a packet containing distance. + Packet format: + Byte 0: 0x01 (distance command) + Byte 1: reserved + Byte 2-3: distance (uint16, mm, little-endian) + Byte 4-6: reserved + Byte 7: checksum (xor of bytes 0-6) + """ + #dist = self.read_distance_mm() + dist = 155 + data = [0] * Packet.LENGTH + data[0] = 0x01 # Command: distance + data[2] = dist & 0xFF # Low byte + data[3] = (dist >> 8) & 0xFF # High byte + + # Checksum: XOR of bytes 0-6 + cs = 0 + for b in data[:-1]: + cs ^= b + data[7] = cs + + print(Packet.from_bytes(data)) + return Packet.from_bytes(data) + +def main(): + handler = DistanceHandler(i2c_id=0, sda=0, scl=1, slave_addr=0x41, trig_pin=3, echo_pin=2) + print("Distance handler I2C slave started") + try: + handler.handle() + except KeyboardInterrupt: + handler.deinit() + print("I2C slave stopped") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/led.py b/led.py new file mode 100644 index 0000000..7e67a63 --- /dev/null +++ b/led.py @@ -0,0 +1,36 @@ +from i2c_handler import I2CSlaveHandler, Packet +import neopixel + +class LedDistanceHandler(I2CSlaveHandler): + def __init__(self, i2c_id, sda, scl, slave_addr): + super().__init__(i2c_id, sda, scl, slave_addr) + self.last_led_color = (0, 0, 0) # RGB tuple + self.np = neopixel.NeoPixel(machine.Pin(23), 1) + + def process_packet(self, packet: Packet): + cmd = packet[0] + # Assume LED color command is 0x10, RGB in bytes 2,3,4 + if cmd == 0x10: # Set LED Color + r = packet[2] + g = packet[3] + b = packet[4] + self.last_led_color = (r, g, b) + print(f"Set LED color to RGB({r},{g},{b})") + # TODO: Set the hardware LED to this color + self.np[0] = self.last_led_color + self.np.write() + else: + print(f"Unknown command 0x{cmd:02X}") + self.response_packet = None + +def main(): + handler = LedDistanceHandler(i2c_id=0, sda=0, scl=1, slave_addr=0x41) + print("LED/Distance handler I2C slave started") + try: + handler.handle() + except KeyboardInterrupt: + handler.deinit() + print("I2C slave stopped") + +if __name__ == "__main__": + main() \ No newline at end of file