GUI (CMM2)

Compatible with:
DOS Maximite CMM MM150 MM170 MM+ MMX Picromite ArmiteL4 Armite F4 ArmiteH7 Picomite CMM2

Syntax:
GUI xxx

Description:

When using this with the Micromite Plus the functionality is tightly integrated with the LCD screen and Touch I/F. However, we have neither available on the CMM2 so the cursor control and 'beep' have been  implemented  as callbacks from the firmware to user supplied Basic subroutines. GUI functionality should be exactly the same as the MM+ with the exception that the PAGE command is replaced with GUI PAGE.

See the GUI page for details on the individual commands.

Two Basic routines are required for full functionality

Function MM.CURSOR and subroutine MM.BEEP

MM.BEEP takes a single parameter which is the time in microseconds that the beep should last. The subroutine pro-forma is

SUB mm.beep beeptime AS INTEGER

and can be implemented as:

SUB mm.beep beeptime AS INTEGER
 IF beeptime AND MM.INFO(sound)="OFF" THEN PLAY TONE 600,600,beeptime
END SUB

The Function MM.CURSOR is more complicated

FUNCTION MM.CURSOR( request AS INTEGER) AS INTEGER

There are 6 requests that it needs to satisfy:

Request 1: Update the Basic programs values of X-coordinate, Y-coordinate and activation (e.g. keypress, or mouse button), if applicable any sprite used to display a cursor must be hidden when receiving this request. Finally this request should return the status of the activation (1=active e.g. mouse button pressed, 0=inactive)

Request 2: Return the current value of the X-coordinate

Request 3: Return the current value of the Y-coordinate

Request 4: Return the current value of the activation (1=active e.g. mouse button pressed, 0=inactive)

Request 5: Show any sprite used for a cursor at the current coordinates X, Y

Request 6: Update the Basic programs values of X-coordinate, Y-coordinate and activation (e.g. keypress, or mouse button), Move any sprite to the new coordinates, Return the current value of the activation (1=active e.g. mouse button pressed, 0=inactive)

My version using the HobbyTronics USB mouse I/F as in the video is as follows:

SUB initmouse
 I2C OPEN 100,1000
 I2C WRITE 41,0,3,20,INT(MM.HRES \ 256),INT(MM.HRES MOD 256)
 I2C WRITE 41,0,3,22,INT(MM.VRES \ 256),INT(MM.VRES MOD 256)
 I2C WRITE 41,0,3,24,INT(MM.HRES \ 512),INT((MM.HRES\2) MOD 256)
 I2C WRITE 41,0,3,26,INT(MM.VRES \ 512),INT((MM.VRES\2) MOD 256)
 I2C WRITE 41,0,2,28,10
END SUB
 '
FUNCTION MM.CURSOR( t AS INTEGER) AS INTEGER
 MM.CURSOR=-1
 IF t=1 THEN
   readtouch
   MM.CURSOR=lb
   IF SPRITE(x,1)<>10000 THEN SPRITE HIDE 1
 ELSEIF t=2 THEN
   IF lb THEN MM.CURSOR=x
 ELSEIF t=3 THEN
   IF lb THEN MM.CURSOR=y
 ELSEIF t=4 THEN
   MM.CURSOR=lb
 ELSEIF t=5 THEN
   SPRITE SHOW 1,x,y,1
 ELSE
   readtouch
   MM.CURSOR=lb
   SPRITE SHOW 1,x,y,1
 ENDIF
END FUNCTION
 '
SUB readtouch
 LOCAL s$
 DO
   I2C WRITE 41,1,1,0
   I2C READ 41,0,10,s$
   x=STR2BIN(UINT16,LEFT$(s$,2),big)
   y=STR2BIN(UINT16,MID$(s$,3,2),big)
   lb=ASC(MID$(s$,5,1))
 LOOP UNTIL x>=0 AND x<MM.HRES AND y>=0 AND y< MM.VRES
END SUB
 '
SUB mm.beep beeptime AS INTEGER
 IF beeptime AND MM.INFO(sound)="OFF" THEN PLAY TONE 600,600,beeptime
END SUB

Full example code based on Geoff's MM+ example

 '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
 ' Demonstration program for the Micromite+
 ' It does not do anything useful except demo the various controls
 '
 ' Geoff Graham, October 2015
 '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
 OPTION EXPLICIT
 DIM ledsY
 'mode 10
 OPTION CONSOLE SERIAL
 COLOUR RGB(WHITE), RGB(BLACK)
 ' reference numbers for the controls are defined as constants
 CONST c_head = 1, c_pmp = 2, sw_pmp = 3, c_flow = 4, tb_flow = 5
 CONST led_run = 6, led_alarm = 7
 CONST frm_alarm = 20, nbr_hi = 21, nbr_lo = 22, pb_test =23
 CONST c_hi = 24, c_lo = 25
 CONST frm_pump = 30, r_econ = 31, r_norm = 32, r_hi = 33
 CONST frm_log = 40, cb_enabled = 41, c_fname = 42, tb_fname = 43
 CONST c_log = 44, cb_flow = 45, cb_pwr = 46, cb_warn = 47
 CONST cb_alarm = 48, c_bright = 49, sb_bright = 50
 ' now draw the "Pump Control" display
 'CLS
 DIM INTEGER x, y, lb, rb, sb, xs, ys, cs, ss
 initmouse
 SPRITE LOAD "mouse.spr",1
 GUI INTERRUPT TouchDown, TouchUp
 ' display the heading
 FONT 2,2 : GUI CAPTION c_head, "Pump Control", 10, 0
 FONT 3 : GUI CAPTION c_pmp, "Pump", 20, 60, , RGB(BROWN)
 ' now, define and display the controls
 ' first
 GUI SWITCH sw_pmp, "ON|OFF", 20, 90, 150, 50, RGB(WHITE),RGB(BROWN)
 CTRLVAL(sw_pmp) = 1
 ' the flow rate display box
 FONT 3 : GUI CAPTION c_flow, "Flow Rate", 20, 170,, RGB(BROWN),0
 FONT 4 : GUI DISPLAYBOX tb_flow, 20, 200, 150, 45
 CTRLVAL(tb_flow) = "20.1"
 ' the radio buttons and their frame
 FONT 3 : GUI FRAME frm_pump, "Power", 20, 290, 170, 163,RGB(200,20,255)
 GUI RADIO r_econ, "Economy", 40, 318, 15, RGB(230, 230, 255)
 GUI RADIO r_norm, "Normal", 40, 364
 GUI RADIO r_hi, "High", 40, 408
 CTRLVAL(r_norm) = 1 ' start with the "normal" button selected
 ' the alarm frame with two number boxes and a push button switch
 FONT 3 : GUI FRAME frm_alarm, "Alarm", 220, 220, 200, 233,RGB(GREEN)
 GUI CAPTION c_hi, "High:", 232, 260, LT, RGB(YELLOW)
 GUI NUMBERBOX nbr_hi, 318,MM.INFO(VPos)-6,90,MM.INFO(FontHeight)+12,RGB(YELLOW),RGB(64,64,64)
 GUI CAPTION c_lo, "Low:", 232, 325, LT, RGB(YELLOW),0
 GUI NUMBERBOX nbr_lo, 318,MM.INFO(VPos)-6,90,MM.INFO(FontHeight)+12,RGB(YELLOW),RGB(64,64,64)
 GUI BUTTON pb_test, "TEST", 257, 383, 130, 40,RGB(YELLOW), RGB(RED)
 CTRLVAL(nbr_lo) = 15.7 : CTRLVAL(nbr_hi) = 35.5
 ' draw the two LEDs
 CONST ledsX = 240, coff = 50 ' define their position
 ledsY = 90 : GUI LED led_run, "Running", ledsX, ledsY, 15, RGB(GREEN)
 ledsY = ledsY+49 : GUI LED led_alarm, "Alarm", ledsX, ledsY, 15, RGB(RED)
 CTRLVAL(led_run) = 1 ' the switch defaults to on so set the LED on
 ' the logging frame with check boxes and a text box
 COLOUR RGB(CYAN), 0
 GUI FRAME frm_log, "Log File", 450, 20, 330, 355, RGB(GREEN)
 GUI CHECKBOX cb_enabled, "Logging Enabled", 470, 50, 30, RGB(CYAN)
 GUI CAPTION c_fname, "File Name", 470, 105
 GUI TEXTBOX tb_fname, 470, 135, 290, 40, RGB(CYAN), RGB(64,64,64)
 GUI CAPTION c_log, "Record:", 470, 205, , RGB(CYAN), 0
 GUI CHECKBOX cb_flow, "Flow Rate", 500, 245, 25
 GUI CHECKBOX cb_alarm, "Alarms", 500, 285, 25
 GUI CHECKBOX cb_warn, "Warnings", 500, 325, 25
 CTRLVAL(cb_enabled) = 1
 CTRLVAL(tb_fname) = "LOGFILE.TXT"
 ' define and display the spinbox for controlling the backlight
 GUI CAPTION c_bright, "Backlight", 442, 415,,RGB(200,200,255),0
 GUI SPINBOX sb_bright, MM.INFO(HPos) + 8, 400, 200, 50,,,10, 10, 100
 CTRLVAL(sb_bright) = 50
 ' All the controls have been defined and displayed. At this point
 ' the program could do some real work but because this is just a
 ' demo there is nothing to do. So it just sits in a loop.
 DO
 LOOP
 ' the interrupt routine for touch down
 ' using a select case command it has a different process for each
 ' control
SUB TouchDown
 LOCAL INTEGER mbox
 '  print "down"
 SELECT CASE TOUCH(REF) ' find out the control touched
   CASE cb_enabled ' the enable check box
     IF CTRLVAL(cb_enabled) THEN
       GUI RESTORE c_fname, tb_fname, c_log, cb_flow, cb_alarm, cb_warn
     ELSE
       mbox=MSGBOX("Are you sure?", "YES","CANCEL")
       '      print mbox
       IF mbox=1 THEN
         GUI DISABLE c_fname, tb_fname, c_log, cb_flow, cb_alarm, cb_warn
       ELSE
         CTRLVAL(cb_enabled)=1
       ENDIF
     ENDIF
   CASE sb_bright ' the brightness spin box
     '    BackLight CtrlVal(sb_bright)
   CASE sw_pmp ' the pump on/off switch
     CTRLVAL(led_run) = CTRLVAL(sw_pmp)
     CTRLVAL(tb_flow) = STR$(CTRLVAL(sw_pmp) * 20.1)
     CTRLVAL(r_norm) = 1
   CASE pb_test ' the alarm test button
     CTRLVAL(led_alarm) = 1
     GUI BEEP 250
   CASE r_econ ' the economy radio button
     CTRLVAL(tb_flow) = STR$(CTRLVAL(sw_pmp) * 18.3)
   CASE r_norm ' the normal radio button
     CTRLVAL(tb_flow) = STR$(CTRLVAL(sw_pmp) * 20.1)
   CASE r_hi ' the high radio button
     CTRLVAL(tb_flow) = STR$(CTRLVAL(sw_pmp) * 23.7)
 END SELECT
END SUB
 ' interrupt routine when the touch is removed
SUB TouchUp
 SELECT CASE TOUCH(LASTREF) ' use the last reference
   CASE pb_test ' was it the test button
     CTRLVAL(led_alarm) = 0 ' turn off the LED
 END SELECT
END SUB
SUB initmouse
 I2C OPEN 100,1000
 I2C WRITE 41,0,3,20,INT(MM.HRES \ 256),INT(MM.HRES MOD 256)
 I2C WRITE 41,0,3,22,INT(MM.VRES \ 256),INT(MM.VRES MOD 256)
 I2C WRITE 41,0,3,24,INT(MM.HRES \ 512),INT((MM.HRES\2) MOD 256)
 I2C WRITE 41,0,3,26,INT(MM.VRES \ 512),INT((MM.VRES\2) MOD 256)
 I2C WRITE 41,0,2,28,10
END SUB
 '
FUNCTION MM.CURSOR( t AS INTEGER) AS INTEGER
 MM.CURSOR=-1
 IF t=1 THEN
   readtouch
   MM.CURSOR=lb
   IF SPRITE(x,1)<>10000 THEN SPRITE HIDE 1
 ELSEIF t=2 THEN
   IF lb THEN MM.CURSOR=x
 ELSEIF t=3 THEN
   IF lb THEN MM.CURSOR=y
 ELSEIF t=4 THEN
   MM.CURSOR=lb
 ELSEIF t=5 THEN
   SPRITE SHOW 1,x,y,1
 ELSE
   readtouch
   MM.CURSOR=lb
   SPRITE SHOW 1,x,y,1
 ENDIF
END FUNCTION
 '
SUB readtouch
 LOCAL s$
 DO
   I2C WRITE 41,1,1,0
   I2C READ 41,0,10,s$
   x=STR2BIN(UINT16,LEFT$(s$,2),big)
   y=STR2BIN(UINT16,MID$(s$,3,2),big)
   lb=ASC(MID$(s$,5,1))
 LOOP UNTIL x>=0 AND x<MM.HRES AND y>=0 AND y< MM.VRES
END SUB
 '
SUB mm.beep beeptime AS INTEGER
 IF beeptime AND MM.INFO(sound)="OFF" THEN PLAY TONE 600,600,beeptime
END SUB

The FUNCTION MM.CURSOR is called by the firmware and will override any normal interrupts. 
This means you need to ensure that the variables accessed by the function are valid at the end of every line of code.

Code run as part of MM.CURSOR is not interrupted. However, code run outside it can have a MM.CURSOR call actioned at any time between statements (including code in MMBasic interrupts). That is why in the above example readtouch is called from within MM.CURSOR.

In the keyboard version X, Y and LB are always valid so there is no issue.

Basically the rule is that X,Y and LB must always be valid at the end of any single Basic statement except during a single call to the MM.CURSOR routine.

The loop in readtouch was because sometimes the Hobbytronic I2C calls gave invalid data so we had to filter them out.

 

 

Last edited: 10 October, 2020