// ================================
// LED Candle for MCOC115 (Moscovium)
//		(c) 2021	1YEN Toru
//
//
//		2021/05/01	ver.1.00
//
// ================================
asm		"mcoc_irom.mif"
#asm		"mcoc_irom.mem"
#asm		"mcoc_irom.dat2",bit16,list
incl	"mcoc115.incl"
# ================================
# 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_cma,0x2c					// comma ',' code
equ		max_rand_1_f,1024				// count of rand_1_f[]
equ		msec_intvl,8*4096/max_rand_1_f	// rand_1_f update interval [ms]
# variables
equ		va,ramtop
equ		candle_e,va						// candle enable
equ		va,va+2
equ		msec,va							// pwm: current time [ms]
equ		va,va+2
equ		idx_rand,va						// index of rand_1_f[] array
equ		va,va+2
equ		col_r,va						// color red for rgb-led (0~255)
equ		va,va+2
equ		col_g,va						// color green for rgb-led (0~255)
equ		va,va+2
equ		col_b,va						// color blue for rgb-led (0~255)
equ		va,va+2
equ		static_va,va
# array variables
equ		lbuf,va							// receive data buffer
equ		va,va+max_lbuf
equ		array_va,va
# ================================


// ================================
// 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

// initialize variables
ldwi	r7,candle_e
ldbiu	r0,1
stw		[r7],r0
ldwi	r7,col_r
ldbiu	r0,128
stw		[r7],r0
ldwi	r7,col_g
ldbiu	r0,8
stw		[r7],r0
ldwi	r7,col_b
ldbiu	r0,0
stw		[r7],r0

// tim0: 1kHz inverted pwm output, ovfe=1
ldwi	r7,timflg0
ldbiu	r0,timr_ovff|timr_cmaf|timr_cmbf|timr_ovfe
stw		[r7],r0
ldwi	r7,timprd0
ldbiu	r0,255-1
stw		[r7],r0
ldwi	r7,timpsc0
ldwi	r0,fcpu/1000/255-1
stw		[r7],r0
ldwi	r7,timctl0
ldbiu	r0,timr_ocma_2|timr_ocmb_2|timr_cnte
stw		[r7],r0

// tim1: 1kHz inverted PWM output
ldwi	r7,timprd1
ldbiu	r0,255-1
stw		[r7],r0
ldwi	r7,timpsc1
ldwi	r0,fcpu/1000/255-1
stw		[r7],r0
ldwi	r7,timctl1
ldbiu	r0,timr_ocma_2|timr_ocmb_2|timr_cnte
stw		[r7],r0

// set iv, interrupt enable
ldc		iv,lab_isr_vect
seie

// 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

// ================================
// 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 "cdl," command
ldwi	r1,lbuf
ldwi	r2,lab_str_cmd_cdl
ldbiu	r5,4
jalwr7	strncmp
mov		r0,r0
bne		cdl_notid
// ================================
// cdl,<on1_off0>
ldwi	r1,lbuf
addi	r1,4
jalwr7	atoi
ldwi	r7,candle_e
stw		[r7],r0
// response
ldwi	r1,lab_str_msg_ok
jalwr7	print
ldwi	r1,lbuf
jalwr7	print
ldwi	r1,lab_str_crlf
jalwr7	print
bra		no_data
cdl_notid:

// check "col," command
ldwi	r1,lbuf
ldwi	r2,lab_str_cmd_col
ldbiu	r5,4
jalwr7	strncmp
mov		r0,r0
bne		col_notid
// ================================
// col,<R_0_255>,<G_0_255>,<B_0_255>
// <R>
ldwi	r1,lbuf
addi	r1,4
jalwr7	atoi
ldwi	r7,col_r
stw		[r7],r0
ldb		r0,[r1]
cmpi	r0,chr_cma
bne		err_syntx
// <G>
addi	r1,1
jalwr7	atoi
ldwi	r7,col_g
stw		[r7],r0
ldb		r0,[r1]
cmpi	r0,chr_cma
bne		err_syntx
// <B>
addi	r1,1
jalwr7	atoi
ldwi	r7,col_b
stw		[r7],r0

// response
ldwi	r1,lab_str_msg_ok
jalwr7	print
ldwi	r1,lbuf
jalwr7	print
ldwi	r1,lab_str_crlf
jalwr7	print
bra		no_data
col_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
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

// end of command interpretation
no_data:


// ================================
// led candle
// if (candle_e)
ldwi	r7,candle_e
ldw		r0,[r7]
mov		r0,r0
bne		cdl_update
// candle_e==0: duty=0%
ldbiu	r0,0
ldwi	r7,timcma0
stw		[r7],r0
ldwi	r7,timcmb0
stw		[r7],r0
ldwi	r7,timcma1
stw		[r7],r0
bra		cdl_endpt

cdl_update:
// update rand_1_f
ldwi	r7,idx_rand
ldw		r0,[r7]
ldwi	r7,lab_rand_1_f
add		r7,r0
ldb		r4,[r7]							// r4=rand_1_f[idx_rand]

// r2=duty_r=col_r*r4/256;
// analogWrite (tim0_pwma, duty_r);
ldwi	r7,col_r
ldw		r1,[r7]
mov		r2,r4
jalwr7	mulu16
lsfti	r0,-8
ldwi	r7,timcma0
stw		[r7],r0

// r2=duty_g=col_g*r4/256;
// analogWrite (tim0_pwmb, duty_g);
ldwi	r7,col_g
ldw		r1,[r7]
mov		r2,r4
jalwr7	mulu16
lsfti	r0,-8
ldwi	r7,timcmb0
stw		[r7],r0

// r2=duty_b=col_b*r4/256;
// analogWrite (tim1_pwma, duty_b);
ldwi	r7,col_b
ldw		r1,[r7]
mov		r2,r4
jalwr7	mulu16
lsfti	r0,-8
ldwi	r7,timcma1
stw		[r7],r0

// analogWrite (tim1_pwmb, r4);
ldwi	r7,timcmb1
stw		[r7],r4

// candle: end point
cdl_endpt:

// ================================
// end of loop
bra		loop


// ================================
// ISR
// ================================
isr_vect:
ldcl	sr,sreg_bk_3
// msec++
ldwi	r7,msec
ldw		r0,[r7]
addi	r0,1
mov		r2,r0
// (msec>=msec_intvl)? msec-msec_intvl
ldwi	r1,msec_intvl
sub		r2,r1
blo		isr_next
mov		r0,r2
// idx_rand++
ldwi	r6,idx_rand
ldw		r1,[r6]
addi	r1,1
// (idx_rand>=max_rand_1_f)? idx_rand-max_rand_1_f
ldwi	r2,max_rand_1_f
mov		r3,r1
sub		r3,r2
blo		pcnt+2
mov		r1,r3
stw		[r6],r1							// idx_rand=r1
isr_next:
stw		[r7],r0							// msec=r0
// flag clear
ldwi	r7,timflg0
ldw		r0,[r7]
stw		[r7],r0
rti


// ================================
// 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
// 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_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"

// ================================
// 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 16*16=16 bits shift multiply routine:
//		r0=r1*r2 ; disturbed r1,r2
// ================================
mulu16:
ldbiu	r0,0
lsfti	r2,-1
bcc		pcnt+2
add		r0,r1
mov		r2,r2
beq		pcnt+4
lsfti	r1,1
bne		mulu16+2
rtnw

// ================================
// c string data
// ================================
str_msg_who:
dats	"OK: rgb_led_candle ver.1.00\r\n\0"
str_msg_rdy:
dats	"RDY\r\n\0"
str_msg_help:
dats	"OK+ cdl,<on1_off0>\r\n"
dats	"OK+ col,<R_0_255>,<G_0_255>,<B_0_255> \r\n"
dats	"OK+ who \r\n"
dats	"OK: help\r\n\0"
str_msg_ok:
dats	"OK: \0"
str_err_unspt:
dats	"ERR: unsupported command: \0"
str_err_syntx:
dats	"ERR: syntax\r\n\0"
str_cmd_cdl:
dats	"cdl,\0"
str_cmd_col:
dats	"col,\0"
str_cmd_who:
dats	"who\0"
str_cmd_help:
dats	"help\0"
str_crlf:
dats	"\r\n\0"

// ================================
// rand_1_f[] data
// ================================
rand_1_f:
incl	"mcoc_candle.incl"

