'>Hxtr0-Doc.txt D Buckley 20-11-01 '============================================================== 'Meta Commands and Program Headers - Hxtr '============================================================== 'Meta Commands overview '---------------------- ' 'Ultrasonic behaviour rules '"A" if the action is A then run the Activity Sequencer with ' the activity A_null. '"a" if selected by the test then triggers the Action sequence ' first parameter is prognumber for the Activity sequencer ' second is Activity '"X" if action ="X" then ignore that result. ' 'Yawn '---- ' The yawn rules are special in that when an outcome of ' other rules is activated scanning through the rule set is ' terminated, however the "Y" rule only tests whether the ' next rule should be used, and the "y" rule only resets ' the "yawn" variable before the rule following it is used. ' The first parameter byte for "Y" or "y" is the index to ' the yawn variable, 0=>usyawn0, 1=>usyawn1. ' The second parameter byte is the threshold '"Y" if selected by the test increments 'usyawnX'. ' If 'usyawnX'> threshold then skip the following rule. '"y" if selected then resets 'usyawnX' to 0 'so select same parameters for rule to be skipped for both Y, y ' 'Rules - 'DATA direction,range,do if >,do if <,activity program,activity 'If the rule doesn't contain "a" then no sequence can be 'activated by it so any value could be used for the pointer 'value. 'Sequences ' z - terminator for sequences ' a - Action, used in sequences, acts as a GOTO ' eg "FBRLa", A_wiggle,"FROP.. ' jumps to the sequence 'A_wiggle' ' and ignores the rest of the original sequence, ' use for endless sequences or for joining sequences ' eg "FBRLa", A_wiggle ' jumps to the sequence 'A_wiggle' instead of ending. ' eg ' wiggle DATA "FBRLa", A_wiggle ' will do wiggle forever (or until battery goes flat) ' Note the name is from the name table not a data pointer. ' i - include, use in sequences, acts as a GOSUB ' eg "FBRLi",word A_wiggle,"FROP.. ' does the sequence 'wiggle' and then returns. ' x - eXecute a Basic subroutine, used in sequences ' "x",, ' eg "FBRLx",xleds,n,"FROP... ' where xleds is the name of a constant used to ' control a Branch command in the subroutine Xecute ' and 'n' is the parameter for the routine. ' see Hextor26.BSx ' e - Evaluate, do a test in Basic and branch on the result ' "e",,,,word ' eg "FBRLe",ebump,%01,"=",word avoid,"FFBB... ' where ebump is the name of a constant used to ' control a Branch command in the subroutine doeval. ' In this case if the test was true then the sequence ' avoid would be GOTOed (as with a) ' see Hextor27.BSx ' u - do USrulename in Ultrasonic behaviour program ' "u", ' if the US-rules result in A then the the activity ' will be returned to ' I - Indicators, change LEDs state ' "I", change LED state ' ' A_null - running the Activity Sequencer program with ' A_null in CommonRAM as the activity to do causes ' the program to look in the CommonRAM stack for the ' place to resume sequencing. If there is no ' suspended activity then the program runs pgm0. ' 'Using BOS commands in sequences ' The ascii BOS commands with decimal arguments, ' ie hwvsrmlng when used from a terminal are sent as ' but when used in a ' sequence are written as ' DATA ... ",, ' without the CR, ie the decimal value is stored by DATA as ' a byte, this made it easier to read the sequence. '-------------------------------------------------------------- 'BOS Commands overview - BOS chip firmware '--------------------- 'On reset the pgm prints a msg:- ' "Bug Commander BC x.x - Milford Instruments",cr ' and waits for a serial ascii command, ready prompt is '>'. 'Control of the Behavioural Operating System BOS is by serial ' commands from another processor or a terminal. 'A command may be halted by:- ' raising the 'cmndhalt' pin until the 'busypin' goes low or ' by sending "H" continuously until ">" is received, ' It is not possible to interupt "h","V","v". 'dec arguments must be ended by CR or other non-numeric code ' 'Main Commands:- ' Can be used manually from a terminal. ' Commands ignored if cmndhalt pin is high or if no prompt. ' 'busypin' goes high as soon as the first byte of a command ' is received and should be ignored for further bytes of ' multibyte commands. 'single character:- ' F - Forward one step ' B - Backward one step ' R - Rightturn one step ' L - Leftturn one step ' H - Halt ' S - Sit ' U - Up ' M - step so feet are in Midposition ' N - goto Neutral position, current values held in EEPROM ' K - Kill servo power, ' jumper selectable to exclude gripper, ' power turned on by any movement command ' or by jumping to direct Control. ' Z - Zzzz all servos to sleep ' Q - Quick, legs move in Trapezoid path, ' smooth but can stub toes ' T - Tall, legs move in Rectangular path, ' leg up/down is vertical ' p - pickup Gripper by 1/16 range ' P - Pickup Gripper by 1/4 range ' d - down Gripper by 1/16 range ' D - Down Gripper by 1/4 range ' o - open Gripper by 1/16 range ' O - Open Gripper by 1/4 range ' c - close Gripper by 1/16 range ' C - Close Gripper by 1/4 range ' W - Wait until all servos finish moving, ' only useful after gripper commands ' and direct control ' V - Voice, beep 1KHz for 0.1sec 'one argument:- defaults ' s - speed, update variable Sspeed 4 (0-15) ' r - rideheight update variable legdown 170 down from neutral (0-255) ' m - move update variable swing 40 +- about neutral (0-255) ' l - lift update variable lift 90 up from down position (0-255) ' updates to s,r,m,l are not remembered during power off ' h - halt for time, 1=0.1sec ' BOS deaf to HALT during this time, ' useful for direct control and voice etc ' w - wait until servo is finished moving ' only useful after gripper commands ' and direct control ' individual control of Legs or Body, used for Wave-Gait:- ' <0,1,2,3,4,5,6>, ' <0=body, 1-6=legs>, ' 1f => Leg 1 steps forwards ' 1m => Leg 1 steps to mid position ' 1b => Leg 1 steps backwards ' similarly for Legs 2,3,4,5,6 ' 0f => Body moves forwards, ie all Legs move backwards without steping ' 0m => Body moves to mid position, ie all Legs move to mid position without steping ' 0b => Body moves backwards, ie all Legs move forwards without steping 'two argument:- ' n - new neutral position ' servos 0 - 11, new values stored in BOS eeprom ' if servo >11 then return to main command prompt ' g - gripper lift and grip ' 0 => no change, 255 - relax servo ' (easy to type a 0 for no change ' or wait for 5sec timeout) ' v - voice, beep,Hz/10,ms/10 'Requests - one argument:- ' ?g - arm and grip positions -> ' ?s - Sspeed -> ' ?r - rideheight -> ' ?m - move -> ' ?l - lift -> ' ?n - neutral positions, ' get EEPROM data for neutral position ' for servos 0 - 11 -> 'Low level Direct Control '------------------------ '3 byte:- ' - direct control of servos ' not suitable for human use from terminal, ' byte values and 100ms timeout ' turns on servo power and exits with servo power on ' first byte - control byte (non printing) character (<6) ' second byte - $speed;$servo - high nibble and low nibble respectively ' third byte - argument ' X - any value - ignored ' commands:- ' 0,$speed;$servo,position ' 1,$X;$servo,X ->P return byte P is actual servo position ' 2,$X;$servo,X ->S return byte S is servo status, ' bit1 0=>servo off ' 1=>on, ie being pulsed ' bit0 0=moving to requested position ' 1=at requested position ' 3,X,X ->hiF,then loF two bytes all servo moved status ' bitX=servoX, 1=>finished ' bit15 is set to 1 ' so all finished=$FFFF ' 4,X,X ->hiR,then loR two bytes all servo on/off status ' bitX=servoX, 1=>being pulsed, ie on ' bit15 always 1 ' 5,$X;$servo,X stop pulsing servo 'The servos are refered to by their logical positions, ' '-------- Legs & Logical-Servos -------- ' ' Plan view of Hextor S - Servo(0 - 13) L - Legs(1 - 6) ' S L L S ' ( ) gripper 13 ' | | lift 12 ' L---F---R LEG NUMBERS ' 1,0 | 1 2 | 6,7 1=LF 2=RF ,L - left, R - Right ' 3,2 | 3 4 | 8,9 3=LM 4=RM ,M - mid, F - Front ' 5,4 | 5 6 | 10,11 5=LB 6=RB ,B - Back ' \-------/ ' '-------- Servo values and leg positions ------- ' f - forward m - middle b - backward 'Left Lf=255 Lm=127 Lb=0 'Right Rf=0 Rm=127 Rb=255 ' ' d - Down u - Up 'Left Ld=0 Lu=255 'Right Rd=255 Ru=0 ' '-------- Arm and Gripper positions ------- 'Arm up 255 'Arm down 0 'Gripper open 255 'Gripper closed 0 '============================================================== ' Program Headers - Hxtr0-0 to Hxtr0-7 '============================================================== '>Hxtr0-0.BSx debug "prog0" '============================================================== '{$stamp BS2sx,Hxtr0-1,Hxtr0-2,Hxtr0-3,Hxtr0-4,Hxtr0-5,Hxtr0-6,Hxtr0-7} 'Unfortunately that was a long line, ask Parallax. '============================================================== 'Hxtr0-0.BSx - main 'Hxtr0-1.BSx - Activity sequencer 'Hxtr0-2.BSx - US Behaviour 'Hxtr0-3.BSx - Direct Control 'Hxtr0-4.BSx - Prog4 'Hxtr0-5.BSx - Prog5 'Hxtr0-6.BSx - Prog6 'Hxtr0-7.BSx - Utils- LCD menu and IR remote 'Hxtr0-Doc.BSx - Meta Commands and Program Headers '============================================================== 'Parallax bug fix for Windoz Editor ver1.1 'must have a debug stmnt as first executable stmnt in page0 'otherwise editor will not always load some higher pages. 'debug cls '============================================================== 'New '--- 'Initialisation of the CommonRAM stack pointer at init1 'test of CommonRam 0 at init ' 'The menu system now no longer responds to IR commands, all IR 'control is in Prog7 ' 'Required knowledge: ' 'Meta command: 'BOS Commands: 'Common RAM: 'Constants: lcdoptions not used now 'Variables: dmbase,btnc now menc 'Routine: set1, set2 renamed as Qs4r170, Ts0r200 'Subroutine:default irin in irget was 15 now set to 0 'Labels: 'Sequence: A_setting1, A_setting2 now A_Qs4r170, A_Ts0r200 'usRules: 'Behaviour: 'LCD text: all messages altered '============================================================== 'Experiment with '============================================================== '>Hxtr0-1.BSx '============================================================== '{$stamp BS2Sx} debug "prog1" '============================================================== 'Hxtr0-0.BSx - main 'Hxtr0-1.BSx - Activity sequencer 'Hxtr0-2.BSx - US Behaviour 'Hxtr0-3.BSx - Direct Control 'Hxtr0-4.BSx - Prog4 'Hxtr0-5.BSx - Prog5 'Hxtr0-6.BSx - Prog6 'Hxtr0-7.BSx - Utils- LCD menu and IR remote 'Hxtr0-Doc.BSx - Meta Commands and Program Headers '============================================================== 'Sorry this program is getting quite complex and several new 'features have been added at once. They were originaly added 'one at a time in the Page0 program. However it was felt 'neccessary to add on the LCD Pendant and this took up room in 'Page0, leaving no room there for these features. 'It is not recommended that this program be altered, rather use 'the sequencing facilities to Jump to the User programs and 'then return back to the original sequence here. Or use the 'eXecute and Evaluate meta commands and add to the subroutines. ' 'New '--- 'In this set of programs a Sequence of actions previously 'called a Sequence will be called an Activity. ' 'To facilitate running an Activity in the Sequencer Program two 'entries will be made in Common Ram indicating the Activity to 'do and the program to return to when it is finished. ' 'To make it easier to keep track of what a name refers to, in 'other programs, Activities will be prefixed by 'A_'. 'Because labels can't be used across program boundaries 'activities will be refered to by name-code, eg A_wiggle1 con 2 'Previously the actual value of the DATA pointer was used which 'in Hextor18.BSx was changed from a byte to a word variable, 'this meant that everytime an activity sequence was refered to 'the WORD command had to be used, here since we are using the 'code value of a name we will revert back to a byte value. 'There isn't really enough space in a 2k program page for more 'then 256 Activities, so a byte is ample. 'Internally these name-values will be *2 and will point to DATA 'locations holding the DATA pointer value of the actual 'activities. (*2 because of storing a word) ' 'Start off by setting Sptr to required Activity and waiting 'until ir is idle. 'Check for usercmnd each time round loop in tellBOSx whilst 'waiting. 'Return at end of dosequence is now RUN calling program in retS 'If Activity is A_null then check if anything is on the stack 'from a previous run, if not run IR pgm. ' '(Clear? good, because next is inter-program communication by 'the vagrancy field of sub-space mesons. OK!) ' 'irentry is used to avoid having to wait for the ir to get to 0 ' 'usercmnd tests for Pendant buttons and ir cmnds other than 0, 'the idle cmnd, and irentry, the value on entry to the pgm. 'If a valid cmnd is received then a goto is made to RUN0 to get 'back to pgm0 to process the cmnd. ' '============================================================== 'The following Section covers the new features in this program. 'earliest at top. '-------------------------------------------------------------- 'Modification of the last three rules of uscorner to use the 'Action sequences F5,R5,L5, similar to ushello, the action is 'faster since the ultrasonic sensor is not tested each step. '-------------------------------------------------------------- 'Dosequence modified to allow h,v,w commands. 'Two voice sequences added in initialisation at init1. 'The first, a chirp, is used instead of a pause whilst waiting 'for the infra-red circuitry to settle and the second, a beep, 'to indicate ready. 'New '--- 'BOS Commands: V, h, v, w 'Subroutine: dosequence modified 'Sequence: chirp1, beep2 '-------------------------------------------------------------- 'Introduction of Wave Gait commands 'renamed tellBOSx routines to better indicate type of message 'New '--- 'BOS Commands: 0,1,2,3,4,5,6,f,m,b 'Subroutine: tellBOScc ' dosequence modified to handle wave gait cmnds ' some dosequence labels renamed ' renamed tellBOS as tellBOSc ' renamed tellBOS1d as tellBOScd ' renamed tellBOS2d as tellBOScdd ' renamed tellBOS3 as tellBOSccc 'Sequence: wiggle3 modified with new commands '-------------------------------------------------------------- 'Introduction of a Meta Command 'I' to control the LEDs 'the cmnd 'I' (Indicators) gosubs to leds written previously 'New '--- 'Meta command: 'I' 'Subroutine: dosequence modified for 'I' 'Sequence: Iflash '-------------------------------------------------------------- 'Introduction of a Meta Command to run Basic subroutines. ' 'If a constant is setup with a name similar to an underscored 'subroutine label then the sequences will be easier to read. 'eg xleds con 0 and x_leds: 'dosequence modified to allow x 'New subroutine leds, led state=arg1 'Argument to leds, 0 - both off ' 1 - right on ' 2 - left on ' 3 - both on 'eg x - eXecute a Basic subroutine, used in sequences ' "x",, ' eg "FBRLx",xleds,n,"FROP... ' where xleds is the name of a constant used to ' control a Branch command in the subroutine Xecute ' and 'n' is the parameter for the routine. 'New '--- 'Meta command: 'x' 'Constants: xleds 'Routine: x_leds 'Subroutine: xecute leds ' dosequence modified for 'x' and xe: 'Sequence: wiggle1 modified with x,xleds '-------------------------- 'Experiment with Xecute '-------------------------------------------------------------- 'Introduction of a Meta Command 'e' to run a Basic test and 'Goto another sequence label on the result of the test. 'If a constant is setup with a name similar to an underscored 'subroutine label then the sequences will be easier to read. 'eg tbump con 0 and t_bump: 'dosequence modified to allow 'e'. 'eresult is a var byte which should receive the result of a 'test and tested in dosequence 'ecode is a var byte which holds the test character <,=,> ' "e",,,,word ' eg "FBRLe",ebump,%01,"=",word avoid,"FFBB... ' where ebump is the name of a constant used to ' control a Branch command in the subroutine doeval. ' In this case if the test was true then the sequence ' avoid would be GOTOed (as with 'a') 'New '--- 'Meta command: e 'Constants: ebump 'Variables: ecode eresult 'Routine: e_bump 'Subroutine: eval ' dosequence modified for e and doe: '---------------------------- 'Experiment with tests in sequences '-------------------------------------------------------------- 'Introduction of a Meta Command "u", which allows the 'Activity Sequencer to initiate control by the US behaviour 'program or to call US rule-sets as subroutines, to behave as a 'subroutine the rule-set must have "A" as its default action or 'as a rule action. ' 'Meta command: u 'Constants: tpace tcccpace 'Variables: Aname USname irentry 'Routine: Sgo & Sinc altered to use activity byte value ' lastS RUN0 USgo 'Subroutine: Aname2Sptr ' in irget default irin was 15 now =0 ' pushword,popword,readword, ' renamed push_arg,pop_arg,read_arg 'Labels: noir in irget renamed irret 'Sequence: A_setting1, A_setting2 now A_Qs4r170, A_Ts0r200 ' A_L3 A_R3 A_L2 A_R2 '============== end New Features Section ====================== '>Hxtr0-2.BSx '============================================================== '{$stamp BS2Sx} debug "prog2" '============================================================== 'Hxtr0-0.BSx - main 'Hxtr0-1.BSx - Activity sequencer 'Hxtr0-2.BSx - US Behaviour 'Hxtr0-3.BSx - Direct Control 'Hxtr0-4.BSx - Prog4 'Hxtr0-5.BSx - Prog5 'Hxtr0-6.BSx - Prog6 'Hxtr0-7.BSx - Utils- LCD menu and IR remote 'Hxtr0-Doc.BSx - Meta Commands and Program Headers '============================================================== 'New '--- 'To facilitate running a set of US-behaviour rules from other 'programs an entry is made in Common Ram indicating the rules 'to use. ' 'When an Activity is to be run the yawn variables and this 'program number are saved in Common RAM and the Sequencer 'program is run. ' 'To make it easier to keep track of what a name refers to, in 'other programs, US-Behaviour rules will be prefixed by 'US_'. 'Because labels can't be used across program boundaries 'activities will be refered to outside this program 'by name-code, eg US_hello con 2, internally these name-values 'will be *2 and will point to DATA locations holding the DATA 'pointer value of the actual activities. '(*2 because of storing a word) ' 'Start off by setting usrules to the required set. 'Check for IR was at start of rule-set, now moved to start of 'each rule so response is faster. 'Check for IR before reading each rule and each time round loop 'in tellBOSx whilst waiting. 'If valid IR received then run 0 to see what to do. 'If the default action for a set of rules is "A" or the outcome 'of a rule is "A" then the pgm puts A_null as the Activity 'desired in CommonRam 1 and runs the Activity sequencer pgm1. 'This allows the Activity sequencer to use US Behaviour rules 'as subroutines. ' '(Clear? see note in program 1 re sub-space mesons.) ' 'irentry is used to avoid having to wait for the ir to get to 0 ' 'irget rewritten and included in usercmnd. 'usercmnd tests for a ir cmnds other than 0, the idle cmnd, and 'irentry, the value on entry to the pgm as well as the buttons. 'If a valid cmnd is received then a goto is made to RUN0 to get 'back to pgm0 to process the cmnd. ' 'usercmnd is called in tellBOSc ' 'Required knowledge: ' 'Meta command: A 'BOS Commands: 'Common RAM: 'Constants: 'Variables: Sptr redefined and renamed as Dptr ' Aprog Activity ythresh yvar lastname yindx ' usyawn0 and usyawn1 now high/low nibbles of usyawn ' yvar renamed yindx 'Routine: RUN0 RUNA RUNX RUNact 'Subroutine:Sact modified to runActivity sequencer ' usrules2Rptr irtest 'Labels: usmove renamed uscmnd, usm renamed usmove ' sact renamed RUNact 'Sequence: A_setting1, A_setting2 now A_Qs4r170, A_Ts0r200 'usRules: 'Behaviour: '============================================================== 'Experiment with '============================================================== '>Hxtr0-3.BSx '============================================================== '{$stamp BS2Sx} debug "prog3" '============================================================== 'Hxtr0-0.BSx - main 'Hxtr0-1.BSx - Activity sequencer 'Hxtr0-2.BSx - US Behaviour 'Hxtr0-3.BSx - Direct Control 'Hxtr0-4.BSx - Prog4 'Hxtr0-5.BSx - Prog5 'Hxtr0-6.BSx - Prog6 'Hxtr0-7.BSx - Utils- LCD menu and IR remote 'Hxtr0-Doc.BSx - Meta Commands and Program Headers '============================================================== 'New '--- 'irentry is used to avoid having to wait for the ir to get to 0 ' 'irget rewritten and renamed as irtest. 'irtest tests for a ir cmnds other than 0, the idle cmnd, and 'irentry, the value on entry to the pgm. If a valid cmnd is 'received then a goto is made to RUN0 to get back to pgm0 to 'process the ir cmnd. ' 'irtest is called in tellBOSccc ' 'Required knowledge: ' 'Meta command: 'BOS Commands: 'Common RAM: 'Constants: tcccpace 'Variables: irentry 'Routine: 'Subroutine: irtest 'Labels: 'Sequence: 'usRules: 'Behaviour: '============================================================== 'Experiment with '============================================================== '>Hxtr0-4.BSx '============================================================== '{$stamp BS2Sx} debug "prog4" '============================================================== 'Hxtr0-0.BSx - main 'Hxtr0-1.BSx - Activity sequencer 'Hxtr0-2.BSx - US Behaviour 'Hxtr0-3.BSx - Direct Control 'Hxtr0-4.BSx - Prog4 'Hxtr0-5.BSx - Prog5 'Hxtr0-6.BSx - Prog6 'Hxtr0-7.BSx - Utils- LCD menu and IR remote 'Hxtr0-Doc.BSx - Meta Commands and Program Headers '============================================================== 'Put your program here, when finished do RUN 0 RUN 0 'so we get back to program 0 '>Hxtr0-5.BSx '============================================================== '{$stamp BS2Sx} debug "prog5" '============================================================== 'Hxtr0-0.BSx - main 'Hxtr0-1.BSx - Activity sequencer 'Hxtr0-2.BSx - US Behaviour 'Hxtr0-3.BSx - Direct Control 'Hxtr0-4.BSx - Prog4 'Hxtr0-5.BSx - Prog5 'Hxtr0-6.BSx - Prog6 'Hxtr0-7.BSx - Utils- LCD menu and IR remote 'Hxtr0-Doc.BSx - Meta Commands and Program Headers '============================================================== 'Put your program here, when finished do RUN 0 RUN 0 'so we get back to program 0 '>Hxtr0-6.BSx '============================================================== '{$stamp BS2Sx} debug "prog6" '============================================================== 'Hxtr0-0.BSx - main 'Hxtr0-1.BSx - Activity sequencer 'Hxtr0-2.BSx - US Behaviour 'Hxtr0-3.BSx - Direct Control 'Hxtr0-4.BSx - Prog4 'Hxtr0-5.BSx - Prog5 'Hxtr0-6.BSx - Prog6 'Hxtr0-7.BSx - Utils- LCD menu and IR remote 'Hxtr0-Doc.BSx - Meta Commands and Program Headers '============================================================== 'Put your program here, when finished do RUN 0 RUN 0 'so we get back to program 0 '>Hxtr0-7.BSx '============================================================== '{$stamp BS2Sx} debug "prog7" '============================================================== 'Hxtr0-0.BSx - main 'Hxtr0-1.BSx - Activity sequencer 'Hxtr0-2.BSx - US Behaviour 'Hxtr0-3.BSx - Direct Control 'Hxtr0-4.BSx - Prog4 'Hxtr0-5.BSx - Prog5 'Hxtr0-6.BSx - Prog6 'Hxtr0-7.BSx - Utils- LCD menu and IR remote 'Hxtr0-Doc.BSx - Meta Commands and Program Headers '============================================================== 'New '--- 'Introduces two routines KlcdCon and KirCon ' 'KlcdCon - allows direct control of Hextor using the Pendant 'LCD and buttons. Only the BOS commands FBRLSUMKPDOCNQT. ' 'KirCon - allows direct control of Hextor using an IR remote 'control. ' 'Both of these are called from the Menu options of Prog0 'IRremote - trained on keys 1,2,3,4,5,6,7,8 'The trained keys are numbered from 1, 'but in the program the commands and command pages are numbered 'from 0 'on powerup cmndpage=0 'pages are indicated by the two LEDs, red,green = 00,01,10,11 ' ' cmnd cmndpage=0 cmndpage=1 cmndpage=2 cmndpage=3 'key1 0 Forward Sit Grip Pick RUN0 * 'key2 1 Backward Up Grip Down 'key3 2 Rightturn Midd Grip Open 'key4 3 Leftturn Kill Grip Close uswander ' ' LEDs 'key5 00 cmndpage=0 'key6 01 cmndpage=1 'key7 10 cmndpage=2 'key8 11 cmndpage=3 '==============================================================