; ; wand.asm - main wand code ; ; Copyright (C) 2006 Nathan (Acorn) Pooley ; ; This program is free software; you can redistribute it and/or ; modify it under the terms of the GNU General Public License ; version 2 as published by the Free Software Foundation. ; ; This program is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; GNU General Public License (gpl.txt) for more details. ; ; You should have received a copy of the GNU General Public License ; along with this program; if not, write to the Free Software ; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ; ; You can contact the author, Nathan (Acorn) Pooley, by writing ; to Nathan (Acorn) Pooley, 949 Buckeye Drive, Sunnyvale, CA 94086, USA ; or through the form at http://www.rawbw.com/~acorn/wand/feedback.html ; ;#@DOC@ This is the main wand program ;########################################################################### ;################################ KERNEL STUFF ############################# ;########################################################################### #define HACK1 0 #define DBPRINT 1 #define SHOW_LED_DURING_MOTION 0 #define USE_CONST_MAGSQ_TH 1 #define QUIT_WHEN_SAMPLE_FULL 0 #define ENAB_BLINKS 0 #define ENAB_ISR_TAP 0 #define ENAB_OLD_TAP_HANDLE 0 #define ENAB_W_PARSE 0 #define ENAB_OLD_MOTION_SPELLS 0 #define ENAB_FMTB_MOTION_SPELLS 1 #define ENAB_TESTS 0 #define DBG_SPELL_MSG_IS_SPELL_NAME 0 ; ; this enables extra org directives to keep code from shifting around ; #define DBORG 0 #include "chip.inc" #include "kernel.inc" radix dec expand ;########################################################################### ;################################ ACCELEROMETER VALUES ##################### ;########################################################################### ; ; Still values ; ; x min = 0x4e ; x mid = 0x55 or 0x56 ; x max = 0x5c ; ; y min = 0x4e ; x mid = 0x55 or 0x56 ; y max = 0x5c ; ; small movements ; ; x = 51 - 5a ; y = 4e - 51 ; ; ; tap ; see TAPS under TIMING CHART ; fast rise time ; mag = 60 = 0x3c ; mag*mag = 0xe10 ; ; ; ; Accelerometer threshhold defaults ; ACC_THESH_X_AVG equ 0x55 ACC_THESH_X_MIN equ 0x4e ACC_THESH_X_MAX equ 0x5c ACC_THESH_Y_AVG equ 0x4f ACC_THESH_Y_MIN equ 0x4e ACC_THESH_Y_MAX equ 0x5c ; ; initial threshhold values ; ACC_INIT_AVGX equ 0x55 ; average x value (initial) ACC_INIT_AVGY equ 0x4f ; average y value (initial) ; ; Time to ignore false-taps after a tap (in sample times - 640usec) ; ACC_TAP_MASK_TIME equ 312 ; counts to mask sampler after a tap #if 1 ACC_INIT_TH_MAGSQ_TAP equ (0x20*0x20) ; min mag squared for tap ACC_INIT_TH_MAGSQ_Z equ (7*7)-1 ; min mag squared to start sampling ;ACC_INIT_TH_MAGSQ_S equ (5*6)-1 ; max mag squared to stop sampling ACC_INIT_TH_MAGSQ_S equ (2*2)-1 ; max mag squared to stop sampling ACC_TH_MAGSQ_WAKE equ (19*19) ; min magsq to wake up ; ; threshholds for saving an angle state or a pause state ; TH_IMP is impulse threshhold ; TH_TIME is time threshhold in sample-times (640us per sample) ; TH_MAG is magnitude threshhold ; ACC_TH_TIME_END equ 0x0927 ; end when still for this long (1.5sec) ACC_TH_TIME_RETIRE equ 0x009c ; max time to keep cur state w/out seeing it ACC_TH_TIME_PAUSE equ 0x009c ; min time to register a pause state ACC_TH_TIME_RETIRE_TAP equ 0x0005 ; max time to keep tap state w/out seeing it ;ACC_TH_TIME_RETIRE_TAP equ 0x009c ; max time to keep tap state w/out seeing it ; ; to save a sample one of these conditions must be met ; - magnitude > ACC_TH_MAG_TAP ; - time and impulse exceed threshholds ; - time and magnitude exceed threshholds ; ;ACC_TH_TIME_SAVE equ 0x0004 ; min time to register a new state ACC_TH_TIME_SAVE equ 0x0004 ; min time to register a new state ;ACC_TH_IMP_SAVE equ 0x0020 ; min impulse to register a new state ACC_TH_IMP_SAVE equ 0x0080 ; min impulse to register a new state ACC_TH_MAG_SAVE equ 0x0015 ; min impulse to register a new state ACC_TH_MAG_TAP equ 0x0020 ; mag to consider as a tap (for rythm) ACC_TH_MAG_DRAW equ 0x0006 ; min delta mag for draw enable ; ACC_TH_MAGSQ_STILL - max magsq to consider still (for ending spell cast) ACC_TH_MAGSQ_STILL equ (18*18) #else ; ; special values for debug taps only ; ACC_INIT_TH_MAGSQ_TAP equ (0x20*0x20) ; min mag squared for tap ACC_INIT_TH_MAGSQ_Z equ (0x20*0x20)-1 ; min mag squared to start sampling ACC_INIT_TH_MAGSQ_S equ (0x20*0x20)-1 ; max mag squared to stop sampling ACC_TH_TIME_END equ 0x0927 ; end when still for this long (1.5sec) ACC_TH_TIME_RETIRE equ 0x0001 ; max time to keep cur state w/out seeing it ACC_TH_TIME_PAUSE equ 0x0001 ; min time to register a pause state ACC_TH_TIME_RETIRE_TAP equ 0x0001 ; max time to keep tap state w/out seeing it ACC_TH_TIME_SAVE equ 0x0001 ; min time to register a new state ACC_TH_IMP_SAVE equ 0x0080 ; min impulse to register a new state ACC_TH_MAG_SAVE equ 0x0015 ; min impulse to register a new state ACC_TH_MAG_TAP equ 0x0020 ; mag to consider as a tap (for rythm) #endif ;########################################################################### ;################################ REGISTER SETTINGS ######################## ;########################################################################### ; ; ADCON0_OFF = 0000 0000 ; 7-6 reserved 00 ; 5-2 CHS3-0 0000 select channel 0 ; 1 GO/DONE 0 do not start conversion ; 0 ADON 0 A/D unit off ; ; ; Acc-X: (A) AN0 0000 0001 ; Acc-Y: (D) AN1 0000 0101 ; Acc-Xmin: (C) AN3 0000 1101 ; Acc-Xmax: (B) AN2 0000 1001 ; Acc-Ymin: (F) AN4 0001 0001 ; Acc-Ymax: (E) AN12 0011 0001 ; ADCON0_OFF equ 0x00 ADCON0_ACCX equ 0x01 ADCON0_ACCY equ 0x05 ADCON0_ACCXMIN equ 0x0d ADCON0_ACCXMAX equ 0x09 ADCON0_ACCYMIN equ 0x11 ADCON0_ACCYMAX equ 0x31 #define b_adgo ADCON0,1 ; ; ADCON1 = 0000 0000 ; 7-6 reserved 00 ; 5 VCFG1 0 Vref- = Vss ; 4 VCFG0 0 Vref+ = Vdd ; 3-0 PCFG3-0 0000 all available pins set as analog inputs ; REGVAL_ADCON1 equ 0x00 ; ; ADCON2 = 0001 0001 ; 7 ADFM = 0 left justified formt ; 6 reserved = 0 ; 5-3 ACQT2-0 = 010 4 Tad cycles for acquisition ; 2-0 ADCS2-0 = 001 A/D conversion clock = Fosc/8 (Tad = 2usec) ; ; Tad = 2usec ; 4 Tad for acquire ; 11 Tad for convert ; 15 Tad total = 30usec per convert ; REGVAL_ADCON2 equ 0x11 ; ; T3CON = 1011 1001 ; 7 RD16 = 1 16 bit read/write mode ; 6 T3CCP2 = 0 Timer1 is the clock source for CCP1 ; 5-4 RD16 = 11 1:8 prescaler ; 3 T3CCP1 = 1 Timer3 is the clock source for CCP2 ; 2 _T3SYNC = 0 unused in Fosc/4 mode ; 1 TMR3CS = 0 use Fosc/4 oscillator ; 0 TMR3ON = 1 Tim ; ; Used to count up to the a/d conversion. CCP2 clears the counter. ; REGVAL_T3CON_OFF equ 0x00 REGVAL_T3CON_AD equ 0xb9 ; ; CCP resets Timer3 & starts A/D conversion evey 640usec ; Fosc/4 = 1usec period ; 1:8 prescale = 8usec period ; 640usec/8usec = 80 clocks ; REGVAL_CCPRL2H equ 0 REGVAL_CCPRL2L equ 80 ; ; CCP2CON = 0000 1011 ; 7-6 reserved = 00 ; 5-4 DC2B1-0 = 00 unused in compare mode ; 3-0 CCP2M3-0 = 1011 mode (compare mode + special event trigger) ; ; Used to start a/d conersion of accx when timer3 reaches the trigger val ; REGVAL_CCP2CON equ 0x0b ;########################################################################### ;########################################################################### ;################################ MACROS ################################### ;########################################################################### ;########################################################################### ; ; Macros ; ; SOUT1 - print string in w_str_base1 block of strings ; SOUT1CR - print string followed by CR ; ; MACROS FOR ADDING TEXT TO WAND OUTPUT ; ------------------------------------- ; ; WCLR - clear wand ; WCOUT - wand print character in w ; WSOUT0 - wand print string in kki_str_base0 block of strings ; WSOUT1 - wand print string in w_str_base1 block of strings ; WSOUT - wand print string ; ; ; SOUT1 - print string from w_str_base1 block of strings ; SOUT1 macro str_addr movlw str_addr-w_str_base1 rcall w_sout_base1 endm SOUT1L macro str_addr movlw str_addr-w_str_base1 call w_sout_base1 endm SOUT1CR macro str_addr movlw str_addr-w_str_base1 rcall w_sout_base1_cr endm SOUT1CRL macro str_addr movlw str_addr-w_str_base1 call w_sout_base1_cr endm ; ; WCLR - clear wand ; WCLR macro rcall w_wclear endm WCLRL macro call w_wclear endm ; ; WCOUT - wand print character in w ; WCOUT macro char movlw char rcall w_wcout endm WCOUTL macro char movlw char call w_wcout endm ; ; WSOUT - print string ; WSOUT macro str_addr movlw LOW str_addr movwf v_strl movlw HIGH str_addr rcall w_wsout_wh endm WSOUTL macro str_addr movlw LOW str_addr movwf v_strl movlw HIGH str_addr call w_wsout_wh endm ; ; WSOUT0 - print string from str_base0 string table ; WSOUT0 macro str_addr movlw str_addr-kki_str_base0 rcall w_wsout_base0 endm WSOUT0L macro str_addr movlw str_addr-kki_str_base0 call w_wsout_base0 endm ; ; WSOUT1 - print string from w_str_base1 block of strings ; WSOUT1 macro str_addr movlw str_addr-w_str_base1 rcall w_wsout_base1 endm WSOUT1L macro str_addr movlw str_addr-w_str_base1 call w_wsout_base1 endm ;########################################################################### ;################################ ERRORS & BREAKPOINTS ##################### ;########################################################################### ERROR_B1_ISR_OVERRUN equ 0xb1 ; ISR took too long ERROR_B2_DRAW2_AD_OVERRUN equ 0xb2 ; A/D not done when expected ;########################################################################### ;########################################################################### ;################################ VARIABLES ################################ ;########################################################################### ;########################################################################### ; ; v_* - wand specific ; ; kk_* - kernel public label ; vk_* - kernel public byte variables ; bk_* - kernel public bit variables ; ; kki_* - kernel private label ; vki_* - kernel private byte variables ; bki_* - kernel private bit variables ; ; vaddr - next free RAM byte ; ;########################################################################### ;################################ EEPROM LAYOUT ############################ ;########################################################################### ; EEPROM_END - first free eeprom address ;########################################################################### ;################################ PERSISTANT GLOBAL VARIABLES ############## ;########################################################################### ; ; These variables are preserved across warm boot. ; ;########################################################################### ;################################ VARIABLES ################################ ;########################################################################### v_bits1 equ vaddr+0 v_bits2 equ vaddr+1 v_bits3 equ vaddr+2 v_tmp equ vaddr+3 vaddr+=4 #define b_do_accx v_bits1,0 ; next A/D conversion is x #define b_accbuf_sample v_bits1,1 ; enable sampling into FSR2 buffer #define b_parse_done v_bits1,2 ; set when no more accbuf entries for parse #define b_parse_wag v_bits1,3 ; set when wagging back & forth #if ENAB_BLINKS #define b_blink v_bits1,4 ; set when v_blink_cnt reaches 0 #endif #if ENAB_ISR_TAP #define b_tap_mask v_bits1,5 ; ignore tap while set (after a tap) #define b_tap v_bits1,6 ; set when a tap occurs #define b_tap_enable v_bits1,7 ; taps are enabled when set #endif #define b_draw_ok v_bits2,0 ; draw enabled (w_draw2) #define b_draw_go v_bits2,1 ; draw going (w_draw2) #define b_draw_scroll v_bits2,2 ; scroll the text #define b_d2_maybe_tap v_bits2,3 ; tap might have occurred (w_draw2) #define b_d2_tap v_bits2,4 ; tap occurred (w_draw2) #define b_d2_sleep v_bits2,5 ; time to sleep (w_draw2) #define b_got_spell v_bits2,6 ; set if spell was recognized #define b_spell_yes_no v_bits3,0 ; current string is a yes/no question #define b_spell_abort v_bits3,1 ; abort spell cast #define b_qsectmr0_done v_bits3,2 ; quarter-second-timer 0 expired if set #define b_qsectmr1_done v_bits3,3 ; quarter-second-timer 1 expired if set #define b_acc_motion v_bits3,4 ; set in acc isr when motion detected while ; sampling #define b_acc_finish v_bits3,5 ; if set isr will stop sampling #define b_show_time v_bits3,6 ; set to show time #if ENAB_ISR_TAP v_tap_bits equ vaddr+0 vaddr+=1 ; ; These bits are set for 1 loop (from w_main_run until next w_main_run) ; #define b_tap_up v_tap_bits,0 ; set when a up tap occurs #define b_tap_right v_tap_bits,1 ; set when a right tap occurs #define b_tap_down v_tap_bits,2 ; set when a down tap occurs #define b_tap_left v_tap_bits,3 ; set when a left tap occurs #endif v_accx equ vaddr+0 ; recent x value v_accy equ vaddr+1 ; recent x value v_accx_min equ vaddr+2 ; min x value v_accx_max equ vaddr+3 ; min x value v_accy_min equ vaddr+4 ; min x value v_accy_max equ vaddr+5 ; min x value vaddr+=6 ;=========================================================================== ; acc sampling ;=========================================================================== v_absx equ vaddr+0 ; abs value of v_accx + v_avgx_neg v_absy equ vaddr+1 ; abs value of v_accy + v_avgy_neg vaddr+=2 v_angle equ vaddr+0 ; angle measured v_mag equ vaddr+1 ; magnitude (sqrt of magsq) v_magsql equ vaddr+2 ; magnitude squared (low byte) v_magsqh equ vaddr+3 ; magnitude squared (high byte) vaddr+=4 #if ENAB_ISR_TAP v_tap_angle equ vaddr+0 ; angle of most recent tap v_tap_mask_acntl equ vaddr+1 ; time left to mask acc (low) v_tap_mask_acnth equ vaddr+2 ; time left to mask acc (high) v_th_magsqh_tap equ vaddr+3 ; threshhold for v_magsqh to be a tap vaddr+=4 #endif v_avgx_neg equ vaddr+0 ; negative of average x value (-0x4f = 0xb1) v_avgy_neg equ vaddr+1 ; negative of average y value (-0x55 = 0xab) v_th_magsqh equ vaddr+2 ; threshhold for v_magsql to sample v_th_magsql equ vaddr+3 ; threshhold for v_magsql to sample ; (v_th_magsql_z or s) v_th_retimeh equ vaddr+4 ; max time to hold state without seeing it v_th_retimel equ vaddr+5 vaddr+=6 #if !USE_CONST_MAGSQ_TH v_th_magsql_z equ vaddr+0 ; v_th_magsql when prev == zero (-8*8 = -64 = 0xc0) v_th_magsql_s equ vaddr+1 ; v_th_magsql when prev != zero (-7*7 = -49 = 0xcf) vaddr+=2 #endif #if HACK1 ; debug v_hack1_magsql equ vaddr+0 v_hack1_magsqh equ vaddr+1 v_hack1_mag equ vaddr+2 v_hack1_angle equ vaddr+3 v_hack1_a equ vaddr+4 v_hack1_b equ vaddr+5 v_hack1_c equ vaddr+6 v_hack1_d equ vaddr+7 vaddr+=8 #endif ;=========================================================================== ; function parameters ;=========================================================================== v_strh equ vaddr+0 ; string high pointer v_strl equ vaddr+1 ; string low pointer vaddr+=2 ;=========================================================================== ; drawing ;=========================================================================== v_sleep_wait equ vaddr+0 ; how long until we sleep v_draw_cnt equ vaddr+1 ; time before next column of pixels v_draw_mask equ vaddr+2 ; which ixel to draw v_tap_wait equ vaddr+3 ; wait between draw and tap vaddr+=4 v_drawbuf_startl equ vaddr+0 v_drawbuf_starth equ vaddr+1 v_drawbuf_endl equ vaddr+2 v_drawbuf_endh equ vaddr+3 vaddr+=4 #define SCROLL_SPEED 1 #if SCROLL_SPEED v_scrollspd equ vaddr+0 vaddr+=1 #endif #if ENAB_BLINKS ;=========================================================================== ; blink counter ;=========================================================================== v_blink_cnt equ vaddr+0 ; countdown to next blink (640 usec counter) v_blink_ptr equ vaddr+1 ; where we are in blink sequence (0=off) vaddr+=2 #endif ;=========================================================================== ; time temporaries - see w_pause_w and w_timer_set_fsr0 ;=========================================================================== v_th equ vaddr+0 ; time v_tl equ vaddr+1 ; v_t0l equ vaddr+2 ; time of s<mins crossing v_t0h equ vaddr+3 ; v_dtl equ vaddr+4 ; deltaT = (t0-t1)/4 v_dth equ vaddr+5 ; v_qsectmr0 equ vaddr+6 ; quarter second timer (see w_qsectmr0_set) v_qsectmr1 equ vaddr+7 ; quarter second timer (see w_qsectmr1_set) vaddr+=8 ;=========================================================================== ; spell casting ;=========================================================================== v_spell_ptrh equ vaddr+0 ; spellinfo for cast spell v_spell_ptrl equ vaddr+1 ; v_spell_yesh equ vaddr+2 ; spellinfo for yes v_spell_yesl equ vaddr+3 ; v_spell_noh equ vaddr+4 ; spellinfo for no v_spell_nol equ vaddr+5 ; vaddr+=6 #if ENAB_W_PARSE v_spell_len equ vaddr+0 ; # of bytes in cast spell vaddr+=1 #endif ;=========================================================================== ; Buffers ;=========================================================================== RAMBUF_DRAW equ 0x300 ; pixels to draw (LEN=0x400) RAMBUF_DRAW_END equ 0xf00 ; end of pixel draw buffer RAMBUF_RYTHM equ 0x300 ; rythm buffer (LEN=0x100) RAMBUF_MOTION equ 0x300 ; motion buffer (LEN=0x100) RAMBUF_ACC equ 0x500 ; acceleration sample buffer (LEN=0x700) RAMBUF_ACC_END equ 0xf00 ; end of acceleration sample buffer ;=========================================================================== ; MEMORY MAP ;=========================================================================== ; ; 0x0000 - 0x007f - access bank RAM ; 0x0080 - 0x00ff - bank 0 RAM (currently accessed through BSR register) ; ; 0x0100 - 0x0dff - buffer mem (see below) ; ; 0x0e00 - 0x0eff - ACC buf (coulod be used for BSR space if needed) ; 0x0f00 - 0x0f7f - persistant wand RAM (if needed - unused for now) ; 0x0f80 - 0x0fff - Special Function Registers (access bank addressable) ; ; BUFFERS ; 0x0100 - 0x01ff - TX ; 0x0200 - 0x02ff - RX ; 0x0300 - 0x03ff - DRAW M2LIST RYTHM ; 0x0400 - 0x04ff - DRAW M2LIST ; 0x0500 - 0x05ff - DRAW ACC M2LIST ; 0x0600 - 0x06ff - DRAW ACC M2LIST ; 0x0700 - 0x07ff - DRAW ACC M2LIST STBL2 ; 0x0800 - 0x08ff - DRAW ACC M3LIST STBL1 ; 0x0900 - 0x09ff - DRAW ACC M3LIST SPELLDATA ; 0x0a00 - 0x0aff - DRAW ACC M3LIST MMATRIX ; 0x0b00 - 0x0bff - DRAW ACC M3LIST STOKENS ; 0x0c00 - 0x0cff - DRAW ACC M3LIST MTOKENS ; 0x0d00 - 0x0dff - DRAW ACC ; 0x0e00 - 0x0eff - DRAW ACC ; 0x0f00 - 0x0f7f - persistant ram (unused) ; ; ; ;=========================================================================== ; TIMING CHART ;=========================================================================== ; ; CLOCKS ; 1 us/cycle - program clock in fast mode ; 122 us/cycle - program clock in slow mode ; 250 ms - bk_qsec set every 1/4 sec (from main_run to main_run) ; 1 min - bk_minute set evry minute (from main_run to main_run) ; 1 hour - bk_hour set evry hour (from main_run to main_run) ; 244 usec - TMR1L increments with this period ; 62 msec - TMR1H increments with this period (TMR1L overflow) ; 16 sec - TMR1H overflows every 16 seconds ; ; A/D ; 30 usec - time to do one A/D conversion (fast mode) (CALCULATED) ; (NOTE: measured time indicated definitely 48usec or less) ; 640 usec - time between kicking off X A/D conversion (for ISR mode) ; 5 msec - time to settle after turning Accelerometer on ; 700 usec - time to settle after turning A/D converter on ; 3.5 msec - time to settle after turning LEDs on/off ; (NOTE: LEDs can change value by 3 units (steady state)) ; (NOTE: LEDs can change value by 15 units (dynamic)) ; 2 usec - Tad (a/d time) 4 + 11 = 15 Tad per conversion (4 for acquire) ; ; TAPS ; Good taps jump 70+ units - peak reached in under 1 ms. ; Cusion taps jump 70+ units - peak reached in under 10 ms. ; Non-taps jump up to 50 units peak reached in over 30 ms. ; ; DRAW ; 9 usec - time each LED is on (1 at a time) ; 52 usec - time to turn on & off all 5 LEDs once ; 1456 usec - column time ; 8736 usec - character time (incl 1-col gap) ; ; ;########################################################################### ;########################################################################### ;################################ CODE ##################################### ;########################################################################### ;########################################################################### ;########################################################################### ;################################ MAIN PROGRAM VECTORS ##################### ;########################################################################### org kk_app_main goto w_main org kk_app_isr_low return org kk_app_isr_high rcall isr_ad retfie 1 ;########################################################################### ;################################ INTERRUPTS ############################### ;########################################################################### ; ; ISR timing: ; ; conversion takes 30usec ; ; time in usec==cycles ; ; isr time section ; -------- ------------ ; 17 top of x ; 3 bottom of x ; 19 top of y (all y if no sampling) ; <=47 top of astate ; ? top of sample ; <=31 calc angle ; ? calc mag (sqrt) ; ? sample ; ; ; <start x convert> ; 30 x convert time ; 45 time until y convert starts ; 30 y convert time ; 169 time to handle x ; --- ; 274 total time ; ; ; <start x> occurs every 640 usec ; ;=========================================================================== ; A/D interrupt ;=========================================================================== isr_ad: bcf b_adif #if ENAB_BLINKS ; ; blink timer - set b_blink when v_blink_cnt reaches 0 ; btfss b_blink dcfsnz v_blink_cnt,f bsf b_blink #endif btg b_do_accx btfsc b_do_accx bra isr_ad_y isr_ad_x: movlw ADCON0_ACCY movwf ADCON0 movf ADRESH,w movwf v_accx movwf v_absx cpfsgt v_accx_max ; remember x, maxx, minx movwf v_accx_max cpfslt v_accx_min movwf v_accx_min isr_ad_x_starty: bsf b_adgo ; start y conversion return ; ; here we are ready to read y result ; isr_ad_y: movlw ADCON0_ACCX movwf ADCON0 movf ADRESH,w cpfsgt v_accy_max movwf v_accy_max cpfslt v_accy_min movwf v_accy_min movwf v_accy movwf v_absy #if ENAB_ISR_TAP ; ; decrement tap mask counter ; if a tap occurred this will clr tapmask when zero ; if a tap did not occur this does nothing ; decfsz v_tap_mask_acntl,f bra isr_ad_astate dcfsnz v_tap_mask_acnth,f bcf b_tap_mask ; timer ran out - start looking for taps again #endif ;=========================================================================== ; ; calculate astate (magnitude and angle) ; ; v_angle - angle measured ; v_mag - magnitude (sqrt of v_magsq) ; v_magsql - magnitude squared (low byte) ; v_magsqh - magnitude squared (high byte) ; v_absx - abs value of v_accx + v_avgx_neg ; v_absy - abs value of v_accy + v_avgy_neg ; ; astate values ; 0x00 - 0x1f angle 0-31 ; 0x82 zero magnitude ; 0x84 scrambled ; ; v_avgx_neg - negative of average x value (-0x4f = 0xb1) ; v_avgy_neg - negative of average y value (-0x55 = 0xab) ; v_th_magsql - threshhold for v_magsql to sample (v_th_magsql_z or s) ; v_th_magsql_z - v_th_magsql when prev == zero ; v_th_magsql_s - v_th_magsql when prev != zero #if ENAB_ISR_TAP ; v_th_magsqh_tap - threshhold for v_magsqh to be a tap (-0xe = 0xf2) #endif ; isr_ad_astate: clrf v_angle ; ; calc abs x ; isr_ad_absx: movf v_avgx_neg,w addwf v_absx,f bnn isr_ad_absy negf v_absx movlw -31 movwf v_angle ; ; calc abs y ; isr_ad_absy: movf v_avgy_neg,w addwf v_absy,f bnn isr_ad_mag negf v_absy movlw 15 addwf v_angle,f negf v_angle ; ; calculate magnitude ; isr_ad_mag: setf v_mag ; assume max magnitude movf v_absx,w mulwf v_absx movff PRODL,v_magsql movff PRODH,v_magsqh movf v_absy,w mulwf v_absy movf PRODL,w addwf v_magsql,f movf PRODH,w addwfc v_magsqh,f bnc isr_ad_mag2 setf v_magsql ; clamp to max magnitude setf v_magsqh isr_ad_mag2: #if HACK1 movff v_magsql,v_hack1_magsql movff v_magsqh,v_hack1_magsqh clrf v_hack1_mag clrf v_hack1_angle #endif ; ; request to stop sampling? ; btfsc b_acc_finish bra isr_ad_sample_zero ; ; is magnitude big enough to register? ; movf v_magsql,w addwf v_th_magsql,w movf v_magsqh,w addwfc v_th_magsqh,w bnc isr_ad_sample_zero ; small magnitude - call it 0 ; ; if mag < ACC_TH_MAGSQ_STILL then skip shrink ; if mag >= ACC_TH_MAGSQ_STILL then set b_accbuf_motion ; movlw LOW (-ACC_TH_MAGSQ_STILL) addwf v_magsql,w movlw HIGH (-ACC_TH_MAGSQ_STILL) addwfc v_magsqh,w bnc isr_ad_shrink_done ; small mag - no shrink needed bsf b_acc_motion ; big mag - set motion bit ; ; ensure absx and absy are less than 0x40 ; (divide both by 2 or 4 if necessary) ; isr_ad_shrink: movf v_absx,w iorwf v_absy,w andlw 0xc0 bz isr_ad_shrink_done rrncf v_absx,f rrncf v_absy,f bcf v_absx,7 bcf v_absy,7 bra isr_ad_shrink isr_ad_shrink_done: #if ENAB_ISR_TAP ; ; big enough to be a tap? ; movf v_magsqh,w addwf v_th_magsqh_tap,w bnc isr_ad_sample ; not big enough to be a tap? ; ; mag is big enough to count as a tap ; isr_ad_tap: btfsc b_tap_enable ; skip tap if not enabled btfsc b_tap_mask ; skip tap if still masked from previous tap bra isr_ad_sample ; ; New tap!! ; movlw (HIGH ACC_TAP_MASK_TIME)+1 movwf v_tap_mask_acnth movlw (LOW ACC_TAP_MASK_TIME)+1 movwf v_tap_mask_acntl bsf b_tap_mask bsf b_tap rcall isr_calc_angle ; calc angle movf v_angle,w movwf v_tap_angle btfss b_accbuf_sample bra isr_ad_done bra isr_ad_sample2 #else bra isr_ad_sample #endif ;=========================================================================== ; ; SAMPLING VARIABLES ; ; ; input variables ; ; v_mag - current magnitude ; v_angle - current angle (garbage if v_mag is 0) ; ; ; prev zero sample (before current sample) ; v_smplpz_cnth equ vaddr+0 ; # of zero samples in a row v_smplpz_cntl equ vaddr+1 ; vaddr+=2 ; ; current sample ; v_smplc_imph equ vaddr+0 ; total impulse v_smplc_impl equ vaddr+1 v_smplc_cnth equ vaddr+2 ; total time v_smplc_cntl equ vaddr+3 v_smplc_angle equ vaddr+4 ; original angle v_smplc_min_mag equ vaddr+5 ; min magnitude v_smplc_max_mag equ vaddr+6 ; max magnitude v_smplc_best_angle equ vaddr+7 ; angle of max magnitude v_smplc_flags equ vaddr+8 ; flags vaddr+=9 #define SMPLC_FLAGS_INIT 0x80 #define b_smplc_zero v_smplc_flags,0 ; includes zero samples ; ; next zero sample (since current sample) ; v_smplnz_cnth equ vaddr+0 ; # of zero samples in a row v_smplnz_cntl equ vaddr+1 ; vaddr+=2 ; ; new sample (since current sample) ; v_smpln_imph equ vaddr+0 ; total impulse v_smpln_impl equ vaddr+1 v_smpln_cnth equ vaddr+2 ; total time v_smpln_cntl equ vaddr+3 v_smpln_angle equ vaddr+4 ; original angle v_smpln_min_mag equ vaddr+5 ; min magnitude v_smpln_max_mag equ vaddr+6 ; max magnitude v_smpln_best_angle equ vaddr+7 ; angle of max magnitude vaddr+=8 ;=========================================================================== ; ; mag is too small to register - use mag==0 ; isr_ad_sample_zero: clrf v_mag ; ; use v_th_magsql_z (larger threshhold) for v_th_magsql ; #if USE_CONST_MAGSQ_TH movlw HIGH (-ACC_INIT_TH_MAGSQ_Z) movwf v_th_magsqh movlw LOW (-ACC_INIT_TH_MAGSQ_Z) movwf v_th_magsql #else movff v_th_magsql_z,v_th_magsql #endif btfss b_accbuf_sample bra isr_ad_done ; ; increment v_smplnz_cntl,h ; incf v_smplnz_cntl,f bnc isr_ad_sample_zero2 incf v_smplnz_cnth,f bnc isr_ad_sample_zero2 setf v_smplnz_cntl ; clamp to 21 sec max setf v_smplnz_cnth isr_ad_sample_zero2: #if SHOW_LED_DURING_MOTION bsf bk_led2 #endif ; ; request to finish up? ; btfsc b_acc_finish bra isr_ad_sample_finish movlw LOW (-ACC_TH_TIME_END) addwf v_smplnz_cntl,w movlw HIGH (-ACC_TH_TIME_END) addwfc v_smplnz_cnth,w bnc isr_ad_sample_zero_done ; ; still for >ACC_TH_TIME_END ; ensure we have at least 4 samples ; movlw LOW (-(RAMBUF_ACC+12)) addwf FSR2L,w movlw HIGH (-(RAMBUF_ACC+12)) addwfc FSR2H,w bnc isr_ad_sample_zero_done isr_ad_sample_finish: ; ; we have some samples and have been still ; - quit sampling ; - send any pending sample ; bcf b_accbuf_sample bra isr_ad_sample_sendresult isr_ad_sample_zero_done: bra isr_ad_done ;=========================================================================== ; ; calc & record angle & magnitude ; isr_ad_sample: btfss b_accbuf_sample bra isr_ad_done rcall isr_calc_angle ; calc angle isr_ad_sample2: rcall isr_calc_mag ; calc magnitude #if HACK1 movff v_mag,v_hack1_mag movff v_angle,v_hack1_angle #endif #if SHOW_LED_DURING_MOTION bcf bk_led2 #endif ; ; use v_th_magsql_s (smaller threshhold) for v_th_magsql ; #if USE_CONST_MAGSQ_TH movlw HIGH (-ACC_INIT_TH_MAGSQ_S) movwf v_th_magsqh movlw LOW (-ACC_INIT_TH_MAGSQ_S) movwf v_th_magsql #else movff v_th_magsql_s,v_th_magsql #endif ; ; do we have a current angle? (v_smplc_angle >= 0) ; btfsc v_smplc_angle,7 bra isr_ad_sample_check_new ; no - check for new state ; ; has it been a while since we saw a current angle? ; (compare smpln_cnt+smplnz_cnt to v_th_retime) ; movf v_th_retimel,w addwf v_smplnz_cntl,w btfss STATUS,C addwf v_smpln_cntl,w movf v_th_retimeh,w addwfc v_smplnz_cnth,w bc isr_ad_sample_check_new addwf v_smpln_cnth,w bc isr_ad_sample_check_new isr_ad_sample_check_current: ; ; are we within +/-1 of current angle? ; movf v_angle,w subwf v_smplc_angle,w bz isr_ad_sample_current btfsc WREG,7 negf WREG addlw -1 bz isr_ad_sample_current addlw -0x1f+1 bz isr_ad_sample_current isr_ad_sample_check_new: ; ; do we even have a new angle? ; btfsc v_smpln_angle,7 bra isr_ad_sample_newnew ; no - check for new state ; ; are we within +/-1 of new angle? ; movf v_angle,w subwf v_smpln_angle,w bz isr_ad_sample_samenew btfsc WREG,7 negf WREG addlw -1 bz isr_ad_sample_samenew addlw -0x1f+1 bz isr_ad_sample_samenew ; ; we are seeing a brand new new angle ; isr_ad_sample_newnew: ; ; count any new time as pause time ; movf v_smpln_cntl,w addwf v_smplnz_cntl,f movf v_smpln_cnth,w addwfc v_smplnz_cnth,f bnc isr_ad_sample_newnew2 setf v_smplnz_cntl ; clamp to max cnt setf v_smplnz_cnth isr_ad_sample_newnew2: movf v_angle,w movwf v_smpln_angle movwf v_smpln_best_angle movf v_mag,w movwf v_smpln_max_mag movwf v_smpln_min_mag movwf v_smpln_impl clrf v_smpln_imph movlw 1 movwf v_smpln_cntl clrf v_smpln_cnth bra isr_ad_done ;=========================================================================== ; we are still seeing the same angle ; isr_ad_sample_current: ; ; integrate impulse ; movf v_mag,w addwf v_smplc_impl,f clrf WREG addwfc v_smplc_imph,f bnc isr_ad_sample_current2 setf v_smplc_imph ; clamp to max impulse setf v_smplc_impl isr_ad_sample_current2: ; ; are we including some zero samples? ; movf v_smplnz_cntl,w iorwf v_smplnz_cnth,w btfss STATUS,Z bsf b_smplc_zero ; yes ; ; increment sample time ; add in smplnz_cnt (and clear it) ; add in smpln_cnt (and clear it) ; Also add in any zcnt time that may exist (and clear it) ; bsf STATUS,C movf v_smplnz_cntl,w addwfc v_smplc_cntl,f movf v_smplnz_cnth,w addwfc v_smplc_cnth,f bc isr_ad_sample_current_maxtime movf v_smpln_cntl,w addwf v_smplc_cntl,f movf v_smpln_cnth,w addwfc v_smplc_cnth,f bnc isr_ad_sample_current3 isr_ad_sample_current_maxtime: setf v_smplc_cnth ; clamp to 21 sec max setf v_smplc_cntl isr_ad_sample_current3: ; ; clear next and next_zero ; clrf v_smplnz_cntl clrf v_smplnz_cnth clrf v_smpln_cntl clrf v_smpln_cnth setf v_smpln_angle ; invalidate next angle ; ; is this the min/max magnitude of the sample so far? ; movf v_mag,w cpfslt v_smplc_min_mag movwf v_smplc_min_mag cpfsgt v_smplc_max_mag bra isr_ad_sample_current_newmaxmag bra isr_ad_done isr_ad_sample_current_newmaxmag: movwf v_smplc_max_mag movf v_angle,w movwf v_smplc_best_angle ; ; is this a tap? ; movlw -ACC_TH_MAG_TAP addwf v_smplc_max_mag,w bnc isr_ad_done ; no - quit ; ; is a tap - use tap retire threshhold ; movlw HIGH (-ACC_TH_TIME_RETIRE_TAP) movwf v_th_retimeh movlw LOW (-ACC_TH_TIME_RETIRE_TAP) movwf v_th_retimel bra isr_ad_done ;=========================================================================== ; we are seeing the same new angle ; isr_ad_sample_samenew: ; ; integrate new impulse ; movf v_mag,w addwf v_smpln_impl,f clrf WREG addwfc v_smpln_imph,f bnc isr_ad_sample_samenew2 setf v_smpln_imph ; clamp to max impulse setf v_smpln_impl isr_ad_sample_samenew2: ; ; increment new time ; incf v_smpln_cntl,f clrf WREG addwfc v_smpln_cnth,f bnc isr_ad_sample_samenew3 setf v_smpln_cntl ; clamp to max cnt setf v_smpln_cnth isr_ad_sample_samenew3: ; ; is this the min/max magnitude of the sample so far? ; movf v_mag,w cpfslt v_smpln_min_mag movwf v_smpln_min_mag cpfsgt v_smpln_max_mag bra isr_ad_sample_samenew3a bra isr_ad_sample_samenew4 isr_ad_sample_samenew3a: movwf v_smpln_max_mag movf v_angle,w movwf v_smpln_best_angle isr_ad_sample_samenew4: ; ; max magnitude big enough to be a tap? ; (if so save even if no time) ; movlw -ACC_TH_MAG_TAP addwf v_smpln_max_mag,w bc isr_ad_sample_sendresult ; ; seen state for a while? ; movlw LOW (-ACC_TH_TIME_SAVE) addwf v_smpln_cntl,w movlw HIGH (-ACC_TH_TIME_SAVE) addwfc v_smpln_cnth,w bnc isr_ad_done ; ; Have we seen enough impulse or magnitude? ; movlw LOW (-ACC_TH_IMP_SAVE) addwf v_smpln_impl,w movlw HIGH (-ACC_TH_IMP_SAVE) addwfc v_smpln_imph,w bc isr_ad_sample_sendresult ; ; Have we seen enough magnitude? ; movlw -ACC_TH_MAG_SAVE addwf v_smpln_max_mag,w bc isr_ad_sample_sendresult ; ; have not seen enough impulse to count this angle yet ; bra isr_ad_done ; ; We have seen the new angle long enough & enough impulse. ; Time to call it the current angle. ; isr_ad_sample_sendresult: bsf b_acc_motion ; ; is there a current angle to send? ; btfsc v_smplc_angle,7 bra isr_ad_sample_newcurrent ; nope ; ; is there a previous zero-time to send? ; movf v_smplpz_cnth,w iorwf v_smplpz_cntl,w bz isr_ad_sample_sendc ; nope ; ; send pause ; 0 time (h) ; 1 time (l) ; 2 unused (0xff) ; 3 angle (0xff indicates pause) ; isr_ad_sample_sendz: rcall isr_ad_sample_pre_save movf v_smplpz_cnth,w movwf POSTINC2 ; time (h) movf v_smplpz_cntl,w movwf POSTINC2 ; time (l) setf POSTINC2 ; unused (0xff) setf POSTINC2 ; angle = 0xff ; ; pause always followed by actual angle - fall thru to send angle ; ; ; send current ; 0 time (h) ; 1 time (l) ; 2 max mag ; 3 angle (0xff indicates pause) ; 4 impulse (h) ; 5 impulse (l) ; 6 min mag ; 7 flags (see below) ; ; valid values for angle ; 0x00 - 0x1f = angle ; 0xff = pause ; 0xfe = end of buffer ; ; flag bits ; 0 set if any zero samples occurred ; 1-6 unused (0) ; 7 must be set (required by isr_ad_sample_pre_save) ; isr_ad_sample_sendc: rcall isr_ad_sample_pre_save movf v_smplc_cnth,w movwf POSTINC2 ; time (h) movf v_smplc_cntl,w movwf POSTINC2 ; time (l) movf v_smplc_max_mag,w movwf POSTINC2 ; max mag movf v_smplc_best_angle,w movwf POSTINC2 ; angle movf v_smplc_imph,w movwf POSTINC2 ; impulse (h) movf v_smplc_impl,w movwf POSTINC2 ; impulse (l) movf v_smplc_min_mag,w movwf POSTINC2 ; min mag movf v_smplc_flags,w movwf POSTINC2 ; flags ;=========================================================================== ; copy smplnz and smpln to smplpz and smplc ; isr_ad_sample_newcurrent: ; ; init flags ; movlw SMPLC_FLAGS_INIT movwf v_smplc_flags ; ; reset retire time threshhold ; movlw HIGH (-ACC_TH_TIME_RETIRE) movwf v_th_retimeh movlw LOW (-ACC_TH_TIME_RETIRE) movwf v_th_retimel ; ; is smplnz_cnt big enough to count as a pause? ; movlw LOW (-ACC_TH_TIME_PAUSE) addwf v_smplnz_cntl,w movlw HIGH (-ACC_TH_TIME_PAUSE) addwfc v_smplnz_cnth,w bc isr_ad_sample_newcurrent2 ; ; no pause - incorporate smplnz time into smpln ; ; ; are we including some zero samples? ; movf v_smplnz_cntl,w iorwf v_smplnz_cnth,w btfss STATUS,Z bsf b_smplc_zero ; yes ; ; incorporate smplnz time into smpln ; movf v_smplnz_cntl,w addwf v_smpln_cntl,f movf v_smplnz_cnth,w clrf v_smplnz_cnth clrf v_smplnz_cntl addwfc v_smpln_cnth,f bnc isr_ad_sample_newcurrent2 setf v_smpln_cnth ; clamp to max setf v_smpln_cntl isr_ad_sample_newcurrent2: movff v_smplnz_cntl,v_smplpz_cntl movff v_smplnz_cnth,v_smplpz_cnth movff v_smpln_cnth,v_smplc_cnth movff v_smpln_cntl,v_smplc_cntl movff v_smpln_imph,v_smplc_imph movff v_smpln_impl,v_smplc_impl movff v_smpln_angle,v_smplc_angle movff v_smpln_best_angle,v_smplc_best_angle movff v_smpln_min_mag,v_smplc_min_mag movff v_smpln_max_mag,v_smplc_max_mag clrf v_smplnz_cntl clrf v_smplnz_cnth clrf v_smpln_cntl clrf v_smpln_cnth setf v_smpln_angle isr_ad_done: btfss b_adif return ERR ERROR_B1_ISR_OVERRUN return ;=========================================================================== ; Ensure there are (at least) 8 entries (32 bytes) in the sample buffer ; isr_ad_sample_pre_save: ; ; check for end of sample buffer ; movlw LOW (-(RAMBUF_ACC_END-32)) addwf FSR2L,w movlw HIGH (-(RAMBUF_ACC_END-32)) addwfc FSR2H,w bnc isr_ad_sample_pre_save_ok ; ; reached end of buffer - set FSR2 and disable sampling ; lfsr FSR2,(RAMBUF_ACC_END-32-1) ; ; if last entry is first half of an angle entry then change it to a pause ; High bit is only clear if it is an angle. ; Could also be a flags entry, but that always has high bit set. ; btfss INDF2,7 setf INDF2 movf POSTINC2,w ; point to 4th to last entry ; ; disable sampling? ; #if QUIT_WHEN_SAMPLE_FULL bcf b_accbuf_sample #endif isr_ad_sample_pre_save_ok: return ;=========================================================================== ; subroutine to calculate v_mag = sqrt(v_magsq) ; At this point ; v_magsql, v_magsqh = magnitude squared ; ; Result is v_mag ; ; ; v_mag is the exponent of the magnitude ; v_magsqh,l is the input ; ; isr_calc_mag: clrf v_mag nop movf v_magsqh,w bnz isr_calc_mag_4 ; high byte is 0 - shift left 8 bits (sqrt shift 4 bits) movf v_magsql,w bz isr_calc_mag_done ; sq==0 so v_mag=0 movwf v_magsqh bsf v_mag,2 ; v_mag = 4 clrf v_magsql isr_calc_mag_4: movf v_magsqh,w andlw 0xf0 bnz isr_calc_mag_2 ; high nibble is 0 - shift left 4 bits (sqrt shift 2 bits) incf v_mag,f incf v_mag,f swapf v_magsqh,w andlw 0xf0 movwf v_magsqh swapf v_magsql,w andlw 0x0f iorwf v_magsqh,f swapf v_magsql,w ; low 4 bits are garbage now isr_calc_mag_2: movf v_magsqh,w andlw 0xc0 bnz isr_calc_mag_1 ; high 2 bits are 0 - shift left 2 bits (sqrt shift 1 bit) incf v_mag,f rlcf v_magsql,f rlcf v_magsqh,f rlcf v_magsql,f ; v_magsql is mostly garbage now rlcf v_magsqh,f isr_calc_mag_1: incf v_mag,f ; loop needs cnt + 1 ; ; round up (+0x02) ; decrement high 2 bits (-0x40) ; (High 2 bits will always be 01, 10, or 11) ; movlw 0x02-0x40 addwf v_magsqh,f rrncf v_magsqh,w rrncf WREG,w andlw 0x3f ; ; save TBLPTR & TABLAT regs in v_magsq and v_isr_save_tablat ; v_isr_save_tablat equ vaddr+0 vaddr+=1 movff TBLPTRL,v_magsql movff TBLPTRH,v_magsqh movff TABLAT,v_isr_save_tablat addlw LOW (w_sqrt_table) movwf TBLPTRL movlw HIGH (w_sqrt_table) addwfc TBLPTRU,w ; add 0 + c (TBLPTRU is always 0) movwf TBLPTRH tblrd* movf TABLAT,w bnz isr_calc_mag_loop_start ; ; special case when table lookup is 0 (actual value should be 0x100) ; movlw 0x80 movwf TABLAT decfsz v_mag,f bra isr_calc_mag_loop_start ; ; special case when maxed out - just set result to 0xff ; setf v_mag return isr_calc_mag_loop: bcf TABLAT,0 rrncf TABLAT,f isr_calc_mag_loop_start: decfsz v_mag,f bra isr_calc_mag_loop movff TABLAT,v_mag ; ; restore TBLPTR & TABLAT regs from v_magsq and v_isr_save_tablat ; movff v_magsql,TBLPTRL movff v_magsqh,TBLPTRH movff v_isr_save_tablat,TABLAT isr_calc_mag_done: return ; ; sqrt table, calculated by my_sqrt16.c ; w_sqrt_table: db 0x80, 0x83, 0x87, 0x8b, 0x8f, 0x92, 0x96, 0x99 db 0x9c, 0xa0, 0xa3, 0xa6, 0xa9, 0xac, 0xaf, 0xb2 db 0xb5, 0xb7, 0xba, 0xbd, 0xc0, 0xc2, 0xc5, 0xc7 db 0xca, 0xcc, 0xcf, 0xd1, 0xd4, 0xd6, 0xd9, 0xdb db 0xdd, 0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xeb, 0xed db 0xef, 0xf1, 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, 0xfe db 0x00 ;=========================================================================== ; subroutine to calculate angle ; At this point ; v_absx = abs val of x ; v_absy = abs val of y ; v_angle = ; 0 if x >= 0 && y >= 0 ; -15 if x >= 0 && y < 0 ; -31 if x < 0 && y >= 0 ; 16 if x < 0 && y < 0 ; isr_calc_angle: movf v_absx,w subwf v_absy,w bnn isr_ad_angle2 ; if absx <= absy skip this ; ; absx > absy ; movlw 7 ; angle = -(angle+7) addwf v_angle,f negf v_angle movf v_absy,w ; swap absx <-> absy movff v_absx,v_absy movwf v_absx isr_ad_angle2: movf v_absx,w addwf v_absx,w ; w = absx * 2 movwf v_absx addwf v_absx,f ; v_absx = absx * 4 ; ; compare 2*absx >? absy ; subwf v_absy,w bnn isr_ad_angle3 ; if 2*absx <= absy skip this ; ; 2*absx > absy ; movlw 3 ; angle = -(angle+3) addwf v_angle,f negf v_angle movf v_absy,w ; w = 3*absy addwf v_absy,w addwf v_absy,w movff v_absx,v_absy ; swap 4*absx and 3*absy movwf v_absx isr_ad_angle3: ; ; do one of these comparisons: ; 4*absx >? 1*absy ; 3*absy >? 4*absx ; movf v_absx,w ; 4*absx or 3*absy subwf v_absy,w ; absy or 4*absx btfsc STATUS,N incf v_angle,f ; v_absx > v_absy - increment angle ; ; absolute value is resulting angle ; btfsc v_angle,7 negf v_angle ; ; compensate for 45 degree rotation of sensor ; movf v_angle,w addlw -4 andlw 0x1f movwf v_angle return #if DBORG org 0x0f00 #endif ;########################################################################### ;################################ DEBUG FUNCTIONS ########################## ;########################################################################### ; ; Macros: ; ; DB_BYTE ch,reg print char and register (save & restore w & other regs) ; DB_FLUSH flush tx buffer ; DB_BYTE macro ch,reg movwf v_dbg_save_w movff reg,v_dbg_low movlw ch call w_dbg_byte endm DB_FLUSH macro call w_dbg_flush endm v_dbg_low equ vaddr+0 ; v_dbg_ch equ vaddr+1 ; v_dbg_save_w equ vaddr+2 ; v_dbg_save_fsr0l equ vaddr+3 ; v_dbg_save_fsr0h equ vaddr+4 ; vaddr+=5 ; ; Functions: ; ; w_dbg_byte - print a byte with a char ; w_dbg_flush - flush tx buffer ; ; ; w_dbg_byte - print a byte with a char ; v_dbg_low - byte ; v_dbg_char - character ; w_dbg_byte: btfss RCSTA,SPEN ; do not bother to print if serial disabled return movff FSR0L,v_dbg_save_fsr0l movff FSR0H,v_dbg_save_fsr0h call kk_cout COUTL '=' movf v_dbg_low,w call kk_outbyte COUTL ' ' w_dbg_return: movff v_dbg_save_fsr0l,FSR0L movff v_dbg_save_fsr0h,FSR0H movf v_dbg_save_w,w return w_dbg_flush: btfsc RCSTA,SPEN ; do not bother to print if serial disabled btfsc bk_rs_halt return call w_main_run movf vk_tx_cnt,w bnz w_dbg_flush return ;########################################################################### ;################################ A/D FUNCTIONS ############################ ;########################################################################### ; ; w_ad_init - turn on the accelerometer for non-ISR sampling ; w_ad_start - turn on the accelerometer ; w_ad_stop - turn off the accelerometer ; w_ad_sample_finish - turn off accelerometer and flush sample output ; w_sample_start - start sampling into buffer (call after w_ad_start) ; w_sample_clear - clear sample buffer to 0 ; ; #if ENAB_ISR_TAP ; w_tap_enable - clear and enable taps (call after w_ad_start) #endif ;=========================================================================== ; w_ad_start - turn on the accelerometer & start ISR ;=========================================================================== w_ad_start: ; ; initialize accelerometer & A/D conversion ; rcall w_ad_init ; ; setup auto-sampling and ISR ; clrf CCPR2H movlw REGVAL_CCPRL2L movwf CCPR2L movlw REGVAL_CCP2CON movwf CCP2CON bsf b_adip ; a/d interrupt is high priority bsf b_adie ; a/d interrupt is enabled movlw REGVAL_T3CON_AD movwf T3CON ; start timer3 return ;=========================================================================== ; w_ad_init - turn on the accelerometer (no ISR) ;=========================================================================== w_ad_init: ; ; disable isr while we set things up ; bcf b_gieh ; disable high priority interrupts ; ; stop ongoing conversion (if any) ; rcall w_ad_stop ; ; clear timer3 ; clrf TMR3H clrf TMR3L ; ; wait until accelerometer settles ; call w_pause_ad_settle ; ; disable sampling ; bcf b_accbuf_sample ; ; setup min/max values ; setf v_accx_min setf v_accy_min clrf v_accx_max clrf v_accy_max clrf v_accx clrf v_accy ; ; init astate ; clrf v_angle clrf v_mag #if ENAB_ISR_TAP ; ; disable taps ; bcf b_tap bcf b_tap_mask bcf b_tap_enable #endif ; ; point FSR2 at acceleration buffer ; lfsr FSR2,RAMBUF_ACC ; ; turn on accelerometer ; bcf b_acc_disable ; ; set up timing ; movlw KERNVAL_ADCON2 movwf ADCON2 ; ; set up to sample x axis ; movlw ADCON0_ACCX movwf ADCON0 bsf b_do_accx ; start with x axis ; ; disable Capture Compare (auto-triggers accelerometer) ; clrf CCP2CON ; ; disable a/d interrupt ; bcf b_adie ; a/d interrupt is disabled bcf b_adif ; clear any old pending interrupt ; ; re-enable high priority interrupts ; bsf b_gieh ; enable high priority interrupts return ;=========================================================================== ; w_ad_sample_finish - turn off accelerometer and flush sample output ;=========================================================================== w_ad_sample_finish: rcall w_ad_stop rcall isr_ad_sample_sendresult rcall isr_ad_sample_sendresult ; ; mark end of buffer with special sample ; (save 2 copies in case first is 2nd half of angle sample) ; rcall isr_ad_sample_pre_save ; ; long pause ; clrf POSTINC2 ; time(h) = 0 setf POSTINC2 ; time(l) = 0xff setf POSTINC2 ; unused setf POSTINC2 ; angle = 0xff (pause) ; ; mark end of buffer ; clrf POSTINC2 setf POSTINC2 setf POSTINC2 movlw 0xfe movwf POSTINC2 ; 0xfe in angle marks end of samples return ;=========================================================================== ; w_ad_stop - turn off the accelerometer ;=========================================================================== w_ad_stop: bcf b_adie ; a/d interrupt is disabled clrf T3CON ; stop timer3 btfsc b_adgo bra w_ad_stop ; wait until any a/d conversion completes clrf ADCON0 ; a/d unit off bsf b_acc_disable ; disable accelerometer power return #if ENAB_ISR_TAP ;=========================================================================== ; w_tap_enable - clear and enable taps ;=========================================================================== w_tap_enable: bcf b_tap bcf b_tap_mask bsf b_tap_enable clrf v_tap_bits return #endif ;=========================================================================== ; w_sample_start - begin storing samples into buffer ; (call w_ad_start first) ;=========================================================================== w_sample_start: bcf b_accbuf_sample ; disable sampling bcf b_acc_finish ; disable finish request lfsr FSR2, RAMBUF_ACC ; ; init astate buffering ; clrf v_angle clrf v_mag #if USE_CONST_MAGSQ_TH movlw HIGH (-ACC_INIT_TH_MAGSQ_Z) movwf v_th_magsqh movlw LOW (-ACC_INIT_TH_MAGSQ_Z) movwf v_th_magsql #else movff v_th_magsql_z,v_th_magsql #endif movlw HIGH (-ACC_TH_TIME_RETIRE) movwf v_th_retimeh movlw LOW (-ACC_TH_TIME_RETIRE) movwf v_th_retimel ; ; init sampling state vars ; setf v_smplc_angle ; we have no sample angle setf v_smpln_angle ; we have no new sample angle clrf v_smpln_cntl ; no new sample time clrf v_smpln_cnth clrf v_smplnz_cntl ; no new zero sample time clrf v_smplnz_cnth #if ENAB_W_PARSE ; ; store initial sample in buffer ; rcall w_sample_store_zero #endif bsf b_accbuf_sample ; enable sampling return #if ENAB_W_PARSE ;=========================================================================== ; w_sample_store_zero - store a zero-entry in acc buffer ; call with b_accbuf_sample not set ;=========================================================================== w_sample_store_zero: rcall isr_ad_sample_pre_save setf POSTINC2 ; time (l) max setf POSTINC2 ; time (h) max setf POSTINC2 ; time (h) max setf POSTINC2 ; angle - none return #endif ;=========================================================================== ; w_sample_clear - clear sample & motion buffer to 0 ;=========================================================================== w_sample_clear: lfsr FSR0,RAMBUF_ACC w_sample_clear_loop: clrf POSTINC0 movlw LOW RAMBUF_ACC_END subwf FSR0L,w movlw HIGH RAMBUF_ACC_END subwfb FSR0H,w bnc w_sample_clear_loop return #if DBORG org 0x1100 #endif ;########################################################################### ;################################ STRINGS ################################## ;########################################################################### #include "wstrings.inc" w_sout_base1: addlw LOW w_str_base1 movwf TBLPTRL movlw HIGH w_str_base1 addwfc TBLPTRU,w ; add 0 + c (TBLPTRU is always 0) ; fall thru w_sout_wh: btfss RCSTA,SPEN ; do not bother to print if serial disabled return goto kk_sout_wh w_outbyte: btfss RCSTA,SPEN ; do not bother to print if serial disabled return goto kk_outbyte w_outbyte_sp: btfss RCSTA,SPEN ; do not bother to print if serial disabled return call kk_outbyte movlw ' ' goto kk_cout w_sout_base1_cr: btfss RCSTA,SPEN ; do not bother to print if serial disabled return rcall w_sout_base1 ; fall thru w_outcr: btfss RCSTA,SPEN ; do not bother to print if serial disabled return call kk_outcr bra w_dbg_flush ;########################################################################### ;################################ LED BLINKING ############################# ;########################################################################### #if ENAB_BLINKS ; ; START_BLINK macro begins a blink sequence ; START_BLINK macro addr movlw addr-w_blinkpatterns+1 movwf v_blink_ptr bsf b_blink endm w_blinkpatterns: w_blinkpat_left: ; (down-up) db 0xfb, 0x04 db 0xff, 0x5f db 0xf7, 0x04 db 0xff, 0x5f db 0xef, 0x04 db 0xff, 0x5f db 0xdf, 0x04 db 0xff, 0x5f db 0xbf, 0x04 db 0xff, 0x5f w_blinkpat_up: db 0x7f, 0x04 db 0xff, 0x5f db 0xbf, 0x04 db 0xff, 0x5f db 0xdf, 0x04 db 0xff, 0x5f db 0xef, 0x04 db 0xff, 0x5f db 0xf7, 0x04 db 0xff, 0x5f db 0xfb, 0x04 db 0x00, 0x00 w_blinkpat_right: ; (up-down) db 0x7f, 0x04 db 0xff, 0x5f db 0xbf, 0x04 db 0xff, 0x5f db 0xdf, 0x04 db 0xff, 0x5f db 0xef, 0x04 db 0xff, 0x5f db 0xf7, 0x04 db 0xff, 0x5f w_blinkpat_down: db 0xfb, 0x04 db 0xff, 0x5f db 0xf7, 0x04 db 0xff, 0x5f db 0xef, 0x04 db 0xff, 0x5f db 0xdf, 0x04 db 0xff, 0x5f db 0xbf, 0x04 db 0xff, 0x5f db 0x7f, 0x04 db 0x00, 0x00 w_blinkpat_countdown: db 0xff, 0x01 db 0x03, 0x04 db 0xff, 0xff db 0x07, 0x04 db 0xff, 0xff db 0x0f, 0x04 db 0xff, 0xff db 0x1f, 0x04 db 0xff, 0xff db 0x3f, 0x04 db 0xff, 0xff db 0x7f, 0x04 db 0x00, 0x00 w_blinkpat_tip: db 0xff, 0xff db 0xfb, 0x04 db 0x00, 0x00 ; ; Call w_blink every main loop to handle blinking. ; Aceleration interrupt must be on (it implements the timer) ; w_blink: movf v_blink_ptr,w ; skip if no sequence is going bz w_blink_end addlw LOW (w_blinkpatterns-1) movwf TBLPTRL movlw HIGH (w_blinkpatterns-1) addwfc TBLPTRU,w ; add 0 + c (TBLPTRU is always 0) movwf TBLPTRH movlw KERNVAL_TRISB_LED_MASK iorwf TRISB,f incf v_blink_ptr,f incf v_blink_ptr,f tblrd*+ movf TABLAT,w bz w_blink_finish andwf TRISB,f tblrd*+ movff TABLAT,v_blink_cnt w_blink_end: bcf b_blink return w_blink_finish: clrf v_blink_ptr bra w_blink_end #endif ;########################################################################### ;################################ HANDLE TAPS ############################## ;########################################################################### #if ENAB_OLD_TAP_HANDLE ; ; Handle taps (call when b_tap is set) ; w_tap: #if DBPRINT ; ; debug - print tap ; COUTL 'T' COUTL 'a' COUTL 'p' movf v_tap_angle,w call kk_outbyte call kk_outcr #endif ; ; clear tap bit ; bcf b_tap ; ; round tap angle to quadrant ; movf v_tap_angle,w addlw 4 rrncf WREG,w rrncf WREG,w rrncf WREG,w andlw 0x03 ; ; up tap? ; w_tap_up: bnz w_tap_right #if ENAB_BLINKS START_BLINK w_blinkpat_up #endif bsf b_tap_up return ; ; right tap? ; w_tap_right: decfsz WREG,w bra w_tap_down #if 0 #if ENAB_BLINKS START_BLINK w_blinkpat_right #endif #endif bsf b_tap_right return ; ; down tap? ; w_tap_down: decfsz WREG,w bra w_tap_left #if ENAB_BLINKS START_BLINK w_blinkpat_down #endif bsf b_tap_down return ; ; left tap? ; w_tap_left: #if 0 #if ENAB_BLINKS START_BLINK w_blinkpat_left #endif #endif bsf b_tap_left return #endif ;########################################################################### ;################################ DRAW CHARACTERS ########################## ;########################################################################### #if DBORG org 0x1300 #endif ; ; DB_DRAW_ABCD - print a,b,c,d when state transition occurs ; DB_DRAW_LED - indicate state on LEDs ; DB_DRAW_TAP - print when tap occurs ; DB_DRAW_SLEEP - print when we need to sleep ; DB_DRAW_STOP - print when stopping ; DB_DRAW_TIME - print min/max time ; DB_DRAW_WHERE - record where we are in program ; #define DB_DRAW_ABCD 0 #define DB_DRAW_LED 0 #define DB_DRAW_TAP 1 #define DB_DRAW_SLEEP 1 #define DB_DRAW_STOP 1 #define DB_DRAW_TIME 0 #define DB_DRAW_WHERE 0 #if DB_DRAW_WHERE v_draw_where1 equ vaddr+0 v_draw_where2 equ vaddr+1 vaddr+=2 DB_DWHERE1 macro val movlw val movwf v_draw_where1 endm DB_DWHERE2 macro val movlw val movwf v_draw_where2 endm #else DB_DWHERE1 macro val endm DB_DWHERE2 macro val endm #endif v_draw_val equ vaddr+0 ; pixel value for current column v_accs equ vaddr+1 ; v_accx - v_accy v_maxs equ vaddr+2 ; max value of v_accs (or threshhold) v_mins equ vaddr+3 ; min value of v_accs (or threshhold) v_last_maxs equ vaddr+4 ; previous max value of v_accs v_last_mins equ vaddr+5 ; previous min value of v_accs vaddr+=6 v_tdrawl equ vaddr+0 ; time when drawing should commence v_tdrawh equ vaddr+1 ; v_tendl equ vaddr+2 ; time when drawing should commence v_tendh equ vaddr+3 ; vaddr+=4 v_zcnt equ vaddr+0 ; how long since magnitude was near 0 (for tap) vaddr+=1 v_tapx equ vaddr+0 ; x and y from tap v_tapy equ vaddr+1 ; vaddr+=2 ; ; all LEDs off ; accelerometer on ; #if HW_VERSION>=2 DRAW2_TRISB_OFF_VAL equ KERNVAL_TRISB_LED_MASK #else DRAW2_TRISB_OFF_VAL equ 0xfd #endif ; ; begin draw sequence ; w_draw2: ; ; check for scrolling (long message) ; rcall w_wscrollcheck call w_ad_init clrf v_accx clrf v_accy movlw DRAW2_TRISB_OFF_VAL movwf v_draw_val ; ; enable brightest LEDS ; bcf b_maxbright_disable bcf b_medbright_disable ; ; wait before sleeping ; allow taps immediately ; movlw DRAW2_SLEEP_WAIT movwf v_sleep_wait setf v_tap_wait ; ; tap stuff ; setf v_zcnt bcf b_d2_tap bcf b_d2_sleep bcf b_d2_maybe_tap ; ; wait for ACC & A/D to warm up ; rcall w_pause_ad_settle ; ; read acc ; rcall w_d2_column movf v_accs,w movwf v_last_maxs movwf v_last_mins ; ; init v_maxs, v_mins ; rcall w_d2_calcmax rcall w_d2_calcmin ; ; init time ; rcall w_d2_trans_min rcall w_d2_trans_min ;============================== ; transition to lookmax state ;============================== w_d2_lookmax_trans: DB_DWHERE1 0x11 rcall w_d2_trans_max w_d2_lookmax_drawstop: DB_DWHERE1 0x12 rcall w_d2_draw_stop #if DB_DRAW_ABCD COUTL 'a' call kk_outcr #endif #if DB_DRAW_LED bcf bk_led4 bsf bk_led3 bsf bk_led2 bsf bk_led1 #endif ;============================== ; w_d2_lookmax STATE ;============================== w_d2_lookmax: DB_DWHERE1 0x21 rcall w_d2_column DB_DWHERE1 0x22 rcall w_main_run btfsc bk_rs_halt bra w_d2_stop DB_DWHERE1 0x23 ; ; every 1/4 sec inc mins to ensure we dont get stuck ; btfsc bk_qsec rcall w_d2_qsec_lookmax DB_DWHERE1 0x24 rcall w_d2_column btfsc b_d2_tap bra w_d2_tap btfsc b_d2_sleep bra w_d2_sleep movf v_accs,w cpfsgt v_maxs movwf v_maxs cpfsgt v_mins bra w_d2_lookmax ;============================== ; transition to lookmin state ;============================== w_d2_lookmin_trans: DB_DWHERE1 0x31 rcall w_d2_draw_stop DB_DWHERE1 0x32 rcall w_d2_trans_min #if DB_DRAW_ABCD COUTL 'b' call kk_outcr #endif #if DB_DRAW_LED bsf bk_led4 bcf bk_led3 bsf bk_led2 bsf bk_led1 #endif ;============================== ; w_d2_lookmin STATE ;============================== w_d2_lookmin: DB_DWHERE1 0x41 rcall w_d2_column DB_DWHERE1 0x42 rcall w_main_run btfsc bk_rs_halt bra w_d2_stop DB_DWHERE1 0x43 #if 0 ; ; test rx overflow ; COUTL 'X' call kk_outcr bra w_d2_lookmin #endif #if DB_DRAW_ABCD btfss bk_qsec bra w_d2_lookmin_noprint COUTL 'N' COUTL ' ' movf v_last_mins,w call kk_outbyte COUTL ' ' movf v_mins,w call kk_outbyte COUTL ' ' movf v_maxs,w call kk_outbyte COUTL ' ' movf v_last_maxs,w call kk_outbyte call kk_outcr w_d2_lookmin_noprint: #endif ; ; every 1/4 sec dec maxs to ensure we dont get stuck ; btfsc bk_qsec rcall w_d2_qsec_lookmin DB_DWHERE1 0x44 rcall w_d2_column btfsc b_d2_tap bra w_d2_tap btfsc b_d2_sleep bra w_d2_sleep movf v_accs,w cpfslt v_mins movwf v_mins cpfsgt v_maxs bra w_d2_lookmax_trans btfss b_draw_ok bra w_d2_lookmin ; ; start drawing if it is time ; movf v_tl,w subwf v_tdrawl,w movf v_th,w subwfb v_tdrawh,w bnn w_d2_lookmin DB_DWHERE1 0x45 rcall w_d2_column ; ; scroll text ; #if SCROLL_SPEED rcall w_wscroll_inc rcall w_d2_column rcall w_wscroll_inc btfss v_scrollspd,0 bra w_d2_draw_start rcall w_d2_column rcall w_wscroll_inc btfss v_scrollspd,1 bra w_d2_draw_start rcall w_d2_column rcall w_wscroll_inc btfss v_scrollspd,2 bra w_d2_draw_start rcall w_d2_column rcall w_wscroll_inc btfss v_scrollspd,3 bra w_d2_draw_start rcall w_d2_column rcall w_wscroll_inc rcall w_d2_column rcall w_wscroll_inc btfss v_scrollspd,4 bra w_d2_draw_start rcall w_d2_column rcall w_wscroll_inc rcall w_d2_column rcall w_wscroll_inc btfss v_scrollspd,5 bra w_d2_draw_start rcall w_d2_column rcall w_wscroll_inc rcall w_d2_column rcall w_wscroll_inc btfss v_scrollspd,6 bra w_d2_draw_start rcall w_d2_column rcall w_wscroll_inc rcall w_d2_column rcall w_wscroll_inc btfss v_scrollspd,7 bra w_d2_draw_start rcall w_d2_column rcall w_wscroll_inc rcall w_d2_column rcall w_wscroll_inc bra w_d2_draw_start #else rcall w_wscroll_inc rcall w_d2_column rcall w_wscroll_inc rcall w_d2_column rcall w_wscroll_inc bra w_d2_draw_start #endif ;============================== ; restart drawing ;============================== w_d2_draw_restart: movwf v_mins ;============================== ; start drawing ;============================== w_d2_draw_start: DB_DWHERE1 0x51 rcall w_d2_column rcall w_main_run btfsc bk_rs_halt bra w_d2_stop ; ; setting v_sleep_wait indicates we see motion (do not sleep) ; setting v_tap_wait indicates we see motion (ignore tap) ; movlw DRAW2_SLEEP_WAIT movwf v_sleep_wait movlw DRAW2_TAP_WAIT movwf v_tap_wait movff v_drawbuf_starth,FSR0H movff v_drawbuf_startl,FSR0L movlw 1 movwf v_draw_cnt bsf b_draw_go #if DB_DRAW_ABCD COUTL 'c' call kk_outcr #endif #if DB_DRAW_LED bsf bk_led4 bsf bk_led3 bcf bk_led2 bsf bk_led1 #endif ;============================== ; w_d2_drawmin STATE ;============================== w_d2_drawmin: DB_DWHERE1 0x61 rcall w_d2_column DB_DWHERE1 0x62 ; ; stop drawing if it is time ; movf v_tl,w subwf v_tendl,w movf v_th,w subwfb v_tendh,w bn w_d2_drawmin_done DB_DWHERE1 0x63 ; ; if s<mins then restart draw ; movf v_accs,w cpfslt v_mins bra w_d2_draw_restart DB_DWHERE1 0x64 ; ; if s>maxs then transition to drawmax state ; cpfsgt v_maxs bra w_d2_drawmax_trans DB_DWHERE1 0x65 rcall w_d2_column btfsc b_draw_go bra w_d2_drawmin ; ; Done drawing ; w_d2_drawmin_done: rcall w_d2_draw_stop bra w_d2_lookmin ;============================== ; transition to drawmax state ;============================== w_d2_drawmax_trans: rcall w_d2_trans_max #if DB_DRAW_ABCD COUTL 'd' call kk_outcr #endif #if DB_DRAW_LED bsf bk_led4 bsf bk_led3 bsf bk_led2 bcf bk_led1 #endif ;============================== ; w_d2_drawmax STATE ;============================== w_d2_drawmax: rcall w_d2_column ; ; if s<mins then stop draw ; movf v_accs,w cpfslt v_mins bra w_d2_lookmin_trans ; ; keep track of maxs ; cpfsgt v_maxs movwf v_maxs rcall w_d2_column ; ; stop drawing if it is time ; movf v_tl,w subwf v_tendl,w movf v_th,w subwfb v_tendh,w bn w_d2_drawax_done btfsc b_draw_go bra w_d2_drawmax ; ; Done drawing ; w_d2_drawax_done: rcall w_d2_draw_stop bra w_d2_lookmax_drawstop ;=========================================================================== ; tap occurred (single down tap) ;=========================================================================== w_d2_tap: DB_DWHERE1 0x71 #if DB_DRAW_TAP SOUT1 w_str_d2tap movf v_tapx,w call w_outbyte_sp movf v_tapy,w call w_outbyte_sp COUTL ' ' movf v_absx,w call w_outbyte_sp movf v_absy,w call w_outbyte_sp movf v_absx,w mulwf v_absy movf PRODH,w call w_outbyte movf PRODL,w call w_outbyte call w_outcr #endif bcf b_d2_sleep ; no sleeping if tap occurred bra w_d2_stop ;=========================================================================== ; time to sleep ;=========================================================================== w_d2_sleep: DB_DWHERE1 0x74 #if DB_DRAW_SLEEP SOUT1CR w_str_d2sleep #endif ;bra w_d2_stop ; fall through to w_d2_stop ;=========================================================================== ; return from draw sequence ;=========================================================================== w_d2_stop: DB_DWHERE1 0x72 #if DB_DRAW_STOP SOUT1CR w_str_d2stop #endif ; ; disable bright LEDS ; bsf b_maxbright_disable bsf b_medbright_disable return ;=========================================================================== ; error occurred ;=========================================================================== w_d2_error: DB_DWHERE1 0x73 ERRL ERROR_B2_DRAW2_AD_OVERRUN ;=========================================================================== ; call this every quarter second ;=========================================================================== DRAW2_SLEEP_WAIT equ 64 ; # of quarter seconds of motionless before sleep ;DRAW2_SLEEP_WAIT equ 128 ; # of quarter seconds of motionless before sleep ;DRAW2_SLEEP_WAIT equ 20 ; # of quarter seconds of motionless before sleep DRAW2_TAP_WAIT equ 2 ; # of quarter seconds of motionless before tap ok w_d2_qsec_lookmin: w_d2_qsec_lookmax: #if DB_DRAW_TIME v_dth_dbmin equ vaddr+0 v_dtl_dbmin equ vaddr+1 v_dth_dbmax equ vaddr+2 v_dtl_dbmax equ vaddr+3 v_dt_dbcnt equ vaddr+4 v_dt_dbpcnt equ vaddr+5 vaddr+=6 v_mins_dbmin equ vaddr+0 v_mins_dbmax equ vaddr+1 v_maxs_dbmin equ vaddr+2 v_maxs_dbmax equ vaddr+3 vaddr+=4 decf v_dt_dbpcnt,f bnn w_d2_qsec_skiptime movlw 10 movwf v_dt_dbpcnt movf v_dth_dbmin,w call kk_outbyte movf v_dtl_dbmin,w call kk_outbyte COUTL ' ' movf v_dth_dbmax,w call kk_outbyte movf v_dtl_dbmax,w call kk_outbyte COUTL ' ' COUTL ' ' movf v_dt_dbcnt,w call kk_outbyte #if DB_DRAW_WHERE COUTL ' ' movf v_draw_where1,w call kk_outbyte #endif COUTL ' ' COUTL ' ' movf v_mins_dbmin,w call kk_outbyte COUTL ' ' movf v_mins,w call kk_outbyte COUTL ' ' movf v_mins_dbmax,w call kk_outbyte COUTL ' ' COUTL ' ' movf v_maxs_dbmin,w call kk_outbyte COUTL ' ' movf v_maxs,w call kk_outbyte COUTL ' ' movf v_maxs_dbmax,w call kk_outbyte call kk_outcr DB_FLUSH setf v_dth_dbmin setf v_dtl_dbmin clrf v_dth_dbmax clrf v_dtl_dbmax clrf v_dt_dbcnt w_d2_qsec_skiptime: #endif w_d2_qsec_common: ; ; still long enough to sleep? ; dcfsnz v_sleep_wait,f bsf b_d2_sleep ; ; still long enough to allow taps? ; btfss v_tap_wait,7 ; clamp to -1 (0xff) decf v_tap_wait,f return ;=========================================================================== ; stop drawing ;=========================================================================== w_d2_draw_stop: bcf b_draw_go bcf b_draw_ok movlw DRAW2_TRISB_OFF_VAL movwf v_draw_val return ;=========================================================================== ; transition from lookmax to lookmin ;=========================================================================== w_d2_trans_min: rcall w_d2_column movf v_maxs,w movwf v_last_maxs #if DB_DRAW_TIME cpfsgt v_maxs_dbmax movwf v_maxs_dbmax cpfslt v_maxs_dbmin movwf v_maxs_dbmin #endif rcall w_d2_calcmax rcall w_d2_column ; ; disable current draw (should be 0 already) ; enable next draw ; bcf b_draw_go bsf b_draw_ok ; ; disable drawing if last_maxs-last_mins < threshhold ; movf v_last_mins,w subwf v_last_maxs,w addlw -ACC_TH_MAG_DRAW btfss STATUS,C bcf b_draw_ok rcall w_d2_column ; ; copy old time to v_dt ; movf v_t0l,w movwf v_dtl movf v_t0h,w movwf v_dth rcall w_d2_column ; ; calc v_dt ; movf v_tl,w movwf v_t0l movwf v_tdrawl movwf v_tendl bsf STATUS,C subfwb v_dtl,f movf v_th,w movwf v_t0h movwf v_tdrawh movwf v_tendh subfwb v_dth,f rcall w_d2_column ; ; disable drawing if time >= 1sec ; movf v_dth,w andlw 0xf0 btfss STATUS,Z bcf b_draw_ok #if DB_DRAW_TIME movf v_dtl,w subwf v_dtl_dbmin,w movf v_dth,w subwfb v_dth_dbmin,w btfsc STATUS,C movff v_dtl,v_dtl_dbmin btfsc STATUS,C movff v_dth,v_dth_dbmin movf v_dtl,w subwf v_dtl_dbmax,w movf v_dth,w subwfb v_dth_dbmax,w btfss STATUS,C movff v_dtl,v_dtl_dbmax btfss STATUS,C movff v_dth,v_dth_dbmax infsnz v_dt_dbcnt,f setf v_dt_dbcnt #endif ; ; calc v_tdraw & v_tend ; bcf STATUS,C rrcf v_dth,f rrcf v_dtl,f movf v_dtl,w addwf v_tendl,f movf v_dth,w addwfc v_tendh,f rcall w_d2_column bcf STATUS,C rrcf v_dth,f rrcf v_dtl,f #if 0 movf v_dtl,w addwf v_tendl,f movf v_dth,w addwfc v_tendh,f #else nop nop nop nop #endif movf v_dtl,w addwf v_tdrawl,f movf v_dth,w addwfc v_tdrawh,f rcall w_d2_column #if 1 bcf STATUS,C rrcf v_dth,f rrcf v_dtl,f movf v_dtl,w addwf v_tendl,f movf v_dth,w addwfc v_tendh,f rcall w_d2_column #endif return ;=========================================================================== ; transition from lookmin to lookmax ;=========================================================================== w_d2_trans_max: movf v_mins,w movwf v_last_mins #if DB_DRAW_TIME cpfsgt v_mins_dbmax movwf v_mins_dbmax cpfslt v_mins_dbmin movwf v_mins_dbmin #endif rcall w_d2_column ; fall thru to w_d2_calcmin ;=========================================================================== ; calc max (threshhold) from lastmax & lastmin ;=========================================================================== w_d2_calcmin: ; ; use mins = (3*last_mins + last_maxs)/4 ; rrncf v_last_mins,w andlw 0x7e movwf v_mins rrncf WREG,w addwf v_mins,f rrncf v_last_maxs,w rrncf WREG,w andlw 0x3f addwf v_mins,f #if 1 ; ; clamp to max 0x70 (stability) ; movlw 0x70 cpfsgt v_mins movwf v_mins #endif return ;=========================================================================== ; calc max (threshhold) from lastmax & lastmin ;=========================================================================== w_d2_calcmax: rrncf v_last_maxs,w andlw 0x7e movwf v_maxs rrncf WREG,w addwf v_maxs,f rrncf v_last_mins,w rrncf WREG,w andlw 0x3f addwf v_maxs,f return ;=========================================================================== ; clear pixels (off) and draw column ;=========================================================================== w_d2_column_clr: movlw DRAW2_TRISB_OFF_VAL movwf v_draw_val ; fall thru to w_d2_column ;=========================================================================== ; draw 1 column of leds (several times) ;=========================================================================== ; also read accelerometer and detect taps ; b_d2_tap is set if tap detected ; w_d2_column: bsf b_adgo ; ; read time ; rcall w_read_time rcall w_d2_pcol ; draw column pass 1 ; ; a/d conversion should be done by now ; btfsc b_adgo bra w_d2_error ; ; read X acceleration ; movf ADRESH,w movwf v_accx movwf v_accs addwf v_avgx_neg,w movwf v_absx movlw ADCON0_ACCY movwf ADCON0 rcall w_d2_pcol ; draw column pass 2 bsf b_adgo ; ; check for tap (A) ; btfsc v_tap_wait,7 bsf b_d2_maybe_tap rcall w_d2_pcol ; draw column pass 3 ; ; a/d conversion should be done by now ; btfsc b_adgo bra w_d2_error ; ; read Y acceleration ; movf ADRESH,w movwf v_accy subwf v_accs,f addwf v_avgy_neg,w movwf v_absy movlw ADCON0_ACCX movwf ADCON0 rcall w_d2_pcol ; draw column pass 4 ; ; check for tap (B) ; rrcf v_accy,w bsf WREG,7 movwf v_accs rrcf v_accx,w andlw 0x7f subwf v_accs,f rcall w_d2_pcol ; draw column pass 5 ; ; check for tap (C) ; movf v_absx,w addwf v_absy,w btfss WREG,7 bcf b_d2_maybe_tap rcall w_d2_pcol ; draw column pass 6 ; ; check for tap (D) ; find magsq ; btfsc v_absx,7 negf v_absx btfsc v_absy,7 negf v_absy movf v_absx,w mulwf v_absy rcall w_d2_pcol ; draw column pass 7 ; ; check for tap (E) ; movf PRODH,w addlw -0x03 ; TAP MAGSQH THRESH btfss STATUS,C bcf b_d2_maybe_tap rcall w_d2_pcol ; draw column pass 8 ; ; check for tap (F) ; movf PRODH,w addlw -0x01 movlw 5 ; SLOPE THRESH: smaller = steeper slope required btfss STATUS,C movwf v_zcnt rcall w_d2_pcol ; draw column pass 9 ; ; check for tap (G) ; btfss v_zcnt,7 decf v_zcnt,f btfsc v_zcnt,7 bcf b_d2_maybe_tap btfss b_d2_tap ; only record first tap btfss b_d2_maybe_tap return ; ; tap occurred! ; movff v_accx,v_tapx movff v_accy,v_tapy bsf b_d2_tap #if 0 COUTL 'T' COUTL 'a' COUTL 'p' COUTL ' ' movf v_accx,w call kk_outbyte COUTL ' ' movf v_accy,w call kk_outbyte COUTL ' ' COUTL ' ' movf v_absx,w call kk_outbyte COUTL ' ' movf v_absy,w call kk_outbyte COUTL ' ' movf PRODH,w call kk_outbyte movf PRODL,w call kk_outbyte COUTL ' ' COUTL ' ' movf v_zcnt,w call kk_outbyte call kk_outcr DB_FLUSH #endif return ;=========================================================================== ; light each LED in column (if needed) ;=========================================================================== w_d2_pcol: movlw 0x7f movwf v_draw_mask w_d2_pcol_loop: movf v_draw_mask,w iorwf v_draw_val,w bcf WREG,1 ; accelerometer enabled bsf WREG,0 ; input E in tristate #if DB_DRAW_LED nop #else movwf TRISB #endif rrncf v_draw_mask,f btfsc v_draw_mask,2 ; loop til mask has enabled each led bra w_d2_pcol_loop movlw DRAW2_TRISB_OFF_VAL #if DB_DRAW_LED nop #else movwf TRISB #endif decfsz v_draw_cnt,f return movlw 20 ; Character width movwf v_draw_cnt btfss b_draw_go return ; ; fetch next column value (off if disabled) ; movf POSTINC0,w bz w_d2_pcol_end movwf v_draw_val return w_d2_pcol_end: movlw DRAW2_TRISB_OFF_VAL movwf v_draw_val lfsr FSR0,RAMBUF_DRAW+1 ; start at beginning of message btfsc b_draw_scroll return bcf b_draw_go bcf b_draw_ok return ;########################################################################### ;################################ WAND PRINTF ############################## ;########################################################################### #if DBORG org 0x1780 #endif ;=========================================================================== ; fill in buffer with characters ; ; w_wclear clear wand outbuffer ; w_wcout output ascii char to wand draw buffer ; w_woutidx output char corresponding to index ; w_wpixels output w as a vertical row of pixels - bit7 is base, bit2 is tip ; w_scroll_faster make scrolling faster ; w_scroll_slower make scrolling slower ; ; ; Clear the draw buffer ; w_wclear: movlw HIGH RAMBUF_DRAW movwf FSR0H movwf v_drawbuf_starth movwf v_drawbuf_endh clrf FSR0L movlw 1 movwf v_drawbuf_startl movwf v_drawbuf_endl clrf POSTINC0 w_wclear_loop: #if (RAMBUF_DRAW_END-RAMBUF_DRAW) != 0xc00 error "Hardcoded to len=0xc00" endif setf POSTINC0 setf POSTINC0 setf POSTINC0 setf POSTINC0 setf POSTINC0 setf POSTINC0 setf POSTINC0 setf POSTINC0 setf POSTINC0 setf POSTINC0 setf POSTINC0 setf POSTINC0 incfsz v_drawbuf_endl,f bra w_wclear_loop setf POSTINC0 setf POSTINC0 clrf POSTINC0 incf v_drawbuf_endl,f ; fall thru to w_woutsp ; ; output space ; w_woutsp: movlw 0 bra w_woutidx ; ; output space or exclamation point ; w_woutexclamation: movlw 1 bra w_woutidx ; ; output nibble ; w_woutnib: andlw 0x0f addlw '0' cpfsgt vki_ten addlw 'A'-'0'-10 ; fall thru to w_wcout ; ; Add char to draw buffer ; w_wcout: andlw 0x5f btfsc WREG,6 addlw -0x20 addlw -1 bz w_woutexclamation addlw 1-0x60 bnn w_woutsp addlw 0x60-0x0b bn w_woutsp addlw 2 w_woutidx: ; ; multiply w times 5 and add w_char_first ; clrf TBLPTRH movwf TBLPTRL rlncf TBLPTRL,f rlncf TBLPTRL,f addwf TBLPTRL,f btfsc STATUS,C incf TBLPTRH,f movlw LOW w_char_first addwf TBLPTRL,f movlw HIGH w_char_first addwfc TBLPTRH,f rcall w_wpixels_tblrd rcall w_wpixels_tblrd rcall w_wpixels_tblrd rcall w_wpixels_tblrd rcall w_wpixels_tblrd setf TABLAT rcall w_wpixels_tablat bra w_wpixels_tablat w_wpixels_tblrd: tblrd*+ w_wpixels_tablat: movf TABLAT,w w_wpixels: movff v_drawbuf_endh,FSR0H movff v_drawbuf_endl,FSR0L movwf POSTINC0 movf INDF0,w bz w_wpixels_end ; end of buffer - do not inc pointer movff FSR0H,v_drawbuf_endh movff FSR0L,v_drawbuf_endl w_wpixels_end: return ; ; w_scroll_faster make scrolling faster ; w_scroll_faster: bsf STATUS,C rlcf v_scrollspd,f return ; ; w_scroll_slower make scrolling slower ; w_scroll_slower: bcf STATUS,C rrcf v_scrollspd,f return ;=========================================================================== ; w_wscrollcheck - check for scrolling ;=========================================================================== ; ; check for scrolling and add spaces at end ; #define MIN_SCROLL_WIDTH (7*7) w_wscrollcheck: bcf b_draw_scroll movff v_drawbuf_endh,FSR0H movff v_drawbuf_endl,FSR0L ; ; search for one that is not 0xff ; w_wscrollcheck_loop: infsnz POSTDEC0,w bra w_wscrollcheck_loop movf POSTINC0,w movf POSTINC0,w ; ; turn scrolling on if 0x23 columns or more ; movlw LOW (-(RAMBUF_DRAW+MIN_SCROLL_WIDTH)) addwf FSR0L,w movlw HIGH (-(RAMBUF_DRAW+MIN_SCROLL_WIDTH)) addwfc FSR0H,w btfss STATUS,C return ; scrolling off ; ; scrolling on ; bsf b_draw_scroll movf FSR0H,w movwf v_drawbuf_endh movwf v_drawbuf_starth movf FSR0L,w movwf v_drawbuf_endl movwf v_drawbuf_startl ; ; add 3 spaces ; rcall w_woutsp rcall w_woutsp ; ; mark end with a 0x00 ; clrf TABLAT rcall w_wpixels_tablat ; ; back up pointer to just before 0x00 and save it ; movf POSTDEC0,w movf POSTDEC0,w movff FSR0H,v_drawbuf_endh movff FSR0L,v_drawbuf_endl w_wscrollcheck_done: return ;=========================================================================== ; w_wscroll_inc - scroll 1 column ;=========================================================================== w_wscroll_inc: movff v_drawbuf_starth,FSR0H movff v_drawbuf_startl,FSR0L btfss b_draw_scroll return movf POSTINC0,w bz w_wscroll_inc_wrap movff FSR0H,v_drawbuf_starth movff FSR0L,v_drawbuf_startl return w_wscroll_inc_wrap: movlw HIGH RAMBUF_DRAW movwf v_drawbuf_starth movlw 1 movwf v_drawbuf_startl return ;=========================================================================== ; output strings from tblptrl,h ;=========================================================================== ; ; w_wsout prints string at v_strl,h ; w_wsout_wh is just like w_wsout, but w is first copied to v_strh ; w_wsout_base0 adds w to kki_str_base0 and prints that string ; w_wsout_base1 adds w to w_str_base1 and prints that string ; w_wsout_base0: addlw LOW kki_str_base0 movwf v_strl movlw HIGH kki_str_base0 addwfc TBLPTRU,w ; add 0 + c (TBLPTRU is always 0) bra w_wsout_wh w_wsout_base1: addlw LOW w_str_base1 movwf v_strl movlw HIGH w_str_base1 addwfc TBLPTRU,w ; add 0 + c (TBLPTRU is always 0) ; fall through to w_wsout_wh w_wsout_wh: movwf v_strh w_wsout: bra w_wsout_start w_wsout_loop: rcall w_wcout w_wsout_start: movff v_strl,TBLPTRL movff v_strh,TBLPTRH tblrd*+ movff TBLPTRL,v_strl movff TBLPTRH,v_strh movf TABLAT,w bnz w_wsout_loop return w_char_first: #include "wchars.inc" ;########################################################################### ;################################ PAUSE #################################### ;########################################################################### ; ; w_read_time - read TMR1 into v_th,v_tl ; w_pause_ad_settle - pause long enough for accelerometer & A/D to settle ; (long enough for turn-on and after LED turn on/off) ; w_pause_qsec - pause for 1/4 sec ; w_pause_5ms - pause for 5 ms ; w_pause_w - pause for WREG * 244 usec ; w_pause_t0h_w - pause for v_t0h,w * 244 usec ; ; w_timer_set_fsr0_w - set timer to expire at now + w*244usec ; w_timer_set_fsr0 - set timer to expire at certain time ; w_timer_check_fsr0 - check if timer expired. N set if expired, else N clr. ; ; w_qsectmr0_set - set quarter second timer #0 to expire in w seconds ; w_qsectmr1_set - set quarter second timer #1 to expire in w seconds ; (up to 255 = 63.75 sec) ; b_qsectmr{0,1}_done is cleared until time expires ; ; ; Note: TMR1L increments every 244 usec ; ; ; pause for 1/4 sec ; w_pause_qsec: movlw HIGH 1025 movwf v_t0h movlw LOW 1025 bra w_pause_t0h_w ; ; pause for 5 msec ; w_pause_ad_settle: w_pause_5ms: movlw 20 ; ; pause for w * 244usec ; w_pause_w: clrf v_t0h ; ; pause for v_t0h,w * 244usec ; w_pause_t0h_w: movwf v_t0l ; ; pause for v_t0h,l * 244usec ; rcall w_read_time movf v_tl,w addwf v_t0l,f movf v_th,w addwfc v_t0h,f rcall w_main_run w_pause_loop: rcall w_read_time movf v_tl,w subwf v_t0l,w movf v_th,w subwfb v_t0h,w bnn w_pause_loop return ; ; Read time into v_th,l ; w_read_time: movf TMR1H,w movwf v_th movff TMR1L,v_tl subwf TMR1H,w bnz w_read_time return ; ; Add the current time to w and place the result in the registers pointer to ; by FSR0. FSR0 should point to the low value. If the result is 0 it will be ; incremented so the final result is never 0. ; ; time units are 244usec ; w_timer_set_fsr0_w: movwf POSTINC0 clrf POSTDEC0 ; ; Add the current time to the time set in the registers pointer to ; by FSR0. FSR0 should point to the low value. If the result is 0 it will be ; incremented so the final result is never 0. ; ; time units are 244usec ; w_timer_set_fsr0: rcall w_read_time movf v_tl,w addwf POSTINC0,f movf v_th,w addwfc POSTDEC0,f btfss STATUS,Z return movf INDF0,w btfsc STATUS,Z incf INDF0,f return ; ; check the current time against the time in the resigsters pointer to by FSR0. ; (low value first). If the time has expired then N will be set. If the ; time is not expired then N will be clear. ; Also, if time has expired then the registers are cleared to 0. If the ; registers are already 0 then the time is always considered expired. ; ; time units are 244usec ; w_timer_check_fsr0: movf POSTINC0,w iorwf POSTDEC0,w bz w_timer_check_fsr0_expired rcall w_read_time movf v_tl,w subwf POSTINC0,w movf v_th,w subwfb POSTDEC0,w btfss STATUS,N return w_timer_check_fsr0_expired: clrf POSTINC0 clrf POSTDEC0 bsf STATUS,N return ; ; when this is called b_qsectmr0_done is cleared. ; after w seconds b_qsectmr0_done gets set. ; w_qsectmr0_set: movwf v_qsectmr0 bcf b_qsectmr0_done return ; ; when this is called b_qsectmr1_done is cleared. ; after w seconds b_qsectmr1_done gets set. ; w_qsectmr1_set: movwf v_qsectmr1 bcf b_qsectmr1_done return ;########################################################################### ;################################ MAIN RUN ################################# ;########################################################################### #if DBORG org 0x1b00 #endif ; call this once every main loop to do periodic chores w_main_run: #if ENAB_BLINKS ; ; handle blink sequence when b_blink is set ; btfsc b_blink rcall w_blink #endif #if ENAB_OLD_TAP_HANDLE ; ; handle taps ; clrf v_tap_bits btfsc b_tap rcall w_tap #endif btfss bk_qsec bra w_mr_not_qsec ; ; handle quarter second timers ; dcfsnz v_qsectmr0,f bsf b_qsectmr0_done dcfsnz v_qsectmr1,f bsf b_qsectmr1_done w_mr_not_qsec: ; ; check serial connect/disconnect (unless going to sleep) ; btfss b_d2_sleep rcall w_check_serial goto kk_main_run ; kernel main loop tasks ;########################################################################### ;################################ SERIAL ################################### ;########################################################################### v_serial_dis_cnt equ vaddr+0 vaddr+=1 ; ; check if serial is connected/disconnected ; w_check_serial btfss RCSTA,SPEN bra w_check_serial_reconnect ; ; serial port enabled - check for disconnect ; btfsc bki_serial_detect bra w_check_serial_connected ; connected ; ; may be disconnected ; decfsz v_serial_dis_cnt,f return ; ; disconnected for 256 loops - disable ; goto kk_serial_disable w_check_serial_connected: clrf v_serial_dis_cnt return ; ; check for reconnection ; w_check_serial_reconnect: btfss bki_serial_detect return clrf v_serial_dis_cnt ; ; serial got reconnected - enable it! ; goto kk_serial_enable ;########################################################################### ;################################ MAIN INIT ################################ ;########################################################################### w_main: w_main_init: ; ; init threshholds ; movlw (-ACC_INIT_AVGX)&0xff movwf v_avgx_neg movlw (-ACC_INIT_AVGY)&0xff movwf v_avgy_neg #if ENAB_ISR_TAP movlw HIGH (-ACC_INIT_TH_MAGSQ_TAP) movwf v_th_magsqh_tap #endif #if !USE_CONST_MAGSQ_TH movlw -ACC_INIT_TH_MAGSQ_Z movwf v_th_magsql_z movlw -ACC_INIT_TH_MAGSQ_S movwf v_th_magsql_s #endif ; ; enable this code to erase the eeprom to 0xff ; #define ERASE_EEPROM 0 #if ERASE_EEPROM movlw 0xff-EEPROM_END movwf v_tmp EEPROM_BEGIN EEPROM_END w_main_erase_eeprom_loop: movlw 0xff call kk_eeprom_write decfsz v_tmp,f bra w_main_erase_eeprom_loop #endif ; ; init variables ; clrf v_bits1 clrf v_bits2 clrf v_bits3 ; ; init scroll speed ; movlw 0x07 movwf v_scrollspd #if ENAB_ISR_TAP clrf v_tap_bits #endif #if ENAB_BLINKS clrf v_blink_ptr #endif ; ; choose wakeup phrase ; rcall w_wakeup_phrase ;########################################################################### ;################################ MAIN LOOP ################################ ;########################################################################### w_main_loop: #define RUN_TEST 0 #if RUN_TEST ;bra w_test1_print ; print acc data (max/min) ;bra w_test2_text ; show text (w_draw) ;bra w_test3_sample ; sample a bunch of data bra w_test4_parse ; cast spells ;bra w_test5_textspell ; show text + cast spell (broken) ;bra w_test6_calibrate ; calibration ;bra w_test7_text2 ; draw text (w_draw2) ;bra w_test8_serial ; show serial connectivity on leds #else #define TEST_PAUSE 0 #if TEST_PAUSE bcf bk_led1 rcall w_pause_qsec bsf bk_led1 rcall w_pause_qsec bcf bk_led1 rcall w_pause_qsec bsf bk_led1 rcall w_pause_qsec bcf bk_led1 rcall w_pause_qsec bsf bk_led1 #endif call w_draw2 btfsc bk_rs_halt bra w_main_stop btfsc b_d2_tap rcall w_main_tap btfsc bk_rs_halt bra w_main_stop btfsc b_d2_sleep rcall w_main_sleep btfsc bk_rs_halt bra w_main_stop bra w_main_loop #endif ; ; turn things off before jumping back to kernel ; w_main_stop: call w_ad_stop goto kk_main_loop ;########################################################################### ;################################ TAP ###################################### ;########################################################################### ; ; call here when a tap occurred during draw ; w_main_tap: ; ; look for the spell ; call w_cast_spell btfsc bk_rs_halt return btfsc b_spell_abort bra w_mt_end ; ; start LED scanning ; rcall w_ledscan_start SOUT1CRL w_str_check_rythm call w_check_rythm_spell SOUT1CRL w_str_check_motion rcall w_ledscan #if 1 btfss RCSTA,SPEN bra w_main_tap_dump1_skip ; ; dump accbuf ; lfsr FSR1,RAMBUF_ACC w_main_tap_dump1: COUTL 'a' movf POSTINC1,w movwf v_tmp call kk_outbyte movf POSTINC1,w iorwf v_tmp,f call kk_outbyte movf POSTINC1,w iorwf v_tmp,f call kk_outbyte movf POSTINC1,w iorwf v_tmp,f call kk_outbyte movf POSTINC1,w iorwf v_tmp,f call kk_outbyte movf POSTINC1,w iorwf v_tmp,f call kk_outbyte movf POSTINC1,w iorwf v_tmp,f call kk_outbyte movf POSTINC1,w iorwf v_tmp,f call kk_outbyte call kk_outcr DB_FLUSH movf v_tmp,w bnz w_main_tap_dump1 rcall w_ledscan w_main_tap_dump1_skip: #endif #if 0 btfsc b_got_spell bra w_got_spell #endif call w_check_motion_spell SOUT1CRL w_str_check_done btfsc b_got_spell bra w_got_spell #if 0 ; ; dump motion tokens ; lfsr FSR1,RAMBUF_MTOKENS bra w_main_tap_dump2_start w_main_tap_dump2: COUTL 'm' movf POSTINC1,w call kk_outbyte call kk_outcr DB_FLUSH w_main_tap_dump2_start: movf INDF1,w addlw -MTOKEN_END bnz w_main_tap_dump2 #endif w_mt_end: ; ; turn LEDs off ; movlw KERNVAL_TRISB_LED_MASK iorwf TRISB,f ; ; Unrecognized spell ; bra w_unrecognized_spell ;########################################################################### ;################################ SCAN_LEDS ################################ ;########################################################################### v_ledscan equ vaddr+0 vaddr+=1 ; ; start scanning led back and forth (starts with LED3) ; w_ledscan_start: clrf v_ledscan ; ; scan led to next location ; w_ledscan: incf v_ledscan,f movf v_ledscan,w setf v_tmp bcf v_tmp,3 btfsc v_ledscan,2 negf WREG andlw 7 bz w_ledscan_disp w_ledscan_loop: rlncf v_tmp,f decfsz WREG,w bra w_ledscan_loop w_ledscan_disp: movlw KERNVAL_TRISB_LED_MASK iorwf TRISB,f movf v_tmp,w iorlw ~KERNVAL_TRISB_LED_MASK andwf TRISB,f return ;########################################################################### ;################################ SLEEP #################################### ;########################################################################### ; ; call here when it is time to sleep ; w_main_sleep: SOUT1CRL w_str_sleep COUTL ' ' COUTL ' ' DB_FLUSH v_save_portc equ vaddr+0 ; value of PORTC when sleeping vaddr+=1 movff PORTC,v_save_portc ; ; prepare to sleep ; call w_ad_stop call kk_serial_disable bcf bki_rx_new bcf b_rcif bcf b_rcif ; ; slow down the clock ; call kk_set_osc_32khz ; ; get reference value for accelerometer ; rcall w_pause_qsec rcall w_sleep_check_motion movff v_accx,v_avgx_neg movff v_accy,v_avgy_neg negf v_avgx_neg negf v_avgy_neg ; ; sleep loop ; w_sleep_loop2: call kk_main_run ; kernel main loop tasks btfsc bk_rs_halt ; pointless, but we check anyway for consistancy bra w_sleep_wake ; ; wait for 100ms ; SLEEP_MOTION_DT equ 0x199 ; 0x199 * 244us = 100ms lfsr FSR0,v_t0l movlw HIGH SLEEP_MOTION_DT movwf v_t0h movlw LOW SLEEP_MOTION_DT movwf v_t0l call w_timer_set_fsr0 w_sleep_loop1: ; ; wake if serial port toggled ; movf PORTC,w xorwf v_save_portc,w btfsc WREG,RX bra w_sleep_wake ; ; time to check for motion? ; lfsr FSR0,v_t0l call w_timer_check_fsr0 bnn w_sleep_loop1 ; ; check for motion ; rcall w_sleep_check_motion ; ; sleep until b_d2_sleep is cleared by w_sleep_check_motion ; btfsc b_d2_sleep bra w_sleep_loop2 ;=========================================================================== ; wake up ;=========================================================================== w_sleep_wake: call kk_set_osc_8mhz btfsc bki_serial_detect call kk_serial_enable bcf b_d2_sleep WCLR WSOUT1 w_str_sleepy movlw DRAW2_SLEEP_WAIT movwf v_sleep_wait SOUT1CRL w_str_wake return ;=========================================================================== ; check for motion ;=========================================================================== ; (clear b_d2_sleep if motion occurrs) ; w_sleep_check_motion: call w_ad_init ; ; ADCON2 = 0001 0001 ; 7 ADFM = 0 left justified formt) ; 6 reserved = 0 ; 5-3 ACQT2-0 = 001 2 Tad cycles for acquisition ; 2-0 ADCS2-0 = 000 A/D conversion clock = Fosc/2 (Tad = 2usec) ; SLEEP_ADCON2 equ 0x08 movlw SLEEP_ADCON2 movwf ADCON2 bsf b_adgo w_sleep_check_motion1: btfss b_adgo bra w_sleep_check_motion1 ; ; read X acceleration ; movlw ADCON0_ACCY movwf ADCON0 movf ADRESH,w movwf v_accx ; save off accx value addwf v_avgx_neg,w btfsc WREG,7 negf WREG mulwf WREG movff PRODL,v_magsql movff PRODH,v_magsqh bsf b_adgo w_sleep_check_motion2: btfss b_adgo bra w_sleep_check_motion2 ; ; read Y acceleration ; movf ADRESH,w movwf v_accy ; save off accy value addwf v_avgy_neg,w btfsc WREG,7 negf WREG mulwf WREG call w_ad_stop movf PRODL,w addwf v_magsql,f movf PRODH,w addwfc v_magsqh,f movlw LOW (-ACC_TH_MAGSQ_WAKE) addwf v_magsql,w movlw HIGH (-ACC_TH_MAGSQ_WAKE) addwfc v_magsqh,w btfsc STATUS,C bcf b_d2_sleep return ;########################################################################### ;################################ GOT SPELL ################################ ;########################################################################### w_spellinfo_default equ w_str_unrecognized #if DBG_SPELL_MSG_IS_SPELL_NAME ; ; spell info - for now just strings ; ;w_spellinfo_shave equ w_str_shave w_spellinfo_row equ w_str_row ;w_spellinfo_anthem equ w_str_anthem ;w_spellinfo_twinkle equ w_str_twinkle w_spellinfo_jingle equ w_str_jingle w_spellinfo_mary equ w_str_mary w_spellinfo_brady equ w_str_brady w_spellinfo_gilligan equ w_str_gilligan w_spellinfo_flint equ w_str_flint w_spellinfo_birthday equ w_str_birthday #endif w_spellinfo_jeff1 equ w_str_jeff1 w_spellinfo_quarters equ w_str_quarters w_spellinfo_star equ w_str_star ; ; SPELLINFO STRUCTURE ; ; if low bit of spellinfo is set then it points to following structure: ; ; byte description ; ---- ----------- ; 0 hour hour that this message expires ; 1 minute ; bit 0-5: minute that this message expires ; bit 6: contains yes/no question (if set) ; bit 7: last spellinfo for this spell (if set) ; 2 string high addr ; 3 string low addr ; ; byte 4-7 only if byte1 bit6 is set ; ; 4 yes spellinfo (h) ; 5 yes spellinfo (l) ; 6 no spellinfo (h) ; 7 no spellinfo (l) ; SPELLINFO_SIZE_YN equ 8 ; size of each spellinfo structure with yes/no SPELLINFO_SIZE_0 equ 4 ; size of each spellinfo structure w/o yes/no #if 0 w_spellinfo_shave1: w_spellinfo_shave equ w_spellinfo_shave1+1 db 0x00, 0x01, HIGH w_str_shavea, LOW w_str_shavea db 0x09, 0x01, HIGH w_str_shaveb, LOW w_str_shaveb db 0xff, 0xbf, HIGH w_str_shavec, LOW w_str_shavec w_spellinfo_twinkle1: w_spellinfo_twinkle equ w_spellinfo_twinkle1+1 db 0xff, 0xff, HIGH w_str_twinkle, LOW w_str_twinkle db HIGH w_str_star_yes, LOW w_str_star_yes db HIGH w_str_star_no, LOW w_str_star_no #endif ; ; got a spell ; w_got_spell: ; ; turn LEDs off ; movlw KERNVAL_TRISB_LED_MASK iorwf TRISB,f #if DBPRINT btfss RCSTA,SPEN bra w_got_spell_skipprint SOUT1L w_str_spell movf v_spell_ptrh,w call kk_outbyte movf v_spell_ptrl,w call kk_outbyte COUTL ' ' COUTL 'T' COUTL '=' movf vk_hour,w call kk_outbyte COUTL ':' movf vk_minute,w call kk_outbyte COUTL ':' rrncf vk_qsec,w rrncf WREG,w andlw 0x3f call kk_outbyte call kk_outcr DB_FLUSH w_got_spell_skipprint: #endif ; ; assume it is not a yes/no spell ; bcf b_spell_yes_no ; ; check for faster ; movf v_spell_ptrl,w addlw -(LOW w_spellinfo_fast) bnz v_gs_notfast movf v_spell_ptrh,w addlw -(HIGH w_spellinfo_fast) bnz v_gs_notfast call w_scroll_faster v_gs_notfast: ; ; check for slower ; movf v_spell_ptrl,w addlw -(LOW w_spellinfo_slow) bnz v_gs_notslow movf v_spell_ptrh,w addlw -(HIGH w_spellinfo_slow) bnz v_gs_notslow call w_scroll_slower v_gs_notslow: ; ; check for twinkle (time) ; movf v_spell_ptrl,w addlw -(LOW w_spellinfo_twinkle) bnz v_gs_nottime movf v_spell_ptrh,w addlw -(HIGH w_spellinfo_twinkle) bnz v_gs_nottime bsf b_show_time v_gs_nottime: ; ; is this a spellinfo structure? ; btfss v_spell_ptrl,0 bra w_gs_string ; no - just a string ; ; yes - spellinfo structure ; movf v_spell_ptrl,w andlw 0xfe movwf TBLPTRL movf v_spell_ptrh,w movwf TBLPTRH ; ; read hour and minute ; w_gs_loop: tblrd*+ movf TABLAT,w tblrd*+ ; ; are we before specified time? ; subwf vk_hour,w bnc w_gs_found ; yes - use this one bnz w_gs_next ; no - try next spellinfo (if any) ; ; same hour - check the minute ; movf TABLAT,w andlw 0x3f ; ignore 2 high bits bsf STATUS,C subfwb vk_minute,w bc w_gs_found ; yes - use this one ; ; did not match - try next spellinfo ; At this point: ; TABLAT contains the minute ; TBLPTR points just after the minute ; w_gs_next: btfsc TABLAT,7 bra w_disabled_spell movlw SPELLINFO_SIZE_0-2 btfsc TABLAT,6 movlw SPELLINFO_SIZE_YN-2 addwf TBLPTRL,f movlw 0 addwfc TBLPTRH,f bra w_gs_loop ; ; matched time - use this spellinfo ; At this point: ; TABLAT contains the minute ; TBLPTR points just after the minute ; w_gs_found: movf TABLAT,w ; byte 2 tblrd*+ movff TABLAT,v_spell_ptrh tblrd*+ movff TABLAT,v_spell_ptrl ; ; have yes/no? ; btfss WREG,6 bra w_got_spell ; no - re-parse spell pointer ; ; yes/no spell - save yes/no values ; tblrd*+ movff TABLAT,v_spell_yesh tblrd*+ movff TABLAT,v_spell_yesl tblrd*+ movff TABLAT,v_spell_noh tblrd*+ movff TABLAT,v_spell_nol bsf b_spell_yes_no ; ; loop in case this is in turn a spellinfo structure ; bra w_got_spell ; ; v_spell_ptrh,l now contains a string pointer ; w_gs_string: WCLR movf v_spell_ptrl,w movwf v_strl movf v_spell_ptrh,w rcall w_wsout_wh #if DBPRINT movf v_spell_ptrl,w movwf TBLPTRL movf v_spell_ptrh,w call w_sout_wh call kk_outcr #endif btfss b_show_time return bcf b_show_time swapf vk_hour,w call w_woutnib movf vk_hour,w call w_woutnib movlw ':' call w_wcout swapf vk_minute,w call w_woutnib movf vk_minute,w call w_woutnib movlw ':' call w_wcout swapf vk_qsec,w call w_woutnib movf vk_qsec,w call w_woutnib return ;########################################################################### ;################################ UNRECOGNIZED SPELL ####################### ;########################################################################### ; ; Unrecognized or disabled spell ; w_disabled_spell: w_unrecognized_spell: WCLR WSOUT1 w_str_unrecognized #if 1 bcf b_d2_sleep ; make extra sure we do not sleep SOUT1CRL w_str_unrecognized call kk_outcr #else bcf b_d2_sleep ; make extra sure we do not sleep ; ; print spell that was cast ; COUTL 'M' COUTL 'o' COUTL 't' COUTL 'i' ;COUTL 'o' ;COUTL 'n' ;COUTL '=' call kk_outcr call kk_outcr call kk_outcr DB_FLUSH #endif return ;########################################################################### ;################################ CHOOSE PHRASES ########################### ;########################################################################### ; ; w_wakeup_phrase - choose random wakeup phrase w_wakeup_phrase: WCLR WSOUT1 w_str_hello return ;########################################################################### ;################################ SAMPLE TEST ############################## ;########################################################################### #if ENAB_TESTS #if DBORG org 0x1f00 #endif w_tst3_stopwait: w_tst3_stop: call w_ad_stop goto kk_main_loop w_test3_sample: COUTL 'A' call w_ad_stop COUTL 'B' ; ; wait for buffer to empty ; w_tst3_mt_loop: rcall w_main_run btfsc bk_rs_halt bra w_tst3_stop movf vk_tx_cnt,w bnz w_tst3_mt_loop ; ; turn on 9 bit xfers ; ;bsf TXSTA,TX9D ;bsf TXSTA,TX9 COUTL 'C' call w_sample_clear call w_ad_start call w_sample_start w_tst3_loop: rcall w_main_run btfsc bk_rs_halt bra w_tst3_stop ; ; indicate fullness with LEDs ; movlw KERNVAL_TRISB_LED_MASK iorwf TRISB,f comf FSR2L,w iorlw (~KERNVAL_TRISB_LED_MASK)&0xff andwf TRISB,f btfsc b_accbuf_sample ; loop until full bra w_tst3_loop ; ; here the buffer has been filled ; call w_ad_stop ; ; turn LEDs off ; movlw KERNVAL_TRISB_LED_MASK iorwf TRISB,f bra w_tst3_aaaa w_tst3_str: db "data is 0x400-0x800: tt tt xx yy\0" w_tst3_aaaa: SOUTL w_tst3_str call kk_outcr w_tst3_end: call w_ad_stop call kk_outcr COUTL 'e' COUTL 'n' COUTL 'd' call kk_outcr w_tst3_end_loop: rcall w_main_run btfsc bk_rs_halt bra w_tst3_stop bra w_tst3_end_loop ;########################################################################### ;################################ PRINT ACC TEST ########################### ;########################################################################### #if DBORG org 0x2000 #endif ;================================================ v_tmra equ vaddr+0 vaddr+=1 w_tst1_stop: call w_ad_stop nop nop goto kk_main_loop w_test1_print: call w_sample_clear call w_ad_start call w_sample_start movlw 5 movwf v_tmra w_tst1_loop: rcall w_main_run btfsc bk_rs_halt bra w_tst1_stop nop #if 0 #if ENAB_BLINKS ; ; test blinking ; v_blink_dbg equ vaddr+0 vaddr+=1 ; ; blink leds every 1/4 sec ; ;movf v_blink_ptr,w ;bnz w_tst1_print btfss bk_qsec bra w_tst1_print incf v_blink_dbg,f movf v_blink_dbg,w addlw -10 bnc w_tst1_print clrf v_blink_dbg ;START_BLINK w_blinkpat_down ;START_BLINK w_blinkpat_up ;START_BLINK w_blinkpat_right START_BLINK w_blinkpat_left #endif #endif w_tst1_print: #if 0 btfss bk_qsec bra w_tst1_loop #else nop nop #endif movf vk_tx_cnt,w bnz w_tst1_loop #if 0 decfsz v_tmra,f bra w_tst1_print2 movlw 50 movwf v_tmra #if 0 #if ENAB_BLINKS START_BLINK w_blinkpat_countdown #endif #else btg bk_led2 btg bk_led1 ;nop #endif w_tst1_print2: #endif SOUT1L w_str_sec movf vk_qsec,w rrncf WREG,w rrncf WREG,w andlw 0x3f call kk_outbyte v_pnt_x equ vaddr+0 v_pnt_y equ vaddr+1 v_pnt_m equ vaddr+2 v_pnt_a equ vaddr+3 v_pnt_ml equ vaddr+6 v_pnt_mh equ vaddr+7 v_pnt_h1a equ vaddr+8 v_pnt_h1b equ vaddr+9 v_pnt_h1c equ vaddr+10 v_pnt_h1d equ vaddr+11 vaddr+=12 movff v_accx,v_pnt_x movff v_accy,v_pnt_y movff v_mag,v_pnt_m movff v_angle,v_pnt_a #if HACK1 movff v_hack1_magsql,v_pnt_ml movff v_hack1_magsqh,v_pnt_mh movff v_hack1_mag,v_pnt_m movff v_hack1_angle,v_pnt_a movff v_smpln_angle,v_pnt_h1a movff v_smpln_cntl,v_pnt_h1b movff v_smpln_imph,v_pnt_h1c movff v_smpln_impl,v_pnt_h1d #endif COUTL ' ' COUTL ' ' COUTL ' ' movf v_accx_min,w call kk_outbyte COUTL ' ' movf v_pnt_x,w call kk_outbyte COUTL ' ' movf v_accx_max,w call kk_outbyte COUTL ' ' COUTL ' ' COUTL ' ' movf v_accy_min,w call kk_outbyte COUTL ' ' movf v_pnt_y,w call kk_outbyte COUTL ' ' movf v_accy_max,w call kk_outbyte COUTL ' ' COUTL ' ' COUTL 'a' movf v_pnt_a,w call kk_outbyte COUTL ' ' COUTL 'm' movf v_pnt_m,w call kk_outbyte #if HACK1 COUTL ' ' movf v_pnt_mh,w call kk_outbyte movf v_pnt_ml,w call kk_outbyte COUTL ' ' movf v_pnt_h1a,w call kk_outbyte COUTL ' ' movf v_pnt_h1b,w call kk_outbyte COUTL ' ' movf v_pnt_h1c,w call kk_outbyte COUTL ' ' movf v_pnt_h1d,w call kk_outbyte #endif #if ENAB_ISR_TAP COUTL ' ' COUTL ' ' movf v_tap_mask_acnth,w call kk_outbyte #endif COUTL ' ' COUTL ' ' COUTL ' ' movf FSR2H,w call kk_outbyte movf FSR2L,w call kk_outbyte #if 0 COUTL ' ' COUTL 'b' movf LATB,w call kk_outbyte movf TRISB,w call kk_outbyte #endif call kk_outcr clrf v_accx_max clrf v_accy_max setf v_accx_min setf v_accy_min w_tst1_noprint: bra w_tst1_loop ;########################################################################### ;################################ PARSE TEST ############################### ;########################################################################### #if ENAB_ISR_TAP #if DBORG org 0x2200 #endif w_tst4_stop: call w_ad_stop goto kk_main_loop w_test4_parse: call w_sample_clear call w_ad_start #if ENAB_ISR_TAP call w_tap_enable #endif w_tst4_loop1: rcall w_main_run btfsc bk_rs_halt bra w_tst4_stop btfss b_tap_down bra w_tst4_loop1 ; down tap begins wait-for-still ; ; look for the spell ; rcall w_cast_spell btfsc bk_rs_halt bra w_tst4_stop ; ; print spell that was cast ; COUTL 'M' COUTL 'o' COUTL 't' COUTL 'i' COUTL 'o' COUTL 'n' COUTL '=' call kk_outcr rcall w_check_rythm_spell #if ENAB_W_PARSE lfsr FSR1,RAMBUF_MOTION w_tst4_loop4: movf POSTINC1,w bn w_tst4_restart call kk_outbyte COUTL ' ' bra w_tst4_loop4 #endif w_tst4_restart: call kk_outcr call w_ad_start call w_tap_enable bra w_tst4_loop1 #endif ;########################################################################### ;################################ CALIBRATION TEST ######################### ;########################################################################### #if DBORG org 0x2400 #endif v_tst6_cnt equ vaddr+0 vaddr+=1 w_tst6_stop: call w_ad_stop goto kk_main_loop w_test6_calibrate: call w_sample_clear call w_ad_init lfsr FSR2, RAMBUF_ACC ; ; setup steady state - all LEDS off ; movlw KERNVAL_TRISB_LED_MASK iorwf TRISB,f movlw (~KERNVAL_TRISB_LED_MASK)&0xff andwf TRISB,f #if 0 ; ; turn off accelerometer ; bsf b_acc_disable #endif #if 0 ; ; turn off A/D ; clrf ADCON0 #endif ; ; wait a while (about 3 sec) ; movlw 10 movwf v_tst6_cnt w_tst6_w1: call w_main_run btfsc bk_rs_halt bra w_tst6_stop btfss bk_qsec bra w_tst6_w1 decfsz v_tst6_cnt,f bra w_tst6_w1 #if 0 ; ; turn on accelerometer ; bcf b_acc_disable #endif #if 0 ; ; set up to sample x axis ; movlw ADCON0_ACCX movwf ADCON0 nop nop nop #endif ; ; start sampling ; bsf b_adgo ; start first conversion w_tst6_loop: rcall w_tst6_sample movlw KERNVAL_TRISB_LED_MASK btfsc FSR2L,4 iorwf TRISB,f ; turn LED on after 4 samples btfsc FSR2H,2 ; loop for 256 samples bra w_tst6_loop ; ; print result ; call w_ad_stop movlw 0 movwf v_tst6_cnt lfsr FSR2, RAMBUF_ACC w_tst6_r1: movf FSR2H,w call kk_outbyte movf FSR2L,w call kk_outbyte COUTL ':' movf POSTINC2,w call kk_outbyte movf POSTINC2,w call kk_outbyte COUTL ':' movf POSTINC2,w call kk_outbyte movf POSTINC2,w call kk_outbyte call kk_outcr DB_FLUSH decfsz v_tst6_cnt,f bra w_tst6_r1 ; ; LEDS off ; movlw KERNVAL_TRISB_LED_MASK iorwf TRISB,f ; ; wait for halt ; w_tst6_endwait: call w_main_run btfsc bk_rs_halt bra w_tst6_stop bra w_tst6_endwait ; ; sample subroutine ; w_tst6_sample: btfss b_adif return bcf b_adif movf ADRESH,w movwf POSTINC2 movf ADRESL,w movwf POSTINC2 bsf b_adgo ; start next conversion movf TMR1H,w movwf POSTINC2 movf TMR1L,w movwf POSTINC2 return ;########################################################################### ;################################ TEXT TEST 2 ############################## ;########################################################################### w_tst7_stop: call w_ad_stop goto kk_main_loop w_test7_text2: WCLRL WSOUT1L w_str_quick w_tst7_loop: call w_draw2 call w_main_run btfsc bk_rs_halt bra w_tst7_stop btfsc b_d2_tap bra w_tst7_loop ; handle tap here bcf b_d2_tap bra w_tst7_loop ;########################################################################### ;################################ SERIAL TEST 8 ############################ ;########################################################################### w_tst8_stop: goto kk_main_loop w_test8_serial: w_tst8_loop: call w_main_run btfsc bk_rs_halt bra w_tst8_stop bsf bk_led4 btfss bki_serial_detect bcf bk_led4 bra w_tst8_loop #endif ; ENAB_TESTS ;########################################################################### ;################################ CAST SPELL ############################### ;########################################################################### #if DBORG org 0x2700 #endif ; ; wait for still, then cast spell ; accelerometer & A/D are OFF on return ; w_cast_spell: bcf b_spell_abort rcall w_still_wait #if ENAB_ISR_TAP ; ; disable taps ; bcf b_tap_enable bcf b_tap #endif btfsc b_spell_abort bra w_cs_end ; ; led0 is on while casting spell ; bsf bk_led0 bcf bk_led4 call w_pause_ad_settle ; ; begin sampling & parsing ; bcf b_accbuf_sample call w_sample_clear call w_sample_start #if ENAB_W_PARSE rcall w_parse_init #endif #if ENAB_ISR_TAP ; ; abort if tap occured (might occur in w_still_wait) ; movf v_tap_bits,f bnz w_cs_done #endif ; ; set timeout timer for stillness ; SPELL_STILL_TIME_INIT equ 15*4 ; 15 sec SPELL_STILL_TIME equ 6 ; 1.5 sec movlw SPELL_STILL_TIME_INIT call w_qsectmr0_set bcf b_acc_motion w_cs_loop: call w_main_run btfsc bk_rs_halt bra w_cs_end #if ENAB_W_PARSE rcall w_parse #endif #if ENAB_W_PARSE ; ; exit loop when wand is wagging left-right ; btfsc b_parse_wag bra w_cs_done #endif #if 0 && DBPRINT v_hack_fsr2h equ vaddr+0 v_hack_fsr2l equ vaddr+1 v_hack_tmp equ vaddr+3 vaddr+=3 movf vk_tx_cnt,w bnz w_cs_skipprint movf FSR2H,w subwf v_hack_fsr2h,w movwf v_hack_tmp movf FSR2L,w subwf v_hack_fsr2l,w iorwf v_hack_tmp,w bz w_cs_skipprint movf FSR2L,w movwf v_hack_fsr2l movf FSR2H,w movwf v_hack_fsr2h call kk_outbyte movf v_hack_fsr2l,w call kk_outbyte call kk_outcr w_cs_skipprint: #endif ; ; check for stillness ; btfss b_acc_motion bra w_cs_check_still movlw SPELL_STILL_TIME call w_qsectmr0_set bcf b_acc_motion bra w_cs_not_still w_cs_check_still: btfsc b_qsectmr0_done bsf b_acc_finish ; tell isr to stop sampling w_cs_not_still: ; ; exit loop when accbuf is full or done sampling ; TODO: wrap accbuf ; btfsc b_accbuf_sample bra w_cs_loop ; ; finish parsing what we got ; w_cs_done: ; ; Turn off A/D and accelerometer ; flush last motions to buffer ; call w_ad_sample_finish bcf b_accbuf_sample #if SHOW_LED_DURING_MOTION bsf bk_led2 #endif bsf bk_led4 #if ENAB_W_PARSE rcall w_parse_finish ; ; remove last 8 entries and mark end with 0xff ; lfsr FSR0,RAMBUF_MOTION movf v_spell_len,w addlw -8 btfss STATUS,C ; less than 8 entries? clrf WREG ; yes - empty spell movwf v_spell_len movwf FSR0L setf INDF0 #endif w_cs_end: movlw KERNVAL_TRISB_LED_MASK iorwf TRISB,f call w_ad_stop return ;########################################################################### ;################################ STILL WAIT ############################### ;########################################################################### #define USE_NEW_STILLWAIT 1 #if USE_NEW_STILLWAIT ; ; NEW STILLNESS TEST - (seems to work fairly well) ; ; ; Wait for wand to be still ; ; when done: ; v_avgx_neg has been calculated ; v_avgy_neg has been calculated ; wand has been still for 1.5 sec ; wand interrupt is enabled ; wand sampling is disabled ; led 5 is on ; ; OR: ; wand has NOT been still for many seconds ; wand interrupt is enabled ; wand sampling is disabled ; v_avgx_neg unchanged ; v_avgy_neg unchanged ; led 5 is on ; ; OR: ; bk_rs_halt is set ; wand interrupt is enabled ; wand sampling is disabled ; v_avgx_neg unchanged ; v_avgy_neg unchanged ; led 5 is on ; w_still_wait: call w_ad_start v_sw_leds equ vaddr+0 ; current led values vaddr+=1 ; ; SHORT_TIMEOUT is time to quit unless getting close to still ; LONG_TIMEOUT is max time before giving up ; time is in quarter second increments ; STILLWAIT_SHORT_TIMEOUT equ 4*4 ; 4 sec STILLWAIT_LONG_TIMEOUT equ 15*4 ; 15 sec movlw STILLWAIT_LONG_TIMEOUT call w_qsectmr0_set movlw STILLWAIT_SHORT_TIMEOUT call w_qsectmr1_set w_sw_err3: movlw 0x07 movwf v_sw_leds bra w_sw_set_leds w_sw_err2: movlw 0x0f andwf v_sw_leds,f bra w_sw_set_leds w_sw_err1: movf STILLWAIT_SHORT_TIMEOUT,w call w_qsectmr1_set bcf v_sw_leds,5 bcf v_sw_leds,6 ; ; set new led values ; w_sw_set_leds: movf v_sw_leds,w andlw KERNVAL_TRISB_LED_MASK iorwf TRISB,f iorlw ~KERNVAL_TRISB_LED_MASK andwf TRISB,f ; ; wait while leds settle ; call w_pause_ad_settle call w_pause_ad_settle call w_pause_ad_settle call w_pause_ad_settle ; ; set timer ; STILLWAIT_DT equ 0x0801 ; time per led = 244us * ? lfsr FSR0,v_t0l movlw HIGH STILLWAIT_DT movwf v_t0h movlw LOW STILLWAIT_DT movwf v_t0l #if 1 ; ; if high leds are set then allow them to go off quickly ; btfss v_sw_leds,5 clrf v_t0h #endif call w_timer_set_fsr0 ; ; reset min/max ; setf v_accx_min setf v_accy_min clrf v_accx_max clrf v_accy_max ; ; check for timeout ; btfsc b_qsectmr0_done bra w_sw_abort btfsc b_qsectmr1_done bra w_sw_abort w_sw_loop1: call w_main_run btfsc bk_rs_halt bra w_sw_abort movf v_accy_max,w bz w_sw_loop1 movf v_accx_max,w bz w_sw_loop1 ; ; calc (ABS(maxx - miny) + ABS(maxy - minx)) ; Trying to get it close to 0 ; movf v_accy_min,w subwf v_accx_max,w btfss STATUS,C negf WREG movwf v_tmp movf v_accx_min,w subwf v_accy_max,w btfss STATUS,C negf WREG addwf v_tmp,w ; ; how big is the error? ; addlw -7 bc w_sw_err3 ; err >= 7 infsnz WREG,w bra w_sw_err2 ; err == 6 infsnz WREG,w bra w_sw_err2 ; err == 5 infsnz WREG,w bra w_sw_err1 ; err == 4 infsnz WREG,w bra w_sw_err1 ; err == 3 ; ; check time ; lfsr FSR0,v_t0l call w_timer_check_fsr0 bnn w_sw_loop1 ; ; timer expired - turn 1 led off ; bsf STATUS,C rlcf v_sw_leds,f incfsz v_sw_leds,w ; done if all set bra w_sw_set_leds ; ; still - calc average accx and accy values ; rcall w_calc_avg ; ; turn on led0 0 only ; bsf bk_led0 bcf bk_led4 ; ; done ; return w_sw_abort: movlw KERNVAL_TRISB_LED_MASK iorwf TRISB,f bsf b_spell_abort return #else ; ; OLD STILLNESS TEST - WORKING & TESTED ; ; ; Wait for wand to be still ; ; when done: ; v_avgx_neg has been calculated ; v_avgy_neg has been calculated ; wand has been still for 1.5 sec ; wand interrupt is enabled ; wand sampling is disabled ; led 5 is on ; #if ENAB_ISR_TAP ; OR: ; v_tap_bits is nonzero ; wand has NOT been still ; wand interrupt is enabled ; wand sampling is disabled ; v_avgx_neg unchanged ; v_avgy_neg unchanged ; led 5 is on #endif ; ; OR: ; bk_rs_halt is set ; wand interrupt is enabled ; wand sampling is disabled ; v_avgx_neg unchanged ; v_avgy_neg unchanged ; led 5 is on ; w_still_wait: call w_ad_start #if ENAB_ISR_TAP call w_tap_enable #endif bra w_sw_restart w_sw_restart_still: bcf bk_led2 ; led3 indicates stillness w_sw_restart_level: bcf bk_led1 ; led4 indicates level v_wait_cnt equ vaddr+0 vaddr+=1 w_sw_restart: ; ; wait for this many quarter seconds of stillness ; movlw 6 movwf v_wait_cnt ; ; reset min/max ; setf v_accx_min setf v_accy_min clrf v_accx_max clrf v_accy_max w_sw_loop: call w_main_run btfsc bk_rs_halt bra w_sw_abort #if ENAB_ISR_TAP ; ; quit if tap occurred ; movf v_tap_bits,f bnz w_sw_abort #endif #if ENAB_BLINKS ; ; wait until tap blink sequence is done ; movf v_blink_ptr,f bnz w_sw_restart #endif ; ; led5 is on while waiting for still ; bcf bk_led0 ; ; restart if maxx - minx > 2 ; movf v_accx_min,w subwf v_accx_max,w addlw -3 bc w_sw_restart_still ; ; restart if maxy - miny > 2 ; movf v_accy_min,w subwf v_accy_max,w addlw -3 bc w_sw_restart_still ; ; turn led3 off when wand is still ; btfss bk_led2 bra w_sw_is_still ; ; NOTE: this just waits until x==y ; This could indicate right-side-up or upside-down. ; Actually indicates 45 degree angle for sensor. ; ; restart if |v_accx - v_accy| > 1 ; movf v_accy,w subwf v_accx,w btfsc WREG,7 negf WREG addlw -2 bc w_sw_restart_level ; ; turn led4 off when wand is level & still ; btfss bk_led1 bra w_sw_is_level #if 0 #define STILL_WAIT_45_CW 1 #if STILL_WAIT_45_CW ; ; this accepts 45 degrees cw from upright ; needs relative and approximate values only ; ; ; restart if |v_accx - v_accy| > 1 ; movf v_accy,w subwf v_accx,w btfsc WREG,7 negf WREG addlw -2 bc w_sw_restart ; ; restart if v_accx > 0x55 ; movf v_accy,w addlw -0x55 bnn w_sw_restart #else ; ; this accepts upright ; relies on 0g = 0x55 ; ; ; restart if v_accy >= 0x52 ; movf v_accy,w addlw -0x52 bnn w_sw_restart ; ; restart if |v_accx-0x55| > 1 ; movf v_accx,w addlw -0x55 btfsc WREG,7 negf WREG addlw -2 bc w_sw_restart #endif #endif ; ; loop for 5/4 - 6/4 sec of stillness ; btfss bk_qsec bra w_sw_loop decfsz v_wait_cnt,f bra w_sw_loop ; ; calc average of min,max for x & y ; rcall w_calc_avg w_sw_abort: bsf bk_led1 bsf bk_led2 return w_sw_is_level: bsf bk_led1 ; turn LED1 off w_sw_is_still: bsf bk_led2 ; turn LED2 off call w_pause_ad_settle bra w_sw_restart #endif ;########################################################################### ;################################ CALC AVG ################################# ;########################################################################### ; ; calc average acc val ; w_calc_avg: movf v_accy_max,w addwf v_accy_min,w rrncf WREG,f andlw 0x7f negf WREG movwf v_avgy_neg movf v_accx_max,w addwf v_accx_min,w rrncf WREG,f andlw 0x7f negf WREG movwf v_avgx_neg #if 0 setf v_accx_min setf v_accy_min clrf v_accx_max clrf v_accy_max #endif #if DBPRINT COUTL 'A' COUTL 'V' COUTL 'G' COUTL ' ' movf v_accx_min,w call kk_outbyte COUTL ' ' movf v_avgx_neg,w negf WREG call kk_outbyte COUTL ' ' movf v_accx_max,w call kk_outbyte COUTL ' ' COUTL ' ' movf v_accy_min,w call kk_outbyte COUTL ' ' movf v_avgy_neg,w negf WREG call kk_outbyte COUTL ' ' movf v_accy_max,w call kk_outbyte call kk_outcr #endif return ;########################################################################### ;################################ MOTION SPELLS ############################ ;########################################################################### #if DBORG org 0x2900 #endif #if ENAB_FMTB_MOTION_SPELLS #include "wparse.inc" #endif #if ENAB_OLD_MOTION_SPELLS ;;; ;;;; ;;;; Call this to check for a motion spell ;;;; ;;;; REQUIRED INPUT CONDITIONS ;;;; - sampling disabled (b_accbuf_sample=0) ;;;; - RAMBUF_ACC contains samples terminated by 8 consecutive 0xfe entries ;;;; ;;;; RESOURCES USED ;;;; ;;;; OUTPUT CONDITIONS ;;;; if spell is recognized: ;;;; - b_got_spell is set ;;;; - v_spell_ptrh,l = pointer to spell info (points to string for now) ;;;; if spell is NOT recognized: ;;;; - b_got_spell is clear ;;;; ;;;w_check_motion_spell: ;;; bcf b_got_spell ; no spell recognized (yet) ;;; ;;; lfsr FSR2,RAMBUF_ACC ;;; lfsr FSR1,RAMBUF_MOTION ;;; ;;; setf v_mo1_s_angle ;;; bsf v_mo1_s_prev_pause ;;; ;;; ; ;;; ; start collecting data for a new shape ;;; ; ;;; ; ;;; ; store each shape as follows ;;; ; ;;; ; 0 - angle ;;; ; 1 - impulseh ;;; ; 2 - impulsel ;;; ; 3 - maxmag ;;; ; 4 - shape ;;; ; ;;;v_mo1_begin_shape: ;;; swapf v_mo1_s_flags,w ;;; andlw MFLG_PN_FLAGS ;;; iorlw MFLG_INIT_FLAGS ;;; movwf v_mo1_s_flags ; init flags (copy next pause to prev pause) ;;; ;;; clrf v_mo1_s_maxstep ;;; clrf v_mo1_s_asum ;;; clrf v_mo1_s_impl ;;; clrf v_mo1_s_imph ;;; clrf v_mo1_s_maxdmag ;;; ;;; ;;; bsf b_mo1_restart ;;;v_mo1_pause_begin: ;;; bsf ;;;v_mo1_pause_loop: ;;; rcall w_mo1_read ;;; btfsc v_mo1_angle,7 ;;; bra v_mo1_start ;;; ;;; ;;; ;;; ;;;; ;;;; read next entry ;;;; input: ;;;; v_mo1_angle = last angle ;;;; b_mo1_pause = previous was pause ;;;; ;;;; output: ;;;; v_mo1_prev_angle = last angle ;;;; v_mo1_angle = angle ;;;; v_mo1_impl = impulse lo ;;;; v_mo1_imph = impulse hi ;;;; v_mo1_flags = flags ;;;; v_mo1_step = ABS(angle - prev_angle) ;;;; ;;;; b_mo1_pause = 1 if pause ;;;; b_mo1_dir = cw(1) or ccw(0) ;;;; b_mo1_end = last ;;;; ;;;; b_mo1_restart - set if any of these conditions occur: ;;;; ;;; ;;; ;;; ;;; ;;; ;;; ;;; ;;; ;;; ;;; ; ;;; ; read & parse next motion entry ;;; ; ;;;v_mo1_read: ;;;; ;;;; parse packets ;;;; ;;;; send pause ;;;; 1 time (h) ;;;; 0 time (l) ;;;; 2 unused (0xff) ;;;; 3 angle (0xff indicates pause) ;;;; ;;;; ;;;; send current ;;;; 0 time (h) ;;;; 1 time (l) ;;;; 2 max mag ;;;; 3 angle (0xff indicates pause) ;;;; 4 impulse (h) ;;;; 5 impulse (l) ;;;; 6 min mag ;;;; 7 flags (see below) ;;;; ;;;; valid values for angle ;;;; 0x00 - 0x1f = angle ;;;; 0xff = pause ;;;; 0xfe = end of buffer ;;;; ;;;; flag bits ;;;; 0 set if any zero samples occurred ;;;; 1-6 unused (0) ;;;; 7 must be set (required by isr_ad_sample_pre_save) ;;;; ;;; movf POSTINC2,w ; time high (ignore) ;;; movf POSTINC2,w ; time low (ignore) ;;; movf POSTINC2,w ;;; movwf v_mo1_maxmag ; max mag ;;; movf POSTINC2,w ;;; movwf v_mo1_angle ; angle ;;; ;;; bnn w_mo1_read_angle ; it is an angle ;;; ;;; ; ;;; ; this is a pause ;;; ; ;;; btfsc b_mo1_s_started ;;; bra w_mo1_check_done ;;; ;;; bsf b_mo1_s_next_pause ;;; ; ;;; ; Handle pause following motion ;;; ; ;;; bra w_mo1_store ;;; ;;; ;;;; ;;;; this is an angle - read the rest of it ;;;; ;;;w_mo1_read_angle: ;;; movff v_mo1_angle,v_mo1_prev_angle ;;; ;;; ; ;;; ; angle - read the rest of the fields ;;; ; ;;; movf POSTINC2,w ; impulse h ;;; movf POSTDEC2,w ; impulse l ;;; addwf v_mo1_s_impl,f ;;; movf POSTINC2,w ; impulse h ;;; addwfc v_mo1_s_imph,f ;;; btfsc STATUS,C ;;; setf v_mo1_s_imph ; clamp to high value ;;; movf POSTINC2,w ; impulse l ;;; movf POSTINC2,w ; min mag ;;; subwf v_mo1_maxmag,w ; delta = max-min ;;; ;;; btfsc INDF2,0 ; ZERO flag ;;; movf v_mo1_maxmag,w ; delta = max (if ZERO flag is set) ;;; ;;; cpfsgt v_mo1_s_maxdmag ; max magnitude delta ;;; movwf v_mo1_s_maxdmag ;;; ;;; movf POSTINC2,w ; flags ;;; andlw MFLG_ZERO ; only care about zero flag ;;; iorwf v_mo1_s_flags,f ;;; ;;; movf v_mo1_prev_angle,w ; calc step ;;; subwf v_mo1_angle,w ;;; rcall w_adiff ;;; bcf b_mo1_s_dir ;;; btfsc WREG,7 ;;; bsf b_mo1_s_dir ;;; btfsc WREG,7 ;;; negf WREG ;;; ;;; ; here w is step ;;; ;;; cpfsgt v_mo1_s_maxstep ;;; movwf v_mo1_s_maxstep ;;; addwf v_mo1_s_asum,f ;;; ;;; swapf v_mo1_s_flags,w ; xor prev & next dir ;;; xorwf v_mo1_s_flags,w ;;; btfsc WREG,1 ; dir changed? ;;; bcf b_mo1_s_mono ; yes - not monotonic ;;; ;;; movf v_mo1_prev_angle,w ;;; rcall a2oct ;;; movwf v_tmp ;;; movf v_mo1_angle,w ;;; rcall a2oct ;;; subwf v_tmp,w ;;; bnz w_mo1_newoct ;;; ;;; ;;;w_mo1_newoct: ;;; ;;; ;;; ;;; ;;; ;;; ;;; ;;; ; ;;; ; re-reading previous? ;;; ; ;;; btfsc b_mo1_s_started ;;; bra w_mo1_read_angle_started ;;; ;;; ; ;;; ; first time - reading preceding record ;;; ; ;;; bsf b_mo1_s_started ;;; ;;; ;;; ;;; ;;; ; get the next one ;;; bra v_mo1_read ;;; ;;;w_mo1_read_angle_started: ;;; ;;; ;;; ;;; ;;; ; ;;; ; get next one ;;; ; ;;; bra v_mo1_read ;;; ;;;; ;;;; something is different. Store this one, then re-read next. ;;;; ;;;w_mo1_store_angle: ;;; ;;; ; ;;; ; cause next record to be re-read ;;; ; ;;; movlw 8 ;;; subwf FSR2L,f ;;; movlw 0 ;;; subwfb FSR2H,f ;;; ;;;w_mo1_store: ;;; ; ;;; ; store preceding collection of pulses ;;; ; ;;; ; 0 - angle ;;; ; 1 - impulseh ;;; ; 2 - impulsel ;;; ; 3 - maxmag ;;; ; 4 - shape ;;; ; ;;; ; bits stored in shape: ;;;#define MSHF_PLUS 0x01 ; (part of shape) ;;;#define MSHF_PULSE 0x04 ; (part of shape) ;;;#define MSHF_CLEAN 0x02 ; (part of shape) ;;;#define MSHF_SHP_MASK 0x07 ; (all bits of shape) ;;;#define MSHF_GAP 0x08 ;;;#define MSHF_PAUSE 0x80 ; set if preceded by pause ;;;#define MSHF_MONO 0x40 ;;;#define MSHF_DIR 0x20 ; dir (set if cw (negative)) ;;;#define MSHF_MONO_PAUSE 0xc0 ;;; ;;; ;;;;define MSHP_PAUSE not used ;;;#define MSHP_DIRTY_CIRCLE 0x00 ;;;#define MSHP_DIRTY_CIRCLE_PLUS 0x01 ;;;#define MSHP_CLEAN_CIRCLE 0x02 ;;;#define MSHP_CLEAN_CIRCLE_PLUS 0x03 ;;;#define MSHP_PULSE 0x04 ;;;#define MSHP_PULSE_PLUS 0x05 ;;;#define MSHP_CIRCLE_GAP 0x0e ;;; ;;; ; ;;; ; bits stored in v_mo1_s_flags ;;; ; ;;;#define MFLG_PREV_PAUSE 0x80 ; b_mo1_s_prev_pause ;;;#define MFLG_NEXT_PAUSE 0x08 ; b_mo1_s_next_pause ;;;#define MFLG_PREV_DIR 0x20 ; b_mo1_s_prev_dir ;;;#define MFLG_NEXT_DIR 0x02 ; b_mo1_s_next_dir ;;;#define MFLG_MONO 0x40 ; b_mo1_s_mono ;;;#define MFLG_ZERO 0x01 ; b_mo1_s_zero ;;;#define MFLG_STARTED 0x04 ; b_mo1_s_started ;;; ;;;#define MFLG_SHAPE_FLAGS 0xe0 ; copy these flags to shape ;;;#define MFLG_PN_FLAGS 0xa0 ; copy these flags to from lo to hi nibble ;;;#define MFLG_INIT_FLAGS 0x40 ; copy these flags to from lo to hi nibble ;;; ;;;#define b_mo1_s_prev_pause v_mo1_s_flags,7 ;;;#define b_mo1_s_next_pause v_mo1_s_flags,3 ;;;#define b_mo1_s_prev_dir v_mo1_s_flags,5 ;;;#define b_mo1_s_next_dir v_mo1_s_flags,1 ;;;#define b_mo1_s_mono v_mo1_s_flags,6 ;;;#define b_mo1_s_zero v_mo1_s_flags,0 ;;;#define b_mo1_s_started v_mo1_s_flags,2 ;;; ;;; ;;; ; ;;; ; ;;; movwf POSTINC1 ; angle ;;; movf v_mo1_s_impulseh ;;; movwf POSTINC1 ; impulse h ;;; movf v_mo1_s_impulsel ;;; movwf POSTINC1 ; impulse l ;;; movf v_mo1_s_maxmag ;;; movwf POSTINC1 ; max magnitude ;;; ;;; btfss b_mo1_s_mono ;;; clrf v_mo1_s_asum ;;; ;;; movlw MSHP_PULSE ;;; movwf INDF1 ; set shape to pulse ;;; ;;; btfss b_mo1_s_mono ;;; bra v_mo1_store_shape ; pulse if not MONO ;;; ;;; btfss b_mo1_s_next_pause ;;; btfsc b_mo1_s_prev_pause ;;; bra v_mo1_store_shape ; pulse if preceded or followed by pause ;;; ;;; movf v_mo1_s_asum,w ;;; addlw -4 ;;; bnc v_mo1_store_shape ; pulse if asum<4 ;;; ;;; movf v_mo1_s_maxstep,w ;;; addlw -6 ;;; bc v_mo1_store_shape ; pulse if maxstep>=6 ;;; ;;; bcf INDF1,2 ; not a pulse - set shape to dirty circle ;;; ;;; addlw 6-4 ;;; bnn v_mo1_store_shape ; dirty circle if maxstep>=4 ;;; ;;; btfsc b_mo1_s_zero ;;; bra v_mo1_store_shape ; dirty circle if ZERO is set ;;; ;;; movf v_mo1_maxdmag,w ;;; addlw -8 ;;; bc v_mo1_store_shape ; dirty circle if maxdmag >= 8 ;;; ;;; bsf INDF1,1 ; clean circle! ;;; ;;;!! todo: if next is pause or end then come back and make this a pulse ;;; ;;; ; ;;; ; store shape & flags (actually already stored at this point) ;;; ; ;;;v_mo1_store_shape: ;;; movf v_mo1_s_flags,w ;;; andlw MFLG_SHAPE_FLAGS ;;; iorwf POSTINC1,f ; store flags & direction ;;; ;;; ;;;w_mo1_check_done: ;;; movf v_mo1_angle,w ;;; addlw -0xfe ;;; bnz v_mo1_begin_shape ;;; ;;; setf POSTDEC1 ; mark end with 0xff ;;; ;;; ; ;;; ; done - make last shape into a pulse ;;; ; ;;; movf INDF1,w ;;; andlw MSHF_MONO_PAUSE ; preserve MONO & PAUSE flags ;;; iorlw MSHP_PULSE ;;; movwf INDF1 ;;; ;;;DONE HERE!!!!!!!!!!!! ;;; ;;; ;;;CRAP FOLLOWS ;;; btf ;;; ;;; ;;; ;;; clrf v_mo1_s_maxstep ;;; movf v_mo1_step,w ;;; movwf v_mo1_s_asum ;;; movf v_mo1_impl,w ;;; movwf v_mo1_s_impl ;;; movf v_mo1_imph,w ;;; movwf v_mo1_s_imph ;;; ;;; ;;; ;;; ;;; ;;; ;;; addlw -0xfe ;;; bz w_mo1_read_loop_done ;;; ;;; ; ;;; ; did we have ;;; ; ;;; addlw 0xfe-0xff ;;; bnz w_mo1_read_loop_notime ; not a pause - ignore it ;;; ;;; ; ;;; ; PAUSE ;;; ; - clear got-tap (been long enough) ;;; ; - include time and get next record ;;; ; ;;; bcf b_ry_got_tap ;;; bra w_crs_read_loop ;;; ;;;xxw_mo1_read_angle: ;;; ; ;;; ; angle - read the rest of the fields ;;; ; ;;; movf POSTINC2,w ;;; movwf v_ry_ih ; impulse high ;;; movf POSTINC2,w ;;; movwf v_ry_il ; impulse low ;;; movf POSTINC2,w ;;; movwf v_ry_magn ; min mag ;;; movf POSTINC2,w ;;; movwf v_ry_magx ; max mag ;;; ;;; ; ;;; ; is force up? (angle = 0x0a - 0x15) ;;; ; ;;; movf v_ry_a,w ;;; addlw -0x0a ;;; addlw -(0x16-0x0a) ;;; bnc w_crs_read_loop_is_up ;;; ;;; ; ;;; ; direction is wrong for a tap - clear got_tap and continue ;;; ; ;;; bcf b_ry_got_tap ;;; bra w_crs_read_loop ;;; ;;; ;;; ;;; return ;;; #endif ;########################################################################### ;################################ RYTHM SPELLS ############################# ;########################################################################### #if DBORG org 0x3400 #endif ; ; need at least this many taps to be a rythm ; #define MIN_RYTM_TAPS 5 ; ; temp variables used in w_check_rythm_spell ; v_ry_bits equ vaddr+0 ; v_ry_tap_cnt equ vaddr+1 ; # of taps v_ry_cnth equ vaddr+2 ; accumulated time for next tap v_ry_cntl equ vaddr+3 ; v_ry_minh equ vaddr+4 ; min tap time v_ry_minl equ vaddr+5 ; v_ry_ch equ vaddr+6 ; sample time v_ry_cl equ vaddr+7 ; v_ry_a equ vaddr+8 ; sample angle v_ry_ih equ vaddr+9 ; sample impulse v_ry_il equ vaddr+10 ; v_ry_magn equ vaddr+11 ; sample min mag v_ry_magx equ vaddr+12 ; sample max mag vaddr+=13 RYTHM_MIN_TAP_TIME equ 100 ; taps must be at least this many counts apart #define b_ry_got_tap v_ry_bits,0 ; 1 if found a tap #define b_ry_got_first_tap v_ry_bits,1 ; set after first tap is found #define b_ry_save_mul v_ry_bits,2 ; set to store multiplier in buffer #define b_ry_got_zero v_ry_bits,3 ; got at least 1 zero #define b_ry_run_on v_ry_bits,4 ; ok if extra notes follow v_ry_loopcnt1 equ vaddr+0 ; v_ry_loopcnt2 equ vaddr+1 ; v_ry_best_minh equ vaddr+2 ; best beat time v_ry_best_minl equ vaddr+3 ; v_ry_best_scoreh equ vaddr+4 ; score for best beat time v_ry_best_scorel equ vaddr+5 ; v_ry_scoreh equ vaddr+6 ; score for current beat time v_ry_scorel equ vaddr+7 ; v_ry_err0h equ vaddr+8 ; error0 v_ry_err0l equ vaddr+9 ; v_ry_err1h equ vaddr+10 ; error1 v_ry_err1l equ vaddr+11 ; vaddr+=12 ; ; Call this to check for a rythm spell ; ; REQUIRED INPUT CONDITIONS ; - sampling disabled (b_accbuf_sample=0) ; - RAMBUF_ACC contains samples terminated by entry with angle=0xfe ; ; RESOURCES USED ; - uses RAMBUF_RYTHM for scratch buffer ; ; OUTPUT CONDITIONS ; if spell is recognized: ; - b_got_spell is set ; - v_spell_ptrh,l = pointer to spell info (points to string for now) ; if spell is NOT recognized: ; - b_got_spell is clear ; w_check_rythm_spell: bcf b_got_spell ; no spell recognized (yet) lfsr FSR2,RAMBUF_ACC lfsr FSR1,RAMBUF_RYTHM setf v_ry_cnth setf v_ry_cntl clrf v_ry_bits clrf v_ry_ch clrf v_ry_cl #define DBG_RYTHM_TTIME 1 #if DBG_RYTHM_TTIME ; ; v_t0l,h are for debug - total time ; clrf v_t0h clrf v_t0l #endif setf v_ry_minh setf v_ry_minl ; ; find each tap in buffer and record time ; w_crs_read_loop: #if DBG_RYTHM_TTIME movf v_ry_cl,w addwf v_t0l,f movf v_ry_ch,w addwfc v_t0h,f ; let it wrap #endif ; ; add time from previous entry ; movf v_ry_cl,w addwf v_ry_cntl,f movf v_ry_ch,w addwfc v_ry_cnth,f bnc w_crs_read_loop_notime setf v_ry_cnth ; clamp to max setf v_ry_cntl ; clamp to max w_crs_read_loop_notime: ; ; read next entry ; movf POSTINC2,w movwf v_ry_ch ; time high movf POSTINC2,w movwf v_ry_cl ; time low movf POSTINC2,w movwf v_ry_magx ; max mag movf POSTINC2,w movwf v_ry_a ; angle bnn w_crs_read_loop_angle ; it is an angle addlw -0xfe bz w_crs_read_loop_done ; ; if (angle == 0xff) then this is a PAUSE ; addlw 0xfe-0xff bnz w_crs_read_loop_notime ; not a pause - ignore it ; ; PAUSE ; - clear got-tap (been long enough) ; - include time and get next record ; bcf b_ry_got_tap bra w_crs_read_loop w_crs_read_loop_angle: ; ; angle - read the rest of the fields ; movf POSTINC2,w ; impulse high movwf v_ry_ih movf POSTINC2,w ; impulse low movwf v_ry_il movf POSTINC2,w ; min mag movwf v_ry_magn movf POSTINC2,w ; flags ; ; is force up? (angle = 0x0a - 0x15) ; movf v_ry_a,w addlw -0x0a addlw -(0x16-0x0a) bnc w_crs_read_loop_is_up ; ; direction is wrong for a tap - clear got_tap and continue ; bcf b_ry_got_tap bra w_crs_read_loop w_crs_read_loop_is_up: ; ; direction is right for a tap - is magnitude big enough? ; movlw -ACC_TH_MAG_TAP addwf v_ry_magx,w bnc w_crs_read_loop ; nope - continue ; ; is this just part of an earlier tap? ; btfsc b_ry_got_tap bra w_crs_read_loop ; ; has it been long enough since last tap? ; movlw LOW RYTHM_MIN_TAP_TIME subwf v_ry_cntl,w movlw HIGH RYTHM_MIN_TAP_TIME subwfb v_ry_cnth,w bnc w_crs_read_loop w_crs_read_loop_tap: btfss b_ry_got_first_tap bra w_crs_read_loop_tap_next ; ; no time accumulated (should not happen) ; movf v_ry_cnth,w iorwf v_ry_cntl,w bz w_crs_read_loop #if 1 && DBPRINT #if DBG_RYTHM_TTIME movf v_t0h,w call kk_outbyte movf v_t0l,w call kk_outbyte COUTL ' ' #endif #endif ; ; save tap time ; movf v_ry_cnth,w movwf POSTINC1 #if 1 && DBPRINT call kk_outbyte #endif movf v_ry_cntl,w movwf POSTINC1 #if 1 && DBPRINT call kk_outbyte call kk_outcr DB_FLUSH #endif ; ; ignore extra taps (only RSPELL_MAX_TAPS count) ; movf FSR1L,w addlw -((RSPELL_MAX_TAPS+1)*2) bc w_crs_read_loop_done ; ; only look for min time in first RSPELL_LATEST_ONE taps ; movf FSR1L,w addlw -((RSPELL_LATEST_ONE+1)*2) bc w_crs_read_loop_tap_next ; ; get min tap time ; movf v_ry_minl,w subwf v_ry_cntl,w movf v_ry_minh,w subwfb v_ry_cnth,w bc w_crs_read_loop_tap_next ; ; new min time ; movf v_ry_cntl,w movwf v_ry_minl movf v_ry_cnth,w movwf v_ry_minh w_crs_read_loop_tap_next: bsf b_ry_got_first_tap bsf b_ry_got_tap ; ; clear tap time ; clrf v_ry_cntl clrf v_ry_cnth bra w_crs_read_loop w_crs_read_loop_done: ; ; scan LED ; call w_ledscan ; ; v_ry_tap_cnt = # taps in buffer ; mark end of buffer with 00 ; rrncf FSR1L,w movwf v_ry_tap_cnt ; ; too few taps? ; addlw -RSPELL_MIN_TAPS btfss STATUS,C bra w_crs_done clrf POSTINC1 clrf POSTINC1 #if DBPRINT ; ; debug printf ; call kk_outcr COUTL 'T' movf v_ry_tap_cnt,w call kk_outbyte COUTL ' ' COUTL 'N' movf v_ry_minh,w call kk_outbyte movf v_ry_minl,w call kk_outbyte call kk_outcr #endif ; ; abort if min time is too big (>2.6 sec) ; movf v_ry_minh,w andlw 0xf0 bnz w_crs_done ; ; prepare to loop over all times between min-0x80 and min+0x80 ; (stepping by 1) ; movlw LOW (-0x81) addwf v_ry_minl,f movlw HIGH (-0x81) addwfc v_ry_minh,f bc w_crs_prep1 clrf v_ry_minl ; clamp clrf v_ry_minh w_crs_prep1: clrf v_ry_loopcnt1 clrf v_ry_best_minh clrf v_ry_best_minl setf v_ry_best_scoreh setf v_ry_best_scorel ; ; loop over all times between min-0x80 and min+0x80 ; (if min<=0x80 then loop from 0x01 - 0x100) ; (stepping by 1) ; w_crs_time_loop: ; ; increment time ; infsnz v_ry_minl,f incf v_ry_minh,f ; ; score this time value (do not save multipliers) ; bcf b_ry_save_mul rcall w_crs_score #if 0 && DBPRINT DB_FLUSH COUTL 'M' movf v_ry_minh,w call kk_outbyte movf v_ry_minl,w call kk_outbyte COUTL ' ' COUTL 'S' movf v_ry_scoreh,w call kk_outbyte movf v_ry_scorel,w call kk_outbyte COUTL ' ' COUTL 'B' movf v_ry_bits,w call kk_outbyte call kk_outcr DB_FLUSH #endif btfss b_ry_got_zero bra w_crs_time_loop_end ; no zeros - probably mul is too big ; ; save smallest score with multiplier that caused it ; movf v_ry_best_scorel,w subwf v_ry_scorel,w movf v_ry_best_scoreh,w subwfb v_ry_scoreh,w bc w_crs_time_loop_end ; new score is bigger - try next mul ; ; new score is smaller - save new mul ; movff v_ry_scorel,v_ry_best_scorel movff v_ry_scoreh,v_ry_best_scoreh movff v_ry_minl,v_ry_best_minl movff v_ry_minh,v_ry_best_minh ; ; end loop over times ; w_crs_time_loop_end: decfsz v_ry_loopcnt1,f bra w_crs_time_loop #if DBPRINT DB_FLUSH COUTL 'S' COUTL 'C' movf v_ry_best_scoreh,w call kk_outbyte movf v_ry_best_scorel,w call kk_outbyte call kk_outcr COUTL 'B' COUTL 'C' movf v_ry_best_minh,w movwf v_ry_minh call kk_outbyte movf v_ry_best_minl,w movwf v_ry_minl call kk_outbyte call kk_outcr DB_FLUSH #endif ; ; scan LED ; call w_ledscan ; ; use the best cnt value and break the rythm into 0-7 numbers ; lfsr FSR2,RAMBUF_RYTHM bsf b_ry_save_mul rcall w_crs_score #if DBPRINT call kk_outcr #endif ; ; scan LED ; call w_ledscan rcall w_crs_check_spells w_crs_done: return ;=========================================================================== ; loop over each tap to calculate score & multiple ;=========================================================================== w_crs_score: bcf b_ry_got_zero clrf v_ry_scorel clrf v_ry_scoreh lfsr FSR1,RAMBUF_RYTHM w_crs_tap_loop: movf POSTINC1,w movwf v_ry_ch movf POSTINC1,w movwf v_ry_cl iorwf v_ry_ch,w ; reached the last one? btfsc STATUS,Z return movlw 8 movwf v_ry_loopcnt2 clrf v_ry_cnth clrf v_ry_cntl setf v_ry_err0l setf v_ry_err0h ; ; loop over 1-8 times minl,h time ; w_crs_mul_loop: movf v_ry_minl,w addwf v_ry_cntl,f movf v_ry_minh,w addwfc v_ry_cnth,f movf v_ry_cntl,w subwf v_ry_cl,w movwf v_ry_err1l movf v_ry_cnth,w subwfb v_ry_ch,w movwf v_ry_err1h bnc w_crs_mul_loop_cnt_bigger movwf v_ry_err0h movff v_ry_err1l,v_ry_err0l ; ; loop over 8 possibilities ; decfsz v_ry_loopcnt2,f bra w_crs_mul_loop ; ; tap time is longer than 8x - just use 8x ; ; ; save multiplier if b_ry_save_mul is set ; w_crs_mul_save: comf v_ry_loopcnt2,w addlw 8 btfsc STATUS,Z bsf b_ry_got_zero incf WREG,w #if 0 && DBPRINT movwf v_ry_loopcnt2 COUTL '.' movf v_ry_loopcnt2,w call kk_outbyte COUTL ' ' movf v_ry_loopcnt2,w #endif btfss b_ry_save_mul bra w_crs_mul_score ; ; turn 7s into 8s (there are no 7s, and 8s are hard to get sometimes) ; addlw -7 btfsc STATUS,Z incf WREG,w addlw 7 #if DBPRINT movwf v_ry_loopcnt2 call kk_outbyte COUTL ' ' movf v_ry_loopcnt2,w #endif iorwf POSTINC2,f ; store in low nibble of byte btfss FSR1L,1 bra w_crs_mul_score clrf POSTDEC2 ; set last one to 0x00 swapf WREG,w movwf INDF2 ; store in high nibble of byte ; (next one will go in low nibble, same byte) ; ; add error to score ; w_crs_mul_score: #if 0 && DBPRINT COUTL 'e' movf v_ry_err0h,w call kk_outbyte movf v_ry_err0l,w call kk_outbyte COUTL ' ' #endif movf v_ry_err0l,w addwf v_ry_scorel,f movf v_ry_err0h,w addwfc v_ry_scoreh,f bnc w_crs_tap_loop ; ; abort if score overflows ; setf v_ry_scorel ; clamp setf v_ry_scoreh return ; ; here err0 is positive and err1 is negative ; if err1 is smaller then cp to err0 and decrement v_ry_loopcnt2 ; w_crs_mul_loop_cnt_bigger: movf v_ry_err0l,w addwf v_ry_err1l,w movf v_ry_err0h,w addwfc v_ry_err1h,w bnc w_crs_mul_save ; err0 is smaller ; ; err1 is smaller ; decf v_ry_loopcnt2,f comf v_ry_err1l,w movwf v_ry_err0l comf v_ry_err1h,w movwf v_ry_err0h infsnz v_ry_err0l,f incf v_ry_err0h,f bra w_crs_mul_save ;=========================================================================== ; compare result against spell (exact match only) ; TBLPTR should point to spell - 1 ; w_crs_spell_cmp: tblrd*- lfsr FSR1,RAMBUF_RYTHM w_crs_spell_cmp_loop: tblrd*+ movf TABLAT,w btfsc b_ry_run_on bz w_crs_spell_cmp_good subwf POSTINC1,w bnz w_crs_spell_cmp_bad movf TABLAT,w bnz w_crs_spell_cmp_loop w_crs_spell_cmp_good: bsf b_got_spell w_crs_spell_cmp_bad: movf TABLAT,w btfsc STATUS,Z return ; ; find end of spell 0x00 ; tblrd*+ bra w_crs_spell_cmp_bad ;=========================================================================== ; ; compare result againste each spell ; w_crs_check_spells: ; ; prepare to recognize spells ; bcf b_ry_run_on movlw HIGH w_rspell1 movwf TBLPTRH movlw LOW w_rspell1 movwf TBLPTRL w_crs_check_loop: tblrd*+ movf TABLAT,w bz w_crs_check_loop ; ignore extra 0x00 ; ; 0xff = done ; 0xfe = partial spell ; 0xfd = alternate version of same spell ; else = check ; infsnz TABLAT,f return ; no rythm matched infsnz TABLAT,f bra w_crs_check_partial ; ; check spell ; rcall w_crs_spell_cmp ; ; read spell info ; tblrd*+ movff TABLAT,v_spell_ptrh tblrd*+ movff TABLAT,v_spell_ptrl ; ; check next if no match ; btfss b_got_spell bra w_crs_check_loop SOUT1L w_str_gotrythm movf v_spell_ptrh,w call w_outbyte movf v_spell_ptrl,w call w_outbyte call w_outcr DB_FLUSH ; ; Recognized a spell!! ; return w_crs_check_partial: bsf b_ry_run_on ; start partial spells bra w_crs_check_loop #if DBORG org 0x3700 #endif ; ; special numbers in spells ; SPELL_END equ 0x00 ; terminate spell - ignored elsewhere SPELL_LAST equ 0xff ; follows last spell SPELL_PARTIAL equ 0xfe ; begin partial spells #include "rspells.inc" ;########################################################################### ;################################ PARSING MOTIONS ########################## ;########################################################################### #if ENAB_W_PARSE #if DBORG org 0x3500 #endif ; ; Acceleration Parser ; ; FUNCTIONS ; --------- ; w_parse_init - initialize parsing ; w_parse - call to parse next accbuf entry (if any) ; w_parse_finish - finish parsing and filling RAMBUF_MOTION ; w_parse_flush - call w_parse until no more accbuf entries available ; ; OVERVIEW ; -------- ; Read output of RAMBUF_ACC and write parsed motion bytes ; ; OUTPUT FORMAT ; 0daa cccc ; ; cccc = count - how many half cirles were made. 0=end (not a circle) ; aa = angle 00=up 01=right 10=down 11=left ; d = direction 0=cw 1=ccw ; ; if cccc==0: aa = angle of largest magnitude ; d = was actual angle cw or ccw of indicated angle ; ; if cccc!=0: aa = average of start angle and end angle. ; d = direction of circles ; ; ; Global state vars ; ; v_spell_len - ptr to dst buffer & # bytes in spell ; ; state vars ; v_ap_srcl equ vaddr+0 ; pointer to source data v_ap_srch equ vaddr+1 v_ap_max_mag equ vaddr+2 ; max magnitude v_ap_max_mag_angle equ vaddr+3 ; angle of max magnitude v_ap_prev_angle equ vaddr+4 ; previous angle v_ap_cnt equ vaddr+5 ; number of circles so far v_ap_dir equ vaddr+6 ; bit7: 1=ccw 0=cw v_ap_wag_cnt equ vaddr+7 ; 8 - # of left-right wags in a row v_ap_angle_pos equ vaddr+8 ; current angle position in circle v_ap_angle_pos_min equ vaddr+9 ; min angle position in circle v_ap_angle_pos_max equ vaddr+10 ; max angle position in circle v_ap_max_angle equ vaddr+11 ; v_ap_angle at angle_pos_max vaddr+=12 ; ; tmp vars ; v_ap_delta_angle_abs equ vaddr+0 ; abs value of delta angle v_ap_delta_angle equ vaddr+1 ; delte angle v_ap_result equ vaddr+2 ; result v_ap_mag equ vaddr+3 ; current mag v_ap_angle equ vaddr+4 ; current angle v_ap_angle_tmp1 equ vaddr+5 ; temporary to save value during result vaddr+=6 ;=========================================================================== ; DEBUG CODE ;=========================================================================== #define WP_DEBUG 0 #define WP_DEBUG2 1 #define WP_DEBUG3 1 #if WP_DEBUG WPARSE_DBG macro whr movlw whr movwf v_tmp rcall w_parse_dbg endm #else WPARSE_DBG macro whr endm #endif ;=========================================================================== ; initialize parsing ;=========================================================================== w_parse_init: movlw LOW RAMBUF_ACC movwf v_ap_srcl movlw HIGH RAMBUF_ACC movwf v_ap_srch movlw ACC_STATE_INVALID clrf v_spell_len clrf v_ap_max_mag bcf b_parse_wag bcf b_parse_done movlw 8 movwf v_ap_wag_cnt return ;=========================================================================== ; finish parsing & flush output ;=========================================================================== w_parse_finish: #if WP_DEBUG COUTL 'x' call kk_outcr #endif bcf b_accbuf_sample ; disable sampling rcall w_sample_store_zero ; store an extra zero sample in buffer rcall w_parse_flush #if WP_DEBUG COUTL 'y' call kk_outcr #endif ; ; store an entry which will force a jump in w_parse (flushes last val) ; rcall w_sample_store_zero ; store an extra zero sample in buffer movff FSR2H,FSR0H movff FSR2L,FSR0L movf POSTDEC0,f ; point to mag movlw 1 movwf POSTDEC0 ; mag=1; point to angle movf v_ap_prev_angle,w btg WREG,4 movwf INDF0 ; angle = opposite of prev angle #if WP_DEBUG COUTL 'w' movf v_ap_prev_angle,w call kk_outbyte call kk_outcr #endif rcall w_sample_store_zero ; store an extra zero sample in buffer ; ; fall through to w_parse_flush ; ;=========================================================================== ; handle all entries in the acc buffer ;=========================================================================== w_parse_flush: WPARSE_DBG 'z' rcall w_parse btfss b_parse_done bra w_parse_flush return ;=========================================================================== ; read one ACC buffer record (if available) and parse it into motions ;=========================================================================== w_parse: ; ; is next record available? ; bsf b_parse_done ; set if no more to read movf v_ap_srch,w movwf FSR0H subwf FSR2H,w movwf v_tmp movf v_ap_srcl,w movwf FSR0L subwf FSR2L,w iorwf v_tmp,w btfsc STATUS,Z return ; return if head==tail ; ; increment src pointer ; movlw 4 addwf v_ap_srcl,f btfsc STATUS,C incf v_ap_srch,f bcf b_parse_done ; still more to read (maybe) ; ; do nothing if spell is complete ; btfsc b_parse_wag bra w_parse_end ; ; read sample (currently pointing just AFTER sample) ; movf POSTDEC0,w ; garbage (now point to mag) movf POSTDEC0,w ; magnitude (now point to astate) movwf v_ap_mag bz w_parse_end ; ignore zero mag states movf POSTINC0,w ; astate (now point to mag) movwf v_ap_angle ; ; check for special astates ; addlw 0xe0 bnc w_parse_check_first ; ; TODO: for long zero states halt circle (send result) bra w_parse_end ; ignore this state ; ; is this the first angle? ; w_parse_check_first: movf v_ap_max_mag,f bnz w_parse_cont ; ; start a new motion ; w_parse_start: movf v_ap_mag,w movwf v_ap_max_mag movf v_ap_angle,w movwf v_ap_prev_angle movwf v_ap_max_mag_angle movwf v_ap_max_angle clrf v_ap_cnt clrf v_ap_dir movlw 0x80 movwf v_ap_angle_pos movwf v_ap_angle_pos_max movwf v_ap_angle_pos_min WPARSE_DBG 'd' w_parse_end: return ; ; not the first motion ; w_parse_cont: ; ; calc delta angle ; negf WREG addwf v_ap_prev_angle,w rcall w_adiff movwf v_ap_delta_angle movff v_ap_angle,v_ap_prev_angle btfsc WREG,7 negf WREG movwf v_ap_delta_angle_abs addlw -4 bnc w_parse_circle ; ; angle difference is >4 ; w_parse_jump: rcall w_parse_result rcall w_parse_start return ; ; delta angle is <4, so we might be circling ; w_parse_circle: ; ; .01 sec - .2 sec is range of times per circle pulse ; ; ; ; ; ; ; ; if mag is bigger save max_mag and max_mag_angle ; movf v_ap_mag,w ; current mag cpfsgt v_ap_max_mag ; bigger than prev mag? movff v_ap_angle,v_ap_max_mag_angle cpfsgt v_ap_max_mag movwf v_ap_max_mag ; ; moving same direction as before? ; movf v_ap_delta_angle,w xorwf v_ap_dir,w bn w_parse_rev ; ; going same direction as circle direction ; w_parse_same: ; ; calc current position ; movf v_ap_delta_angle_abs,w addwf v_ap_angle_pos,f ; ; increased max angle? ; movf v_ap_angle_pos,w cpfslt v_ap_angle_pos_max return ; no - do nothing ; ; biggest angle so far - save it ; also save the v_ap_angle corresponding to this angle ; movwf v_ap_angle_pos_max movff v_ap_angle,v_ap_max_angle ; ; Have we moved more than 2 circles? ; subwf v_ap_angle_pos_min,w ; NEGATIVE total movement addlw 0x40 btfsc STATUS,C return ; no - do nothing ; ; moved more than 2 circles - subtract off 1 circle ; movf v_ap_angle_pos,w addlw -0x20 movwf v_ap_angle_pos movwf v_ap_angle_pos_max infsnz v_ap_cnt,f setf v_ap_cnt ; clamp to 0xff return ; ; going opposite direction from circle direction ; w_parse_rev: ; ; calc current position ; movf v_ap_delta_angle_abs,w subwf v_ap_angle_pos,f ; ; keep track of min angle_pos ; movf v_ap_angle_pos,w cpfslt v_ap_angle_pos_min movwf v_ap_angle_pos_min ; ; how far backwards have we moved? ; subwf v_ap_angle_pos_max,w movwf v_ap_angle_tmp1 addlw -8 ; REVERSE THRESHHOLD btfss STATUS,C return ; < REVERSE THRESHHOLD - do nothing ; ; we are reversing direction - send result if precvious circle big enough ; movf v_ap_cnt,w bnz w_parse_rev_result ; at least a circle - send result movf v_ap_angle_pos_min,w subwf v_ap_angle_pos_max,w addlw -24 ; MIN REV CIRCLE THRESHHOLD bnc w_parse_rev_yes ; < MIN REV CIRCLE THRESHHOLD - do not send w_parse_rev_result: rcall w_parse_result ; ; reverse direction of circles ; w_parse_rev_yes: ; ; max - min ; movf v_ap_angle_pos_min,w subwf v_ap_angle_pos_max,w ; ; adjust angle at max (becomes angle at what was min) ; btfss v_ap_dir,7 subwf v_ap_max_angle,f btfss v_ap_dir,7 addwf v_ap_max_angle,f ; ; new max = 0x80 + old (max-min) ; new min = 0x80 + 0 ; addlw 0x80 movwf v_ap_angle_pos_max movlw 0x80 movwf v_ap_angle_pos_min addwf v_ap_angle_tmp1,w movwf v_ap_angle_pos clrf v_ap_cnt btg v_ap_dir,7 return ; ; w_parse_result - send result to motion buffer ; Must not modify any of: ; v_ap_prev_angle ; v_ap_angle_pos_max ; v_ap_angle_pos_min ; w_parse_result: movf v_ap_angle_pos_min,w subwf v_ap_angle_pos_max,w addlw -24 ; MIN CIRCLE THRESHHOLD bnc w_parse_result_check ; < MIN CIRCLE THRESHHOLD - no extra circle w_parse_result_cnt_loop: infsnz v_ap_cnt,f setf v_ap_cnt ; clamp to 0xff addlw -32 bc w_parse_result_cnt_loop ; another circle w_parse_result_check: movf v_ap_cnt,f bnz w_parse_result_circle ; at least 1 circle w_parse_result_jerk: ; ; clamp to 4 directions - 0=up 1=right 2=down 3=left ; movf v_ap_max_mag_angle,w addlw 4 rlncf WREG,w andlw 0x30 movwf v_ap_result bra w_parse_result_send w_parse_result_circle: #if WP_DEBUG3 DB_BYTE 'A',v_ap_max_angle DB_BYTE 'n',v_ap_angle_pos_min DB_BYTE 'p',v_ap_angle_pos DB_BYTE 'x',v_ap_angle_pos_max DB_BYTE '1',WREG #endif ; ; calc start direction ; w contains max-min-24 ; addlw 24 andlw 0x1f ; ; Now w is (max - min) mod 32 ; ; ; bias by 24 so that if w is 0-24 average will be between min...max and if ; 25-31 then average will be between max...min ; addlw -24 btfss STATUS,N addlw -0x20 addlw 24 #if WP_DEBUG3 DB_BYTE '2',WREG #endif ; ; Here w is the delta from max to min in range -7 ... 24 ; btfsc v_ap_dir,7 negf WREG ; w now contains the signed delta between min and max angle mod 32 #if WP_DEBUG3 DB_BYTE '3',WREG #endif btfsc WREG,7 addlw 1 bcf WREG,0 btfsc WREG,7 bsf WREG,0 rrncf WREG,w ; w is now half the delta angle from min to max #if WP_DEBUG3 DB_BYTE '4',WREG #endif ; ; add to the angle at max to get avg of start & end angle ; addwf v_ap_max_angle,w #if WP_DEBUG3 DB_BYTE '5',WREG #endif ; ; round to quadrant ; addlw 4 rlncf WREG,w andlw 0x30 movwf v_ap_result #if WP_DEBUG3 DB_BYTE 'a',WREG #endif ; ; clamp cnt to 0x0f and store in result ; movf v_ap_cnt,w andlw 0xf0 btfss STATUS,Z setf v_ap_cnt movf v_ap_cnt,w andlw 0x0f iorwf v_ap_result,f ; ; store cw/ccw ; btfsc v_ap_dir,7 bsf v_ap_result,6 #if WP_DEBUG3 DB_BYTE 'r',v_ap_result call kk_outcr #endif ; ; send result to output buffer ; w_parse_result_send: ; ; point to next dst and increment spell len (clamp to 0xff) ; lfsr FSR0,RAMBUF_MOTION movf v_spell_len,w movwf FSR0L incfsz WREG,w movwf v_spell_len movf v_ap_result,w movwf INDF0 ; result to buffer ; ; check for v_ap_result == 0x10 or 0x30 ; movf v_ap_result,w addlw -0x10 bz w_parse_result_wag addlw 0x10-0x30 bz w_parse_result_wag movlw 9 movwf v_ap_wag_cnt ; reset wag count w_parse_result_wag: dcfsnz v_ap_wag_cnt,f bsf b_parse_wag WPARSE_DBG 'c' #if WP_DEBUG2 COUTL 'r' movf v_ap_result,w call kk_outbyte call kk_outcr #endif return ; ; angle convert - convert a1-a2 to signed angle from -16 to +15 ; input: w=a1-a2 ; output w = signed angle -16 ... 15 ; w_adiff: andlw 0x1f btfss WREG,4 return addlw -0x20 return ; ; convert angle to octant ; input: angle (0-31) in W ; output: octant (0-7) in W ; w_a2oct: addlw 2 rrncf WREG,w rrncf WREG,w andlw 7 return #if 0 ; ; convert angle to octant ; input: angle (0-31) in W ; output: quad (0-3) in W ; w_a2quad: addlw 4 rrncf WREG,w rrncf WREG,w rrncf WREG,w andlw 3 return #endif #if WP_DEBUG w_parse_dbg: movf FSR0L,w andlw 0xfc addlw 2 movwf FSR0L movf INDF0,w call kk_outbyte COUTL ' ' movf v_tmp,w call kk_cout COUTL ' ' COUTL 'C' movf v_ap_cnt,w call kk_outbyte COUTL ' ' COUTL 'S' movf v_ap_start_angle,w call kk_outbyte COUTL ' ' COUTL 'P' movf v_ap_prev_angle,w call kk_outbyte COUTL ' ' COUTL 'D' movf v_ap_delta_angle,w call kk_outbyte COUTL ' ' COUTL 'M' movf v_ap_max_mag,w call kk_outbyte COUTL ' ' COUTL 'A' movf v_ap_max_mag_angle,w call kk_outbyte COUTL ' ' COUTL 'R' movf v_ap_dir_save,w call kk_outbyte COUTL ' ' COUTL 'X' movf v_ap_dbg_spx,w call kk_outbyte COUTL ' ' COUTL 'Y' movf v_ap_dbg_spy,w call kk_outbyte COUTL ' ' movf v_ap_srch,w call kk_outbyte movf v_ap_srcl,w call kk_outbyte COUTL ' ' movf FSR2H,w call kk_outbyte movf FSR2L,w call kk_outbyte COUTL ' ' COUTL ' ' movf v_bits1,w call kk_outbyte call kk_outcr w_parse_dbg_loop: call w_main_run movf vk_tx_cnt,w bnz w_parse_dbg_loop return #endif #endif #if vaddr>0xff error "Too many variables!" #endif ;########################################################################### ;################################ DATA ##################################### ;########################################################################### #if DBG_SPELL_MSG_IS_SPELL_NAME w_spellinfo_puffthemagicdragon: db "Puff the magic_dragon" #endif #if DBORG org 0x3800 #endif #include "wmspells.inc" #include "wmspells2.inc" #if DBORG org 0x3c00 #endif #if !DBG_SPELL_MSG_IS_SPELL_NAME #include "wspell_info.inc" #include "wspell_str.inc" #endif #if !DBG_SPELL_MSG_IS_SPELL_NAME w_spellinfo_wandy: db "You cast wandy! Next: grecian ____ a living. \0" w_spellinfo_urn: db "You cast urn/earn! Next: finger ____ of darkness. \0" w_spellinfo_prince: db "You cast prints/prince! Next: hole in ____ the match. \0" w_spellinfo_one: db "You cast one/won! Next: samurai ____ like an eagle. \0" #if 0 ;db "You cast wandy! Next: grecian ____ a living. \0" ;db "You cast urn/earn! Next: pad ____ ness. \0" ;db "You cast lock/loch! Next: jewler's ____ de loop. \0" ;db "You cast loupe/loop! Next: prickly ____ of aces. \0" ;db "You cast pear/pair! Next: finger ____ of darkness. \0" ;db "You cast prints/prince! Next: hole in ____ the match. \0" ;db "You cast one/won! Next: samurai ____ like an eagle. \0" w_spellinfo_sword: db "You cast sword/soared! Well done! Go make potions at Tsakopoulos Library Galleria.\0" #endif #endif #if !DBG_SPELL_MSG_IS_SPELL_NAME w_spellinfo_fast: db "You cast fast! Cast ;fast; again for even faster text. Also try the ;slow; spell.\0" w_spellinfo_slow: db "You cast slow! Cast ;slow; again for even slower text. Also try the ;fast; spell.\0" w_spellinfo_yay1: w_spellinfo_yay equ w_spellinfo_yay1+1 db 0x3c, 0x0, HIGH w_str_yayA, LOW w_str_yayA db 0xff, 0x80, HIGH w_str_yayB, LOW w_str_yayB w_spellinfo_ankle1: w_spellinfo_ankle equ w_spellinfo_ankle1+1 db 0x3c, 0x0, HIGH w_str_ankleA, LOW w_str_ankleA db 0xff, 0x80, HIGH w_str_ankleB, LOW w_str_ankleB w_spellinfo_ask1: w_spellinfo_ask equ w_spellinfo_ask1+1 db 0x3c, 0x0, HIGH w_str_askA, LOW w_str_askA db 0xff, 0x80, HIGH w_str_askB, LOW w_str_askB w_spellinfo_dad1: w_spellinfo_dad equ w_spellinfo_dad1+1 db 0x3c, 0x0, HIGH w_str_dadA, LOW w_str_dadA db 0xff, 0x80, HIGH w_str_dadB, LOW w_str_dadB w_spellinfo_jaw1: w_spellinfo_jaw equ w_spellinfo_jaw1+1 db 0x3c, 0x0, HIGH w_str_jawA, LOW w_str_jawA db 0xff, 0x80, HIGH w_str_jawB, LOW w_str_jawB w_spellinfo_cheese1: w_spellinfo_cheese equ w_spellinfo_cheese1+1 db 0x3c, 0x0, HIGH w_str_cheeseA, LOW w_str_cheeseA db 0x48, 0x00, HIGH w_str_cheeseB, LOW w_str_cheeseB db 0xff, 0x80, HIGH w_str_cheeseC, LOW w_str_cheeseC w_spellinfo_hush1: w_spellinfo_hush equ w_spellinfo_hush1+1 db 0x3c, 0x0, HIGH w_str_hushA, LOW w_str_hushA db 0xff, 0x80, HIGH w_str_hushB, LOW w_str_hushB w_spellinfo_hello1: w_spellinfo_hello equ w_spellinfo_hello1+1 db 0x3c, 0x0, HIGH w_str_helloA, LOW w_str_helloA db 0xff, 0x80, HIGH w_str_helloB, LOW w_str_helloB w_spellinfo_poem1: w_spellinfo_poem equ w_spellinfo_poem1+1 db 0x3c, 0x0, HIGH w_str_poemA, LOW w_str_poemA db 0xff, 0x80, HIGH w_str_poemB, LOW w_str_poemB w_spellinfo_noel1: w_spellinfo_noel equ w_spellinfo_noel1+1 db 0x3c, 0x0, HIGH w_str_noelA, LOW w_str_noelA db 0xff, 0x80, HIGH w_str_noelB, LOW w_str_noelB w_spellinfo_chanters1: w_spellinfo_chanters equ w_spellinfo_chanters1+1 db 0x3c, 0x0, HIGH w_str_chantersA, LOW w_str_chantersA db 0xff, 0x80, HIGH w_str_chantersB, LOW w_str_chantersB w_spellinfo_draconis1: w_spellinfo_draconis equ w_spellinfo_draconis1+1 db 0x3c, 0x0, HIGH w_str_draconisA, LOW w_str_draconisA db 0xff, 0x80, HIGH w_str_draconisB, LOW w_str_draconisB w_spellinfo_gorilla1: w_spellinfo_gorilla equ w_spellinfo_gorilla1+1 db 0x3c, 0x0, HIGH w_str_gorillaA, LOW w_str_gorillaA db 0xff, 0x80, HIGH w_str_gorillaB, LOW w_str_gorillaB w_spellinfo_shave1: w_spellinfo_shave equ w_spellinfo_shave1+1 db 0x3c, 0x0, HIGH w_str_shaveA, LOW w_str_shaveA db 0xff, 0x80, HIGH w_str_shaveB, LOW w_str_shaveB w_spellinfo_row1: w_spellinfo_row equ w_spellinfo_row1+1 db 0x3c, 0x0, HIGH w_str_rowA, LOW w_str_rowA db 0xff, 0x80, HIGH w_str_rowB, LOW w_str_rowB w_spellinfo_jingle1: w_spellinfo_jingle equ w_spellinfo_jingle1+1 db 0x3c, 0x0, HIGH w_str_jingleA, LOW w_str_jingleA db 0xff, 0x80, HIGH w_str_jingleB, LOW w_str_jingleB w_spellinfo_mary1: w_spellinfo_mary equ w_spellinfo_mary1+1 db 0x3c, 0x0, HIGH w_str_maryA, LOW w_str_maryA db 0xff, 0x80, HIGH w_str_maryB, LOW w_str_maryB w_spellinfo_brady1: w_spellinfo_brady equ w_spellinfo_brady1+1 db 0x3c, 0x0, HIGH w_str_bradyA, LOW w_str_bradyA db 0xff, 0x80, HIGH w_str_bradyB, LOW w_str_bradyB w_spellinfo_gilligan1: w_spellinfo_gilligan equ w_spellinfo_gilligan1+1 db 0x3c, 0x0, HIGH w_str_gilliganA, LOW w_str_gilliganA db 0xff, 0x80, HIGH w_str_gilliganB, LOW w_str_gilliganB w_spellinfo_flint1: w_spellinfo_flint equ w_spellinfo_flint1+1 db 0x3c, 0x0, HIGH w_str_flintA, LOW w_str_flintA db 0xff, 0x80, HIGH w_str_flintB, LOW w_str_flintB w_spellinfo_twinkle1: w_spellinfo_twinkle equ w_spellinfo_twinkle1+1 db 0x3c, 0x0, HIGH w_str_twinkleA, LOW w_str_twinkleA db 0xff, 0x80, HIGH w_str_twinkleB, LOW w_str_twinkleB w_spellinfo_birthday1: w_spellinfo_birthday equ w_spellinfo_birthday1+1 db 0x3c, 0x0, HIGH w_str_birthdayA, LOW w_str_birthdayA db 0xff, 0x80, HIGH w_str_birthdayB, LOW w_str_birthdayB w_str_yayA: db "you cast YAY! Hurray for you!\0" w_str_ankleA: db "you cast ANKLE! \0" w_str_askA: db "you cast ASK! \0" w_str_dadA: db "you cast DAD! \0" w_str_jawA: db "you cast JAW! \0" w_str_cheeseA: db "you cast CHEESE! \0" w_str_hushA: db "you cast HUSH! Ssshhh!!!\0" w_str_helloA: db "you cast HELLO! Try the 'fast' spell too!\0" w_str_poemA: db "you cast POEM! \0" w_str_noelA: db "you cast NOEL! Merry Christmas!\0" w_str_chantersA: db "you cast CHANTERS! That is a password, not a spell!\0" w_str_draconisA: db "you cast DRACONIS! You're scaring me!\0" w_str_gorillaA: db "you cast Gorilla! \0" w_str_yayB: db "you cast YAY! Thanks for playing 'Hogwarts the draconian prophecy!' Tr casting 'Hello'\0" w_str_ankleB: db "you cast ANKLE! Don't trip!\0" w_str_askB: db "you cast ASK! Ask and you shall receive... NOT! \0" w_str_dadB: db "you cast DAD! My father is Acorn. http://www.rawbw.com/[acorn\0" w_str_jawB: db "you cast JAW! We're going to need a bigger boat!\0" w_str_cheeseB: db "you cast CHEESE! After Sunday check out the wand website at http://www.rawbw.com/[acorn/wand\0" w_str_hushB: db "you cast HUSH! No need to be so quiet now that the game is over!\0" w_str_helloB: db "you cast HELLO! Try tapping songs. Twinkle twinkle. Row your boat. Mary had a little lamb. Shave and a haircut. Jingle Bells. Brady Bunch. Flintstones. Gilligan. Happy Birthday. \0" w_str_poemB: db "you cast POEM! Suzie was a chemist. Suzie is no more. For what she thought was h2o was h2so4!\0" w_str_noelB: db "you cast NOEL! Happy hanukkah!\0" w_str_chantersB: db "you cast CHANTERS! That is you portrait password!\0" w_str_draconisB: db "you cast DRACONIS! You're scaring me!\0" w_str_gorillaB: db "you cast Gorilla! \0" w_str_cheeseC: db "you cast CHEESE! Check out the wand website at http://www.rawbw.com/[acorn/wand\0" w_str_rowA: db "you cast 'Row row row your boat'! \0" w_str_shaveA: db "you cast 'Shave and a Haircut'! \0" w_str_jingleA: db "you cast Jingle Bells! \0" w_str_maryA: db "you cast 'Mary had a little lamb'! \0" w_str_bradyA: db "you cast 'The Brady Bunch'! \0" w_str_gilliganA: db "you cast 'Gilligan'! \0" w_str_flintA: db "you cast 'The Flintstones'! \0" w_str_twinkleA: db "you cast 'Twinkle'! \0" w_str_birthdayA: db "you cast 'Happy Birthday'!\0" w_str_rowB: db "you cast 'Row row row your boat'! Check out the website http://www.gotohogwarts.com\0" w_str_shaveB: db "you cast 'Shave and a Haircut'! You know what happens when you can't stop laughing? One of these days, you're gonna die laughing.\0" w_str_jingleB: db "you cast Jingle Bells! Try casting 'Noel'\0" w_str_maryB: db "you cast 'Mary had a little lamb'! ry had a little lamb. her father shot it dead. Now Mary takes her lamb to school between two hunks of bread.\0" w_str_bradyB: db "you cast 'The Brady Bunch'! Sorry, no more than 6 people per team.\0" w_str_gilliganB: db "you cast 'Gilligan'! Don't miss the boat!\0" w_str_flintB: db "you cast 'The Flintstones'! Who would win in a fight: astronauts or cavemen? Discuss.\0" w_str_twinkleB: db "you cast 'Twinkle'! Happy 40th anniversary, Star Trek! \0" w_str_birthdayB: db "you cast 'Happy Birthday'! Hogwats and the Draconian Prophecy. September 10-11 2006. http://www.gotohogwarts.com\0" #endif ;########################################################################### ;################################ END ###################################### ;########################################################################### end |
This file Copyright (C) 2006 by Nathan (Acorn) Pooley
Go to TOP Wand page
Go to Acorn's personal webpage
Go to Hogwarts website: www.gotohogwarts.com
Snout: www.snout.org/game
Gadgets of Justice Unlimited
Snout GC (Wiki)
Snout Wiki
File created by do_doc at Wed May 30 03:21:41 PDT 2007