// ================================
// range finder by ultrasonic sensor
//		(c) 2022	1YEN Toru
//
//
//		2022/09/03	ver.1.00
//
// ================================
asm		"mcoc_irom.mif"
#asm		"mcoc_irom.mem"
#asm		"mcoc_irom.dat2",bit16,list
incl	"mcoc115.incl"
incl	"mcvm_lib_wire_h.incl"
# ================================
# string macros
def		prog_name,"range_finder"
def		prog_vers,"1.00"
def		s,"#"							// simulation="" / real fpga="#"
def		r,"#"							// ole: rotate="" / normal="#"
# 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/400000-1			// i2c: clock speed
$(s)// ********************************
$(s)equ		stws_baud,fcpu/400000/3-1	// i2c: clock speed for sim
$(s)// ********************************
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,0x20					// dht: sda signal pin iop[5]
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
## (20,50ms) for short distance < 1m
#equ		dst_mva_max,20					// dst: count of moving average
#equ		dst_msec_itvl,50				// dst: measure interval [ms]
# (10,250ms) for general purpose
equ		dst_mva_max,10					// dst: count of moving average
equ		dst_msec_itvl,250				// dst: measure interval [ms]
#
equ		dst_ole_upd_cnt,4				// dst: oled update count
equ		dst_usec_dht,5000000			// dst: dht11 measure interval [us]
equ		dst_trig,0x80					// dst: trig signal pin iop[7]
equ		dst_echo,0x40					// dst: echo signal pin iop[6]
equ		dst_err_no,0					// dst: error: no
equ		dst_err_timeout,4				// dst: error: time out (too far)
equ		dst_err_echo,5					// dst: error: echo=1 on start
# oled driver ssd1306 i/o registers
equ		i2c_ssd1306,0x3c				// i2c: ssd1306 slave address
equ		ole_siz_h,128					// ole: screen size
equ		ole_siz_v,64
equ		ole_reg_ctrl_c,0x00				// ole: ctr: co=0, d/c#=0 (command)
equ		ole_reg_ctrl_d,0x40				// ole: ctr: co=0, d/c#=1 (data)
equ		ole_reg_ctrl_cc,0x80			// ole: ctr: co=1, d/c#=0 (command)
equ		ole_reg_ctrl_cd,0xc0			// ole: ctr: co=1, d/c#=1 (data)
equ		ole_reg_madr_mod,0x20			// ole: reg: memory addressing mode
equ		ole_reg_col_adr,0x21			// ole: reg: column address
equ		ole_reg_pag_adr,0x22			// ole: reg: page address
equ		ole_reg_disp_lin,0x40			// ole: reg: display start line
equ		ole_reg_cont_ctrl,0x81			// ole: reg: contrast control
equ		ole_reg_chg_pump,0x8d			// ole: reg: charge pump setting
equ		ole_reg_seg_remap,0xa0			// ole: reg: segment re-map
equ		ole_reg_ent_disp,0xa4			// ole: reg: entire display on
equ		ole_reg_nor_disp,0xa6			// ole: reg: normal display
equ		ole_reg_inv_disp,0xa7			// ole: reg: inverse display
equ		ole_reg_mux_rat,0xa8			// ole: reg: multiplex ratio
equ		ole_reg_disp_off,0xae			// ole: reg: display off
equ		ole_reg_disp_on,0xaf			// ole: reg: display on
equ		ole_reg_scan_dir,0xc0			// ole: reg: com output scan dir
equ		ole_reg_disp_ofst,0xd3			// ole: reg: display offset
equ		ole_reg_clk_div,0xd5			// ole: reg: display clock divide
equ		ole_reg_com_cnfg,0xda			// ole: reg: com pins h/w config
# 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		dst_mode,va						// dst: measurement mode: 0 / 1
equ		va,va+2
equ		dst_dist,va						// dst: measured distance [mm]
equ		va,va+2
equ		dst_temp,va						// dst: temperature [degC]
equ		va,va+2
equ		dst_spd_sonic,va				// dst: speed of sonic [m/s]
equ		va,va+2
equ		dst_spd_sonic10,va				// dst: 10*dst_spd_sonic
equ		va,va+2
equ		dst_mva_ptr,va					// dst: write pointer to dst_mva_buf
equ		va,va+2
equ		dst_mva_sum,va					// dst: sum for moving average
equ		va,va+2
equ		dst_msec_prev,va				// dst: previously measured time [ms]
equ		va,va+4
equ		prn_line,va						// prn: print line
equ		va,va+2
equ		ole_update,va					// ole: update display
equ		va,va+2
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		dst_mva_buf,va					// dst: buffer for moving average
equ		va,va+dst_mva_max
equ		i2c_buf,va						// i2c: buffer for i2c frame
equ		va,va+2*64
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
// ================================
// nh=1
sesr	sreg_b_nh

// 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,dst_trig|dst_echo|dht_sda
ldwi	r7,porsel
stw		[r7],r0
ldwi	r7,porode
ldbiu	r0,dht_sda
stw		[r7],r0
ldwi	r7,porset
ldbiu	r0,dht_sda
stw		[r7],r0
ldwi	r7,porclr
ldbiu	r0,dst_trig
stw		[r7],r0
ldwi	r7,pordir
ldw		r0,[r7]
andi	r0,~(dst_trig|dht_sda)
ori		r0,dst_echo
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
ldwi	r0,stws_baud
ldwi	r7,stwmbaud
stw		[r7],r0
// check stwser unit
ldw		r1,[r7]
cmp		r0,r1
beq		stw_found
// ERROR: stwser unit not found
ldwi	r1,lab_str_err_nostws
jmpr7	error_halt
stw_found:

// fontjp setting
ldwi	r7,fnjpctl
ldbiu	r0,fnjp_rot_1
stw		[r7],r0
// check fontjp unit
ldw		r1,[r7]
cmp		r0,r1
beq		fjp_found
// ERROR: fontjp unit not found
ldwi	r1,lab_str_err_nofnjp
jmpr7	error_halt
fjp_found:

// check distus unit
ldwi	r7,distctl
ldw		r0,[r7]
andi	r0,dist_dist
bne		dst_found
// ERROR: distus unit not found
ldwi	r1,lab_str_err_nodist
jmpr7	error_halt
dst_found:

// measure dht11
jalwr7	meas_dht11
ldwi	r7,dst_temp
ldbiu	r0,140
stw		[r7],r0

// distus setting
ldwi	r7,disttrig
ldbiu	r0,dst_trig
stw		[r7],r0
ldwi	r7,distecho
ldbiu	r0,dst_echo
stw		[r7],r0

// check Nihonium
movfc	r0,sr
lsfti	r0,-sreg_b_nh
andi	r0,1
bne		chk_nihonium
// ERROR: not Nihonium
ldwi	r1,lab_str_err_not_nh
jmpr7	error_halt
chk_nihonium:

$(s)// ********************************
$(s)// setup dummy slave
$(s)ldbiu	r0,i2c_ssd1306
$(s)ldwi	r7,stwsadr
$(s)stw		[r7],r0
$(s)ldbiu	r0,0
$(s)bra		pcnt+6
$(s)// ********************************
// oled display init
jalwr7	ole_init
mov		r0,r0
beq		ole_init_done
// ERROR: oled display could not initialize
ldwi	r1,lab_str_err_oled
jmpr7	error_halt
ole_init_done:
$(s)// ********************************
$(s)bra		sim_skip_oleprn
$(s)// ********************************
ldwi	r1,lab_str_msg_oled6
ldbiu	r2,0
jalwr7	ole_kprint
ldwi	r1,lab_str_msg_oled3
ldbiu	r2,1
jalwr7	ole_kprint
$(s)// ********************************
$(s)sim_skip_oleprn:
$(s)// ********************************

// send RDY
ldwi	r1,lab_str_msg_rdy
jalwr7	print

$(s)// ********************************
$(s)// for simulation
$(s)// cancel time out
$(s)ldwi	r7,simctrl
$(s)ldbiu	r0,simc_noto
$(s)stw		[r7],r0
$(s)// command test
$(s)ldwi	r6,lab_sim_str_cmnd
$(s)sim_cmnd_loop2:
$(s)ldwi	r7,lbuf
$(s)sim_cmnd_loop:
$(s)ldb		r0,[r6]
$(s)addi	r6,1
$(s)stb		[r7],r0
$(s)addi	r7,1
$(s)cmpi	r0,0
$(s)bne		sim_cmnd_loop
$(s)pushw	r6
$(s)jalwr7	sim_cmnd
$(s)// skip nil, check end mark (*)
$(s)popw	r6
$(s)sim_loop_1:
$(s)ldb		r0,[r6]
$(s)addi	r6,1
$(s)cmpi	r0,0
$(s)beq		sim_loop_1
$(s)subi	r6,1
$(s)cmpi	r0,0x2a						// asterisk(*)
$(s)bne		sim_cmnd_loop2
$(s)bra		sim_cmnd_end
$(s)sim_str_cmnd:
$(s)dats	"dst,1\0"
$(s)dats	"*"							// end mark
$(s)dats	"prn,0,こんにちは、世界\0"
$(s)dats	"who\0"
$(s)dats	"help\0"
$(s)sim_cmnd_end:
$(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
beq		no_data
jalwr7	get_line
$(s)// ********************************
$(s)sim_cmnd:
$(s)// ********************************

// 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 "dst," command
ldwi	r1,lbuf
ldwi	r2,lab_str_cmd_dst
ldbiu	r5,4
jalwr7	strncmp
mov		r0,r0
bne		dst_notid
// ================================
// dst,<mode_0_1>
ldwi	r1,lbuf+4
jalwr7	atoi
mov		r0,r0
beq		pcnt+2
ldbiu	r0,true
ldwi	r7,dst_mode
stw		[r7],r0
// measurement
mov		r0,r0
beq		dst_not_enb
// measure dht11
jalwr7	meas_dht11
ldwi	r7,dht_buf+2
ldb		r1,[r7]
exsgw	r1
ldbiu	r2,10
muls	r1,r2
addi	r7,1
ldb		r2,[r7]
add		r1,r2
cmpi	r0,dht_err_no
beq		pcnt+2
ldbiu	r1,140
ldwi	r7,dst_temp
stw		[r7],r1
// measure distance
jalwr7	meas_dist
mov		r0,r0
beq		dst_not_err
// ERROR:
pushw	r0
ldwi	r1,lab_str_err_dst
jalwr7	print
popw	r0
pushw	r1
mov		r1,r0
jalwr7	print_lng_dec
popw	r1
jalwr7	print
bra		no_data

dst_not_err:
// show calculation information
ldwi	r1,lab_str_msg_dst_inf
jalwr7	print
pushw	r1
// temperature
ldwi	r7,dst_temp
ldw		r1,[r7]
jalwr7	print_lng_dec
popw	r1
jalwr7	print
// skip nil
ldb		r0,[r1]
mov		r0,r0
bne		pcnt+2
addi	r1,1
jalwr7	print
pushw	r1
// speed of sonic
ldwi	r7,dst_spd_sonic
ldw		r1,[r7]
jalwr7	print_lng_dec
popw	r1
jalwr7	print
// skip nil
ldb		r0,[r1]
mov		r0,r0
bne		pcnt+2
addi	r1,1
jalwr7	print
pushw	r1
// distance measured
ldwi	r7,dst_dist
ldw		r1,[r7]
jalwr7	print_lng_dec
popw	r1
jalwr7	print

dst_not_enb:
// response
ldwi	r1,lab_str_msg_dst
jalwr7	print
pushw	r1
ldwi	r7,dst_mode
ldw		r1,[r7]
jalwr7	print_lng_dec
popw	r1
jalwr7	print
bra		no_data
dst_notid:

// check "prn," command
ldwi	r1,lbuf
ldwi	r2,lab_str_cmd_prn
ldbiu	r5,4
jalwr7	strncmp
cmpi	r0,0
bne		prn_notid
// ================================
// prn,<line_0_1>,<print_string>
// <line_0_1>
ldwi	r1,lbuf+4
jalwr7	atoi
andi	r0,0x01
ldwi	r7,prn_line
stw		[r7],r0
ldb		r0,[r1]
cmpi	r0,chr_cma
bne		err_syntx
// <print_string>
addi	r1,1
mov		r2,r1
ldwi	r1,lbuf
jalwr7	strcpy
// print
ldwi	r1,lbuf
ldwi	r7,prn_line
ldw		r2,[r7]
jalwr7	ole_kprint
// response
ldwi	r1,lab_str_msg_prn
jalwr7	print
bra		no_data
prn_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:


// ================================
// measure distance
ldwi	r7,dst_mode
ldw		r0,[r7]
cmpi	r0,true
bne		dst_next
// clear offset
ldwi	r7,sytmctl
ldw		r0,[r7]
andi	r0,~sytm_mloe
stw		[r7],r0
// check measurement interval
ldwi	r7,sytmmilh
ldl		r0,[r7]
mov		r2,r0
ldwi	r7,dst_msec_prev
ldl		r1,[r7]
sub		r0,r1
ldwi	r1,dst_msec_itvl
cmp		r0,r1
blo		dst_next

// update dst_msec_prev
stl		[r7],r2
ldwi	r7,ole_update
ldw		r0,[r7]
addi	r0,1
stw		[r7],r0
// measure
jalwr7	meas_dist

// moving average
// dst_mva_sum -= dst_mva_buf[dst_mva_ptr]
ldwi	r7,dst_mva_buf
ldwi	r6,dst_mva_ptr
ldw		r6,[r6]
add		r7,r6
ldw		r1,[r7]
ldwi	r6,dst_mva_sum
ldw		r0,[r6]
sub		r0,r1
// dst_mva_sum += dst_dist; dst_mva_buf[dst_mva_ptr]=dst_dist
ldwi	r1,dst_dist
ldw		r1,[r1]
stw		[r7],r1
add		r0,r1
stw		[r6],r0
// update pointer
ldwi	r7,dst_mva_ptr
ldw		r0,[r7]
addi	r0,2
cmpi	r0,dst_mva_max
blo		pcnt+2
ldbiu	r0,0
stw		[r7],r0

dst_next:
// end of distance measurement


// ================================
// measure temperature
// clear offset
ldwi	r7,sytmctl
ldw		r0,[r7]
andi	r0,~sytm_mcoe
stw		[r7],r0
// check measurement interval
ldwi	r7,sytmmcrh
ldl		r0,[r7]
mov		r2,r0
ldwi	r7,dht_usec_prev
ldl		r1,[r7]
sub		r0,r1
ldli	r1,dst_usec_dht
cmp		r0,r1
blo		dht_next

// measure temperature
jalwr7	meas_dht11
cmpi	r0,dht_err_no
beq		dht_err_else
// WARNING: error on dht11 measurement
ldwi	r0,140							// 14.0degC
bra		dht_err_endif

dht_err_else:
// temp.
ldwi	r7,dht_buf+2
ldb		r0,[r7]
exsgw	r0
ldbiu	r1,10
muls	r0,r1
addi	r7,1
ldb		r1,[r7]
add		r0,r1							// r0=10*T[degC]

dht_err_endif:
// store
ldwi	r7,dst_temp
stw		[r7],r0

dht_next:
// end of dht11 measurement


// ================================
// oled display
ldwi	r7,ole_update
ldw		r0,[r7]
cmpi	r0,dst_ole_upd_cnt
blo		ole_next
ldbiu	r0,0
stw		[r7],r0

// update display
// [0123456789012345]
// [999/10 C,340 m/s]
ldwi	r1,lbuf
ldwi	r7,dst_temp
ldw		r2,[r7]
jalwr7	strcpy_dec
ldwi	r2,lab_str_msg_oled1
jalwr7	strcpy
ldwi	r7,dst_spd_sonic
ldw		r2,[r7]
jalwr7	strcpy_dec
ldwi	r2,lab_str_msg_oled2
jalwr7	strcpy
// 16 characters
ldwi	r7,lbuf+16+1					// +1 for degC character
ldbiu	r0,0
stb		[r7],r0
// oled print string
ldwi	r1,lbuf
$(s)// ********************************
$(s)pushw	r1
$(s)jalwr7	print
$(s)ldwi	r7,princhr
$(s)ldbiu	r0,chr_lf
$(s)stw		[r7],r0
$(s)popw	r1
$(s)// ********************************
ldbiu	r2,0
jalwr7	ole_kprint

// [0123456789012345]
// [dist=   12345 mm]
ldwi	r1,lbuf
ldwi	r2,lab_str_msg_oled3
jalwr7	strcpy
ldwi	r7,dst_dist
ldw		r2,[r7]
jalwr7	strcpy_dec
ldwi	r2,lab_str_msg_oled4
jalwr7	strcpy
// 16 characters
subi	r1,16
pushw	r1
ldwi	r2,lab_str_msg_oled5
jalwr7	strcpy
ldbiu	r0,chr_spc
stb		[r1],r0
// oled print string
popw	r1
$(s)// ********************************
$(s)pushw	r1
$(s)jalwr7	print
$(s)ldwi	r7,princhr
$(s)ldbiu	r0,chr_lf
$(s)stw		[r7],r0
$(s)popw	r1
$(s)// ********************************
ldbiu	r2,1
jalwr7	ole_kprint

ole_next:
// end of oled display


// ================================
// end of loop
$(s)// ********************************
$(s)rtnw
$(s)// ********************************
bra		loop


// ================================
// ERROR: halted
error_halt:
jalwr7	print
$(s)// ********************************
$(s)ldwi	r0,simfail
$(s)ldwi	r7,simfnsh
$(s)stw		[r7],r0
$(s)// ********************************
pause
bra		pcnt-4


// ================================
// oled kanji print r1 at line r2 ; disturbed r0~r3,r7
// ================================
ole_kprint:
ldbiu	r3,0
pushw	r1
cmpi	r2,ole_siz_v/16
blo		pcnt+2
ldbiu	r2,ole_siz_v/16-1
// set rect
ldwi	r7,i2c_buf
// S [adr,w]
ldwi	r0,0x4100+(i2c_ssd1306<<1)
stw		[r7],r0
addi	r7,2
// [0x00]
ldwi	r0,0x4000+ole_reg_ctrl_c
stw		[r7],r0
addi	r7,2
// [COL_ADR]
ldwi	r0,0x4000+ole_reg_col_adr
stw		[r7],r0
addi	r7,2
// [8*r3]
lsli	r3,3
ldwi	r0,0x4000
add		r0,r3
stw		[r7],r0
addi	r7,2
// [127]
ldwi	r0,0x4000+ole_siz_h-1
stw		[r7],r0
addi	r7,2
// [PAG_ADR]
ldwi	r0,0x4000+ole_reg_pag_adr
stw		[r7],r0
addi	r7,2
// [2*r2]
ldwi	r0,0x4000
lsli	r2,1
add		r0,r2
stw		[r7],r0
addi	r7,2
// [2*r2+1]
addi	r0,1
stw		[r7],r0
addi	r7,2
// P
ldbiu	r0,0
stw		[r7],r0
addi	r7,2
// call mcvm_wire
ldwi	r1,i2c_buf
$(s)// ********************************
$(s)bra		pcnt+6
$(s)// ********************************
jalwr7	mcvm_wire

// print
popw	r1
ole_prn_loop:
ldb		r0,[r1]
addi	r1,1
lsli	r0,8
beq		ole_prn_break
// s-jis?
ldwi	r7,fnjpcod
stw		[r7],r0
ldwi	r7,fnjpctl
ldw		r2,[r7]
andi	r2,fnjp_sjs1
beq		pcnt+6
// yes, s-jis 2 bytes code
ldb		r2,[r1]
addi	r1,1
add		r0,r2
jalwr7	ole_kprint_chr
bra		ole_prn_loop

ole_prn_break:

ole_prn_return:
rtnw

// ================================
// oled kanji print 1 character r0 ; disturbed r0,r7
// ================================
ole_kprint_chr:
pushwm	r1,r2,r3,r4,r6
// font
ldwi	r7,fnjpcod
stw		[r7],r0
$(s)// ********************************
$(s)ldwi	r7,prinhex
$(s)stw		[r7],r0
$(s)// ********************************
// i2c frame
ldwi	r1,i2c_buf
ldwi	r0,0x4100+(i2c_ssd1306<<1)
stw		[r1],r0
addi	r1,2
ldwi	r0,0x4000+ole_reg_ctrl_d
stw		[r1],r0
addi	r1,2
// draw character
ldwi	r6,fnjpdbl
ldwi	r7,fnjpdata
ldbiu	r4,8
ole_prc_loop:
ldb		r0,[r7]
stw		[r6],r0
ldw		r0,[r6]
mov		r2,r0
andi	r0,0xff
lsri	r2,8
ldwi	r3,0x4000
add		r0,r3
add		r2,r3
stw		[r1],r0
addi	r1,2
stw		[r1],r2
addi	r1,2
addi	r7,1
// end of loop
subi	r4,1
bne		ole_prc_loop
// P
ldbiu	r0,0
stw		[r1],r0
// call mcvm_wire
ldwi	r1,i2c_buf
$(s)// ********************************
$(s)pushc	sr
$(s)ldcl	sr,sreg_bk_1
$(s)ldwi	r7,fnjpdata
$(s)ldwi	r6,princhr
$(s)ldbiu	r2,8
$(s)sim_ole_prc_loop2:
$(s)ldb		r0,[r7]
$(s)lsli	r0,32-8						// 32=Nh
$(s)ldbiu	r1,8
$(s)sim_ole_prc_loop1:
$(s)lsli	r0,1
$(s)bcc		pcnt+4
$(s)ldbiu	r3,0ax-0x20
$(s)bra		pcnt+2
$(s)ldbiu	r3,chr_spc
$(s)stw		[r6],r3
$(s)stw		[r6],r3
$(s)subi	r1,1
$(s)bne		sim_ole_prc_loop1
$(s)ldbiu	r3,chr_lf
$(s)stw		[r6],r3
$(s)addi	r7,1
$(s)subi	r2,1
$(s)bne		sim_ole_prc_loop2
$(s)popc	sr
$(s)bra		ole_prc_return
$(s)// ********************************
jalwr7	mcvm_wire

ole_prc_return:
popwm	r6,r4,r3,r2,r1
rtnw

// ================================
// oled display (ssd1306) initialize
// ================================
ole_init:
// call mcvm_wire
ldwi	r1,lab_ole_init_reg
jalwr7	mcvm_wire
rtnw

// oled display (ssd1306) initialization i2c frame
ole_init_reg:
// [adr,w] [0x00]
datw	0x4100+(i2c_ssd1306<<1)
datw	0x4000+ole_reg_ctrl_c
// set mux ratio (0xa8, 0x3f)
datw	0x4000+ole_reg_mux_rat
datw	0x4000+0x3f
// set display offset (0xd3,0x00)
datw	0x4000+ole_reg_disp_ofst
datw	0x4000+0x00
// set display start line (0x40)
datw	0x4000+ole_reg_disp_lin+0x00
// set segment re-map (0xa0 / 0x0a1)
datw	0x4000+ole_reg_seg_remap
$(r)datw	0x4000+ole_reg_seg_remap+0x01
// set com output scan direction (0xc0 / 0xc8)
datw	0x4000+ole_reg_scan_dir
$(r)datw	0x4000+ole_reg_scan_dir+0x08
// set com pins hardware configuration (0xda,0x02)
datw	0x4000+ole_reg_com_cnfg
datw	0x4000+0x02
$(r)datw	0x4000+ole_reg_com_cnfg
$(r)datw	0x4000+0x22
// set contrast control (0x81,0x7f)
datw	0x4000+ole_reg_cont_ctrl
datw	0x4000+0x7f
// disable entire display on (0xa4)
datw	0x4000+ole_reg_ent_disp
// set normal display (0xa6)
datw	0x4000+ole_reg_nor_disp
// set osc frequency (0xd5,0x80)
datw	0x4000+ole_reg_clk_div
datw	0x4000+0x80
// enable charge pump regulator (0x8d,0x14)
datw	0x4000+ole_reg_chg_pump
datw	0x4000+0x14
// display on (0xaf)
datw	0x4000+ole_reg_disp_on
// vertical addressing mode
datw	0x4000+ole_reg_madr_mod
datw	0x4000+0x01
// P
datw	0x0000


// ================================
// measure distance by ultrasonic sensor
//	measured data stored: dst_dist
//	dst_dist=0 on error
//	return: r0=0 (no error) / !=0 (on error)
// ================================
meas_dist:
// temperature
ldwi	r7,dst_temp
ldw		r0,[r7]
// speed of sonic:
//	U[m/s]=331.5 + 0.61*T[degC]
//	U[m/s]=331.5*1000/1000 + 0.61*(10*T[degC])/10*1000/1000
//	U[m/s]=331500/1000 + 610*(10*T[degC])/10/1000
//	U[m/s]=(331500 + 61*(10*T[degC]))/1000
//	... dst_temp=10*T[degC]
ldli	r1,331500
ldbiu	r2,61
muls	r0,r2
add		r0,r1
addi	r0,50							// round
ldwi	r1,100
divs	r0,r1
// store
ldwi	r7,dst_spd_sonic10
stw		[r7],r0
ldwi	r1,10
divs	r0,r1
ldwi	r7,dst_spd_sonic
stw		[r7],r0

// measure round trip time
$(s)// ********************************
$(s)pushc	sr
$(s)ldcl	sr,sreg_bk_1
$(s)// echo=0
$(s)ldwi	r7,simpord
$(s)ldbiu	r0,dst_echo
$(s)stw		[r7],r0
$(s)ldwi	r7,simpori
$(s)ldbiu	r0,0
$(s)stw		[r7],r0
$(s)popc	sr
$(s)// ********************************
// check echo=0
ldwi	r7,porin
ldw		r0,[r7]
andi	r0,dst_echo
beq		dst_echo0_endif
// ERROR: echo=1 at start of measurement
ldwi	r7,dst_dist
ldbiu	r0,0
stw		[r7],r0
ldbiu	r0,dst_err_echo
bra		dst_return

dst_echo0_endif:
// trig=1
ldwi	r7,porset
ldbiu	r0,dst_trig
stw		[r7],r0
// wait 10us
ldbiu	r0,10*(fcpu/1000000)/3+1
$(s)// ********************************
$(s)ldbiu	r0,1*(fcpu/1000000)/3
$(s)// ********************************
subi	r0,1
bne		pcnt-4
// trig=0
ldwi	r7,porclr
ldbiu	r0,dst_trig
stw		[r7],r0
$(s)// ********************************
$(s)pushc	sr
$(s)ldcl	sr,sreg_bk_1
$(s)// echo=1
$(s)ldwi	r7,simpori
$(s)ldbiu	r0,dst_echo
$(s)stw		[r7],r0
$(s)// wait 23us
$(s)ldwi	r0,23*(fcpu/1000000)/3
$(s)subi	r0,1
$(s)bne		pcnt-4
$(s)// echo=0
$(s)ldbiu	r0,0
$(s)stw		[r7],r0
$(s)popc	sr
$(s)// ********************************
// polling bsy=0
ldwi	r7,distctl
ldw		r0,[r7]
andi	r0,dist_bsy
bne		pcnt-6
ldw		r0,[r7]
andi	r0,dist_err
beq		dst_meas_err_else
// ERROR: err=1
ldwi	r7,dst_dist
ldbiu	r0,0
stw		[r7],r0
ldbiu	r0,dst_err_timeout
bra		dst_return

dst_meas_err_else:
// calculate distance
//	dist[m]=distcnt/fcpu[Hz]*U[m/s]/2
//	dist[mm]=distcnt*(U[m/s]*10)/10*1000[mm/m]/fcpu[Hz]/2
//	dist[mm]=distcnt*(U[m/s]*10)/(10*fcpu[Hz]*2/1000[mm/m])
//	... dst_spd_sonic10=U[m/s]*10
ldwi	r7,distcnth
ldl		r0,[r7]
ldwi	r7,dst_spd_sonic10
ldw		r1,[r7]
mulu	r0,r1
ldli	r1,2*10*(fcpu/1000)				// 1000[mm/m]
$(s)// ********************************
$(s)ldwi	r1,2*10*(fcpu/1000000)		// 1000000[um/m]
$(s)// ********************************
// round
mov		r2,r1
lsfti	r2,-1
add		r0,r2
divu	r0,r1
// store
ldwi	r7,dst_dist
stw		[r7],r0

dst_meas_err_endif:
// return
ldbiu	r0,dst_err_no
dst_return:
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:
$(s)// ********************************
$(s)ldwi	r7,dht_buf+2
$(s)ldbiu	r0,25
$(s)stb		[r7],r0
$(s)ldwi	r7,dht_buf+3
$(s)ldbiu	r0,1
$(s)stb		[r7],r0
$(s)ldbiu	r0,dht_err_no
$(s)rtnw
$(s)// ********************************
// 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,[r7]
ldwi	r7,sytmmcrh
ldl		r0,[r7]
sub		r0,r2
ldli	r2,dht_usec_tcyc
cmp		r0,r2
blo		dht_poll
// send start
sytm_ofst_us
dht_sda_0
// wait tbe
ldwi	r7,sytmmcrl
ldwi	r1,dht_usec_tbe
ldw		r0,[r7]
cmp		r0,r1
blo		pcnt-6
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:
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

// 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,[r7]
ldwi	r7,dht_usec_prev
stl		[r7],r2
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
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_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		pdc3_not_0
// 0
ldbiu	r1,0a0
jalwr7	print_chr
bra		pdc3_fin

pdc3_not_0:
// for each r0=100, 10, 1
ldwi	r6,lab_pdc3_tab
ldbiu	r3,true							// omit leading zero flag
pdc3_loop:
ldw		r0,[r6]
mov		r0,r0
beq		pdc3_fin
// r2=r1/r0
ldbiu	r2,0
pdc3_div:
sub		r1,r0
blo		pcnt+4
addi	r2,1
bra		pdc3_div

// omit leading zero
mov		r3,r3
beq		pcnt+4
mov		r2,r2
beq		pdc3_omit
// print 1 digit
addi	r2,0a0
pushwm	r0,r1,r7
mov		r1,r2
jalwr7	print_chr
popwm	r7,r1,r0
ldbiu	r3,false
pdc3_omit:
// add back r1; loop
add		r1,r0
addi	r6,2
bra		pdc3_loop

pdc3_fin:
rtnw

pdc3_tab:
datw	100
datw	10
datw	1
datw	0

// ================================
// print long decimal r1 ; disturbed r0~r4,r6,r7
// ================================
print_lng_dec:
#$(s)// ********************************
#$(s)ldwi	r7,prindec
#$(s)stw	[r7],r1
#$(s)rtnw
#$(s)// ********************************
cmpi	r1,0
bne		pdc_not_0
// 0
ldbiu	r1,0a0
jalwr7	print_chr
bra		pdc_fin

pdc_not_0:
// for each r0=1000000000, ~, 10, 1
ldwi	r6,lab_pdc_tab
ldbiu	r3,true							// omit leading zero flag
pdc_loop:
ldl		r0,[r6]
cmpi	r0,0
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
cmpi	r3,0
beq		pcnt+4
cmpi	r2,0
beq		pdc_omit
// print 1 digit
addi	r2,0a0
pushlm	r0,r1,r7
mov		r1,r2
jalwr7	print_chr
poplm	r7,r1,r0
ldbiu	r3,false
pdc_omit:
// add back r1; loop
add		r1,r0
addi	r6,4
bra		pdc_loop

pdc_fin:
rtnw

pdc_tab:
datl	1000000000
datl	100000000
datl	10000000
datl	1000000
datl	100000
datl	10000
datl	1000
datl	100
datl	10
datl	1
datl	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
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

// ================================
// 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
lsli	r3,3
add		r0,r0
add		r0,r3
add		r0,r2
// loop
addi	r1,1
bra		atoi+2
a2i_finish:
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 decimal r2 to r1 ; disturbed r0,r2~r4,r6,r7
//	'\0' is copied after copying decimal
//	return: r1=pointer to the last '\0'
// ================================
strcpy_dec:
mov		r2,r2
bne		cpd_not_0
// 0
ldbiu	r2,0a0
stb		[r1],r2
addi	r1,1
ldbiu	r0,0
bra		cpd_fin

cpd_not_0:
// for each r0=10000, ~, 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	10000
datw	1000
datw	100
datw	10
datw	1
datw	0

// ================================
// 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+ dst,<mode_0_1>\r\n"
dats	"OK+ prn,<line_0_1>,<print_string>\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_msg_dst_inf:
dats	"OK+ temp=\0/10[degC]\r\n\0"
dats	"OK+ speed=\0[m/s]\r\n\0"
dats	"OK+ distance=\0[mm]\r\n\0"
str_msg_dst:
dats	"OK: dst (\0)\r\n\0"
str_msg_prn:
dats	"OK: prn\r\n\0"
str_msg_oled1:
dats	"/10 ℃,\0"
str_msg_oled2:
dats	" m/s            \0"
str_msg_oled3:
dats	"                \0"
str_msg_oled4:
dats	" mm\0"
str_msg_oled5:
dats	"dist=\0"
str_msg_oled6:
dats	"RDY             \0"
str_err_unspt:
dats	"ERR: unsupported command: \0\r\n\0"
str_err_syntx:
dats	"ERR: syntax\r\n\0"
str_err_not_nh:
dats	"ERR: not Nihonium, halted.\r\n\0"
str_err_nostws:
dats	"ERR: no STWSER unit found, halted.\r\n\0"
str_err_nofnjp:
dats	"ERR: no FONTJP unit found, halted.\r\n\0"
str_err_nodist:
dats	"ERR: no DISTUS unit found, halted.\r\n\0"
str_err_oled:
dats	"ERR: could not init. OLED display, ignore.\r\n\0"
str_err_req:
dats	"ERR,\0\r\n\0"
str_err_dst:
dats	"ERR: dst errcod=\0\r\n\0"
str_cmd_req:
dats	"req\0"
str_cmd_rrq:
dats	"rrq\0"
str_cmd_dst:
dats	"dst,\0"
str_cmd_prn:
dats	"prn,\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"

