'******************************************************************************
'* 
'* MS MOUSE CONTROLLER (CHIP DEVICE)
'*
'* Supported platform/bus: X86
'* 
'* Version history:
'*  2008 - initial emulation (by WadiM)
'*
'****************************************************************************** 

//DEBUG.ON 'uncomment to enable debug messages (can be slow for hi-freq events)

'UART/COM device implementation
public use object COM_I8250

//device name
DeviceName="MS_MOUSE"
DebugName="MOUSE"

'------------------------------- H/W Interface --------------------------------

//4H - Modem Control Register (read/write)
public property MCR_PORT(Value as byte)
 dim b as byte=MCR_Value and 3 'preserve state of RTS and DTR lines to analize
 'parent call
 MCR_PORT=Value
 'check mouse activated (DTR+RTS lines on) to send 'M' (ascii 77) - MS Mouse ID
 if (not Loopback) and (b<>3) and ((MCR_Value and 3)=3) then
    if receive_buffer.size<MAX_BUFFER_SIZE then receive_buffer.PushByte(Asc("M")) //'M'
    ?? DebugPrefix;"Send 'M' identifier"
 end if
end

'---------------------------- H/W All I/O Ports -------------------------------

'Write all standard ports
public property PORTS(Index as word, Value as byte)
  select case Index-DEVPARAM_PORT
  case 4 : MCR_PORT=Value
  case else : PORTS(Index)=Value 'parent call
 end select
end

'------------------------------ Mouse Handler ---------------------------------

//Handle mouse events from emulator (convert to packet and place to buffer)
public procedure HandleMouse(keys as byte, rx as single, ry as single, ex as single, ey as single)
 ?? DebugPrefix;"Mouse Event Handled (keys=";keys;" rx=";rx;" ry=";ry;" ex=";ex;" ey=";ey;")"
 //calc offsets
 dim dx as integer=roundDn(rx), dy as integer=roundDn(ry)
 if dx<-127 then dx=-127 : if dy<-127 then dy=-127
 if dx>127 then dx=127 : if dy>127 then dy=127
 //create and send packet 
 dim b as byte=0x40 
 if (keys and 1)<>0 then b=b or 0x20 //left button flag
 if (keys and 2)<>0 then b=b or 0x10 //right button flag
 b=b or shr(dy and 0xC0,4) or shr(dx and 0xC0,6) //7..6 bits of dx and dy
 if receive_buffer.size<MAX_BUFFER_SIZE then 'to prevent buffer overflow
    receive_buffer.PushByte(b)
    receive_buffer.PushByte(dx and 0x3F)
    receive_buffer.PushByte(dy and 0x3F)
 end if
end

'---------------------------- DEVICE Interface --------------------------------

//Device initialization
public function DEV_INIT(stream as object,byref EventFreq as integer) as boolean

 'parent call
 if not DEV_INIT(stream,EventFreq) then exit(false)
 if EventFreq<1200 then EventFreq=1200

 'disable loss of data (to avoid incomplete packet receiving)
 AllowDataLosses=false

 //success
 result=true
end
