mirror of
https://github.com/clockworkpi/PicoCalc.git
synced 2026-03-21 11:32:38 +01:00
add pico_multi_booter code
This commit is contained in:
447
Code/pico_multi_booter/picomite/mouse.c
Normal file
447
Code/pico_multi_booter/picomite/mouse.c
Normal file
@@ -0,0 +1,447 @@
|
||||
/***********************************************************************************************************************
|
||||
MMBasic
|
||||
|
||||
mouse.c
|
||||
|
||||
Handles the a few miscellaneous functions for the MX470 version.
|
||||
|
||||
Copyright 2016 - 2021 Peter Mather. All Rights Reserved.
|
||||
|
||||
This file and modified versions of this file are supplied to specific individuals or organisations under the following
|
||||
provisions:
|
||||
|
||||
- This file, or any files that comprise the MMBasic source (modified or not), may not be distributed or copied to any other
|
||||
person or organisation without written permission.
|
||||
|
||||
- Object files (.o and .hex files) generated using this file (modified or not) may not be distributed or copied to any other
|
||||
person or organisation without written permission.
|
||||
|
||||
- This file is provided 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.
|
||||
|
||||
************************************************************************************************************************/
|
||||
|
||||
|
||||
#include "MMBasic_Includes.h"
|
||||
#include "Hardware_Includes.h"
|
||||
char *mouse0Interruptc=NULL;
|
||||
volatile int mouse0foundc=0;
|
||||
bool mouse0=false;
|
||||
int mouseID=0;
|
||||
volatile int readreturn=-1;
|
||||
static volatile int PS2State, KCount, KParity, runmode=0;
|
||||
bool mouseupdated=false;
|
||||
volatile unsigned char Code = 0;
|
||||
int MOUSE_CLOCK,MOUSE_DATA;
|
||||
volatile short mouse[4];
|
||||
volatile unsigned int bno=0;
|
||||
volatile unsigned char LastCode = 0;
|
||||
void setstream(void);
|
||||
void mouse_init();
|
||||
static bool sendCommand(int cmd);
|
||||
int ReadReturn(int timeout);
|
||||
// definition of the mouse PS/2 state machine
|
||||
#define PS2START 0
|
||||
#define PS2BIT 1
|
||||
#define PS2PARITY 2
|
||||
#define PS2STOP 3
|
||||
#define PS2ERROR 9
|
||||
#define MDATA 1
|
||||
#define MCLK 0
|
||||
#define HIGH 1
|
||||
#define LOW 0
|
||||
#define MouseTimeout 500
|
||||
void MouseKBDIntEnable(int status){
|
||||
if (status)
|
||||
{
|
||||
PinSetBit(MOUSE_CLOCK, TRISSET); // same for data
|
||||
PinSetBit(MOUSE_DATA, TRISSET); // data low
|
||||
if (!CallBackEnabled)
|
||||
{
|
||||
CallBackEnabled = 64;
|
||||
gpio_set_irq_enabled_with_callback(PinDef[MOUSE_CLOCK].GPno, GPIO_IRQ_EDGE_FALL, true, &gpio_callback);
|
||||
}
|
||||
else
|
||||
{
|
||||
CallBackEnabled |= 64;
|
||||
gpio_set_irq_enabled(PinDef[MOUSE_CLOCK].GPno, GPIO_IRQ_EDGE_FALL, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PinSetBit(MOUSE_CLOCK, TRISSET); // same for data
|
||||
PinSetBit(MOUSE_DATA, TRISSET); // data low
|
||||
if (CallBackEnabled == 64){
|
||||
CallBackEnabled=0;
|
||||
gpio_set_irq_enabled_with_callback(PinDef[MOUSE_CLOCK].GPno, GPIO_IRQ_EDGE_FALL, false, &gpio_callback);
|
||||
} else {
|
||||
gpio_set_irq_enabled(PinDef[MOUSE_CLOCK].GPno, GPIO_IRQ_EDGE_FALL, false);
|
||||
CallBackEnabled &= (~64);
|
||||
}
|
||||
PS2State = PS2START;
|
||||
}
|
||||
}
|
||||
void mousecheck(int n){
|
||||
if(MouseTimer < MouseTimeout){
|
||||
routinechecks();
|
||||
return;
|
||||
}
|
||||
MouseKBDIntEnable(0); // disable interrupt in case called from within CNInterrupt()
|
||||
runmode=0;
|
||||
mouse0=false;
|
||||
ExtCfg(MOUSE_CLOCK, EXT_NOT_CONFIG, 0);
|
||||
ExtCfg(MOUSE_DATA, EXT_NOT_CONFIG, 0);
|
||||
PS2State = PS2START;
|
||||
error("Mouse timeout % ",n);
|
||||
}
|
||||
/***************************************************************************************************
|
||||
initMouse
|
||||
Initialise the mouse routine.
|
||||
****************************************************************************************************/
|
||||
void initMouse0(int sensitivity) {
|
||||
if(!(MOUSE_CLOCK || Option.MOUSE_CLOCK))return;
|
||||
if(!Option.MOUSE_CLOCK){
|
||||
ExtCfg(MOUSE_CLOCK, EXT_COM_RESERVED, 0);
|
||||
ExtCfg(MOUSE_DATA, EXT_COM_RESERVED, 0);
|
||||
} else {
|
||||
MOUSE_CLOCK=Option.MOUSE_CLOCK;
|
||||
MOUSE_DATA=Option.MOUSE_DATA;
|
||||
}
|
||||
gpio_init(PinDef[MOUSE_CLOCK].GPno);
|
||||
gpio_set_pulls(PinDef[MOUSE_CLOCK].GPno,true,false);
|
||||
gpio_set_dir(PinDef[MOUSE_CLOCK].GPno, GPIO_IN);
|
||||
gpio_set_input_hysteresis_enabled(PinDef[MOUSE_CLOCK].GPno,true);
|
||||
gpio_init(PinDef[MOUSE_DATA].GPno);
|
||||
gpio_set_pulls(PinDef[MOUSE_DATA].GPno,true,false);
|
||||
gpio_set_dir(PinDef[MOUSE_DATA].GPno, GPIO_IN);
|
||||
gpio_set_drive_strength(PinDef[MOUSE_DATA].GPno,GPIO_DRIVE_STRENGTH_8MA);
|
||||
gpio_set_drive_strength(PinDef[MOUSE_CLOCK].GPno,GPIO_DRIVE_STRENGTH_8MA);
|
||||
int maxW=HRes;
|
||||
int maxH=VRes;
|
||||
mouseID=0;
|
||||
runmode=0;
|
||||
MouseKBDIntEnable(0); // disable interrupt in case called from within CNInterrupt()
|
||||
// enable pullups on the clock and data lines.
|
||||
// This stops them from floating and generating random chars when no mouse is attached
|
||||
|
||||
// reserve the mouse pins
|
||||
if(!sendCommand(0xFF))return; // Reset
|
||||
ReadReturn(500);
|
||||
sendCommand(0xF5); // Turn off streaming
|
||||
ReadReturn(5);
|
||||
if(sensitivity){
|
||||
int scaling;
|
||||
if(sensitivity>4){
|
||||
scaling=1;
|
||||
sensitivity-=4;
|
||||
}
|
||||
sensitivity--;
|
||||
if(scaling){
|
||||
sendCommand(0xE7); //
|
||||
ReadReturn(5);
|
||||
}
|
||||
sendCommand(0xE8);
|
||||
ReadReturn(5);
|
||||
sendCommand(sensitivity);
|
||||
ReadReturn(5);
|
||||
}
|
||||
sendCommand(0xF3); //
|
||||
ReadReturn(5);
|
||||
sendCommand(200); //
|
||||
ReadReturn(5);
|
||||
sendCommand(0xF3); //
|
||||
ReadReturn(5);
|
||||
sendCommand(100); //
|
||||
ReadReturn(5);
|
||||
sendCommand(0xF3); //
|
||||
ReadReturn(5);
|
||||
sendCommand(80); //
|
||||
ReadReturn(5);
|
||||
sendCommand(0xF2); //
|
||||
mouseID=ReadReturn(10);
|
||||
sendCommand(0xF3); //
|
||||
ReadReturn(5);
|
||||
sendCommand(200); //
|
||||
ReadReturn(5);
|
||||
sendCommand(0xF4); // Turn on streaming
|
||||
ReadReturn(5);
|
||||
|
||||
// setup Change Notification interrupt
|
||||
PS2State = PS2START;
|
||||
memset((struct s_nunstruct *)&nunstruct[2],0,sizeof(struct s_nunstruct));
|
||||
nunstruct[2].classic[0]=mouseID;
|
||||
nunstruct[2].type=0; //used for the double click timer
|
||||
nunstruct[2].ax=maxW/2;
|
||||
nunstruct[2].ay=maxH/2;
|
||||
runmode=1;
|
||||
Code = 0;
|
||||
bno=0;
|
||||
LastCode = 0;
|
||||
// __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_3);
|
||||
MouseKBDIntEnable(1); // enable interrupt
|
||||
mouse0=true;
|
||||
}
|
||||
void mouse0close(void){
|
||||
if(!mouse0)return;
|
||||
mouseID=0;
|
||||
runmode=0;
|
||||
sendCommand(0xFF); // Turn off streaming
|
||||
ReadReturn(5);
|
||||
MouseKBDIntEnable(0); // disable interrupt in case called from within CNInterrupt()
|
||||
ExtCfg(MOUSE_CLOCK, EXT_NOT_CONFIG, 0);
|
||||
ExtCfg(MOUSE_DATA, EXT_NOT_CONFIG, 0);
|
||||
mouse0=false;
|
||||
runmode=0;
|
||||
mouse0Interruptc=NULL;
|
||||
memset((struct s_nunstruct *)&nunstruct[2],0,sizeof(struct s_nunstruct));
|
||||
}
|
||||
static bool sendCommand(int cmd)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
// calculate the parity and add to the command as the 9th bit
|
||||
for (j = i = 0; i < 8; i++)
|
||||
j += ((cmd >> i) & 1);
|
||||
cmd = (cmd & 0xff) | (((j + 1) & 1) << 8);
|
||||
PinSetBit(MOUSE_CLOCK, TRISCLR);
|
||||
PinSetBit(MOUSE_CLOCK, LATCLR);
|
||||
uSec(250);
|
||||
PinSetBit(MOUSE_DATA, TRISCLR);
|
||||
PinSetBit(MOUSE_DATA, LATCLR);
|
||||
PinSetBit(MOUSE_CLOCK, TRISSET);
|
||||
InkeyTimer = 0;
|
||||
uSec(2);
|
||||
while (PinRead(MOUSE_CLOCK))
|
||||
if (InkeyTimer >= 500)
|
||||
{ // wait for the keyboard to pull the clock low
|
||||
return false; // wait for the keyboard to pull the clock low
|
||||
}
|
||||
|
||||
// send each bit including parity
|
||||
for (i = 0; i < 9; i++)
|
||||
{
|
||||
if (cmd & 1)
|
||||
{
|
||||
PinSetBit(MOUSE_DATA, LATSET);
|
||||
}
|
||||
else
|
||||
{
|
||||
PinSetBit(MOUSE_DATA, LATCLR);
|
||||
}
|
||||
while (!PinRead(MOUSE_CLOCK))
|
||||
if (InkeyTimer >= 500)
|
||||
{ // wait for the keyboard to pull the clock low
|
||||
return false; // wait for the keyboard to pull the clock low
|
||||
}
|
||||
while (PinRead(MOUSE_CLOCK))
|
||||
if (InkeyTimer >= 500)
|
||||
{ // wait for the keyboard to pull the clock low
|
||||
return false; // wait for the keyboard to pull the clock low
|
||||
}
|
||||
cmd >>= 1;
|
||||
}
|
||||
|
||||
// PinSetBit(MOUSE_CLOCK, TRISSET);
|
||||
PinSetBit(MOUSE_DATA, TRISSET);
|
||||
|
||||
while (PinRead(MOUSE_DATA))
|
||||
if (InkeyTimer >= 500)
|
||||
{ // wait for the keyboard to pull the clock low
|
||||
return false; // wait for the keyboard to pull the clock low
|
||||
} // wait for the keyboard to pull data low (ACK)
|
||||
while (PinRead(MOUSE_CLOCK))
|
||||
if (InkeyTimer >= 500)
|
||||
{ // wait for the keyboard to pull the clock low
|
||||
return false; // wait for the keyboard to pull the clock low
|
||||
} // wait for the clock to go low
|
||||
while (!(PinRead(MOUSE_CLOCK)) || !(PinRead(MOUSE_DATA)))
|
||||
if (InkeyTimer >= 500)
|
||||
{ // wait for the keyboard to pull the clock low
|
||||
return false; // wait for the keyboard to pull the clock low
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/***************************************************************************************************
|
||||
sendCommand - Send a command to to mouse.
|
||||
****************************************************************************************************/
|
||||
|
||||
int ReadReturn(int timeout){
|
||||
int i;
|
||||
Code = 0;
|
||||
bno=0;
|
||||
LastCode = 0;
|
||||
readreturn=-1;
|
||||
MouseKBDIntEnable(1);
|
||||
i=100;
|
||||
MouseTimer = 0;
|
||||
while(MouseTimer<timeout){
|
||||
if(readreturn!=-1){
|
||||
i=readreturn;
|
||||
readreturn=-1;
|
||||
routinechecks();
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************************************
|
||||
change notification interrupt service routine
|
||||
****************************************************************************************************/
|
||||
void __not_in_flash_func(MNInterrupt)(uint64_t dd) {
|
||||
static unsigned long long int lefttimer=0, righttimer=0;
|
||||
int maxW=HRes;
|
||||
int maxH=VRes;
|
||||
int d = dd & (1<<PinDef[MOUSE_DATA].GPno);
|
||||
|
||||
// Make sure it was a falling edge
|
||||
if (!(dd & (1<<PinDef[MOUSE_CLOCK].GPno)))
|
||||
{
|
||||
if(!Timer5)PS2State=PS2START;
|
||||
// Sample the data
|
||||
switch(PS2State){
|
||||
default:
|
||||
case PS2ERROR: // this can happen if a timing or parity error occurs
|
||||
// fall through to PS2START
|
||||
|
||||
case PS2START:
|
||||
if(!d) { // PS2DAT == 0
|
||||
KCount = 8; // init bit counter
|
||||
KParity = 0; // init parity check
|
||||
Code = 0;
|
||||
PS2State = PS2BIT;
|
||||
Timer5=5;
|
||||
}
|
||||
break;
|
||||
|
||||
case PS2BIT:
|
||||
Code >>= 1; // shift in data bit
|
||||
if(d) Code |= 0x80; // PS2DAT == 1
|
||||
KParity ^= Code; // calculate parity
|
||||
if (--KCount <= 0) PS2State = PS2PARITY; // all bit read
|
||||
break;
|
||||
|
||||
case PS2PARITY:
|
||||
if(d) KParity ^= 0x80; // PS2DAT == 1
|
||||
if (KParity & 0x80) { // parity odd, continue
|
||||
PS2State = PS2STOP;
|
||||
} else {
|
||||
PS2State = PS2ERROR;
|
||||
}
|
||||
break;
|
||||
case PS2STOP:
|
||||
if(d) { // PS2DAT == 1
|
||||
readreturn=Code;
|
||||
if(runmode){
|
||||
mouse[bno++]=Code;
|
||||
if(!(mouse[0] & 0x08))bno=0;//bit 3 must be set in first byte
|
||||
if(bno==(mouseID==3 ? 4: 3)){
|
||||
bno=0;
|
||||
if(mouse[0] & 0b10000)mouse[1] |=0xFF00;
|
||||
if(mouse[0] & 0b100000)mouse[2] |=0xFF00;
|
||||
nunstruct[2].ax+=mouse[1];
|
||||
if(nunstruct[2].ax<0)nunstruct[2].ax=0;
|
||||
if(nunstruct[2].ax>=maxW)nunstruct[2].ax=maxW-1;
|
||||
nunstruct[2].ay-=mouse[2];
|
||||
mouseupdated=1;
|
||||
if(nunstruct[2].ay<0)nunstruct[2].ay=0;
|
||||
if(nunstruct[2].ay>=maxH)nunstruct[2].ay=maxH-1;
|
||||
nunstruct[2].L = mouse[0] & 0b1;
|
||||
nunstruct[2].R=(mouse[0] & 0b10)>>1;
|
||||
nunstruct[2].C=(mouse[0] & 0b100)>>2;
|
||||
if(nunstruct[2].type>1000) nunstruct[2].Z=0;
|
||||
if((mouse[0] & 3) != (LastCode & 3)){
|
||||
if((mouse[0] & 1) && !(LastCode & 1) && (mSecTimer-lefttimer>16)){ //left button press
|
||||
nunfoundc[2]=1;
|
||||
if(nunstruct[2].type>=500 || nunstruct[2].type<100) nunstruct[2].type=0;
|
||||
else {
|
||||
nunstruct[2].Z=1;
|
||||
nunstruct[2].type=500 ;
|
||||
}
|
||||
lefttimer=mSecTimer;
|
||||
}
|
||||
if(!(mouse[0] & 1) && (LastCode & 1)){ //left button release
|
||||
}
|
||||
if((mouse[0] & 2) && !(LastCode & 2) && (mSecTimer-righttimer>16)){
|
||||
righttimer=mSecTimer;
|
||||
}
|
||||
}
|
||||
LastCode=mouse[0];
|
||||
if(mouseID==3){
|
||||
if(mouse[3] & 0x80)mouse[3]|=0xFF00;
|
||||
nunstruct[2].az=(volatile int)nunstruct[2].az+mouse[3];
|
||||
}
|
||||
nunstruct[2].x1=nunstruct[2].ax/(FontTable[gui_font >> 4][0] * (gui_font & 0b1111));
|
||||
nunstruct[2].y1=nunstruct[2].ay/(FontTable[gui_font >> 4][1] * (gui_font & 0b1111));
|
||||
}
|
||||
}
|
||||
}
|
||||
PS2State = PS2START;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
void cmd_mouse(void){
|
||||
unsigned char *tp=NULL;
|
||||
int n;
|
||||
if((tp=checkstring(cmdline, (unsigned char *)"OPEN"))){
|
||||
getargs(&tp,7,(unsigned char *)",");
|
||||
// if(Option.MOUSE_CLOCK)error("Already open");
|
||||
if(!(argc==5))error("Syntax");
|
||||
getint(argv[0],2,2);
|
||||
char code;
|
||||
if(!(code=codecheck(argv[2])))argv[2]+=2;
|
||||
int pin1 = getinteger(argv[2]);
|
||||
if(!code)pin1=codemap(pin1);
|
||||
if(!(code=codecheck(argv[4])))argv[4]+=2;
|
||||
int pin2 = getinteger(argv[4]);
|
||||
if(!code)pin2=codemap(pin2);
|
||||
if(IsInvalidPin(pin1)) error("Invalid pin %/|",pin1,pin1);
|
||||
if(IsInvalidPin(pin2)) error("Invalid pin %/|",pin2,pin2);
|
||||
if(!(pin1==Option.MOUSE_CLOCK && pin2==Option.MOUSE_DATA)){
|
||||
if(ExtCurrentConfig[pin1] >= EXT_COM_RESERVED ) error("Pin %/| is in use",pin1,pin1);
|
||||
if(ExtCurrentConfig[pin2] >= EXT_COM_RESERVED ) error("Pin %/| is in use",pin2,pin2);
|
||||
}
|
||||
if(Option.MOUSE_CLOCK && !(pin1==Option.MOUSE_CLOCK && pin2==Option.MOUSE_DATA))error("OPTION MOUSE declared with different pins");
|
||||
MOUSE_CLOCK=pin1;
|
||||
MOUSE_DATA=pin2;
|
||||
if(!mouse0)initMouse0(0);
|
||||
if(!mouse0){
|
||||
if(!Option.MOUSE_CLOCK){
|
||||
ExtCfg(MOUSE_CLOCK, EXT_NOT_CONFIG, 0);
|
||||
ExtCfg(MOUSE_DATA, EXT_NOT_CONFIG, 0);
|
||||
}
|
||||
MOUSE_CLOCK=0;
|
||||
MOUSE_DATA=0;
|
||||
error("Open failed");
|
||||
}
|
||||
} else if((tp=checkstring(cmdline, (unsigned char *)"CLOSE"))){
|
||||
getargs(&tp,1,(unsigned char *)",");
|
||||
if(!mouse0)error("Not open");
|
||||
if(Option.MOUSE_CLOCK)error("Option MOUSE set - close invalid");
|
||||
n=getint(argv[0],2,2);
|
||||
mouse0close();
|
||||
} else if((tp=checkstring(cmdline,(unsigned char *)"INTERRUPT ENABLE"))){
|
||||
getargs(&tp,3,(unsigned char *)",");
|
||||
if(!mouse0)error("Not open");
|
||||
if(!(argc==3))error("Syntax");
|
||||
n=getint(argv[0],2,2);
|
||||
nunInterruptc[n] = (char *)GetIntAddress(argv[2]); // get the interrupt location
|
||||
InterruptUsed = true;
|
||||
return;
|
||||
} else if((tp = checkstring(cmdline, (unsigned char *)"SET"))){
|
||||
getargs(&tp,7,(unsigned char *)",");
|
||||
if(!mouse0)error("Not open");
|
||||
if(!(argc==7))error("Syntax");
|
||||
n=getint(argv[0],2,2);
|
||||
nunstruct[n].ax=getint(argv[2],-HRes,HRes);
|
||||
nunstruct[n].ay=getint(argv[4],-VRes,VRes);
|
||||
nunstruct[n].az=getint(argv[6],-1000000,1000000);
|
||||
} else if((tp = checkstring(cmdline, (unsigned char *)"INTERRUPT DISABLE"))){
|
||||
getargs(&tp,1,(unsigned char *)",");
|
||||
if(!mouse0)error("Not open");
|
||||
n=getint(argv[0],2,2);
|
||||
nunInterruptc[n]=NULL;
|
||||
} else error("Syntax");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user