; ***************************************************************************
; copyright   : (C) 2026 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 AQH_AVR_COMMON_ITOA_ASM
#define AQH_AVR_COMMON_ITOA_ASM



; ***************************************************************************
; defines


.equ ITOA_BUFFER_SIZE = 8



; ***************************************************************************
; global data

.dseg


itoa_buffer:    ; max uint16 65535, 5 digits, plus komma, sign, ZERO
  .byte ITOA_BUFFER_SIZE



; ***************************************************************************
; code

.cseg



; ---------------------------------------------------------------------------
; @routine IntToAscii @global
;
; @param R21:R20 value to transform to ascii
; @param R24     number of digits after komma
; @return X      pointer to result string (will be overwritten by next call!)
; @clobbers R16, R17, R18, R19, R20, R21, R22, R23

IntToAscii:
  ldi xl, LOW(itoa_buffer)
  ldi xh, HIGH(itoa_buffer)
  adiw xh:xl, ITOA_BUFFER_SIZE
  clr r16
  st -X, r16
  ldi r25, ITOA_BUFFER_SIZE-1      ; byte counter

IntToAscii_loop:
    ; divide by 10
    ldi r22, 10
    clr r23
    push r25
      bigcall Utils_Divu16_16_16     ; R17:R16=result, R19:R18=remainder (R25)
    pop r25
    ; move result for next loop
    mov r20, r16
    mov r21, r17
    ; store digit of remainder (can only be 0-9 when dividing by 10)
    ldi r19, '0'
    add r19, r18
    st -X, r19
    dec r25
    breq IntToAscii_ret
    ; maybe insert komma
    tst r24
    breq IntToAscii_next
    dec r24
    brne IntToAscii_next
    ldi r19, ','
    st -X, r19
    dec r25
    breq IntToAscii_ret
IntToAscii_next:
    mov r16, r20         ; result == 0?
    or r16, r21
    breq IntToAscii_ret  ; yes, done
  rjmp IntToAscii_loop
IntToAscii_ret:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine HexWordToAscii @global
;
; Shares buffer with @ref IntToAscii !
;
; @param R21:R20 value to transform to ascii
; @return X      pointer to result string (will be overwritten by next call!)
; @clobbers R16, R17

HexWordToAscii:
  ldi xl, LOW(itoa_buffer)
  ldi xh, HIGH(itoa_buffer)
  mov r16, r21
  rcall writeHexByteToBuffer  ; write hi byte
  mov r16, r20
  rcall writeHexByteToBuffer  ; write low byte
  clr r16
  st X+, r16
  sbiw xh:xl, 5
  ret
; @end



; ---------------------------------------------------------------------------
; @routine HexByteToAscii @global
;
; Shares buffer with @ref IntToAscii !
;
; @param R16 value to transform to ascii
; @return X      pointer to result string (will be overwritten by next call!)
; @clobbers R16, R17

HexByteToAscii:
  ldi xl, LOW(itoa_buffer)
  ldi xh, HIGH(itoa_buffer)
  rcall writeHexByteToBuffer
  clr r16
  st X+, r16
  sbiw xh:xl, 3
  ret
; @end



; ---------------------------------------------------------------------------
; @routine writeHexByteToBuffer
;
; @param R16 value to transform to ascii
; @param X      pointer to current pos in result buffer
; @clobbers R16, R17

writeHexByteToBuffer:
  push r16
    swap r16
    rcall hexNibbleToAscii ; transform high nibble (r16, r17)
    st X+, r16
  pop r16
  rcall hexNibbleToAscii   ; transform low nibble (r16, r17)
  st X+, r16
  ret
; @end



; ---------------------------------------------------------------------------
; @routine hexNibbleToAscii
;
; Convert a nibble to an ASCII char.
; @return R16 ASCII representation of that nibble (e.g. '0' for 0)
; @param  R16 byte (in bits 0-3)
; @clobbers r16, r17

hexNibbleToAscii:
  andi r16, 0xf
  cpi r16, 10
  brcs hexNibbleToAscii_l1
  ldi r17, 7
  add r16, r17
hexNibbleToAscii_l1:
  ldi r17, '0'
  add r16, r17
  ret
; @end



#endif


