import machine
import network
import socket
import struct


class ArtNet():
    def __init__(self, id_universe, id_ch_start, id_ch_end):
        self.id_universe = id_universe
        self.id_ch_start = id_ch_start
        self.id_ch_end = id_ch_end

        self.channels = [0]*(id_ch_end-id_ch_start+1)
        self.clbk = None

        spi = machine.SPI(0, baudrate=20000000, polarity=0, phase=0, 
                          sck=machine.Pin(18), mosi=machine.Pin(19), miso=machine.Pin(16))
        nic = network.WIZNET5K(spi, machine.Pin(17), machine.Pin(20))
        nic.active(True)

        while not nic.isconnected():
            pass

        print('Art-Net Node IP:', nic.ifconfig()[0])

        ARTNET_PORT = 6454
        self.s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.s.bind(('0.0.0.0', ARTNET_PORT))

    def tick(self):
        data, addr = self.s.recvfrom(1024)
        
        # packets start with 'Art-Net' + null byte
        if len(data) > 18 and data[0:8] == b'Art-Net\x00':
            opcode = struct.unpack('<H', data[8:10])[0]
            
            # 0x5000 is OpOutput / OpDmx
            if opcode == 0x5000:
                universe = struct.unpack('<H', data[14:16])[0]
                if(universe == self.id_universe):
                    # DMX data starts at byte 18
                    dmx_data = data[18:]

                    if(len(dmx_data) > self.id_ch_end):
                        for i,n in enumerate(range(self.id_ch_start, self.id_ch_end+1)):
                            self.channels[i] = int(dmx_data[n])
                        
                        if(self.clbk is not None):
                            self.clbk(self)
