diff --git a/avr/modules/uart_bitbang/0BUILD b/avr/modules/uart_bitbang/0BUILD
new file mode 100644
index 0000000..ac289d9
--- /dev/null
+++ b/avr/modules/uart_bitbang/0BUILD
@@ -0,0 +1,12 @@
+
+
+
+
+
+ main.asm
+ bytelevel.asm
+
+
+
+
+
diff --git a/avr/modules/uart_bitbang/bytelevel.asm b/avr/modules/uart_bitbang/bytelevel.asm
new file mode 100644
index 0000000..caf5ffa
--- /dev/null
+++ b/avr/modules/uart_bitbang/bytelevel.asm
@@ -0,0 +1,186 @@
+; ***************************************************************************
+; copyright : (C) 2024 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. *
+; ***************************************************************************
+
+
+
+; ---------------------------------------------------------------------------
+; @macro UART_BB_M_WAIT_FOR_PIN_LOW IN_REG_DATA, IN_PINNUM
+; 0 1
+; Wait for a pin to become low
+; @param %0 DATA register for input pin (e.g. PINB)
+; @param %1 pin number for input (e.g. PORTB1)
+; @return CFLAG set if okay, clear otherwise
+; @clobbers R17, R22
+
+.macro UART_BB_M_WAIT_FOR_PIN_LOW
+ ldi r17, 200
+l_loop:
+ sbis @0, @1
+ rjmp l_reached
+ Utils_WaitNanoSecs 5000, 0, r22 ; wait for 5us
+ dec r17
+ brne l_loop
+ clc
+ rjmp l_end
+l_reached:
+ sec
+l_end:
+.endmacro
+; @end
+
+
+
+; ---------------------------------------------------------------------------
+; @macro UART_BB_M_WAIT_FOR_PIN_HIGH IN_REG_DATA, IN_PINNUM
+; 0 1
+; Wait for a pin to become high
+; @param %0 DATA register for input pin (e.g. PINB)
+; @param %1 pin number for input (e.g. PORTB1)
+; @return CFLAG set if okay, clear otherwise
+; @clobbers R17, R22
+
+.macro UART_BB_M_WAIT_FOR_PIN_HIGH
+ ldi r17, 200
+l_loop:
+ sbic @0, @1
+ rjmp l_reached
+ Utils_WaitNanoSecs 5000, 0, r22 ; wait for 5us
+ dec r17
+ brne l_loop
+ clc
+ rjmp l_end
+l_reached:
+ sec
+l_end:
+.endmacro
+; @end
+
+
+
+; ---------------------------------------------------------------------------
+; @routine uartBitbang_SendByte
+;
+; Send a byte.
+; We only set the data pin to low at the beginning for the startbit. After that
+; we only change the pin direction (e.g. input vs output):
+; - for 0 bit: set DDR to output, forcing the data line low
+; - for 1 bit: set DDR to input, letting the external pullup R pull the data line to HIGH
+; since the output pin is still set to 0 the internal pullup is disabled
+; Expects interrupts to be disabled.
+;
+; @param R16 byte to send
+; @return CFLAG set if okay, clear otherwise
+; @clobbers R16, R21, R22
+
+uartBitbang_SendByte:
+ ldi r21, 8 ; +1 bits left
+ ; send startbit
+ cbi COM_TXD_DATA, COM_TXD_PIN ; +2 set DATA low
+ sbi COM_TXD_DDR, COM_TXD_PIN ; +2 set DATA as output
+ Utils_WaitNanoSecs COM_BIT_LENGTH, 1, r22 ; wait for one bit duration
+ ; send data bits
+uartBitbang_SendByte_loop: ; 9 for low bit
+ lsr r16 ; 1+ bit to send -> CARRY
+ brcs uartBitbang_SendByte_setHigh ; HI: +2, LO: +1
+uartBitbang_SendByte_setLow:
+ sbi COM_TXD_DDR, COM_TXD_PIN ; +2 set DATA as output
+ Utils_WaitNanoSecs COM_BIT_LENGTH, 9, r22
+ rjmp uartBitbang_SendByte_loopEnd ; +2
+uartBitbang_SendByte_setHigh:
+ cbi COM_TXD_DDR, COM_TXD_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_RXD_DATA, COM_RXD_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_TXD_DDR, COM_TXD_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:
+ 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_RXD_DATA, COM_RXD_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 for data pin to become low
+; @return CFLAG set if okay, clear otherwise
+; @clobbers R17, R22
+
+uartBitbang_WaitForDataLow:
+ UART_BB_M_WAIT_FOR_PIN_LOW COM_RXD_DATA, COM_RXD_PIN
+ ret
+; @end
+
+
+
+; ---------------------------------------------------------------------------
+; @routine uartBitbang_WaitForDataHigh
+;
+; Wait for data pin to become high
+; @return CFLAG set if okay, clear otherwise
+; @clobbers R17, R22
+
+uartBitbang_WaitForDataHigh:
+ UART_BB_M_WAIT_FOR_PIN_LOW COM_RXD_DATA, COM_RXD_PIN
+ ret
+; @end
+
+
+
+
+
diff --git a/avr/modules/uart_bitbang/defs.asm b/avr/modules/uart_bitbang/defs.asm
new file mode 100644
index 0000000..9485944
--- /dev/null
+++ b/avr/modules/uart_bitbang/defs.asm
@@ -0,0 +1,13 @@
+; ***************************************************************************
+; copyright : (C) 2024 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. *
+; ***************************************************************************
+
+
+.equ UART_BITBANG_BUFFER_NUM = 4
+
+
diff --git a/avr/modules/uart_bitbang/main.asm b/avr/modules/uart_bitbang/main.asm
new file mode 100644
index 0000000..ca10971
--- /dev/null
+++ b/avr/modules/uart_bitbang/main.asm
@@ -0,0 +1,398 @@
+; ***************************************************************************
+; copyright : (C) 2024 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. *
+; ***************************************************************************
+
+
+
+; UART_BitBang_Init
+; UART_BitBang_Fini
+; UART_BitBang_Run
+; UART_BitBang_SendPacket:
+; UART_BitBang_GetNextReceivedPacket:
+; UART_BitBang_ReleaseReceivedPacket:
+
+
+.include "modules/com2/buffer.asm"
+
+
+
+.dseg
+
+
+uartBitbangDataBegin:
+ uartBitbangRecvBuffersUsed: .byte 1
+ uartBitbangMaxBuffersUsed: .byte 1
+ uartBitbangRecvBuffersWritePos: .byte 1
+ uartBitbangRecvBuffersReadPos: .byte 1
+ uartBitbangRecvBuffers: .byte COM2_BUFFER_SIZE*UART_BITBANG_BUFFER_NUM
+uartBitbangDataEnd:
+
+
+
+
+.cseg
+
+
+
+
+; ---------------------------------------------------------------------------
+; @routine UART_BitBang_Init
+;
+; @return CFLAG set if okay, clear on error
+; @clobbers R16, R17, X, Y
+
+UART_BitBang_Init:
+ ; preset SRAM data area
+ ldi xh, HIGH(uartBitbangDataBegin)
+ ldi xl, LOW(uartBitbangDataBegin)
+ clr r16
+ ldi r17, (uartBitbangDataEnd-uartBitbangDataBegin)
+ rcall Utils_FillSram
+
+ ; setup pins and interrupts
+ cbi COM_TXD_DATA, COM_TXD_PIN ; disable internal pullup for TXD
+ cbi COM_TXD_DDR, COM_TXD_PIN ; set TXD port as input
+
+ cbi COM_RXD_DATA, COM_RXD_PIN ; disable internal pullup for RXD
+ cbi COM_RXD_DDR, COM_RXD_PIN ; set RXD port as input
+
+ cbi COM_ATTN_OUTPUT, COM_ATTN_PIN ; disable internal pullup for ATTN
+ cbi COM_ATTN_DDR, COM_ATTN_PIN ; set ATTN port as input
+
+ 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<