unit main;

interface


uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ComCtrls, ExtCtrls, Menus, A3nalogGauge, Buttons, PDJButton;
Const
   MAXSIZE=64;
   MPUSB_FAIL=0;
   MPUSB_SUCCESS=1;
   MP_WRITE:DWORD=0;
   MP_READ:DWORD=1;
   MAX_NUM_MPUSB_DEV=127;
   //-----------------------------------------
   // Main command
   READ_VERSION    = $00;    // user.h
   MOTOR_ON        = $01;
   RESET_DEVICE    = $FF;    // reset PIC chip
   //-----------------------------------------
   // Sub command
   STOP            = $00;
   TURN_LEFT       = $01;
   TURN_RIGHT      = $02;

type
  DWORD = LongInt;
  PCHAR8 =  array[0..MAXSIZE] of char;
  PBYTE = array[0..MAXSIZE] of BYTE;
  PDWORD =  array[0..MAXSIZE] of DWORD;
  PVOID = Pointer;
  UINT = Cardinal;

  TForm1 = class(TForm)
    StatusBar1: TStatusBar;
    Image1: TImage;
    Label1: TLabel;
    Label2: TLabel;
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Button4: TButton;
    Bevel1: TBevel;
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure Label2Click(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

function _MPUSBGetDLLVersion():DWORD; stdcall;external 'mpusbapi.dll';
function _MPUSBGetDeviceCount(pVID_PID:PCHAR8):DWORD; stdcall;external 'mpusbapi.dll';
function _MPUSBOpen(instance:DWORD;pVID_PID:PCHAR8;pEP:PCHAR8;dwDir:DWORD;dwReserved:DWORD):THANDLE; stdcall;external 'mpusbapi.dll';
function _MPUSBRead(handle:THANDLE;var pData:PBYTE;dwLen:DWORD;var pLength:DWORD;dwMilliseconds:DWORD):DWORD; stdcall;external 'mpusbapi.dll';
function _MPUSBReadInt(handle:THANDLE;var pData:PBYTE;dwLen:DWORD;var pLength:PDWORD;dwMilliseconds:DWORD):DWORD; stdcall;external 'mpusbapi.dll';
function _MPUSBWrite(handle:THANDLE;pData:PBYTE;dwLen:DWORD;var pLength:DWORD;dwMilliseconds:DWORD):DWORD; stdcall;external 'mpusbapi.dll';
function _MPUSBClose(handle:THANDLE):DWORD; stdcall;external 'mpusbapi.dll';

var
  Form1: TForm1;
  vid_pid:PCHAR8='vid_04d8&pid_000c';  // VID and PID for Demo USB FS board
  out_pipe:PCHAR8='\MCHP_EP1';
  in_pipe:PCHAR8='\MCHP_EP1';
  myOutPipe:THANDLE;
  myInPipe:THANDLE;
  isConnected:boolean;

implementation
uses ShellAPI;
{$R *.DFM}
procedure CheckInvalidHandle();
begin
  if(GetLastError=ERROR_INVALID_HANDLE) then
  begin
        _MPUSBClose(myOutPipe);
        _MPUSBClose(myInPipe);

        myInPipe:=INVALID_HANDLE_VALUE;
        myOutPipe:=INVALID_HANDLE_VALUE;
  end
  else
    ShowMessage('Error Code :'+inttostr(GetLastError()));
end;

function SendReceivePacket(SendData:PBYTE;SendLength:DWORD;var ReceiveData:PBYTE;
var ReceiveLength:DWORD;SendDelay:UINT;ReceiveDelay:UINT):DWORD; stdcall;
var
  SentDataLength:DWORD ;
  ExpectedReceiveLength:DWORD;
begin
 ExpectedReceiveLength:= ReceiveLength;
 if((myOutPipe <> INVALID_HANDLE_VALUE) and (myInPipe <> INVALID_HANDLE_VALUE)) then
   begin
    if(_MPUSBWrite(myOutPipe,SendData,SendLength,SentDataLength,SendDelay)<>0) then
     if(_MPUSBRead(myInPipe,ReceiveData,ExpectedReceiveLength,ReceiveLength,ReceiveDelay)<>0) then
       begin
       if(ReceiveLength = ExpectedReceiveLength) then
        begin
         Result:=1; // OK
         exit;
        end
       else
        if(ReceiveLength < ExpectedReceiveLength) then
         begin
           Result:=2; // failed, incorrect receive length
           exit;
         end
        end
     else
      CheckInvalidHandle()
    else
      CheckInvalidHandle()
   end
 else
   begin
     Result:=0; // Error
   end;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
        if (myOutPipe <> INVALID_HANDLE_VALUE) then _MPUSBClose(myOutPipe);
        if (myInPipe <> INVALID_HANDLE_VALUE) then _MPUSBClose(myInPipe);
        myInPipe:= INVALID_HANDLE_VALUE;
        myOutPipe:=INVALID_HANDLE_VALUE;
end;

procedure TForm1.Label2Click(Sender: TObject);
var
  AnUrl: array[0..255] of char;
begin
  StrPCopy(AnUrl, 'http://www.sixca.com/');
  ShellExecute(Application.Handle, 'open', AnUrl, nil, nil, SW_NORMAL);
end;


//-------------------------------------------------
// Connect to USB device and read firmware version
//-------------------------------------------------
procedure TForm1.Button1Click(Sender: TObject);
var
   selection:DWORD;
   send_buf:PBYTE;
   receive_buf:PBYTE;
   RecvLength:DWORD;
begin
  selection:=0; // USB device that have PID & VID as we configed.
  if (_MPUSBGetDeviceCount(vid_pid)=0) then
  begin
    StatusBar1.Panels[1].text:='Status : Device not connected';
    StatusBar1.Panels[0].text:='Firmware version : unkhown';
    exit;
  end
  else
  begin
    StatusBar1.Panels[1].text:='Status : Device connected';
  end;

  myOutPipe:= _MPUSBOpen(selection,vid_pid,out_pipe,MP_WRITE,0);
  myInPipe:= _MPUSBOpen(selection,vid_pid,out_pipe,MP_READ,0);

  if ((myOutPipe = INVALID_HANDLE_VALUE) or (myInPipe = INVALID_HANDLE_VALUE)) then
  begin
   StatusBar1.Panels[1].text:='Status : USB Error';
   exit;
  end;


  // The default demo firmware application has a defined application
  // level protocol.
  // To read the firmware version, the host must send the READ_VERSION
  // command which is defined as 0x00, follows by the length of the
  // expected result, in this case is 2 bytes, major version, and minor
  // version.
  // i.e. <READ_VERSION><0x02>
  //
  // The response packet from the board has the following format:
  // <READ_VERSION><0x02><MINOR_VER><MAJOR_VER>

  send_buf[0]:=READ_VERSION;    // command
  send_buf[1]:=2;               // Expected length of the result
  RecvLength:=4;
  if(SendReceivePacket(send_buf,2,receive_buf,RecvLength,1000,1000) = 1) then
  begin
   if ((receive_buf[0] =  READ_VERSION) and (RecvLength = 4) and (receive_buf[1] =  2)) then
   begin
     StatusBar1.Panels[0].Text:='Firmware version : '+ IntToStr(receive_buf[3])+'.'+IntToStr(receive_buf[2]);
     Button2.Enabled:=true;
     Button3.Enabled:=true;
     Button4.Enabled:=true;
   end;
  end
  else
  begin
     StatusBar1.Panels[1].Text:='Status : Communication Error!';
  end;

  _MPUSBClose(myOutPipe);
  _MPUSBClose(myInPipe);
  myInPipe:= INVALID_HANDLE_VALUE;
  myOutPipe:=INVALID_HANDLE_VALUE;
end;

//----------------------------
// turn left
//----------------------------
procedure TForm1.Button2Click(Sender: TObject);
var
   selection:DWORD;
   send_buf:PBYTE;
   receive_buf:PBYTE;
   RecvLength:DWORD;
   DIRECTION:BYTE;  // motor direction
begin
  selection:=0; // USB device that have PID & VID as we configed.
  {
  if (_MPUSBGetDeviceCount(vid_pid)=0) then
  begin
    StatusBar1.Panels[1].text:='Status : Device not connected';
    exit;
  end
  else
  begin
    StatusBar1.Panels[1].text:='Status : Device connected';
  end;
  }

  myOutPipe:= _MPUSBOpen(selection,vid_pid,out_pipe,MP_WRITE,0);
  myInPipe:= _MPUSBOpen(selection,vid_pid,out_pipe,MP_READ,0);

  if ((myOutPipe = INVALID_HANDLE_VALUE) or (myInPipe = INVALID_HANDLE_VALUE)) then
  begin
   StatusBar1.Panels[1].text:='Status : USB Error';
   exit;
  end;

  // PC send : <MOTOR_ON><0x01><DIRECTION> = 3 bytes
  // Device respone : <MOTOR_ON> =  1 bytes
  DIRECTION := TURN_LEFT;
  send_buf[0]:=MOTOR_ON;        // Command
  send_buf[1]:=0;               // Expected length of the result
  send_buf[2]:=DIRECTION;       // Motor direction
  RecvLength:=1;                // Length of the Packet
  if(SendReceivePacket(send_buf,3,receive_buf,RecvLength,1000,1000) = 1) then
  begin
   //if ((receive_buf[0] <>  MOTOR_ON) or (RecvLength <> 3) or (receive_buf[2] <>  DIRECTION)) then
   if (receive_buf[0] <>  MOTOR_ON) then
     StatusBar1.Panels[1].Text:='Status : Communication Error!';
  end;

  _MPUSBClose(myOutPipe);
  _MPUSBClose(myInPipe);
  myInPipe:= INVALID_HANDLE_VALUE;
  myOutPipe:=INVALID_HANDLE_VALUE;

end;

//------------------------------
// turn right
//------------------------------
procedure TForm1.Button3Click(Sender: TObject);
var
   selection:DWORD;
   send_buf:PBYTE;
   receive_buf:PBYTE;
   RecvLength:DWORD;
   DIRECTION:BYTE;  // motor direction
begin
  selection:=0; // USB device that have PID & VID as we configed.
  {
  if (_MPUSBGetDeviceCount(vid_pid)=0) then
  begin
    StatusBar1.Panels[1].text:='Status : Device not connected';
    exit;
  end
  else
  begin
    StatusBar1.Panels[1].text:='Status : Device connected';
  end;
  }
  myOutPipe:= _MPUSBOpen(selection,vid_pid,out_pipe,MP_WRITE,0);
  myInPipe:= _MPUSBOpen(selection,vid_pid,out_pipe,MP_READ,0);

  if ((myOutPipe = INVALID_HANDLE_VALUE) or (myInPipe = INVALID_HANDLE_VALUE)) then
  begin
   StatusBar1.Panels[1].text:='Status : USB Error';
   exit;
  end;

  // PC send : <MOTOR_ON><0x01><DIRECTION> = 3 bytes
  // Device respone : <MOTOR_ON> =  1 bytes
  DIRECTION := TURN_RIGHT;
  send_buf[0]:=MOTOR_ON;        // Command
  send_buf[1]:=0;               // Expected length of the result
  send_buf[2]:=DIRECTION;       // Motor direction
  RecvLength:=1;                // Length of the Packet
  if(SendReceivePacket(send_buf,3,receive_buf,RecvLength,1000,1000) = 1) then
  begin
   //if ((receive_buf[0] <>  MOTOR_ON) or (RecvLength <> 3) or (receive_buf[2] <>  DIRECTION)) then
   if (receive_buf[0] <>  MOTOR_ON) then
     StatusBar1.Panels[1].Text:='Status : Communication Error!';
  end;

  _MPUSBClose(myOutPipe);
  _MPUSBClose(myInPipe);
  myInPipe:= INVALID_HANDLE_VALUE;
  myOutPipe:=INVALID_HANDLE_VALUE;

end;

//-------------------------------
// stop
//-------------------------------
procedure TForm1.Button4Click(Sender: TObject);
var
   selection:DWORD;
   send_buf:PBYTE;
   receive_buf:PBYTE;
   RecvLength:DWORD;
   DIRECTION:BYTE;  // motor direction
begin
  selection:=0; // USB device that have PID & VID as we configed.
  {
  if (_MPUSBGetDeviceCount(vid_pid)=0) then
  begin
    StatusBar1.Panels[1].text:='Status : Device not connected';
    exit;
  end
  else
  begin
    StatusBar1.Panels[1].text:='Status : Device connected';
  end;
  }
  myOutPipe:= _MPUSBOpen(selection,vid_pid,out_pipe,MP_WRITE,0);
  myInPipe:= _MPUSBOpen(selection,vid_pid,out_pipe,MP_READ,0);

  if ((myOutPipe = INVALID_HANDLE_VALUE) or (myInPipe = INVALID_HANDLE_VALUE)) then
  begin
   StatusBar1.Panels[1].text:='Status : USB Error';
   exit;
  end;

  // PC send : <MOTOR_ON><0x01><DIRECTION> = 3 bytes
  // Device respone : <MOTOR_ON> = 1 bytes
  DIRECTION := STOP;
  send_buf[0]:=MOTOR_ON;        // Command
  send_buf[1]:=0;               // Expected length of the result
  send_buf[2]:=DIRECTION;       // Motor direction
  RecvLength:=1;                // Length of the Packet
  if(SendReceivePacket(send_buf,3,receive_buf,RecvLength,1000,1000) = 1) then
  begin
   //if ((receive_buf[0] <>  MOTOR_ON) or (RecvLength <> 3) or (receive_buf[2] <>  DIRECTION)) then
   if (receive_buf[0] <>  MOTOR_ON) then
     StatusBar1.Panels[1].Text:='Status : Communication Error!';
  end;

  _MPUSBClose(myOutPipe);
  _MPUSBClose(myInPipe);
  myInPipe:= INVALID_HANDLE_VALUE;
  myOutPipe:=INVALID_HANDLE_VALUE;


end;

procedure TForm1.FormCreate(Sender: TObject);
begin
        myOutPipe:=INVALID_HANDLE_VALUE;
        myInPipe:= INVALID_HANDLE_VALUE;
end;

end.





