diff --git a/src/lib.rs b/src/lib.rs
index 9115ce1e423b9834c2c4e6c5252d276ec78faa31..6edf4830d3fe8f5611cda3aa8d6ea29d450fc424 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -95,36 +95,10 @@ impl<E, S: FullDuplex<u8, Error=E> + Sized, O: OutputPin> W5500<E, S, O> {
 
         self.set_mac(&MacAddress::new(0x00, 0x08, 0xDC, 0x01, 0x02, 0x03))?;
 
-
         self.set_ip(&IpAddress::new(192, 168, 3, 222))?;
         self.set_subnet(&IpAddress::new(255, 255, 255, 0))?;
         self.set_gateway(&IpAddress::new(192, 168, 3, 1))?;
 
-        // socket 0 with udp
-
-        self.write_to(
-            Register::Socket0Register(0x00_00),
-            &[
-                0b0000_0010, // UDP
-                0x01 // OPEN / initialize
-            ]
-        );
-        self.write_to(
-            Register::Socket0Register(0x00_04),
-            &[
-                0, 50, // local port u16
-                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // destination mac
-                192, 168, 3, 55, // target IP
-                0x14, 0xEA, // destination port (5354)
-            ]
-        )?;
-
-        self.write_to(
-            Register::Socket0Register(0x00_01),
-            &[
-                0x20 // SEND
-            ]
-        )?;
         Ok(self)
     }
 
@@ -208,8 +182,8 @@ impl<E, S: FullDuplex<u8, Error=E> + Sized, O: OutputPin> W5500<E, S, O> {
         self.write_to(
             socket.register_at(0x00_00),
             &[
-                0b0000_0010, // UDP
-                0x01 // OPEN / initialize
+                Protocol::UDP as u8, // Socket Mode Register
+                SocketCommand::Open as u8 // Socket Command Regsiter
             ]
         );
 
@@ -256,6 +230,80 @@ impl<E, S: FullDuplex<u8, Error=E> + Sized, O: OutputPin> W5500<E, S, O> {
         )
     }
 
+    pub fn listen_udp(&mut self, socket: Socket, port: u16) -> Result<(), E> {
+        self.write_u16(
+            socket.register_at(0x00_04),
+            port
+        )?;
+        self.write_to(
+            socket.register_at(0x00_00),
+            &[
+                Protocol::UDP as u8, // Socket Mode Register
+                SocketCommand::Open as u8 // Socket Command Regsiter
+            ]
+        )
+    }
+
+    /// TODO destination buffer has to be as large as the receive buffer or complete read is not guaranteed
+    pub fn try_receive_udp(&mut self, socket: Socket, destination: &mut [u8]) -> Result<Option<(IpAddress, u16, usize)>, E> {
+        if self.read_u8(socket.register_at(0x00_2c))? & 0x04 == 0 {
+            return Ok(None);
+        }
+        let receive_size = loop {
+            let s0 = self.read_u16(socket.register_at(0x00_26))?;
+            let s1 = self.read_u16(socket.register_at(0x00_26))?;
+            if s0 == s1 {
+                break s0 as usize;
+            }
+        };
+        if receive_size > 8 {
+            let read_pointer = self.read_u16(socket.register_at(0x00_28))?;
+
+            // |<-- read_pointer                                read_pointer + received_size -->|
+            // |Destination IP Address | Destination Port | Byte Size of DATA | Actual DATA ... |
+            // |   --- 4 Bytes ---     |  --- 2 Bytes --- |  --- 2 Bytes ---  |      ....       |
+
+            let ip = self.read_ip(socket.rx_register_at(read_pointer))?;
+            let port = self.read_u16(socket.rx_register_at(read_pointer+4))?;
+            let data_length = destination.len().min(self.read_u16(socket.rx_register_at(read_pointer+6))? as usize);
+
+            self.read_from(
+                socket.rx_register_at(read_pointer+8),
+                &mut destination[..data_length]
+            )?;
+
+            // self.read_from(socket.register_at(0x00_0C), &mut ip.address)?;
+            // self.read_u16(socket.register_at(0x00_10))?;
+
+            // reset
+            self.write_u16(socket.register_at(0x00_28), read_pointer + receive_size as u16)?;
+            self.write_u8(socket.register_at(0x00_01), SocketCommand::Recv as u8)?;
+
+            Ok(Some((ip, port, data_length)))
+
+        } else {
+            Ok(None)
+        }
+    }
+
+    pub fn read_u8(&mut self, register: Register) -> Result<u8, E> {
+        let mut buffer = [0u8; 1];
+        self.read_from(register, &mut buffer)?;
+        Ok(buffer[0])
+    }
+
+    pub fn read_u16(&mut self, register: Register) -> Result<u16, E> {
+        let mut buffer = [0u8; 2];
+        self.read_from(register, &mut buffer)?;
+        Ok(BigEndian::read_u16(&buffer))
+    }
+
+    pub fn read_ip(&mut self, register: Register) -> Result<IpAddress, E> {
+        let mut ip = IpAddress::default();
+        self.read_from(register, &mut ip.address)?;
+        Ok(ip)
+    }
+
     pub fn read_from(&mut self, register: Register, target: &mut [u8]) -> Result<(), E> {
         self.chip_select();
         let mut request = [0_u8, 0_u8, register.control_byte() | COMMAND_READ | VARIABLE_DATA_LENGTH];
@@ -267,6 +315,16 @@ impl<E, S: FullDuplex<u8, Error=E> + Sized, O: OutputPin> W5500<E, S, O> {
         result
     }
 
+    pub fn write_u8(&mut self, register: Register, value: u8) -> Result<(), E> {
+        self.write_to(register, &[value])
+    }
+
+    pub fn write_u16(&mut self, register: Register, value: u16) -> Result<(), E> {
+        let mut data = [0u8; 2];
+        BigEndian::write_u16(&mut data, value);
+        self.write_to(register, &data)
+    }
+
     pub fn write_to(&mut self, register: Register, data: &[u8]) -> Result<(), E> {
         self.chip_select();
         let mut request = [0_u8, 0_u8, register.control_byte() | COMMAND_WRITE | VARIABLE_DATA_LENGTH];
@@ -320,6 +378,28 @@ fn u16_to_be_bytes(u16: u16) -> [u8; 2] {
     bytes
 }
 
+#[repr(u8)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub enum Protocol {
+    TCP = 0b0001,
+    UDP = 0b0010,
+    MACRAW = 0b0100,
+}
+
+#[repr(u8)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub enum SocketCommand {
+    Open = 0x01,
+    Listen = 0x02,
+    Connect = 0x04,
+    Disconnect = 0x08,
+    Close = 0x10,
+    Send = 0x20,
+    SendMac = 0x21,
+    SendKeep = 0x22,
+    Recv = 0x40,
+}
+
 #[derive(Copy, Clone, PartialEq, PartialOrd, Debug)]
 pub enum Socket {
     Socket0,