// ================================
//	wbgt clock
//		(c) 2021	1YEN Toru
//
//
//		2021/09/18	ver.1.00
//
// ================================
asm		"mcoc_irom.mif"
#asm		"mcoc_irom.mem"
#asm		"mcoc_irom.dat2",bit16,list
incl	"mcoc115.incl"
incl	"mcvm_mcr_long.incl"
incl	"mcvm_lib_wire_h.incl"
# ================================
# string macros
def		prog_name,"wbgt_clock"
def		prog_vers,"1.00"
def		s,"#"							// simulation="" / real fpga="#"
# constants
equ		max_lbuf,64						// size of lbuf
equ		baud,9600						// baud rate
equ		uart_baud,fcpu/baud-1			// uartbaud setting
equ		stws_baud,fcpu/100000-1			// i2c: clock speed
$(s)// ********************************
$(s)equ		stws_baud,fcpu/400000/3-1	// i2c: clock speed for sim
$(s)// ********************************
equ		i2c_lcdc,0x27					// i2c: LCDC slave address
equ		chr_lf,0x0a						// lf code
equ		chr_cr,0x0d						// cr code
equ		chr_spc,0x20					// space ' ' code
equ		chr_pct,0x25					// percent '%' code
equ		chr_cma,0x2c					// comma ',' code
equ		chr_mns,0x2d					// minus '-' code
equ		chr_dot,0x2e					// period '.' code
equ		chr_cln,0x3a					// colon ':' code
equ		dht_sda,0x80					// dht: sda signal pin
equ		dht_usec_tbe,20000				// dht: start signal low width[us]
equ		dht_usec_tore,500				// dht: time out for response[us]
equ		dht_usec_toda,200				// dht: time out for data[us]
equ		dht_usec_th,(27+68)/2			// dht: threshold of HIGH width[us]
equ		dht_msec_tpow,2000				// dht: power on stabilization time[ms]
equ		dht_usec_tcyc,2000000			// dht: read interval time[us]
equ		dht_err_no,0					// dht: error: no
equ		dht_err_resp,1					// dht: error: not respond
equ		dht_err_recv,2					// dht: error: receive
equ		dht_err_chks,3					// dht: error: check sum
equ		lcd_rs_inst,0					// lcd: rs: instruction/status register
equ		lcd_rs_data,1					// lcd: rs: data ram
equ		lcd_clear,0x01					// lcd: clear display
equ		lcd_rtn_home,0x02				// lcd: return home
equ		lcd_ent_mode,0x04				// lcd: entry mode
equ		lcd_disp_cur,0x08				// lcd: display on/off
equ		lcd_cur_sft,0x10				// lcd: cursor or display shift
equ		lcd_func_set,0x20				// lcd: function set
equ		lcd_set_cra,0x40				// lcd: set cgram address
equ		lcd_set_dra,0x80				// lcd: set ddram address
equ		lcd_bf,0x80						// lcd: status register BF flag
equ		lcd_width,40					// lcd: width of ddram
equ		lcd_line,2						// lcd: lines
equ		lcd_line_0,0					// lcd: line location 0 or 1
equ		lcd_line_1,1
equ		wbgt_ws,0						// wbgt: WS (wind speed) *1/10[m/s]
equ		wbgt_ws_1,572*wbgt_ws/100		// wbgt: 0.0572*WS (*1k)
equ		wbgt_ofst,-wbgt_ws_1-4064		// wbgt: offset (*1k)
# variables
equ		va,ramtop
equ		dht_idx,va						// dht: index 5 bytes
equ		va,va+2
equ		dht_idx2,va						// dht: index 8 bits
equ		va,va+2
equ		dht_usec_prev,va				// dht: previously measured time [us]
equ		va,va+4
equ		dht_prev_mm,va					// dht: previously measured minute
equ		va,va+2
equ		dht_ta,va						// dht: measured temperature *1/10[degC]
equ		va,va+2
equ		dht_rh,va						// dht: measured humidity *1/10[%RH]
equ		va,va+2
equ		dht_wbgt,va						// dht: estimated wbgt *1/10[degC]
equ		va,va+2
equ		clk_hh,va						// clk: hour
equ		va,va+2
equ		clk_mm,va						// clk: minute
equ		va,va+2
equ		clk_ss,va						// clk: second
equ		va,va+2
equ		clk_msec_next,va				// clk: next second update timing
equ		va,va+4
equ		static_va,va
# array variables
equ		lbuf,va							// receive data buffer
equ		va,va+max_lbuf
equ		dht_buf,va						// dht: receive data buffer
equ		va,va+6
equ		i2c_buf,va						// i2c: i2c frame buffer
equ		va,va+2*16
equ		lcd_buf,va						// lcd: lcd print buffer
equ		va,va+48
equ		array_va,va
# ================================
# user macros
macro	dht_sda_0
// dht: sda=0
ldwi	r7,porclr
ldbiu	r0,dht_sda
stw		[r7],r0
endm

macro	dht_sda_1
// dht: sda=1
ldwi	r7,porset
ldbiu	r0,dht_sda
stw		[r7],r0
endm

macro	sytm_ofst_ms
// sytmmil: set offset
ldwi	r7,sytmctl
ldw		r2,[r7]
andi	r2,~sytm_mloe
stw		[r7],r2
ori		r2,sytm_mloe
stw		[r7],r2
endm

macro	sytm_ofst_us
// sytmmcr: set offset
ldwi	r7,sytmctl
ldw		r2,[r7]
andi	r2,~sytm_mcoe
stw		[r7],r2
ori		r2,sytm_mcoe
stw		[r7],r2
endm

macro	delay_us	imm_uint16
# delay_us imm16 ; disturbed r0
# delay about imm16[us]
# ldi(2) -> <subi,bne>(3)*(r0-1) -> <subi,bne>(2)
// delay_us: about $(imm_uint16)[us]
ldwi	r0,(($(imm_uint16))*(fcpu/1000)/1000-2-2)/3+1
$(s)// ********************************
$(s)ldbiu	r0,16
$(s)// ********************************
subi	r0,1
bne		pcnt-4
endm
# ================================

// ================================
// setup
// ================================

// set sp to the bottom of ram area
ldwi	r7,idrgramt						// idrg: ram top address
ldw		r7,[r7]
ldwi	r6,idrgrams						// idrg: ram size
ldw		r6,[r6]
add		r7,r6
movtc	sp,r7

// clear variables
ldwi	r7,ramtop
ldwi	r1,static_va
ldbiu	r0,0
st_clrvar:
stw		[r7],r0
addi	r7,2
cmp		r7,r1
blo		st_clrvar

// port setting
ldbiu	r0,dht_sda
ldwi	r7,porsel
stw		[r7],r0
ldwi	r7,porode
stw		[r7],r0
ldwi	r7,porset
stw		[r7],r0
ldwi	r7,pordir
ldw		r0,[r7]
andi	r0,~dht_sda
stw		[r7],r0

// uart setting: RXE, TXE, baud rate
ldwi	r7,uartbaud
ldwi	r0,uart_baud
stw		[r7],r0
ldwi	r7,uartctl
ldbiu	r0,uart_rxe|uart_txe
stw		[r7],r0

// stwser setting: clock speed
ldwi	r0,stws_baud
ldwi	r7,stwmbaud
stw		[r7],r0

// check mulc16 and divc32
ldbiu	r0,1
mov		r1,r0
mulu	r0,r1
cmpi	r0,1
beq		chk_mul_pass
ldwi	r1,lab_str_err_no_mul
jalwr7	print
chk_mul_pass:
ldbiu	r0,1
mov		r1,r0
divu	r0,r1
cmpi	r0,1
beq		chk_div_pass
ldwi	r1,lab_str_err_no_div
jalwr7	print
chk_div_pass:

// initialize lcd1602
$(s)// ********************************
$(s)bra		pcnt+6
$(s)// ********************************
jalwr7	lcd_init

// send RDY
ldwi	r1,lab_str_msg_rdy
jalwr7	print

$(s)// ********************************
$(s)// for simulation
$(s)// setup dummy slave
$(s)ldbiu	r0,i2c_lcdc
$(s)ldwi	r7,stwsadr
$(s)stw		[r7],r0
$(s)// dummy parameter set
$(s)ldwi	r7,dht_ta
$(s)ldwi	r0,316
$(s)stw		[r7],r0
$(s)ldwi	r7,dht_rh
$(s)ldwi	r0,641
$(s)stw		[r7],r0
$(s)ldwi	r7,dht_wbgt
$(s)ldwi	r0,300
$(s)stw		[r7],r0
$(s)ldwi	r7,clk_hh
$(s)ldbiu	r0,12
$(s)stw		[r7],r0
$(s)ldwi	r7,clk_mm
$(s)ldbiu	r0,59
$(s)stw		[r7],r0
$(s)ldwi	r7,clk_ss
$(s)ldbiu	r0,3
$(s)stw		[r7],r0
$(s)// wbgt test
$(s)jalwr7	calc_wbgt
$(s)ldwi	r7,dht_wbgt
$(s)ldw		r0,[r7]
$(s)ldwi	r7,prindec
$(s)stw		[r7],r0
$(s)ldbiu	r0,0
$(s)// simulation finish
$(s)mov		r0,r0
$(s)beq		pcnt+6
$(s)ldwi	r0,simfail
$(s)bra		pcnt+4
$(s)ldwi	r0,simpass
$(s)ldwi	r7,simfnsh
$(s)stw		[r7],r0
$(s)bra		pcnt-2
$(s)// ********************************

// ================================
// loop
// ================================
loop:

// ================================
// serial monitor handling
// check uartctl.RAVL
ldwi	r7,uartctl
ldw		r0,[r7]
andi	r0,uart_ravl
beq		no_data
jalwr7	get_line

// check "clk," command
ldwi	r1,lbuf
ldwi	r2,lab_str_cmd_clk
ldbiu	r5,4
jalwr7	strncmp
mov		r0,r0
bne		clk_notid
// ================================
// clk,<hh>,<mm>,<ss>
ldwi	r1,lbuf
// <hh>
addi	r1,4
jalwr7	atoi
cmpi	r0,24
blo		pcnt+2
ldbiu	r0,0
ldwi	r7,clk_hh
stw		[r7],r0
// check ','
ldb		r0,[r1]
cmpi	r0,chr_cma
bne		err_syntx
// <mm>
addi	r1,1
jalwr7	atoi
cmpi	r0,60
blo	pcnt+2
ldbiu	r0,0
ldwi	r7,clk_mm
stw		[r7],r0
// check ','
ldb		r0,[r1]
cmpi	r0,chr_cma
bne		err_syntx
// <ss>
addi	r1,1
jalwr7	atoi
cmpi	r0,60
blo		pcnt+2
ldbiu	r0,0
ldwi	r7,clk_ss
stw		[r7],r0
// clock
ldwi	r7,clk_msec_next
ldbiu	r0,0
ldwi	r1,1000
stl		[r7],r0,r1
sytm_ofst_ms
// response
// "OK: clk="
ldwi	r1,lab_str_msg_clk
jalwr7	print
pushw	r1
// <hh>
ldwi	r7,clk_hh
ldw		r1,[r7]
jalwr7	print_dec2
// ":"
popw	r1
jalwr7	print
pushw	r1
// <mm>
ldwi	r7,clk_mm
ldw		r1,[r7]
jalwr7	print_dec2
// ":"
popw	r1
jalwr7	print
pushw	r1
// <ss>
ldwi	r7,clk_ss
ldw		r1,[r7]
jalwr7	print_dec2
// "\r\n"
popw	r1
jalwr7	print
bra		no_data
clk_notid:

// check "who" command
ldwi	r1,lbuf
ldwi	r2,lab_str_cmd_who
jalwr7	strcmp
mov		r0,r0
bne		who_notid
// ================================
// who
// response
ldwi	r1,lab_str_msg_who
jalwr7	print
bra		no_data
who_notid:

// check "help" command
ldwi	r1,lbuf
ldwi	r2,lab_str_cmd_help
jalwr7	strcmp
mov		r0,r0
bne		help_notid
// ================================
// help
// response
ldwi	r1,lab_str_msg_help
jalwr7	print_lst
bra		no_data
help_notid:

// ================================
// ignore empty line
ldwi	r1,lbuf
ldb		r0,[r1]
mov		r0,r0
beq		no_data
// ================================
// ERROR: unsupported command
ldwi	r1,lab_str_err_unspt
jalwr7	print
ldwi	r1,lbuf
jalwr7	print
ldwi	r1,lab_str_crlf
jalwr7	print
bra		no_data

// ERROR: syntax
err_syntx:
ldwi	r1,lab_str_err_syntx
jalwr7	print
bra		no_data

no_data:
// end of command interpretation


// ================================
// clock
ldbiu	r4,0							// display clock flag
ldwi	r7,sytmmilh
ldl		r2,r3,[r7]
ldwi	r7,clk_msec_next
ldl		r0,r1,[r7]
cmpl	r2,r3, r0,r1
blo		clk_same_ss
// update next update timing
ldbiu	r4,1							// display clock flag
ldbiu	r2,0
ldwi	r3,1000
addl	r0,r1, r2,r3
stl		[r7],r0,r1
// update clock
ldwi	r7,clk_ss
ldw		r0,[r7]
addi	r0,1
stw		[r7],r0
cmpi	r0,60
blo		clk_same_ss
subi	r0,60
stw		[r7],r0
// mm++
ldwi	r7,clk_mm
ldw		r0,[r7]
addi	r0,1
stw		[r7],r0
cmpi	r0,60
blo		clk_same_ss
subi	r0,60
stw		[r7],r0
// hh++
ldwi	r7,clk_hh
ldw		r0,[r7]
addi	r0,1
stw		[r7],r0
cmpi	r0,24
blo		clk_same_ss
ldbiu	r0,0
stw		[r7],r0
// new day 00:00:00
ldwi	r7,clk_msec_next
ldbiu	r0,0
ldwi	r1,1000
stl		[r7],r0,r1
sytm_ofst_ms

clk_same_ss:

// ================================
// display clock
mov		r4,r4
beq		clk_not_disp
// lcd: line 1
ldwi	r6,lcd_buf+6
ldbiu	r0,chr_spc
stb		[r6],r0
subi	r6,6
// temperature
ldwi	r7,dht_ta
ldw		r1,[r7]
bpl		clk_temp_plus
neg		r1
ldbiu	r0,chr_mns
addi	r6,6
stb		[r6],r0
subi	r6,6
clk_temp_plus:
jalwr7	store_dec_xxdx
// "ßC- "
ldbiu	r0,0aß
stb		[r6],r0
addi	r6,1
ldbiu	r0,(0aC-0x20)
stb		[r6],r0
addi	r6,1
addi	r6,1
ldbiu	r0,chr_spc
stb		[r6],r0
addi	r6,1
// alert
ldwi	r7,dht_wbgt
ldw		r0,[r7]
ldwi	r1,310
cmp		r0,r1
blo		clk_alt1
ldwi	r7,lab_clk_str_dang
bra		clk_alt0
clk_alt1:
ldwi	r1,280
cmp		r0,r1
blo		clk_alt2
ldwi	r7,lab_clk_str_warn
bra		clk_alt0
clk_alt2:
cmpi	r0,250
blo		clk_alt3
ldwi	r7,lab_clk_str_caut
bra		clk_alt0
clk_alt3:
ldwi	r7,lab_clk_str_attn
clk_alt0:
// strcpy [r6++]=[r7++]
clk_loop:
ldb		r0,[r7]
addi	r7,1
stb		[r6],r0
addi	r6,1
mov		r0,r0
bne		clk_loop
subi	r6,1
// wbgt
ldwi	r7,dht_wbgt
ldw		r1,[r7]
mov		r1,r1
bpl		pcnt+2
ldbiu	r1,0
jalwr7	store_dec_xxdx
// lcd print
ldbiu	r0,0
stb		[r6],r0
ldbiu	r0,lcd_line_0
ldwi	r1,lcd_buf
jalwr7	lcd_print

// lcd: line 2
ldwi	r6,lcd_buf
// humidity
ldwi	r7,dht_rh
ldw		r1,[r7]
jalwr7	store_dec_xxdx
// "%RH "
ldbiu	r0,chr_pct
stb		[r6],r0
addi	r6,1
ldbiu	r0,(0aR-0x20)
stb		[r6],r0
addi	r6,1
ldbiu	r0,(0aH-0x20)
stb		[r6],r0
addi	r6,1
ldbiu	r0,chr_spc
stb		[r6],r0
addi	r6,1
// clock hh:mm:ss
ldwi	r7,clk_hh
ldw		r1,[r7]
ldbiu	r0,10
mulu	r1,r0
jalwr7	store_dec_xxdx
subi	r6,2
ldbiu	r0,chr_cln
stb		[r6],r0
addi	r6,1
ldwi	r7,clk_mm
ldw		r1,[r7]
ldbiu	r0,10
mulu	r1,r0
jalwr7	store_dec_xxdx
subi	r6,2
ldbiu	r0,chr_cln
stb		[r6],r0
addi	r6,1
ldwi	r7,clk_ss
ldw		r1,[r7]
ldbiu	r0,10
mulu	r1,r0
jalwr7	store_dec_xxdx
subi	r6,2

// lcd print
ldbiu	r0,0
stb		[r6],r0
ldbiu	r0,lcd_line_1
ldwi	r1,lcd_buf
jalwr7	lcd_print
bra		clk_not_disp

// alert string
clk_str_dang:
dats	"DANG\0"
clk_str_warn:
dats	"WARN\0"
clk_str_caut:
dats	"CAUT\0"
clk_str_attn:
dats	"ATTN\0"

clk_not_disp:

// ================================
// measure dht11 every minute
ldwi	r7,clk_mm
ldw		r0,[r7]
ldwi	r7,dht_prev_mm
ldw		r1,[r7]
cmp		r0,r1
beq		dht_not_meas
stw		[r7],r0
jalwr7	meas_dht11
mov		r0,r0
beq		dht_not_err
ldwi	r1,lab_str_err_meas_dht
jalwr7	print
bra		dht_not_meas
dht_not_err:
// temperature *10[degC]
ldwi	r7,dht_buf+2
ldb		r0,[r7]
exsgw	r0
ldbiu	r1,10
muls	r0,r1
ldwi	r7,dht_ta
stw		[r7],r0
// humidity *10[%RH]
ldwi	r7,dht_buf+0
ldb		r0,[r7]
ldbiu	r1,10
muls	r0,r1
ldwi	r7,dht_rh
stw		[r7],r0
// wbgt
jalwr7	calc_wbgt
dht_not_meas:

// ================================
// end of loop
bra		loop


// ================================
// calculate wbgt
//	wbgt=0.735*Ta + 0.0374*RH + 0.00292*Ta*RH +
//		7.619*SR - 4.557*SR**2 - 0.0572*WS - 4.064
// ================================
calc_wbgt:
// 0.735*Ta (*1k)
ldwi	r7,dht_ta
ldw		r1,[r7]
mov		r1,r1
bpl		pcnt+2
ldbiu	r1,0
ldbiu	r0,0
ldbiu	r2,0
ldwi	r3,735
jalwr7	mulu32
ldbiu	r2,0
ldwi	r3,10
divlu
divlq
pushwm	r0,r1
// 0.0374*RH (*1k)
ldwi	r7,dht_rh
ldw		r1,[r7]
ldbiu	r0,0
ldbiu	r2,0
ldwi	r3,374
jalwr7	mulu32
ldbiu	r2,0
ldwi	r3,100
divlu
divlq
pushwm	r0,r1
// 0.00292*Ta*RH (*1k)
ldwi	r7,dht_ta
ldw		r1,[r7]
mov		r1,r1
bpl		pcnt+2
ldbiu	r1,0
ldbiu	r0,0
ldwi	r7,dht_rh
ldw		r3,[r7]
ldbiu	r2,0
jalwr7	mulu32
ldbiu	r2,0
ldwi	r3,292
jalwr7	mulu32
ldbiu	r2,0
ldwi	r3,10000
divlu
divlq
pushwm	r0,r1
// SR table lookup
ldwi	r7,clk_hh
ldw		r4,[r7]
ldwi	r7,lab_cwb_sr_table
add		r7,r4
add		r7,r4
ldw		r4,[r7]
// 7.619*SR (*1k)
ldbiu	r0,0
mov		r1,r4
ldbiu	r2,0
ldwi	r3,7619
jalwr7	mulu32
ldbiu	r2,0
ldwi	r3,1000
divlu
divlq
pushwm	r0,r1
// -4.557*SR**2 (*1k)
ldbiu	r0,0
mov		r1,r4
ldbiu	r2,0
mov		r3,r4
jalwr7	mulu32
ldbiu	r2,0
ldwi	r3,1000
divlu
divlq
ldbiu	r2,0
ldwi	r3,4557
jalwr7	mulu32
ldbiu	r2,0
ldwi	r3,1000
divlu
divlq
negl	r0,r1
pushwm	r0,r1
// (constant): -0.0572*WS - 4.064 (*1k)
ldlip	r0,r1,wbgt_ofst
// wbgt
rept	5
popwm	r3,r2
addl	r0,r1, r2,r3
endr
ldbiu	r2,0
ldwi	r3,100
divlu
divlq
ldwi	r7,dht_wbgt
stw		[r7],r1
rtnw

// sr data, every hour
cwb_sr_table:
datw	0, 0, 0, 0, 0, 2
datw	26, 79, 188, 308, 414, 489
datw	516, 500, 444, 350, 228, 112
datw	41, 7, 0, 0, 0, 0

// ================================
// store decimal number "xx.x"
//	r1=abs (xx.x*10)
//	r6=pointer to store "xx.x"
// ================================
store_dec_xxdx:
ldwi	r0,1000
cmp		r1,r0
blo		sdx_lo1k
ldbiu	r0,0a1
stb		[r6],r0
addi	r6,1
ldbiu	r0,0a0
stb		[r6],r0
addi	r6,1
stb		[r6],r0
addi	r6,1
ldbiu	r0,chr_dot
stb		[r6],r0
addi	r6,1
rtnw
sdx_lo1k:
// xx.x 10
ldbiu	r0,0
addi	r0,1
subi	r1,100
bhs		pcnt-6
addi	r1,100
subi	r0,1
bne		pcnt+4
ldbiu	r0,chr_spc
bra		pcnt+2
addi	r0,0a0
stb		[r6],r0
addi	r6,1
// xx.x 1
ldbiu	r0,0
addi	r0,1
subi	r1,10
bhs		pcnt-6
addi	r1,10
subi	r0,1
addi	r0,0a0
stb		[r6],r0
addi	r6,1
// xx.x .1
ldbiu	r0,chr_dot
stb		[r6],r0
addi	r6,1
addi	r1,0a0
stb		[r6],r1
addi	r6,1
rtnw

// ================================
// measure dht11
//	received data stored: dht_buf[5]
//		dht_buf[0]: humidity integer
//		dht_buf[1]: humidity decimal
//		dht_buf[2]: temperature integer
//		dht_buf[3]: temperature decimal
//		dht_buf[4]: parity
//	return: r0=0 (no error) / !=0 (on error)
// ================================
meas_dht11:
// clear offset
ldwi	r7,sytmctl
ldw		r0,[r7]
andi	r0,~sytm_mcoe
stw		[r7],r0
// check & wait cycle time
dht_poll:
ldwi	r7,dht_usec_prev
ldl		r2,r3,[r7]
ldwi	r7,sytmmcrh
ldl		r0,r1,[r7]
subl	r0,r1,r2,r3
ldlip	r2,r3,dht_usec_tcyc
cmpl	r0,r1,r2,r3
blo		dht_poll
// send start
sytm_ofst_us
dht_sda_0
// wait tbe
ldwi	r7,sytmmcrl
ldw		r0,[r7]
ldwi	r1,dht_usec_tbe
cmp		r0,r1
blo		pcnt-10
dht_sda_1
// receive response
ldbiu	r0,dht_sda
ldwi	r1,dht_usec_tore
jalwr7	pulse_in_high
cmp		r0,r1
bhs		dht_error_1
bra		dht_noerr_1
// ERROR: could not receive response from dht
dht_error_1:
ldwi	r0,dht_err_resp
bra		dht_return

dht_noerr_1:
// receive 5 bytes
ldwi	r7,dht_idx
ldbiu	r0,0
stw		[r7],r0
dht_loop_idx:
// receive 8 bits
ldwi	r7,dht_idx2
ldbiu	r0,0
stw		[r7],r0
dht_loop_idx2:
// receive 1 bit
ldbiu	r0,dht_sda
ldbiu	r1,dht_usec_toda
jalwr7	pulse_in_high
cmpi	r0,dht_usec_toda
blo		dht_noerr_2
// ERROR: could not receive data from dht
ldwi	r0,dht_err_recv
bra		dht_return

dht_noerr_2:
$(s)// ********************************
$(s)ldwi	r7,prindec
$(s)stb		[r7],r0
$(s)// ********************************
lsfti	r3,1
cmpi	r0,dht_usec_th
blo		pcnt+2
ori		r3,1

// end of loop idx2
ldwi	r7,dht_idx2
ldw		r0,[r7]
addi	r0,1
stw		[r7],r0
cmpi	r0,8
blo		dht_loop_idx2

// store received data
ldwi	r7,dht_idx
ldw		r0,[r7]
ldwi	r7,dht_buf
add		r7,r0
stb		[r7],r3
$(s)// ********************************
$(s)ldwi	r7,prinhex
$(s)stb		[r7],r3
$(s)// ********************************

// end of loop idx
ldwi	r7,dht_idx
ldw		r0,[r7]
addi	r0,1
stw		[r7],r0
cmpi	r0,5
blo		dht_loop_idx

// check integrity
ldbiu	r1,0
ldwi	r7,dht_buf
// sum
rept	4
ldb		r0,[r7]
addi	r7,1
add		r1,r0
endr
// parity
ldb		r0,[r7]
andi	r1,0xff
cmp		r0,r1
beq		dht_noerr_3
// ERROR: parity not match
ldbiu	r0,dht_err_chks
bra		dht_return

dht_noerr_3:
ldbiu	r0,0
dht_return:
// clear offset
ldwi	r7,sytmctl
ldw		r1,[r7]
andi	r1,~sytm_mcoe
stw		[r7],r1
// update dht_usec_prev
ldwi	r7,sytmmcrh
ldl		r2,r3,[r7]
ldwi	r7,dht_usec_prev
stl		[r7],r2,r3
rtnw

// ================================
// pulse in, high level ; disturbed r2,r6,r7,sytmctl[MCOE]
//	r0=input port
//	r1=time out [us]
//	wait port(r0)=0, measure port(r0)=1 time
//	return: r0=high pulse width [us]
//		r0>=r1 (if time out occurred)
// ================================
pulse_in_high:
// wait port(r0)=0
sytm_ofst_us
ldwi	r7,porind
ldwi	r6,sytmmcrl
pih_loop_1:
ldw		r2,[r7]
and		r2,r0
beq		pih_break_1
ldw		r2,[r6]
cmp		r2,r1
blo		pih_loop_1
// ERROR: time out
bra		pih_return
pih_break_1:
// wait port(r0)=1
sytm_ofst_us
ldwi	r7,porind
ldwi	r6,sytmmcrl
pih_loop_2:
ldw		r2,[r7]
and		r2,r0
bne		pih_break_2
ldw		r2,[r6]
cmp		r2,r1
blo		pih_loop_2
// ERROR: time out
bra		pih_return
pih_break_2:
// measure high pulse time [us]
sytm_ofst_us
ldwi	r7,porind
ldwi	r6,sytmmcrl
pih_loop_3:
ldw		r2,[r7]
and		r2,r0
beq		pih_break_3
ldw		r2,[r6]
cmp		r2,r1
blo		pih_loop_3
pih_break_3:
pih_return:
ldw		r0,[r6]
rtnw

// ================================
// lcd_write_nibl ; disturbed tr
//	write 4 bit data to lcdc
//	using general register bank 2
//	parameter:
//		sp+6=rs strobe (0 or 1)
//		sp+4=write data[7:4]
//		sp+2=caller address
//		sp+0=sr backup
//	return:
//		sp+6=error code
// ================================
equ		lcwn_rs,6
equ		lcwn_wdat,4
lcd_write_nibl:
pushc	sr
ldcl	sr,sreg_bk_2
// load parameter: r2=rs
ldbiu	r7,lcwn_rs
ldwsp	r2,[r7]
// copy i2c frame to i2c_buf[]
ldwi	r7,i2c_buf
ldwi	r6,lab_lcwn_i2cf
lcwn_loop:
ldw		r0,[r6]
// set rs strobe
mov		r1,r0
lsfti	r1,-8
cmpi	r1,0x40
bne		pcnt+2
add		r0,r2							// rs(=r2)
stw		[r7],r0
// end of loop
addi	r7,2
addi	r6,2
mov		r0,r0
bne		lcwn_loop
// set data[7:4]
ldbiu	r7,lcwn_wdat
ldwsp	r1,[r7]
andi	r1,0xf0
# 1
ldwi	r7,i2c_buf+4
ldw		r0,[r7]
add		r0,r1
stw		[r7],r0
# 2
addi	r7,2
ldw		r0,[r7]
add		r0,r1
stw		[r7],r0
// i2c transfer
ldwi	r1,i2c_buf
jalwr7	mcvm_wire
// return error code
ldbiu	r7,lcwn_rs
stwsp	[r7],r0
rti

// i2c frame: lcd_write_nibl
lcwn_i2cf:
datw	0x4100+(i2c_lcdc<<1)
datw	0x40f8							// rw=0;	+rs
datw	0x400c							// e=1;		+rs+db[7:4]
datw	0x4008							// e=0;		+rs+db[7:4]
datw	0x40f8							// dbz;
datw	0x0000

// ================================
// lcd_write ; disturbed tr
//	write 8 bit data to lcdc
//	using general register bank 2
//	parameter:
//		sp+2(6)=rs strobe (0 or 1)
//		sp+0(4)=write data[7:0]
//	return:
//		sp+2(6)=error code
//	*) "sp+x(y)": x=an offset before jumping to sub, y=an offset inside sub
// ================================
equ		lcw_rs,6
equ		lcw_wdat,4
lcd_write:
pushc	sr
ldcl	sr,sreg_bk_2
// polling until BF=0
jalwr7	lcd_wait
andi	r0,lcd_bf
beq		lcw_bf_0
// ERROR: bf polling time out
ldwi	r1,lab_str_err_lcd_bfto
jalwr7	print
lcw_bf_0:
// load parameter: r2=rs
ldbiu	r7,lcw_rs
ldwsp	r2,[r7]
// copy i2c frame to i2c_buf[]
ldwi	r7,i2c_buf
ldwi	r6,lab_lcw_i2cf
lcw_loop:
ldw		r0,[r6]
// set rs strobe
mov		r1,r0
lsfti	r1,-8
cmpi	r1,0x40
bne		pcnt+2
add		r0,r2							// rs(=r2)
stw		[r7],r0
// end of loop
addi	r7,2
addi	r6,2
mov		r0,r0
bne		lcw_loop
// set data[7:4]
ldbiu	r6,lcw_wdat
ldwsp	r1,[r6]
andi	r1,0xf0
# 1
ldwi	r7,i2c_buf+4
ldw		r0,[r7]
add		r0,r1
stw		[r7],r0
# 2
addi	r7,2
ldw		r0,[r7]
add		r0,r1
stw		[r7],r0
// set data[3:0]
#ldbiu	r6,lcw_wdat
ldwsp	r1,[r6]
lsfti	r1,4
andi	r1,0xf0
# 1
addi	r7,2
ldw		r0,[r7]
add		r0,r1
stw		[r7],r0
# 2
addi	r7,2
ldw		r0,[r7]
add		r0,r1
stw		[r7],r0
// i2c transfer
ldwi	r1,i2c_buf
jalwr7	mcvm_wire
// return error code
ldbiu	r7,lcw_rs
stwsp	[r7],r0
rti

// i2c frame: lcd_write
lcw_i2cf:
datw	0x4100+(i2c_lcdc<<1)
datw	0x40F8							// rw=0;	+rs
datw	0x400C							// e=1;		+rs+db[7:4]
datw	0x4008							// e=0;		+rs+db[7:4]
datw	0x400C							// e=1;		+rs+db[3:0]
datw	0x4008							// e=0;		+rs+db[3:0]
datw	0x40F8							// dbz;
datw	0x0000

// ================================
// lcd_read ; disturbed tr
//	write 8 bit data to lcdc
//	using general register bank 2
//	parameter:
//		sp+0(4)=rs strobe (0 or 1)
//	return:
//		sp+0(4)=read data[7:0]
//	*) "sp+x(y)": x=an offset before jumping to sub, y=an offset inside sub
// ================================
equ		lcr_rs,4
lcd_read:
pushc	sr
ldcl	sr,sreg_bk_2
// load parameter: r2=rs
ldbiu	r7,lcr_rs
ldwsp	r2,[r7]
// copy i2c frame to i2c_buf[]
ldwi	r7,i2c_buf
ldwi	r6,lab_lcr_i2cf
lcr_loop:
ldw		r0,[r6]
// set rs strobe
mov		r1,r0
lsfti	r1,-8
cmpi	r1,0x40
bne		pcnt+2
add		r0,r2							// rs(=r2)
stw		[r7],r0
// end of loop
addi	r7,2
addi	r6,2
mov		r0,r0
bne		lcr_loop
// i2c transfer
ldwi	r1,i2c_buf
jalwr7	mcvm_wire
mov		r0,r0
bne		lcr_error
// get read data[7:0]
ldwi	r7,i2c_buf+8
ldw		r0,[r7]
andi	r0,0xf0
addi	r7,10
ldw		r1,[r7]
andi	r1,0xf0
lsfti	r1,-4
// return error code
lcr_error:
ldwi	r1,0x8000
lcr_return:
or		r0,r1
ldbiu	r7,lcr_rs
stwsp	[r7],r0
rti

// i2c frame: lcd_read
lcr_i2cf:
datw	0x4100+(i2c_lcdc<<1)
datw	0x40fa							// rw=1;	+rs
datw	0x40fe							// e=1;		+rs
datw	0x4101+(i2c_lcdc<<1)
datw	0x8200							// read db[7:4]
datw	0x4100+(i2c_lcdc<<1)
datw	0x40fa							// e=0;		+rs
datw	0x40fe							// e=1;		+rs
datw	0x4101+(i2c_lcdc<<1)
datw	0x8200							// read db[3:0]
datw	0x4100+(i2c_lcdc<<1)
datw	0x40fa							// e=0;		+rs
datw	0x0000

// ================================
// lcd_wait ; disturbed r0,r1,r7
//	return: r0=lcd status register
// ================================
lcd_wait:
ldbiu	r1,0
lwt_loop:
ldbiu	r0,lcd_rs_inst
pushw	r0
jalwr7	lcd_read
popw	r0
addi	r1,1
beq		lwt_break
andi	r0,lcd_bf
bne		lwt_loop
lwt_break:
rtnw

// ================================
// lcd_init
//	initialize lcd1602
// ================================
lcd_init:
// set 8 bit bus
ldbiu	r0,lcd_rs_inst
pushw	r0
ldbiu	r0,lcd_func_set+0x18
pushw	r0
jalwr7	lcd_write_nibl
popwm	r0,r0
// delay (1)G
delay_us	1000
// set 8 bit bus
ldbiu	r0,lcd_rs_inst
pushw	r0
ldbiu	r0,lcd_func_set+0x18
pushw	r0
jalwr7	lcd_write_nibl
popwm	r0,r0
// delay (1)G
delay_us	1000
// set 4 bit bus
ldbiu	r0,lcd_rs_inst
pushw	r0
ldbiu	r0,lcd_func_set+0x08
pushw	r0
jalwr7	lcd_write_nibl
popwm	r0,r0
// delay (1)G
delay_us	1000
//
// set 4 bit bus, 2 lines
ldbiu	r0,lcd_rs_inst
pushw	r0
ldbiu	r0,lcd_func_set+0x08
pushw	r0
jalwr7	lcd_write
popwm	r0,r0
// clear display
ldbiu	r0,lcd_rs_inst
pushw	r0
ldbiu	r0,lcd_clear
pushw	r0
jalwr7	lcd_write
popwm	r0,r0
// return home
ldbiu	r0,lcd_rs_inst
pushw	r0
ldbiu	r0,lcd_rtn_home
pushw	r0
jalwr7	lcd_write
popwm	r0,r0
// entry +1 (right)
ldbiu	r0,lcd_rs_inst
pushw	r0
ldbiu	r0,lcd_ent_mode+0x02
pushw	r0
jalwr7	lcd_write
popwm	r0,r0
// disp on, cur off
ldbiu	r0,lcd_rs_inst
pushw	r0
ldbiu	r0,lcd_disp_cur+0x04
pushw	r0
jalwr7	lcd_write
popwm	r0,r0
rtnw

// ================================
// lcd_print ; disturbed r1,r2,r7
//	print string to lcd1602
//	parameter:
//		r0=line number to print, should be 0 or 1
//		r1=pointer to the string
//	return:
//		r0=error code
// ================================
lcd_print:
$(s)ldwi	r7,princhr
$(s)ldb		r0,[r1]
$(s)addi	r1,1
$(s)mov		r2,r0
$(s)bne		pcnt+2
$(s)ldbiu	r2,chr_lf
$(s)stw		[r7],r2
$(s)mov		r0,r0
$(s)bne		pcnt-16
$(s)rtnw
// set ddram address
ldbiu	r2,lcd_rs_inst
pushw	r2
ldbiu	r2,lcd_set_dra
mov		r0,r0
beq		pcnt+2
addi	r2,0x40
pushw	r2
jalwr7	lcd_write
popwm	r0,r0
mov		r0,r0
bne		lpr_return
// write to ddram
lpr_loop:
ldbiu	r0,lcd_rs_data
pushw	r0
ldb		r0,[r1]
addi	r1,1
mov		r0,r0
bne		lpr_not_nil
// end of string
popw	r0
bra		lpr_break
lpr_not_nil:
pushw	r0
jalwr7	lcd_write
popwm	r0,r0
bra		lpr_loop
lpr_break:
ldbiu	r0,0

lpr_return:
rtnw


// ================================
// get line from uart ; disturbed r0,r5~r7
// ================================
get_line:
ldwi	r7,uartrdat
ldwi	r6,uartctl
ldwi	r5,lbuf
gl_loop:
// polling until RAVL=1
ldw		r0,[r6]
andi	r0,uart_ravl
beq		gl_loop
// get byte
ldw		r0,[r7]
stb		[r5],r0
addi	r5,1
// LF code check
cmpi	r0,chr_lf
beq		gl_got
// size check
ldwi	r0,lbuf+max_lbuf-1
cmp		r5,r0
blo		gl_loop
// got line
gl_got:
// string terminate
ldbiu	r0,0
subi	r5,1
stb		[r5],r0
// CR code check
subi	r5,1
ldb		r0,[r5]
cmpi	r0,chr_cr
bne		gl_notcr
ldbiu	r0,0
stb		[r5],r0
gl_notcr:
rtnw

// ================================
// print r1 ; disturbed r0~r2,r6,r7
// ================================
print:
ldwi	r7,uarttdat
ldwi	r6,uartctl
pr_loop:
// get 1 byte
ldb		r2,[r1]
addi	r1,1
mov		r2,r2
beq		pr_finish
$(s)// ********************************
$(s)ldwi	r7,princhr
$(s)stw		[r7],r2
$(s)bra		pr_loop
$(s)// ********************************
// polling uartctl.TFUL=0
pr_poll:
ldw		r0,[r6]
andi	r0,uart_tful
bne		pr_poll
// send data
stw		[r7],r2
bra		pr_loop
pr_finish:
rtnw

// ================================
// print_lst r1 ; disturbed r0~r2,r6,r7
// ================================
print_lst:
jalwr7	print
ldb		r0,[r1]
mov		r0,r0
bne		print_lst
rtnw

// ================================
// print_hex r1 ; disturbed r0~r7
//		print r1 as 4 digits hexadecimal number
// ================================
print_hex:
ldbiu	r3,4
ldwi	r7,uarttdat
ldwi	r6,uartctl
ldwi	r5,lab_ph_hexdig
ph_loop:
// print nibble
mov		r0,r1
mov		r4,r5
lsfti	r0,-12
andi	r0,0x0f
add		r4,r0
ldb		r2,[r4]
// polling uartctl.TFUL=0
ph_poll:
ldw		r0,[r6]
andi	r0,uart_tful
bne		ph_poll
// send data
stw		[r7],r2
// loop
lsfti	r1,4
subi	r3,1
bne		ph_loop
rtnw

ph_hexdig:
dats	"0123456789abcdef"

// ================================
// print_chr r1 ; disturbed r0,r7
// ================================
print_chr:
$(s)// ********************************
$(s)ldwi	r7,princhr
$(s)stw		[r7],r1
$(s)rtnw
$(s)// ********************************
// polling uartctl.TFUL=0
ldwi	r7,uartctl
pc_poll:
ldw		r0,[r7]
andi	r0,uart_tful
bne		pc_poll
// send data
ldwi	r7,uarttdat
stw		[r7],r1
rtnw

// ================================
// print decimal2 r1 ; disturbed r0~r4,r6,r7
// ================================
print_dec2:
mov		r1,r1
bne		pdc_not_0
// 00
ldbiu	r1,0a0
jalwr7	print_chr
jalwr7	print_chr
bra		pdc_fin

pdc_not_0:
// for each r0=10, 1
ldwi	r6,lab_pdc_tab
ldbiu	r3,false						// omit leading zero flag
pdc_loop:
ldw		r0,[r6]
mov		r0,r0
beq		pdc_fin
// r2=r1/r0
ldbiu	r2,0
pdc_div:
sub		r1,r0
blo		pcnt+4
addi	r2,1
bra		pdc_div

// omit leading zero
mov		r3,r3
beq		pcnt+4
mov		r2,r2
beq		pdc_omit
// print 1 digit
addi	r2,0a0
pushwm	r0,r1,r7
mov		r1,r2
jalwr7	print_chr
popwm	r7,r1,r0
ldbiu	r3,false
pdc_omit:
// add back r1; loop
add		r1,r0
addi	r6,2
bra		pdc_loop

pdc_fin:
rtnw

pdc_tab:
datw	10,1,0

// ================================
// string compare: r0=strcmp (r1,r2) ; disturbed r1~r4
// ================================
strcmp:
ldb		r3,[r1]
addi	r1,1
ldb		r4,[r2]
addi	r2,1
mov		r0,r3
sub		r0,r4
bne		sc_finish
// check nil code
mov		r3,r3
beq		sc_finish
mov		r4,r4
bne		strcmp
sc_finish:
rtnw

// ================================
// string n compare: r0=strncmp (r1,r2,r5) ; disturbed r1~r5
// ================================
strncmp:
ldb		r3,[r1]
addi	r1,1
ldb		r4,[r2]
addi	r2,1
mov		r0,r3
sub		r0,r4
bne		snc_finish
// check n character
subi	r5,1
beq		snc_finish
// check nil code
mov		r3,r3
beq		snc_finish
mov		r4,r4
bne		strncmp
snc_finish:
rtnw

// ================================
// ascii to integer: r0=atoi (r1)>=0 ; disturbed r1~r3
// ================================
atoi:
ldbiu	r0,0
// r2=[r1]-'0'
ldb		r2,[r1]
subi	r2,0a0
blo		a2i_finish
cmpi	r2,10
bhs		a2i_finish
// r0=10*r0+r2
mov		r3,r0
lsfti	r3,3
add		r0,r0
add		r0,r3
add		r0,r2
// loop
addi	r1,1
bra		atoi+2
a2i_finish:
rtnw

// ================================
// unsigned 32*32=32 bits multiply routine:
//		r0:r1=r0:r1*r2:r3 ; disturbed r2,r3,sr[ML]
// ================================
#			r0:r1
#			r2:r3
#		*)-------
#			r3:r1	: 3) ML=1
#		 r3:r0		: 1) ML=0
#		 r1:r2		: 2) ML=0
#	  r0:r2			: not calculate
#	+)-----------
#			r0:r1	: 4)
# ================================
mulu32:
clsr	sreg_b_ml						// ML=0
mulu	r0,r3							// 1)
mulu	r2,r1							// 2)
sesr	sreg_b_ml						// ML=1
mulu	r1,r3							// 3)
add		r0,r2							// 4)
add		r0,r3
rtnw

// ================================
// c string data
// ================================
str_msg_who:
dats	"OK: $(prog_name) ver.$(prog_vers)\r\n\0"
str_msg_rdy:
dats	"RDY\r\n\0"
str_msg_help:
dats	"OK+ clk,<hh>,<mm>,<ss>\r\n"
dats	"OK+ who\r\n"
dats	"OK: help\r\n\0\0"
str_msg_clk:
dats	"OK: clk=\0:\0:\0\r\n\0"
str_err_unspt:
dats	"ERR: unsupported command: \0"
str_err_syntx:
dats	"ERR: syntax\r\n\0"
str_err_no_mul:
dats	"ERR: no mulc16\r\n\0"
str_err_no_div:
dats	"ERR: no divc32\r\n\0"
str_err_meas_dht:
dats	"ERR: measure dht11\r\n\0"
str_err_lcd_bfto:
dats	"ERR: bf time out\r\n\0"
str_cmd_clk:
dats	"clk,\0"
str_cmd_who:
dats	"who\0"
str_cmd_help:
dats	"help\0"
str_crlf:
dats	"\r\n\0"

# ================================
incl	"mcvm_lib_wire_m.incl"

