// ================================
// measure dht11
//		(c) 2021	1YEN Toru
//
//
//		2021/09/11	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"
# ================================
# string macros
def		prog_name,"meas_dht11"
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		chr_lf,0x0a						// lf code
equ		chr_cr,0x0d						// cr code
equ		chr_spc,0x20					// space ' ' code
equ		chr_cma,0x2c					// comma ',' code
equ		chr_mns,0x2d					// minus '-' 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
# 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		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		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
# ================================

// ================================
// setup
// ================================

// set sp to the bottom of ram area
ldwi	r7,idrgramt						// idrg: ram top addr.
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

// send RDY
ldwi	r1,lab_str_msg_rdy
jalwr7	print

$(s)// ********************************
$(s)// for simulation
$(s)//	need dht11 behavior in the stimulus
$(s)equ		dht_usec_tbe,10
$(s)equ		dht_usec_tore,100
$(s)equ		dht_usec_toda,100
$(s)equ		dht_usec_tcyc,2
$(s)jalwr7	req_cmnd
$(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 "req" command
ldwi	r1,lbuf
ldwi	r2,lab_str_cmd_req
ldbiu	r5,3
jalwr7	strncmp
mov		r0,r0
bne		req_notid
// ================================
// req
req_cmnd:
jalwr7	meas_dht11
// response
req_response:
mov		r0,r0
bne		req_error
// OK,
ldwi	r1,lab_str_msg_req
jalwr7	print
pushw	r1
// temperature integer
ldwi	r7,dht_buf+2
ldb		r1,[r7]
exsgw	r1
bpl		req_posi
neg		r1
pushw	r1
ldbiu	r1,chr_mns
jalwr7	print_chr
popw	r1
req_posi:
jalwr7	print_dec3
// period (.)
popw	r1
jalwr7	print
pushw	r1
// temperature decimal
ldwi	r7,dht_buf+3
ldb		r1,[r7]
addi	r1,0a0
jalwr7	print_chr
// comma (,)
popw	r1
jalwr7	print
pushw	r1
// humidity integer
ldwi	r7,dht_buf+0
ldb		r1,[r7]
jalwr7	print_dec3
// period (.)
popw	r1
jalwr7	print
pushw	r1
// humidity decimal
ldwi	r7,dht_buf+1
ldb		r1,[r7]
addi	r1,0a0
jalwr7	print_chr
// cr+lf
popw	r1
jalwr7	print
bra		req_endif

req_error:
// ERROR:
pushw	r0
// ERR,
ldwi	r1,lab_str_err_req
jalwr7	print
// error code (r0)
popw	r0
pushw	r1
mov		r1,r0
jalwr7	print_dec3
// cr+lf
popw	r1
jalwr7	print
req_endif:
bra		no_data
req_notid:

// check "rrq" command
ldwi	r1,lbuf
ldwi	r2,lab_str_cmd_rrq
ldbiu	r5,3
jalwr7	strncmp
mov		r0,r0
bne		rrq_notid
// ================================
// rrq
jalwr7	meas_dht11
bra		req_cmnd
rrq_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


// ================================
// end of loop
$(s)// ********************************
$(s)rtnw
$(s)// ********************************
bra		loop


// ================================
// 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


// ================================
// 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
// check CR code
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_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 decimal3 r1 ; disturbed r0~r4,r6,r7
// ================================
print_dec3:
mov		r1,r1
bne		pdc_not_0
// 0
ldbiu	r1,0a0
jalwr7	print_chr
bra		pdc_fin

pdc_not_0:
// for each r0=100, 10, 1
ldwi	r6,lab_pdc_tab
ldbiu	r3,true							// 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	100,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

// ================================
// 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+ req\r\n"
dats	"OK+ rrq\r\n"
dats	"OK+ who\r\n"
dats	"OK: help\r\n\0\0"
str_msg_req:
dats	"OK,\0.\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_req:
dats	"ERR,\0\r\n\0"
str_cmd_req:
dats	"req\0"
str_cmd_rrq:
dats	"rrq\0"
str_cmd_who:
dats	"who\0"
str_cmd_help:
dats	"help\0"
str_crlf:
dats	"\r\n\0"

