// ================================
// Moscovium + ESP32 SMTP mail
//		(c) 2021	1YEN Toru
//
//
//		2024/01/27	ver.1.02
//			brush up
//
//		2021/11/20	ver.1.00
//
// ================================
asm		"mcoc_irom_8k.mif"
#asm		"mcoc_irom.mem"
#asm		"mcoc_irom.dat2",bit16,list
romsiz	8192
incl	"mcoc115.incl"
incl	"mcvm_mcr_long.incl"
# ================================
# string macros
def		prog_name,"smtp_mail"
def		prog_vers,"1.02"
def		s,"#"							// simulation="" / real fpga="#"
def		d,""							// show debug="" / not="#"
# smtp definitions
#def	smtp_host,"smtp.xxxx.com"		// smtp: server name
#def	smtp_port,"465"					// smtp: port name
#def	smtp_upwd,"AHVzZXIAcHdk"		// smtp: base64("\0user\0pwd")
#def	smtp_from,"from.addr@xxxx.com"	// smtp: "From:" mail address
#def	smtp_toad,"to.addr@xxxx.com"	// smtp: "To:" mail address
incl	"smtp_mail.incl"
# constants
equ		max_lbuf,128					// size of lbuf
equ		max_smtp,128					// smtp: mail buffer size
equ		baud,9600						// baud rate
equ		uart_baud,fcpu/baud-1			// uartbaud setting
equ		baud_esp,115200					// esp32: baud rate
equ		uart_baud_esp,fcpu/baud_esp-1	// esp32: uartbaud setting
equ		chr_lf,0x0a						// lf code
equ		chr_cr,0x0d						// cr code
equ		chr_spc,0x20					// space ' ' code
equ		chr_pls,0x2b					// plus '+' code
equ		chr_cma,0x2c					// comma ',' code
#equ		esp_msec_tout,20000				// esp32: response time out [ms]
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		esp_ewr_idx,va					// esp32: response list code (0~)
equ		va,va+2
equ		path_ptr,va						// path: write pointer to lbuf
equ		va,va+2
equ		smtp_rtncod,va					// smtp: return code
equ		va,va+2
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		esp_lbuf,va						// esp32: line buffer
equ		va,va+max_lbuf
equ		smtp_upwd,va					// smtp: base64(\0user\0pwd)
equ		va,va+max_smtp
equ		smtp_date,va					// smtp: Date: buffer
equ		va,va+max_smtp
equ		smtp_from,va					// smtp: From: buffer
equ		va,va+max_smtp
equ		smtp_toad,va					// smtp: To: buffer
equ		va,va+max_smtp
equ		smtp_body,va					// smtp: additional mail body
equ		va,va+max_smtp
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_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
ldbiu	r0,dht_sda|led_builtin
ldwi	r7,porset
stw		[r7],r0
ldwi	r7,pordir
ldw		r0,[r7]
andi	r0,~(dht_sda|led_builtin)
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

// uart#1 setting: RXE, TXE, baud rate
ldwi	r7,uartbaud1
ldwi	r0,uart_baud_esp
stw		[r7],r0
ldwi	r7,uartctl1
ldbiu	r0,uart_rxe|uart_txe
stw		[r7],r0

// esp32
ldwi	r1,lab_str_msg_esp_init
jalwr7	print
// at+rst (reset)
ldwi	r1,lab_str_atc_rst
ldwi	r2,lab_str_res_rst
jalwr7	esp_cast_at
mov		r0,r0
beq		eit_pass
// esp32 init error
ldwi	r1,lab_str_err_esp_init
jalwr7	print
bra		eit_end

eit_pass:
// at+sntpconfig (sntp config)
ldwi	r1,lab_str_atc_cipsntpcfg
ldwi	r2,lab_str_res_atc
jalwr7	esp_cast_at
// at+cipmux (single connection mode)
ldwi	r1,lab_str_atc_cipmux
ldwi	r2,lab_str_res_atc
jalwr7	esp_cast_at
// at+cipmode (pass through mode)
ldwi	r1,lab_str_atc_cipmode
ldwi	r2,lab_str_res_atc
jalwr7	esp_cast_at
// at+gmr (at-firmware version)
ldwi	r1,lab_str_atc_gmr
ldwi	r2,lab_str_res_atc
jalwr7	esp_cast_at
// at+cipsta? (query ip address)
ldwi	r1,lab_str_atc_cipstaq
ldwi	r2,lab_str_res_atc
jalwr7	esp_cast_at
// esp32 init done
ldwi	r1,lab_str_msg_esp_init_done
jalwr7	print
eit_end:

// send RDY
ldwi	r1,lab_str_msg_rdy
jalwr7	print

$(s)// ********************************
$(s)// for simulation
$(s)// result_dht11 test
$(s)ldwi	r7,dht_buf
$(s)ldwi	r0,(59<<8)+0
$(s)stw		[r7],r0
$(s)ldwi	r7,dht_buf+2
$(s)ldwi	r0,(25<<8)+1
$(s)stw		[r7],r0
$(s)jalwr7	result_dht11
$(s)ldwi	r1,lbuf
$(s)jalwr7	print
$(s)ldbiu	r0,0
$(s)// simulation finish
$(s)cmpi	r0,0
$(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|uart_brdf
beq		no_data
jalwr7	get_line

// check "smtp" command
ldwi	r1,lbuf
ldwi	r2,lab_str_cmd_smtp
ldbiu	r5,4
jalwr7	strncmp
mov		r0,r0
bne		smtp_notid
// ================================
// smtp[,<base64(\"\0user\0pwd\")>]
ldwi	r1,smtp_upwd
ldwi	r2,lab_str_smtp_upwd
jalwr7	strcpy
// check ','
ldwi	r7,lbuf+4
ldb		r0,[r7]
cmpi	r0,chr_cma
bne		smtp_no_comma
// has parameter
ldwi	r1,smtp_upwd
ldwi	r2,lbuf+5
jalwr7	strcpy
smtp_no_comma:
// check smtp_upwd
ldwi	r7,smtp_upwd
ldb		r0,[r7]
cmpi	r0,0x00
bne		smtp_has_upwd
// ERROR:
ldwi	r1,lab_str_err_upwd
jalwr7	print
bra		no_data
smtp_has_upwd:
jalwr7	smtp_head
jalwr7	smtp_send
// response
mov		r0,r0
beq		pcnt+6
ldwi	r1,lab_str_err_smtp
bra		pcnt+4
ldwi	r1,lab_str_msg_smtp
jalwr7	print
bra		no_data
smtp_notid:

// check "path" command
ldwi	r1,lbuf
ldwi	r2,lab_str_cmd_path
jalwr7	strcmp
mov		r0,r0
bne		path_notid
// ================================
// path
jalwr7	esp_passthru
// response
ldwi	r1,lab_str_msg_path
jalwr7	print
bra		no_data
path_notid:

// check "dht11" command
ldwi	r1,lbuf
ldwi	r2,lab_str_cmd_dht11
jalwr7	strcmp
mov		r0,r0
bne		dht11_notid
// ================================
// dht11
jalwr7	meas_dht11
jalwr7	meas_dht11
mov		r0,r0
beq		dht11_meas_ok
// ERROR:
ldwi	r1,lab_str_err_dht11
jalwr7	print
bra		no_data
dht11_meas_ok:
jalwr7	result_dht11
// response
ldwi	r1,lbuf
jalwr7	print
bra		no_data
dht11_notid:

// check "who" command
ldwi	r1,lbuf
ldwi	r2,lab_str_cmd_who
jalwr7	strcmp
cmpi	r0,0
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
cmpi	r0,0
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]
cmpi	r0,0
beq		no_data
// ================================
// ERROR: unsupported command
ldwi	r1,lab_str_err_unspt
jalwr7	print
pushw	r1
ldwi	r1,lbuf
jalwr7	print
popw	r1
jalwr7	print
bra		no_data

// ERROR: syntax
err_syntx:
ldwi	r1,lab_str_err_syntx
jalwr7	print
bra		no_data

// end of command interpretation
no_data:


// ================================
// redirect uart#1 (esp32) to uart#0 (serial monitor)
// check RAVL1
ldwi	r7,uartctl1
ldw		r0,[r7]
andi	r0,uart_ravl
beq		rdir_not_ravl
// get line (redirect)
jalwr7	esp_get_line
rdir_not_ravl:


// ================================
// end of loop
bra		loop


// ================================
// result of dht11 measurement ; disturbed r0~r4,r6,r7
//	data stored in lbuf[]
// ================================
result_dht11:
ldwi	r1,lbuf
ldwi	r2,lab_str_msg_dht11
jalwr7	strcpy
pushw	r2
ldwi	r7,dht_buf+2					// temperature int
ldb		r2,[r7]
jalwr7	strcpy_dec3
popw	r2
jalwr7	strcpy
pushw	r2
ldwi	r7,dht_buf+3					// temperature dec
ldb		r2,[r7]
jalwr7	strcpy_dec3
popw	r2
jalwr7	strcpy
pushw	r2
ldwi	r7,dht_buf+0					// humidity int
ldb		r2,[r7]
jalwr7	strcpy_dec3
popw	r2
jalwr7	strcpy
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


// ================================
// smtp communication routines
// ================================
// ================================
// smtp generate header ; disturbed r0~r3,r5~r7
// ================================
smtp_head:
// sntp time
ldwi	r1,lab_str_atc_sntptime
ldwi	r2,lab_str_res_sntp
jalwr7	esp_cast_at
cmpi	r0,1
beq		smhd_time
// ERROR:
ldwi	r7,smtp_date
ldbiu	r0,0
stb		[r7],r0
bra		smhd_from

smhd_time:
// strcpy (lbuf,esp_lbuf)
ldwi	r1,lbuf
ldwi	r2,esp_lbuf
jalwr7	strcpy
// discard ok response
smhd_dscd_ok:
ldwi	r1,lab_str_res_sntp
jalwr7	esp_wait_response
cmpi	r0,0
bne		smhd_dscd_ok
// lbuf[]="+CIPSNTPTIME:www mmm dd HH:MM:SS yyyy"
// ________0123456789_123456789_123456789_123456789
ldbiu	r0,0
ldwi	r7,lbuf+16
stb		[r7],r0
ldwi	r7,lbuf+20
stb		[r7],r0
ldwi	r7,lbuf+23
stb		[r7],r0
ldwi	r7,lbuf+32
stb		[r7],r0
ldwi	r7,lbuf+37
stb		[r7],r0

// Date:
ldwi	r1,smtp_date
// "Date: "
ldwi	r2,lab_str_head_date
jalwr7	strcpy
// "www"
pushw	r2
ldwi	r2,lbuf+13
jalwr7	strcpy
// ", "
popw	r2
jalwr7	strcpy
// "dd"
pushw	r2
ldwi	r2,lbuf+21
jalwr7	strcpy
// " "
popw	r2
jalwr7	strcpy
// "mmm"
pushw	r2
ldwi	r2,lbuf+17
jalwr7	strcpy
// " "
popw	r2
jalwr7	strcpy
// "yyyy"
pushw	r2
ldwi	r2,lbuf+33
jalwr7	strcpy
// " "
popw	r2
jalwr7	strcpy
// "HH:MM:SS"
pushw	r2
ldwi	r2,lbuf+24
jalwr7	strcpy
// " +0900 (JST)"
popw	r2
jalwr7	strcpy

smhd_from:
// From:
ldwi	r1,smtp_from
// "From: <"
ldwi	r2,lab_str_head_from
jalwr7	strcpy
// "$(smtp_from)"
pushw	r2
ldwi	r2,lab_str_smtp_from
jalwr7	strcpy
// ">"
popw	r2
jalwr7	strcpy

// To:
ldwi	r1,smtp_toad
// "To: <"
ldwi	r2,lab_str_head_toad
jalwr7	strcpy
// "$(smtp_toad)"
pushw	r2
ldwi	r2,lab_str_smtp_toad
jalwr7	strcpy
// ">"
popw	r2
jalwr7	strcpy

// additional mail body
ldwi	r7,smtp_body
ldbiu	r0,0
stb		[r7],r0
// measure
jalwr7	meas_dht11
jalwr7	meas_dht11
// result
mov		r0,r0
bne		smhd_meas_err
jalwr7	result_dht11
ldwi	r1,smtp_body
ldwi	r2,lbuf
jalwr7	strcpy
smhd_meas_err:

rtnw

// ================================
// smtp send mail ; disturbed r1~r3,r5~r7,sytmctl[MLOE]
//	return: r0=0 (no error) / 255 (on error)
// ================================
smtp_send:
ldwi	r7,smtp_rtncod
ldbiu	r0,0
stw		[r7],r0
// at+cipstart (smtp connect)
ldwi	r1,lab_str_atc_cipstart
ldwi	r2,lab_str_res_start
jalwr7	esp_cast_at
cmpi	r0,2
beq		smsd_connected
// ERROR: not "CONNECT" response
smsd_loop1:
cmpi	r0,2
blo		smsd_break1
ldwi	r1,lab_str_res_start
jalwr7	esp_wait_response
bra		smsd_loop1
smsd_break1:
// message
ldwi	r1,lab_str_err_esp_start
jalwr7	print
// return code
ldwi	r7,smtp_rtncod
ldbiu	r0,255
stw		[r7],r0
bra		smsd_return

smsd_connected:
// discard "OK" message
ldwi	r1,lab_str_res_start
jalwr7	esp_wait_response

// ================================
// enter pass through mode
// at+cipsend (enter pass through mode)
ldwi	r1,lab_str_atc_cipsend
ldwi	r2,lab_str_res_atc
jalwr7	esp_cast_at
mov		r0,r0
beq		smsd_enter_path
// ERROR:
ldwi	r1,lab_str_err_esp_path
jalwr7	print
ldwi	r7,smtp_rtncod
ldbiu	r0,255
stw		[r7],r0
bra		smsd_return

smsd_enter_path:
// clear receiving data (wrap return ">" and greeting if received)
ldwi	r1,500
jalwr7	delay
smsd_loop2:
// check RAVL1
ldwi	r7,uartctl1
ldw		r0,[r7]
andi	r0,uart_ravl
beq		smsd_break2
// receive and discard a byte
ldwi	r7,uartrdat1
ldw		r0,[r7]
bra		smsd_loop2
smsd_break2:

// ================================
// smtp session
// ehlo
ldwi	r1,lab_str_smcm_ehlo
jalwr7	esp_print
jalwr7	smtp_get_response
lsfti	r0,-8
cmpi	r0,0x02
beq		smsd_ehlo_ok
// ERROR:
ldwi	r1,lab_str_err_smtp_ehlo
jalwr7	print
ldbiu	r0,255
bra		smsd_quit_close
smsd_ehlo_ok:

// auth plain
ldwi	r1,lab_str_smcm_auth
jalwr7	esp_print
pushw	r1
ldwi	r1,smtp_upwd
jalwr7	esp_print
popw	r1
jalwr7	esp_print
jalwr7	smtp_get_response
lsfti	r0,-8
cmpi	r0,0x02
beq		smsd_auth_ok
// ERROR:
ldwi	r1,lab_str_err_smtp_auth
jalwr7	print
ldbiu	r0,255
bra		smsd_quit_close
smsd_auth_ok:

// ================================
// mail
ldwi	r1,lab_str_smcm_mail
jalwr7	esp_print
pushw	r1
ldwi	r1,lab_str_smtp_from
jalwr7	esp_print
popw	r1
jalwr7	esp_print
jalwr7	smtp_get_response
lsfti	r0,-8
cmpi	r0,0x02
beq		smsd_mail_ok
// ERROR:
ldwi	r1,lab_str_err_smtp_mail
jalwr7	print
ldbiu	r0,255
bra		smsd_quit_close
smsd_mail_ok:

// rcpt
ldwi	r1,lab_str_smcm_rcpt
jalwr7	esp_print
pushw	r1
ldwi	r1,lab_str_smtp_toad
jalwr7	esp_print
popw	r1
jalwr7	esp_print
jalwr7	smtp_get_response
lsfti	r0,-8
cmpi	r0,0x02
beq		smsd_rcpt_ok
// ERROR:
ldwi	r1,lab_str_err_smtp_rcpt
jalwr7	print
ldbiu	r0,255
bra		smsd_quit_close
smsd_rcpt_ok:

// data~.
ldwi	r1,lab_str_smcm_data
jalwr7	esp_print
pushw	r1
jalwr7	smtp_get_response
lsfti	r0,-8
cmpi	r0,0x03
beq		smsd_data_ok
// ERROR:
ldwi	r1,lab_str_err_smtp_data
jalwr7	print
ldbiu	r0,255
bra		smsd_quit_close
smsd_data_ok:
// header and body
ldwi	r1,smtp_date
jalwr7	esp_print
ldwi	r1,smtp_from
jalwr7	esp_print
ldwi	r1,smtp_toad
jalwr7	esp_print
ldwi	r1,lab_str_smtp_mail
smsd_data_loop:
jalwr7	esp_print
ldb		r0,[r1]
mov		r0,r0
bne		smsd_data_loop
// additional body
ldwi	r1,smtp_body
jalwr7	esp_print
// data end (.)
popw	r1
jalwr7	esp_print
jalwr7	smtp_get_response

// ================================
// no error
ldbiu	r0,0
smsd_quit_close:
ldwi	r7,smtp_rtncod
stw		[r7],r0
// quit
ldwi	r1,lab_str_smcm_quit
jalwr7	esp_print
jalwr7	smtp_get_response

// ================================
// exit pass through mode
ldwi	r1,500
jalwr7	delay
ldwi	r1,lab_str_cmd_exit_send
jalwr7	esp_print
ldwi	r1,1000
jalwr7	delay

// at+cipclose (close connection)
ldwi	r1,lab_str_atc_cipclose
ldwi	r2,lab_str_res_atc
jalwr7	esp_cast_at

smsd_return:
// return code
ldwi	r7,smtp_rtncod
ldw		r0,[r7]
rtnw

// ================================
// smtp get response ; disturbed r1,r5~r7
//	return: r0=response code (bcd)
// ================================
smtp_get_response:
jalwr7	esp_get_line
// check esp_lbuf[3]
ldwi	r7,esp_lbuf+3
ldb		r0,[r7]
cmpi	r0,chr_spc
bne		smtp_get_response
// response code
ldwi	r7,esp_lbuf
ldbiu	r0,0
rept	3
lsfti	r0,4
ldb		r1,[r7]
addi	r7,1
andi	r1,0x0f
add		r0,r1
endr
rtnw


// ================================
// esp32 access routines
// ================================
// ================================
// esp32 pass through command
// ================================
esp_passthru:
ldwi	r1,lab_str_msg_path_ent
jalwr7	print_lst
// initialize
ldwi	r7,path_ptr
ldbiu	r0,0
stw		[r7],r0
wpt_loop:
// handling uart#0 (serial monitor)
// check RAVL0
ldwi	r7,uartctl
ldw		r0,[r7]
andi	r0,uart_ravl
beq		wpt0_not_ravl
// receive a byte
ldwi	r7,uartrdat
ldw		r0,[r7]
ldwi	r7,path_ptr
ldw		r1,[r7]
ldwi	r7,lbuf
add		r7,r1
stb		[r7],r0
// update path_ptr
ldwi	r2,max_lbuf-2					// -2:=CR+LF
addi	r1,1
cmp		r1,r2
blo		pcnt+2
subi	r1,1
ldwi	r7,path_ptr
stw		[r7],r1
// check lf code
cmpi	r0,chr_lf
bne		wpt0_not_lf
// lbuf termination
ldwi	r7,lbuf
add		r7,r1
subi	r1,1
ldb		r0,[r7]
addi	r1,1
cmpi	r0,chr_cr
beq		pcnt+6
ldbiu	r0,chr_cr
stb		[r7],r0
addi	r7,1
ldbiu	r0,chr_lf
stb		[r7],r0
addi	r7,1
ldbiu	r0,0
stb		[r7],r0

// check "+++"
ldwi	r1,lab_str_cmd_exit_send
ldwi	r2,lbuf
jalwr7	strfcmp
mov		r0,r0
bne		wpt0_not_pls
// "+++"
ldwi	r7,lbuf+3
ldbiu	r0,0
stb		[r7],r0
// message
ldwi	r1,lab_str_msg_path_snd
jalwr7	print
wpt0_not_pls:

// check exit command "---"
ldwi	r1,lab_str_cmd_exit_path
ldwi	r2,lbuf
jalwr7	strfcmp
mov		r0,r0
bne		wpt0_not_exit
// "---"
bra		wpt_break

wpt0_not_exit:
// send data to esp32
ldwi	r1,lbuf
jalwr7	esp_print
// reset path_ptr
ldwi	r7,path_ptr
ldbiu	r0,0
stw		[r7],r0
wpt0_not_lf:
wpt0_not_ravl:

// handling uart#1 (esp32 communication)
// check TFUL0
ldwi	r7,uartctl
ldw		r0,[r7]
andi	r0,uart_tful
bne		wpt1_not_ravl
// check RAVL1
ldwi	r7,uartctl1
ldw		r0,[r7]
andi	r0,uart_ravl
beq		wpt1_not_ravl
// receive a byte
ldwi	r7,uartrdat1
ldw		r0,[r7]
// redirect data to uart#0
ldwi	r7,uarttdat
stw		[r7],r0
wpt1_not_ravl:

// end of loop
bra		wpt_loop
wpt_break:

rtnw

// ================================
// esp32 cast at-command and get response ; disturbed r1~r3,r5~r7
//	parameter: r1=at_cmnd, r2=response list
//	return: r0=response number (0~)
// ================================
esp_cast_at:
// send at-command
pushw	r2
jalwr7	esp_print
popw	r1
jalwr7	esp_wait_response
rtnw

// ================================
// esp32 wait response ; disturbed r1~r3,r5~r7
//	parameter: r1=response list
//	return: r0=response number (0~)
// ================================
esp_wait_response:
$(s)// ********************************
$(s)ldbiu	r0,0
$(s)rtnw
$(s)// ********************************
pushw	r1
ewr_loop:
popw	r3
pushw	r3
ldbiu	r0,0
ldwi	r7,esp_ewr_idx
stw		[r7],r0
pushw	r3
jalwr7	esp_get_line
popw	r3
ewr_loop2:
mov		r1,r3
ldwi	r2,esp_lbuf
pushw	r3
jalwr7	strfcmp
popw	r3
mov		r0,r0
beq		ewr_match
// next string in the list
// idx++
ldwi	r7,esp_ewr_idx
ldw		r0,[r7]
addi	r0,1
stw		[r7],r0
// search next string
ldb		r0,[r3]
addi	r3,1
mov		r0,r0
bne		pcnt-8
ldb		r0,[r3]
mov		r0,r0
bne		ewr_loop2
// not match
bra		ewr_loop

ewr_match:
popw	r0
ldwi	r7,esp_ewr_idx
ldw		r0,[r7]
rtnw

// ================================
// esp32 get line from uart ; disturbed r0,r5~r7
// ================================
esp_get_line:
ldwi	r7,uartrdat1
ldwi	r6,uartctl1
ldwi	r5,esp_lbuf
egl_loop:
// polling until RAVL=1
ldw		r0,[r6]
andi	r0,uart_ravl
beq		egl_loop
// get byte
ldw		r0,[r7]
stb		[r5],r0
addi	r5,1
// LF code check
cmpi	r0,chr_lf
beq		egl_got
// size check
ldwi	r0,esp_lbuf+max_lbuf-1
cmp		r5,r0
blo		egl_loop
// string too long, discard until receiving a LF
egl_discard:
// polling until RAVL=1
ldw		r0,[r6]
andi	r0,uart_ravl
beq		egl_loop
// discard byte
ldw		r0,[r7]
// LF code check
cmpi	r0,chr_lf
bne		egl_discard
// got line
egl_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		egl_notcr
ldbiu	r0,0
stb		[r5],r0
egl_notcr:
$(d)// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
$(d)// print esp_lbuf
$(d)pushc	sr
$(d)ldcl	sr,sreg_bk_3
$(d)ldwi	r1,lab_str_msg_esp_rdir
$(d)jalwr7	print
$(d)pushw	r1
$(d)ldwi	r1,esp_lbuf
$(d)jalwr7	print
$(d)popw	r1
$(d)jalwr7	print
$(d)popc	sr
$(d)// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
rtnw

// ================================
// esp32 print r1 ; disturbed r0~r2,r6,r7
// ================================
esp_print:
$(s)// ********************************
$(s)jalwr7	print
$(s)rtnw
$(s)// ********************************
$(d)// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
$(d)// print to uart#0 (serial monitor)
$(d)pushc	sr
$(d)pushw	r1
$(d)ldcl	sr,sreg_bk_3
$(d)popw	r1
$(d)jalwr7	print
$(d)popc	sr
$(d)// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
ldwi	r7,uarttdat1
ldwi	r6,uartctl1
epr_loop:
// get 1 byte
ldb		r2,[r1]
addi	r1,1
mov		r2,r2
beq		epr_finish
// polling uartctl1.TFUL=0
epr_poll:
ldw		r0,[r6]
andi	r0,uart_tful
bne		epr_poll
// send data
stw		[r7],r2
bra		epr_loop
epr_finish:
rtnw


// ================================
// baud rate detection ; disturbed none
//	return: r0=new baud rate detected
// ================================
det_baud:
pushwm	r1,r2,r3,r4,r5,r6,r7
ldwi	r7,uartctl
ldw		r0,[r7]
stw		[r7],r0							// clear brdf
andi	r0,uart_brdf
beq		dbr_not_brdf
// detected
ldwi	r7,uartbres
ldw		r0,[r7]
ldwi	r7,uartbaud
ldw		r3,[r7]
// margin
mov		r2,r3
lsri	r2,6
// r3=abs (r3 - r0)
$(s)// ********************************
$(s)lsli	r3,1
$(s)// ********************************
sub		r3,r0
bpl		dbr_plus
neg		r3
dbr_plus:
cmp		r3,r2
blo		dbr_not_brdf
// update uartbaud
stw		[r7],r0
// message
ldwi	r1,lab_dbr_str_msg_det
jalwr7	print
pushw	r1
ldwi	r7,uartbaud
ldw		r1,[r7]
jalwr7	print_hex
popw	r1
jalwr7	print
ldwi	r7,uartbres
ldw		r0,[r7]
bra		dbr_not_brdf+2
// return
dbr_not_brdf:
ldbiu	r0,0
popwm	r7,r6,r5,r4,r3,r2,r1
rtnw

dbr_str_msg_det:
dats	"OK: new baud rate detected: uartbaud=0x\0\r\n\0"

// ================================
// get line from uart ; disturbed r0,r5~r7
// ================================
get_line:
ldwi	r7,uartrdat
ldwi	r6,uartctl
ldwi	r5,lbuf
gl_loop:
// check baud rate detection
jalwr0	det_baud
// 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
cmpi	r2,0
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]
cmpi	r0,0
bne		print_lst
rtnw

// ================================
// print_hex r1 ; disturbed r0~r7
//		print r1 as 4 digits hexadecimal number
// ================================
print_hex:
ldbiu	r3,4
$(s)// ********************************
$(s)ldwi	r7,princtl
$(s)ldbiu	r0,prin_nld
$(s)stw		[r7],r0
$(s)ldwi	r7,prinhex
$(s)cmpi	r3,4
$(s)beq		ph_else
$(s)cendw	r1
$(s)stb		[r7],r1
$(s)bra		ph_endif
$(s)ph_else:
$(s)stw		[r7],r1
$(s)ph_endif:
$(s)rtnw
$(s)// ********************************
ldwi	r7,uarttdat
ldwi	r6,uartctl
ldwi	r5,lab_ph_hexdig
ph_loop:
// print nibble
mov		r0,r1
mov		r4,r5
cendw	r0
lsri	r0,8
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
lsli	r1,4
subi	r3,1
bne		ph_loop
rtnw

ph_hexdig:
dats	"0123456789abcdef"

// ================================
// 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
cmpi	r3,0
beq		sc_finish
cmpi	r4,0
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
cmpi	r3,0
beq		snc_finish
cmpi	r4,0
bne		strncmp
snc_finish:
rtnw

// ================================
// string forward match compare: r0=strfcmp (r1,r2) ; disturbed r1~r3
//	if r1 equal to left(r2,strlen(r1)) then match
//	if strlen(r1)>strlen(r2) then always mismatch
// ================================
strfcmp:
ldbiu	r0,0
sfc_loop:
ldb		r3,[r1]
addi	r1,1
mov		r3,r3
beq		sfc_return
mov		r0,r3
ldb		r3,[r2]
addi	r2,1
sub		r0,r3
beq		sfc_loop
sfc_return:
rtnw

// ================================
// string copy: strcpy (r1,r2) ; disturbed r0~r2
//	return: r1 pointed to '\0' position
//			r2 pointed to '\0'+1 position
// ================================
strcpy:
ldb		r0,[r2]
addi	r2,1
stb		[r1],r0
addi	r1,1
mov		r0,r0
bne		strcpy
subi	r1,1
rtnw

// ================================
// string copy decimal3 r2 to r1 ; disturbed r0,r2~r4,r6,r7
//	'\0' is copied after copying decimal3
//	return: r1=pointer to the last '\0'
// ================================
strcpy_dec3:
mov		r2,r2
bne		cpd_not_0
// 0
ldbiu	r2,0a0
stb		[r1],r2
addi	r1,1
bra		cpd_fin

cpd_not_0:
// for each r0=100, 10, 1
ldwi	r6,lab_cpd_tab
ldbiu	r3,true							// omit leading zero flag
cpd_loop:
ldw		r0,[r6]
mov		r0,r0
beq		cpd_fin
// r4=r2/r0
ldbiu	r4,0
cpd_div:
sub		r2,r0
blo		pcnt+4
addi	r4,1
bra		cpd_div

// omit leading zero
mov		r3,r3
beq		pcnt+4
mov		r4,r4
beq		cpd_omit
// copy 1 digit
addi	r4,0a0
stb		[r1],r4
addi	r1,1
ldbiu	r3,false
cpd_omit:
// add back r2; loop
add		r2,r0
addi	r6,2
bra		cpd_loop

cpd_fin:
stb		[r1],r0
rtnw

cpd_tab:
datw	100
datw	10
datw	1
datw	0

// ================================
// delay r1 [ms] ; disturbed r0,r7,sytmctl[MLOE]
// ================================
delay:
$(s)// ********************************
$(s)ldbiu	r1,3
$(s)// ********************************
// sytmmil: set offset
ldwi	r7,sytmctl
ldw		r0,[r7]
andi	r0,~sytm_mloe
stw		[r7],r0
ori		r0,sytm_mloe
stw		[r7],r0
// wait r1 [ms]
ldwi	r7,sytmmill
dly_loop:
ldw		r0,[r7]
cmp		r0,r1
blo		dly_loop
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+ smtp[,<base64(\"\\0user\\0pwd\")>]\r\n"
dats	"OK+ dht11\r\n"
dats	"OK+ path\r\n"
dats	"OK+ U\r\n"
dats	"OK+ who\r\n"
dats	"OK: help\r\n\0\0"
str_msg_smtp:
dats	"OK: SMTP send mail\r\n\0"
str_msg_path_ent:
dats	"OK+ enter ESP32 pass through mode\r\n"
dats	"OK+ ---<return> to exit pass through mode\r\n\0\0"
str_msg_path_snd:
dats	"OK: exit AT+CIPSEND\r\n\0"
str_msg_path:
dats	"OK: exit ESP32 pass through mode\r\n\0"
str_msg_esp_init:
dats	"OK+ ESP32 init...\r\n\0"
str_msg_esp_init_done:
dats	"OK: ESP32 init done.\r\n\0"
str_msg_esp_rdir:
dats	"ESP32: \0\r\n\0"
str_msg_dht11:
dats	"OK: dht11=\0.\0[degC] \0[%RH]\r\n\0"
str_err_unspt:
dats	"ERR: unsupported command: \0\r\n\0"
str_err_syntx:
dats	"ERR: syntax\r\n\0"
str_err_esp_init:
dats	"ERR: ESP32 init failed\r\n\0"
str_err_upwd:
dats	"ERR: smtp: no base64(\"\\0user\\0pwd\")\r\n\0"
str_err_smtp:
dats	"ERR: SMTP send mail failed\r\n\0"
str_err_esp_start:
dats	"ERR: could not connect server\r\n\0"
str_err_esp_path:
dats	"ERR: could not enter pass through mode\r\n\0"
str_err_smtp_ehlo:
dats	"ERR: ehlo\r\n\0"
str_err_smtp_auth:
dats	"ERR: auth\r\n\0"
str_err_smtp_mail:
dats	"ERR: mail\r\n\0"
str_err_smtp_rcpt:
dats	"ERR: rcpt\r\n\0"
str_err_smtp_data:
dats	"ERR: data\r\n\0"
str_err_dht11:
dats	"ERR: dht11\r\n\0"
str_cmd_smtp:
dats	"smtp\0"
str_cmd_path:
dats	"path\0"
str_cmd_dht11:
dats	"dht11\0"
str_cmd_exit_send:
dats	"+++\0"
str_cmd_exit_path:
dats	"---\0"
str_cmd_who:
dats	"who\0"
str_cmd_help:
dats	"help\0"

// ================================
// at-command
str_atc_rst:
dats	"AT+RST\r\n\0"
str_atc_gmr:
dats	"AT+GMR\r\n\0"
str_atc_cipsntpcfg:
dats	"AT+CIPSNTPCFG=1,9\r\n\0"
str_atc_cipmux:
dats	"AT+CIPMUX=0\r\n\0"
str_atc_cipstaq:
dats	"AT+CIPSTA?\r\n\0"
str_atc_sntpcfg:
dats	"AT+CIPSNTPCFG=1,9\r\n\0"
str_atc_sntptime:
dats	"AT+CIPSNTPTIME?\r\n\0"
str_atc_cipstart:
dats	"AT+CIPSTART=\"SSL\",\"$(smtp_host)\",$(smtp_port)\r\n\0"
str_atc_cipmode:
dats	"AT+CIPMODE=1\r\n\0"
str_atc_cipsend:
dats	"AT+CIPSEND\r\n\0"
str_atc_cipclose:
dats	"AT+CIPCLOSE\r\n\0"

// ================================
// at-command response list
str_res_rst:
dats	"WIFI GOT IP\0\0"
str_res_atc:
dats	"OK\0ERROR\0\0"
str_res_sntp:
dats	"OK\0+CIPSNTPTIME:\0\0"
str_res_start:
dats	"OK\0ERROR\0CONNECT\0CLOSE\0\0"

// ================================
// smtp command
str_smcm_ehlo:
dats	"ehlo esp32\r\n\0"
str_smcm_auth:
dats	"auth plain \0\r\n\0"
str_smcm_mail:
dats	"mail from:<\0>\r\n\0"
str_smcm_rcpt:
dats	"rcpt to:<\0>\r\n\0"
str_smcm_data:
dats	"data\r\n\0\r\n.\r\n\0"
str_smcm_quit:
dats	"quit\r\n\0"

// ================================
// smtp definitions
str_smtp_host:
dats	"$(smtp_host)\0"
str_smtp_port:
dats	"$(smtp_port)\0"
str_smtp_upwd:
dats	"$(smtp_upwd)\0"
str_smtp_from:
dats	"$(smtp_from)\0"
str_smtp_toad:
dats	"$(smtp_toad)\0"

// ================================
// smtp header
str_head_date:
dats	"Date: \0, \0 \0 \0 \0 +0900 (JST)\r\n\0"
str_head_from:
dats	"From: <\0>\r\n\0"
str_head_toad:
dats	"To: <\0>\r\n\0"

// ================================
// mail header and body
str_smtp_mail:
// header: except "Date:", "From:", "To:"
dats	"Subject: DHT11 data\r\n"
// delimitation header / body
dats	"\r\n"
// body: additional user message
dats	"DHT11 measurement data was below.\r\n"
// end mark
dats	"\0\0"

