diff --git a/avr/modules/uart_bitbang2/0BUILD b/avr/modules/uart_bitbang2/0BUILD
new file mode 100644
index 0000000..71d9bfa
--- /dev/null
+++ b/avr/modules/uart_bitbang2/0BUILD
@@ -0,0 +1,14 @@
+
+
+
+
+
+ bytelevel.asm
+ defs.asm
+ main.asm
+ packetlevel.asm
+
+
+
+
+
diff --git a/avr/modules/uart_bitbang2/defs.asm b/avr/modules/uart_bitbang2/defs.asm
new file mode 100644
index 0000000..a6bd53a
--- /dev/null
+++ b/avr/modules/uart_bitbang2/defs.asm
@@ -0,0 +1,10 @@
+; ***************************************************************************
+; copyright : (C) 2025 by Martin Preuss
+; email : martin@libchipcard.de
+;
+; ***************************************************************************
+; * This file is part of the project "AqHome". *
+; * Please see toplevel file COPYING of that project for license details. *
+; ***************************************************************************
+
+
diff --git a/avr/modules/uart_bitbang2/iface.asm b/avr/modules/uart_bitbang2/iface.asm
new file mode 100644
index 0000000..f507bd5
--- /dev/null
+++ b/avr/modules/uart_bitbang2/iface.asm
@@ -0,0 +1,274 @@
+; ***************************************************************************
+; copyright : (C) 2025 by Martin Preuss
+; email : martin@libchipcard.de
+;
+; ***************************************************************************
+; * This file is part of the project "AqHome". *
+; * Please see toplevel file COPYING of that project for license details. *
+; ***************************************************************************
+
+#ifndef UART_BITBANG_IFACE_H
+#define UART_BITBANG_IFACE_H
+
+; ***************************************************************************
+; includes
+
+.include "modules/uart_bitbang2/defs.asm"
+.include "modules/uart_bitbang2/lowlevel.asm"
+
+.include "modules/network/iface.asm"
+
+
+
+; ***************************************************************************
+; data
+
+.dseg
+
+uart_bitbang_iface: .byte NET_IFACE_SIZE
+
+
+
+
+
+; ***************************************************************************
+; code
+
+.cseg
+
+
+
+; ---------------------------------------------------------------------------
+; @routine UART_BitBang_Init @global
+;
+; @return CFLAG set if okay, clear on error
+; @clobbers R16, R17, X, Y
+
+UART_BitBang_Init:
+ ldi yl, LOW(uart_bitbang_iface)
+ ldi yh, HIGH(uart_bitbang_iface)
+ rcall NET_Interface_Init ; (R16, R17, X)
+
+ ; init hw
+ sbi COM_IRQ_ADDR_ATTN, COM_IRQ_BIT_ATTN ; enable pin change irq for ATTN line
+ in r16, GIMSK ; enable pin change irq PCIE0 or PCIE1
+ ori r16, (1< CARRY
+ brcs uartBitbang_SendByte_setHigh ; HI: +2, LO: +1
+uartBitbang_SendByte_setLow:
+ sbi COM_DATA_DDR, COM_DATA_PIN ; +2 set DATA as output
+ cbi COM_DATA_OUTPUT, COM_DATA_PIN ; +2 set DATA low
+ Utils_WaitNanoSecs COM_BIT_LENGTH, 11, r22
+ rjmp uartBitbang_SendByte_loopEnd ; +2
+uartBitbang_SendByte_setHigh:
+ cbi COM_DATA_DDR, COM_DATA_PIN ; +2 set DATA as input, pullup R makes it ONE
+ nop ; +1 (to make pin change available)
+ Utils_WaitNanoSecs COM_HALFBIT_LENGTH, 0, r22 ; wait for half a bit length for line to safely settle
+ sbis COM_DATA_INPUT, COM_DATA_PIN ; +1 if no skip, +2 if skipped
+ rjmp uartBitbang_SendByte_error ; +2 if error (collision: we wanted line to be high but it is low)
+ Utils_WaitNanoSecs COM_HALFBIT_LENGTH, 11, r22
+uartBitbang_SendByte_loopEnd:
+ dec r21 ; +1
+ brne uartBitbang_SendByte_loop ; +2, sum per loop: 10 cycles
+ ; send stopbit
+ cbi COM_DATA_DDR, COM_DATA_PIN ; +2 set DATA as input, pullup R makes it ONE
+ Utils_WaitNanoSecs COM_BIT_LENGTH, 0, r22 ; wait for one bit length
+ sec
+ ret
+
+uartBitbang_SendByte_error:
+ clc
+ ret
+; @end
+
+
+
+; ---------------------------------------------------------------------------
+; @routine uartBitbangReceiveByte
+;
+; Read a byte.
+; Expects interrupts to be disabled.
+;
+; @return CFLAG set if okay, clear otherwise
+; @return R16 byte received
+; @clobbers R16, R20, R21, R22 (R17)
+
+uartBitbang_ReceiveByte:
+ cbi COM_DATA_DDR, COM_DATA_PIN ; set DATA port as input
+ cbi COM_DATA_OUTPUT, COM_DATA_PIN ; disable internal pullup for RXD
+ ldi r21, 8 ; bits left
+ clr r20 ; byte currently receiving
+ ; wait for startbit
+ rcall uartBitbang_WaitForDataLow ; (R17, R22)
+ brcc uartBitbang_ReceiveByte_error
+ Utils_WaitNanoSecs COM_HALFBIT_LENGTH, 10, r22 ; goto middle of startbit to maximize sync stability
+uartBitbang_ReceiveByte_loop:
+ Utils_WaitNanoSecs COM_BIT_LENGTH, 8, r22 ; 8 cycles used in the complete loop between waits
+ sec ; +1
+ sbic COM_DATA_INPUT, COM_DATA_PIN ; LOW: +2, HIGH: +1
+ rjmp uartBitbang_ReceiveByte_shiftIn ; HIGH: +2, rjmp, use set CFLAG
+ clc ; LOW: +1
+uartBitbang_ReceiveByte_shiftIn:
+ ror r20 ; +1
+ dec r21 ; +1
+ brne uartBitbang_ReceiveByte_loop ; +2, sum per loop: 8 cycles
+ rcall uartBitbang_WaitForDataHigh ; wait for start of stopbit
+ brcc uartBitbang_ReceiveByte_error
+ mov r16, r20
+ sec
+ ret
+uartBitbang_ReceiveByte_error:
+ clc
+ ret
+; @end
+
+
+
+; ---------------------------------------------------------------------------
+; @routine uartBitbang_WaitForDataLow
+;
+; Wait up to 1ms for data pin to become low
+; @return CFLAG set if okay, clear otherwise
+; @clobbers R17, R22
+
+uartBitbang_WaitForDataLow:
+ cbi COM_DATA_DDR, COM_DATA_PIN ; set DATA port as input
+ cbi COM_DATA_OUTPUT, COM_DATA_PIN ; disable internal pullup for TXD
+ UART_BB_M_WAIT_FOR_PIN_LOW COM_DATA_INPUT, COM_DATA_PIN
+ ret
+; @end
+
+
+
+; ---------------------------------------------------------------------------
+; @routine uartBitbang_WaitForDataHigh
+;
+; Wait up to 1ms for data pin to become high
+; @return CFLAG set if okay, clear otherwise
+; @clobbers R17, R22
+
+uartBitbang_WaitForDataHigh:
+ cbi COM_DATA_DDR, COM_DATA_PIN ; set DATA port as input
+ cbi COM_DATA_OUTPUT, COM_DATA_PIN ; disable internal pullup for TXD
+ UART_BB_M_WAIT_FOR_PIN_HIGH COM_DATA_INPUT, COM_DATA_PIN
+ ret
+; @end
+
+
+
+; ---------------------------------------------------------------------------
+; @routine uartBitbang_WaitForAttnHigh
+;
+; Wait up to 1ms for data pin to become high
+; @return CFLAG set if okay, clear otherwise
+; @clobbers R17, R22
+
+uartBitbang_WaitForAttnHigh:
+ cbi COM_ATTN_DDR, COM_ATTN_PIN ; set ATTN port as input
+ cbi COM_ATTN_OUTPUT, COM_ATTN_PIN ; disable internal pullup for ATTN
+ UART_BB_M_WAIT_FOR_PIN_HIGH COM_ATTN_INPUT, COM_ATTN_PIN
+ ret
+; @end
+
+
+
+
+
+
+; ---------------------------------------------------------------------------
+; @routine uartBitbang_ReceivePacketIntoBuffer
+;
+; Receive a packet into buffer pointed to by X.
+; Expects interrupts to be disabled.
+;
+; @param R16 COM address to listen to
+; @param R17 maximum value for accepted msg data (i.e. buffersize minus 3)
+; @param X buffer to receive to
+; @return CFLAG set if okay (packet received), cleared on error
+; @return R16 error code if CFLAG is cleared (COM2_ERROR_NOTFORME, COM2_ERROR_IOERROR, COM2_ERROR_DATAERROR)
+; @clobbers: r16, r17, r18, X (r19, r20, r21, r22)
+
+uartBitbang_ReceivePacketIntoBuffer:
+ mov r18, r17
+ push r16
+ ; read destination address
+ rcall uartBitbang_ReceiveByte ; read byte (R16, R17, R20, R21, R22)
+ pop r17 ; pop from R16 to R17
+ brcc uartBitbang_ReceivePacketIntoBuffer_ioError
+#ifndef COM_ACCEPT_ALL_DEST ; accept every destination address
+ ; compare destination address (accept "FF" and own address)
+ cp r16, r17
+ breq uartBitbang_ReceivePacketIntoBuffer_acceptAddr
+ cpi r16, 0xff
+ breq uartBitbang_ReceivePacketIntoBuffer_acceptAddr
+ clr r16
+ rjmp uartBitbang_ReceivePacketIntoBuffer_error ; clc/ret
+#endif
+uartBitbang_ReceivePacketIntoBuffer_acceptAddr:
+ st X+, r16 ; store dest address, lock buffer
+ ; read msg length
+ rcall uartBitbang_ReceiveByte ; read packet length (R16, R17, R20, R21, R22)
+ brcc uartBitbang_ReceivePacketIntoBuffer_ioError
+ st X+, r16
+ cp r16, r18 ; (COM2_BUFFER_SIZE-3)
+ brcc uartBitbang_ReceivePacketIntoBuffer_contentError ; packet too long
+ inc r16 ; account for checksum byte
+ mov r17, r16
+uartBitbang_ReceivePacketIntoBuffer_loop:
+ push r17
+ rcall uartBitbang_ReceiveByte ; read byte (R16, R17, R20, R21, R22)
+ pop r17
+ brcc uartBitbang_ReceivePacketIntoBuffer_ioError
+ st X+, r16
+ dec r17
+ brne uartBitbang_ReceivePacketIntoBuffer_loop
+ sec
+ ret
+uartBitbang_ReceivePacketIntoBuffer_ioError:
+ ldi r16, NET_IFACE_OFFS_ERR_IO_LOW
+ rjmp uartBitbang_ReceivePacketIntoBuffer_error
+uartBitbang_ReceivePacketIntoBuffer_contentError:
+ ldi r16, NET_IFACE_OFFS_ERR_CONTENT_LOW
+uartBitbang_ReceivePacketIntoBuffer_error:
+ clc
+ ret
+; @end
+
+
+
+; ---------------------------------------------------------------------------
+; @routine uartBitbang_SendPacket
+;
+; Send packet over wire, handle ATTN line.
+;
+; @param X ptr to buffer to send
+; @return CFLAGS set if okay, cleared otherwise (index of error variable in R16)
+; @return R16 index of error variable (if CFLAGS cleared)
+; @clobbers R16, R22 (R17, R21, X)
+
+uartBitbang_SendPacket:
+ rcall uartBitbang_AcquireBus
+ brcc uartBitbang_SendPacket_lineBusyError
+
+ rcall uartBitbang_WaitForOneBitLength ; wait for one bit duration (R22)
+ rcall uartBitbang_WaitForOneBitLength ; wait for one bit duration (R22)
+
+ adiw xh:xl, COM2_MSG_OFFS_MSGLEN
+ ld r17, X
+ sbiw xh:xl, COM2_MSG_OFFS_MSGLEN
+ inc r17 ; account for dest addr
+ inc r17 ; account for msglen byte
+ inc r17 ; account for crc byte
+
+uartBitbang_SendPacket_loop:
+ ld r16, X+
+ rcall uartBitbang_SendByte ; send byte (R16, R21, R22)
+ brcc uartBitbang_SendPacket_releaseBusRet
+ dec r17
+ brne uartBitbang_SendPacket_loop
+ sec
+uartBitbang_SendPacket_releaseBusRet:
+ cbi COM_ATTN_DDR, COM_ATTN_PIN ; release ATTN line (by setting direction to IN)
+ brcc uartBitbang_SendPacket_ioError
+ ; packet successfully sent
+ ret
+uartBitbang_SendPacket_ioError:
+ ldi r16, NET_IFACE_OFFS_ERR_COLLISIONS_LOW
+ ret
+uartBitbang_SendPacket_lineBusyError:
+ ldi r16, NET_IFACE_OFFS_ERR_BUSY_LOW
+ ret
+; @end
+
+
+
+; ---------------------------------------------------------------------------
+; @routine uartBitbang_AcquireBus
+;
+; Reserve bus if free (otherwise return error)
+; Expects interrupts to be disabled.
+;
+; @return CFLAG set if okay (bus acquired), cleared on error
+; @clobbers: none
+
+uartBitbang_AcquireBus:
+ ; check for ATTN line: busy?
+ cbi COM_ATTN_DDR, COM_ATTN_PIN ; set ATTN as input
+ cbi COM_ATTN_OUTPUT, COM_ATTN_PIN ; disable pullup on ATTN
+ nop ; needed to sample current input
+ sbis COM_ATTN_INPUT, COM_ATTN_PIN ; ATTN low?
+ rjmp uartBitbang_AcquireBus_busy ; jump if it is
+ sbi COM_ATTN_DDR, COM_ATTN_PIN ; set ATTN as output
+ cbi COM_ATTN_OUTPUT, COM_ATTN_PIN ; set ATTN low
+ sec
+ ret
+uartBitbang_AcquireBus_busy:
+ clc
+ ret
+; @end
+
+
+
+; ---------------------------------------------------------------------------
+; @routine uartBitbang_WaitForOneBitLength
+;
+; wait for one bit length (minus cycles for call and ret).
+;
+; @clobbers r22
+
+uartBitbang_WaitForOneBitLength:
+ Utils_WaitNanoSecs COM_BIT_LENGTH, 7, r22 ; wait for one bit duration (minus RCALL/RET)
+ ret
+; @end
+
+
+
+
diff --git a/avr/modules/uart_bitbang2/main.asm b/avr/modules/uart_bitbang2/main.asm
new file mode 100644
index 0000000..a6bd53a
--- /dev/null
+++ b/avr/modules/uart_bitbang2/main.asm
@@ -0,0 +1,10 @@
+; ***************************************************************************
+; copyright : (C) 2025 by Martin Preuss
+; email : martin@libchipcard.de
+;
+; ***************************************************************************
+; * This file is part of the project "AqHome". *
+; * Please see toplevel file COPYING of that project for license details. *
+; ***************************************************************************
+
+