358 lines
9.2 KiB
NASM
358 lines
9.2 KiB
NASM
; ***************************************************************************
|
|
; This sub-module contains code for cooperative address management.
|
|
; Because the network of nodes doen't have a central control unit the nodes
|
|
; need to assign addresses to themselves with help from the community of existing
|
|
; nodes.
|
|
;
|
|
; The protocol is as follows:
|
|
; 1) a node needs an address. It sends the packet "NEED_ADDRESS"
|
|
; 2) every node which already has an address sees this message and answers with
|
|
; a "HAVE_ADDRESS" packet. The nodes must not answer all at once to avoid
|
|
; congestions. Instead, the time it takes for a node to respond depends on
|
|
; its own address (e.g. a node with address 10 will wait for 10s before answering)
|
|
; 3) the initial node collects all "HAVE_ADDRESS" packets and puts the addresses
|
|
; received this way into a bitfield in which for every address received a bit is
|
|
; set
|
|
; 4) after about 130s all nodes in the address range 1-127 should have answered.
|
|
; So after this time the initial node looks at the bitfield of received addresses
|
|
; and selects the first unused address (corresponding bit cleared in bitfield).
|
|
; For this address the initial node sends a "CLAIM_ADDRESS" packet, three times
|
|
; with about 30s between the packets.
|
|
; 5) if the to-be-claimed address is already in use by another node, that node will
|
|
; send a "DENY_ADDRESS" packet. This is the second line of defense against address
|
|
; collisions and should very rarely occur.
|
|
; 6) after no node denied the to-be-claimed address the initial node finally takes the
|
|
; address and sends a "HAVE_ADDRESS" packet.
|
|
; 7) this concludes the address assignemt protocol
|
|
|
|
|
|
|
|
|
|
; ***************************************************************************
|
|
; code
|
|
|
|
.cseg
|
|
|
|
|
|
|
|
|
|
; ***************************************************************************
|
|
; onEverySecond handlers
|
|
|
|
|
|
|
|
cproHandle1sSendingHaveAddress:
|
|
; waiting for counter to reach zero to send a HAVE_ADDRESS packet
|
|
lds r16, cproAddressWaitCounter
|
|
dec r16
|
|
sts cproAddressWaitCounter, r16
|
|
brne cproHandle1sSendingHaveAddress_done ; counter not 0, done for now
|
|
rcall CPRO_EnqueueHaveAddress ; counter is 0, send HAVE_ADDRESS
|
|
ldi r16, CPRO_MODE_NORMAL
|
|
sts cproMode, r16
|
|
cproHandle1sSendingHaveAddress_done:
|
|
ret
|
|
|
|
|
|
|
|
cproHandle1sGetAddrStarted:
|
|
lds r16, cproAddressWaitCounter
|
|
dec r16
|
|
sts cproAddressWaitCounter, r16
|
|
brne cproHandle1sGetAddrStarted_done ; counter not 0, done for now
|
|
rcall cproClaimFirstFreeAddr ; counter 0, find first free address and claim it
|
|
brcs cproHandle1sGetAddrStarted_done
|
|
; no free address, abort TODO: send an error message to bus ("bus full")
|
|
ldi r16, CPRO_MODE_NORMAL
|
|
sts cproMode, r16
|
|
cproHandle1sGetAddrStarted_done:
|
|
ret
|
|
|
|
|
|
|
|
cproHandle1sClaimingAddr12:
|
|
lds r16, cproAddressWaitCounter
|
|
dec r16
|
|
sts cproAddressWaitCounter, r16
|
|
brne cproHandle1sClaimingAddr12_done ; counter not 0, done for now
|
|
push r17
|
|
lds r19, cproAddrRangeBegin ; currently claimed address
|
|
rcall CPRO_EnqueueClaimAddress
|
|
pop r17
|
|
ldi r16, CPRO_WAITTIME_CLAIMADDR
|
|
sts cproAddressWaitCounter, r16
|
|
inc r17 ; next mode (CPRO_MODE_CLAIMING_ADDR1 and 2)
|
|
sts cproMode, r17
|
|
cproHandle1sClaimingAddr12_done:
|
|
ret
|
|
|
|
|
|
cproHandle1sClaimingAddr3:
|
|
lds r16, cproAddressWaitCounter
|
|
dec r16
|
|
sts cproAddressWaitCounter, r16
|
|
brne cproHandle1sClaimingAddr3_done ; counter not 0, done for now
|
|
; claimed given address 3rd time, set address and enter "normal" mode
|
|
lds r16, cproAddrRangeBegin ; currently sent address is in cproAddrRangeBegin
|
|
in r15, SREG
|
|
cli
|
|
sts comAddress, r16 ; write address into eeprom
|
|
ldi xl, LOW(EEPROM_OFFS_COMADDR)
|
|
ldi xh, HIGH(EEPROM_OFFS_COMADDR)
|
|
; TODO rcall Utils_WriteEeprom
|
|
ldi r16, CPRO_MODE_NORMAL ; set mode to "normal"
|
|
sts cproMode, r16
|
|
rcall CPRO_EnqueueHaveAddress
|
|
out SREG, r15
|
|
cproHandle1sClaimingAddr3_done:
|
|
ret
|
|
|
|
|
|
|
|
|
|
|
|
; ***************************************************************************
|
|
; onPacketReceived handlers
|
|
|
|
|
|
|
|
cproHandlePckNeedAddr:
|
|
lds r17, cproMode
|
|
cpi r17, CPRO_MODE_NORMAL
|
|
brne cproHandlePckNeedAddr_done
|
|
; enter CPRO_MODE_SENDING_HAVE_ADDRESS mode
|
|
lds r16, comAddress
|
|
tst r16
|
|
breq cproHandlePckNeedAddr_done ; we have no address, don't handle
|
|
rcall cproEnterSendingHaveAddressMode
|
|
cproHandlePckNeedAddr_done:
|
|
sec
|
|
ret
|
|
|
|
|
|
|
|
cproHandlePckHaveAddr:
|
|
lds r17, cproMode
|
|
cpi r17, CPRO_MODE_GETADDRSTARTED
|
|
brne cproHandlePckHaveAddr_done
|
|
; validate address
|
|
ldd r16, y+(COM_BUFFER_OFFS_DATA+CPRO_PACKET_HAVEADDR_OFFS_ADDRESS)
|
|
tst r16
|
|
breq cproHandlePckHaveAddr_done ; invalid address, ignore
|
|
cpi r16, 127
|
|
brcc cproHandlePckHaveAddr_done ; invalid address, ignore
|
|
; set bit corresponding to given address in bitfield of used addresses
|
|
dec r16
|
|
rcall cproSetBitInBitfield
|
|
cproHandlePckHaveAddr_done:
|
|
sec
|
|
ret
|
|
|
|
|
|
|
|
cproHandlePckClaimAddr:
|
|
ldd r16, y+(COM_BUFFER_OFFS_DATA+CPRO_PACKET_CLAIMADDR_OFFS_ADDRESS)
|
|
tst r16
|
|
breq cproHandlePckClaimAddr_done
|
|
cpi r16, 0xff
|
|
breq cproHandlePckClaimAddr_done
|
|
lds r17, comAddress
|
|
cp r16, r17
|
|
brne cproHandlePckClaimAddr_done
|
|
rcall CPRO_EnqueueDenyAddress
|
|
cproHandlePckClaimAddr_done:
|
|
sec
|
|
ret
|
|
|
|
|
|
|
|
cproHandleDenyAddr:
|
|
ldd r16, y+(COM_BUFFER_OFFS_DATA+CPRO_PACKET_DENYADDR_OFFS_ADDRESS)
|
|
lds r17, cproAddrRangeBegin
|
|
cp r16, r17
|
|
brne cproHandleDenyAddr_done ; not our currently claimed address, ignore
|
|
rcall cproClaimNextFreeAddr ; claim next free address
|
|
brcs cproHandleDenyAddr_done
|
|
; no free address, abort TODO: send an error message to bus ("bus full")
|
|
ldi r16, CPRO_MODE_NORMAL
|
|
sts cproMode, r16
|
|
cproHandleDenyAddr_done:
|
|
sec
|
|
ret
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cproClaimFirstFreeAddr:
|
|
rjmp cproFindAndClaimFreeAddr
|
|
|
|
|
|
|
|
cproClaimNextFreeAddr:
|
|
lds r16, cproAddrRangeBegin
|
|
inc r16
|
|
sts cproAddrRangeBegin, r16
|
|
rjmp cproFindAndClaimFreeAddr
|
|
|
|
|
|
; IN:
|
|
; - R16: address to claim
|
|
|
|
cproFindAndClaimFreeAddr:
|
|
lds r16, cproAddrRangeBegin
|
|
lds r17, cproAddrRangeEnd
|
|
cp r16, r17
|
|
brge cproFindAndClaimFreeAddr_error
|
|
rcall cproFindFreeAddr
|
|
brcc cproFindAndClaimFreeAddr_error
|
|
lds r19, cproAddrRangeBegin ; currently claimed address
|
|
rcall CPRO_EnqueueClaimAddress
|
|
ldi r16, CPRO_WAITTIME_CLAIMADDR
|
|
sts cproAddressWaitCounter, r16
|
|
ldi r16, CPRO_MODE_CLAIMING_ADDR1
|
|
sts cproMode, r16
|
|
sec
|
|
ret
|
|
cproFindAndClaimFreeAddr_error:
|
|
clc
|
|
ret
|
|
|
|
|
|
|
|
cproHandleAddrRange: ; not handled for now
|
|
; TODO
|
|
clc
|
|
ret
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cproEnterSendingHaveAddressMode:
|
|
sts cproAddressWaitCounter, r16 ; set counter to own address
|
|
ldi r16, CPRO_MODE_SENDING_HAVE_ADDRESS
|
|
sts cproMode, r16
|
|
ret
|
|
|
|
|
|
|
|
CPRO_StartGetAddrProcedure:
|
|
; reset bitfield of used addresses
|
|
ldi xh, HIGH(cproUsedAddresses)
|
|
ldi xl, LOW(cproUsedAddresses)
|
|
clr r16
|
|
ldi r17, 16
|
|
rcall Utils_FillSram
|
|
; preset range
|
|
ldi r16, 1
|
|
sts cproAddrRangeBegin, r16
|
|
ldi r16, 126
|
|
sts cproAddrRangeEnd, r16
|
|
; send "NEED_ADDRESS" packet
|
|
rcall CPRO_EnqueueNeedAddress
|
|
brcc CPRO_StartGetAddrProcedure_error
|
|
; set waittimer for sampling of "HAVE_ADDRESS" packets
|
|
ldi r16, CPRO_WAITTIME_GETADDR
|
|
sts cproAddressWaitCounter, r16
|
|
ldi r16, CPRO_MODE_GETADDRSTARTED
|
|
sts cproMode, r16
|
|
sec
|
|
ret
|
|
CPRO_StartGetAddrProcedure_error:
|
|
clc
|
|
ret
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; cproFindFreeAddr
|
|
;
|
|
; find a free address in the bitfield cproUsedAddresses
|
|
;
|
|
; IN:
|
|
; - nothing
|
|
; OUT:
|
|
; - CFLAG: set if handled, cleared otherwise
|
|
; - R16: free address (if CFLAG set)
|
|
; USED: R16, R17, R18, R19, R20, R21 X, (R1, R2, Z)
|
|
|
|
cproFindFreeAddr:
|
|
ldi xl, LOW(cproUsedAddresses)
|
|
ldi xh, HIGH(cproUsedAddresses)
|
|
lds r16, cproAddrRangeBegin
|
|
dec r16
|
|
rcall Utils_GetPosAndMaskInBitField ; r1=bit pos, r2=mask (r1, r2, r17, Z)
|
|
clr r17
|
|
add xl, r1
|
|
adc xh, r17 ; X: pointer to byte
|
|
mov r17, r2 ; mask
|
|
lds r18, cproAddrRangeBegin
|
|
dec r18
|
|
lds r19, cproAddrRangeEnd
|
|
inc r19 ; to make comparision easier
|
|
ldi r20, 8
|
|
cproFindFreeAddr_byteLoop:
|
|
ld r16, X+
|
|
cpi r16, 0xff
|
|
breq cproFindFreeAddr_nextByte ; byte full, skip
|
|
cproFindFreeAddr_bitLoop:
|
|
mov r21, r16
|
|
and r21, r17
|
|
brne cproFindFreeAddr_nextBit
|
|
; found a clear bit, return
|
|
inc r18
|
|
sts cproAddrRangeBegin, r18
|
|
mov r16, r18
|
|
sec
|
|
ret
|
|
cproFindFreeAddr_nextBit:
|
|
inc r18 ; next address
|
|
lsl r17 ; shift mask to the left
|
|
brcc cproFindFreeAddr_bitLoop
|
|
dec r18 ; take back inc
|
|
cproFindFreeAddr_nextByte:
|
|
add r18, r20
|
|
andi r18, 0xf8 ; clear lower 3 bits
|
|
cp r18, r19 ; compare to end address+1
|
|
brcc cproFindFreeAddr_allFull
|
|
ldi r17, 0x01 ; mask
|
|
rjmp cproFindFreeAddr_byteLoop
|
|
cproFindFreeAddr_allFull:
|
|
clc
|
|
ret
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; cproSetBitInBitfield
|
|
;
|
|
; IN:
|
|
; - R16 : bit number to set (0-127)
|
|
; OUT:
|
|
; - nothing
|
|
; USED: R16, R17, X (r1, r2, Z)
|
|
|
|
cproSetBitInBitfield:
|
|
; set bit corresponding to given address in bitfield of used addresses
|
|
rcall Utils_GetPosAndMaskInBitField ; get offset into R1, mask into R2 (r1, r2, r17, Z)
|
|
ldi xl, LOW(cproUsedAddresses)
|
|
ldi xh, HIGH(cproUsedAddresses)
|
|
clr r17
|
|
add xl, r1
|
|
adc xh, r17
|
|
ld r16, X
|
|
or r16, r2
|
|
st X, r16
|
|
ret
|
|
|
|
|
|
|
|
|
|
|