Hola a todos.
He instalado Debian en una maquina virtual con VirtualBox y por supuesto Lazarus. Funciona muy bien, hay que decirlo.
Mi proposito erá encontrar librerias bluetooth para hacer alguna aplicación y encontré BluettothLaz 0.1 en la
http://wiki.lazarus.freepascal.org/Bluetooth/es.
He instalado la libreria libbluetooth-dev y luego he ido a instalar el paquete. Me da un error de compilación en una unit llamada wiimotetools.
Como no tengo ninguna esperiencia en realizar componentes os pido a ver si le podeis echar un ojo y decirme la solución: (Quito el chorizo variables, sino el mensaje es muy largo y no me deja publicarlo)
Código Delphi
[-]
unit WiiMoteTools;
{$mode objfpc}{$H+}
{$linklib bluetooth}
interface
uses
Classes, SysUtils, Bluetooth, ctypes, Sockets;
type
__time_t = longint;
__suseconds_t = longint;
Ptimeval = ^timeval;
timeval = record
tv_sec : __time_t;
tv_usec : __suseconds_t;
end;
__fd_mask = dWord;
const
__FD_SETSIZE = 1024;
__NFDBITS = 8 * sizeof(__fd_mask);
type
__fd_set = record
fds_bits: packed array[0..(__FD_SETSIZE div __NFDBITS)-1] of __fd_mask;
end;
TFdSet = __fd_set;
PFdSet = ^TFdSet;
Type
Pfd_set = ^_fd_set;
_fd_set = __fd_set;
const
FD_SETSIZE = __FD_SETSIZE;
Type
Pfd_mask = ^fd_mask;
fd_mask = __fd_mask;
const
NFDBITS = __NFDBITS;
Function __FDELT(d: longint): Integer;
Function __FDMASK(d: longint): __fd_mask;
procedure FD_ZERO(out fdset: _fd_set);
procedure FD_SET(fd: longint; var fdset: _fd_Set);
type
TAccelVector = record
x,y,z: integer;
end;
TAccelCalibration = record
cal_zero: TAccelVector;
cal_g: TAccelVector;
end;
TWiiMoteReadRequest = class;
TWiiMoteReadCallback = procedure(Request: TWiiMoteReadRequest) of object;
TWiiMoteReadRequest = class
public
Callback: TWiiMoteReadCallback;
Addr: cardinal;
BufSize: word;
Buf: PByte;
Received: word;
constructor Create(const TheCallback: TWiiMoteReadCallback;
TheAddr: cardinal; TheBufSize: word);
destructor Destroy; override;
end;
TWiiMoteDot = record
X: word;
Y: word;
Size: word;
Visible: boolean;
end;
TWiimotes = class;
TWiimote = class
private
FLEDS: integer;
FRealizedIR: boolean;
FReadRequests: TFPList; function SendCmd(ReportType: byte; Msg: PByte; Count: integer): PtrInt;
function SendData(Addr: cuint; Data: Pointer; Count: byte): PtrInt;
function RequestRead(const Callback: TWiiMoteReadCallback;
Addr: cuint; BufSize: cushort): TWiiMoteReadRequest;
procedure SendNextReadRequest;
procedure OnHandShake(Request: TWiiMoteReadRequest);
procedure HandleEvents;
procedure HandleRead;
public
constructor Create;
destructor Destroy; override;
procedure SetLEDs(const AValue: integer);
function Connect: boolean;
procedure Disconnect;
procedure EnableHandshake;
function RealizeReportType: boolean;
procedure RealizeIR;
WiiMotes: TWiiMotes;
ID: integer;
Name: string;
bdaddr: bdaddr_t;
Found: boolean;
Connected: boolean;
OutSocket: cint;
InSocket: cint;
Handshaking: boolean;
HandshakeComplete: boolean;
Event: TWiimoteEventType;
EventBuf: array[0..31] of byte;
LEDs: integer;
Rumble: boolean;
Continuous: boolean;
ReportMotion: boolean;
ReportIR: boolean;
ReportExpansion: boolean;
Buttons: word; Accel: TAccelVector; AccelCalibration: TAccelCalibration;
Dots: array[0..3] of TWiiMoteDot;
end;
TWiimotes = class
private
FItems: TFPList;
function GetItems(Index: integer): TWiimote;
public
constructor Create;
destructor Destroy; override;
function Add(Item: TWiimote): integer;
function Count: integer;
property Items[Index: integer]: TWiimote read GetItems; default;
procedure FindWiiMotes(timeout: integer);
function Connect: integer;
procedure Disconnect;
function HandleEvents: boolean;
end;
function c_close(fd: cint): cint; external name 'close';
implementation
function __FDELT(d: longint): Integer;
begin
Result:=d div __NFDBITS;
end;
function __FDMASK(d: longint): __fd_mask;
begin
Result:=1 shl (d mod __NFDBITS);
end;
procedure FD_ZERO(out fdset: _fd_set);
var
I: Integer;
begin
with fdset do
for I:=Low(fds_bits) to High(fds_bits) do
fds_bits[i]:=0;
end;
procedure FD_SET(fd: longint; var fdset: _fd_Set);
begin
fdset.fds_bits[__FDELT(fd)]:=fdset.fds_bits[__FDELT(fd)] or __FDMASK(fd);
end;
procedure FD_CLR(fd: longint; var fdset: _fd_set);
begin
fdset.fds_bits[__FDELT(fd)]:=fdset.fds_bits[__FDELT(fd)] and (not __FDMASK(fd));
end;
function FD_ISSET(fd: longint; const fdset: _fd_set): Boolean;
begin
Result:=(fdset.fds_bits[__FDELT(fd)] and __FDMASK(fd))<>0;
end;
procedure TWiimotes.FindWiiMotes(timeout: integer);
var
device_id, device_sock: cint;
scan_info: array[0..127] of inquiry_info;
scan_info_ptr: Pinquiry_info;
found_devices: cint;
DevName: PCChar;
CurWiiMote: TWiimote;
i: Integer;
begin
device_id := hci_get_route(nil);
if (device_id < 0) then
raise Exception.Create('FindWiiMotes: hci_get_route');
device_sock := hci_open_dev(device_id);
if (device_sock < 0) then
raise Exception.Create('hci_open_dev');
scan_info_ptr:=@scan_info[0];
FillByte(scan_info[0],SizeOf(inquiry_info)*128,0);
found_devices := hci_inquiry_1(device_id, timeout, 128, nil,
@scan_info_ptr, IREQ_CACHE_FLUSH);
if (found_devices < 0) then
raise Exception.Create('hci_inquiry');
writeln('found_devices=',found_devices);
DevName:=nil;
GetMem(DevName,20);
for i:=0 to found_devices-1 do begin
if ((scan_info[i].dev_class[0] = WM_DEV_CLASS_0) and
(scan_info[i].dev_class[1] = WM_DEV_CLASS_1) and
(scan_info[i].dev_class[2] = WM_DEV_CLASS_2)) then
begin
CurWiiMote:=TWiimote.Create;
Add(CurWiiMote);
ba2str(@scan_info[i].bdaddr, DevName);
CurWiiMote.Name:=PChar(DevName);
CurWiiMote.bdaddr:=scan_info[i].bdaddr;
CurWiiMote.Found:=true;
writeln(i,' Device=',CurWiiMote.Name);
end;
end;
FreeMem(DevName);
c_close(device_sock);
end;
function TWiimotes.Connect: integer;
var
CurWiiMote: TWiimote;
i: Integer;
begin
Result:=0;
for i:=0 to Count-1 do begin
CurWiiMote:=Items[i];
if not CurWiiMote.Found then
continue;
if CurWiiMote.Connect then
inc(Result);
end;
end;
procedure TWiimotes.Disconnect;
var
i: Integer;
begin
for i:=0 to Count-1 do Items[i].Disconnect;
end;
function TWiimotes.HandleEvents: boolean;
var
fds: _fd_set;
highest_fd: integer;
tv: timeval;
i: integer;
r: PtrInt;
begin
highest_fd:=0;
Result:=false;
tv.tv_sec := 0;
tv.tv_usec := 500;
FD_ZERO(fds);
for i:=0 to Count-1 do begin
if Items[i].Connected then begin
FD_SET(Items[i].InSocket, fds);
if (Items[i].InSocket > highest_fd) then
highest_fd := Items[i].InSocket;
end;
Items[i].Event:= WiiMote_NONE;
end;
if (select(highest_fd + 1, @fds, nil, nil, @tv) = -1) then
raise Exception.Create('Unable to select() the wiimote interrupt socket(s)');
for i:=0 to Count-1 do begin
if not Items[i].Connected then
continue;
if (FD_ISSET(Items[i].InSocket, fds)) then begin
FillByte(Items[i].EventBuf[0],32,0);
r := fprecv(Items[i].InSocket,@Items[i].EventBuf[0], 32,0);
if (r = -1) then begin
writeln('Receiving wiimote data '+IntToStr(Items[i].ID));
Items[i].Disconnect;
Result:=true;
continue;
end;
if Items[i].EventBuf[1]<>0 then begin
Items[i].HandleEvents;
Result:=true;
end;
end else begin
end;
end;
end;
function TWiimotes.GetItems(Index: integer): TWiimote;
begin
Result:=TWiimote(FItems[Index]);
end;
constructor TWiimotes.Create;
begin
FItems:=TFPList.Create;
end;
destructor TWiimotes.Destroy;
var
i: Integer;
begin
for i:=0 to FItems.Count-1 do TObject(FItems[i]).Free;
FreeAndNil(FItems);
inherited Destroy;
end;
function TWiimotes.Add(Item: TWiimote): integer;
begin
Item.ID:=Count;
Item.WiiMotes:=Self;
Result:=FItems.Add(Item);
end;
function TWiimotes.Count: integer;
begin
Result:=FItems.Count;
end;
procedure TWiimote.SetLEDs(const AValue: integer);
var
buf: byte;
begin
FLEDs:=AValue and $F0;
if Rumble then
FLEDs := FLEDs or 1;
if Connected then begin
buf := FLEDs;
SendCmd(WM_CMD_LED, @buf, 1);
end;
end;
function TWiimote.Connect: boolean;
var
Addr: sockaddr_l2;
begin
Addr.l2_family:=AF_BLUETOOTH;
Addr.l2_bdaddr:=bdaddr;
OutSocket:=fpsocket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
if (OutSocket = -1) then
exit(false);
{$IFDEF BIG_ENDIAN}
{$ERROR ToDo BIG_ENDIAN}
{$ENDIF}
Addr.l2_psm := WM_OUTPUT_CHANNEL;
if (fpconnect(OutSocket, psockaddr(@addr), SizeOf(addr)) < 0) then
raise Exception.Create('fpconnect output');
InSocket:=fpsocket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
if (InSocket = -1) then begin
CloseSocket(OutSocket);
OutSocket := -1;
exit(false);
end;
Addr.l2_psm := WM_INPUT_CHANNEL;
if (fpconnect(InSocket, psockaddr(@addr), SizeOf(addr)) < 0) then
begin
CloseSocket(OutSocket);
OutSocket := -1;
raise Exception.Create('fpconnect input');
end;
writeln('Connected to wiimote ',ID);
Connected:=true;
EnableHandshake;
RealizeReportType;
Result:=true;
end;
procedure TWiimote.Disconnect;
begin
if not Connected then exit;
CloseSocket(OutSocket);
CloseSocket(InSocket);
OutSocket:=-1;
InSocket:=-1;
Connected:=false;
Handshaking:=false;
HandshakeComplete:=false;
FRealizedIR:=false;
end;
procedure TWiimote.EnableHandshake;
begin
Handshaking:=true;
SetLEDs(WIIMOTE_LED_ALL);
RequestRead(@OnHandShake,WM_MEM_OFFSET_CALIBRATION, 7);
end;
function TWiimote.RealizeReportType: boolean;
var
buf: array[0..1] of byte;
begin
if not Connected then exit(false);
if Continuous then
buf[0] := 4 else
buf[0] :=0;
buf[1] := 0;
if Rumble then
buf[0] := buf[0] or 1;
if ReportMotion then buf[1] := buf[1] or WM_RPT_BTN_ACC;
if ReportExpansion then buf[1] := buf[1] or WM_RPT_BTN_EXP;
if ReportIR then buf[1] := buf[1] or WM_RPT_BTN_IR;
writeln('TWiiMote.RealizeReportType ',buf[1]);
if SendCmd(WM_CMD_REPORT_TYPE,@buf[0],2)<=0 then begin
writeln('TWiiMote.RealizeReportType FAILED');
exit(false);
end;
Result:=true;
end;
procedure TWiimote.RealizeIR;
var
buf: byte;
begin
if not HandshakeComplete then begin
writeln('TWiiMote.EnableIR still handshaking');
exit;
end;
if ReportIR=FRealizedIR then exit;
writeln('TWiiMote.RealizeIR ReportIR=',ReportIR);
if ReportIR then
buf:=4
else
buf:=0;
SendCmd(WM_CMD_IR,@buf,1);
SendCmd(WM_CMD_IR_2,@buf,1);
if ReportIR then begin
buf:=8;
SendData(WM_REG_IR,@buf,1);
Sleep(50);
SendData(WM_REG_IR_BLOCK1, Pointer(WM_IR_BLOCK1_CLIFF), length(WM_IR_BLOCK1_CLIFF));
SendData(WM_REG_IR_BLOCK2, Pointer(WM_IR_BLOCK2_CLIFF), length(WM_IR_BLOCK2_CLIFF));
if ReportExpansion then
buf := WM_IR_TYPE_BASIC
else
buf := WM_IR_TYPE_EXTENDED;
SendData(WM_REG_IR_MODENUM,@buf,1);
Sleep(50);
RealizeReportType;
writeln('TWiiMote.RealizeIR IR enabled');
end;
end;
procedure TWiimote.HandleEvents;
var
Data: PByte;
i: Integer;
begin
case EventBuf[1] of
WM_RPT_CTRL_STATUS:
begin
writeln('TWiiMote.HandleEvent WM_RPT_CTRL_STATUS');
end;
WM_RPT_READ:
begin
writeln('TWiiMote.HandleEvent WM_RPT_READ');
HandleRead;
end;
WM_RPT_WRITE:
begin
writeln('TWiiMote.HandleEvent WM_RPT_WRITE');
end;
WM_RPT_BTN:
begin
Buttons:=PWord(@EventBuf[2])^ and WIIMOTE_BUTTON_ALL;
writeln('TWiiMote.HandleEvent Button ',Buttons);
end;
WM_RPT_BTN_ACC or WM_RPT_BTN_IR:
begin
Buttons:=PWord(@EventBuf[2])^ and WIIMOTE_BUTTON_ALL;
Accel.x:=EventBuf[4];
Accel.y:=EventBuf[5];
Accel.z:=EventBuf[6];
Data:=PByte(@EventBuf[7]);
for i := 0 to 3 do begin
Dots[i].x := 1023 - (data[3*i] or ((data[(3*i)+2] and $30) shl 4));
Dots[i].y := data[(3*i)+1] or ((data[(3*i)+2] and $C0) shl 2);
Dots[i].size := data[(3*i)+2] and $0F;
Dots[i].visible := (Dots[i].y <> 1023);
end;
end;
else
writeln('TWiiMotes.HandleEvent other decimal=',EventBuf[1],' hex=',IntToHex(EventBuf[1],2));
end;
end;
procedure TWiimote.HandleRead;
var
Error: byte;
len: byte;
offset: word;
Request: TWiiMoteReadRequest;
begin
Buttons:=PWord(@EventBuf[2])^ and WIIMOTE_BUTTON_ALL;
if FReadRequests.Count=0 then begin
writeln('TWiiMote.HandleRead Received data packet whithout request');
exit;
end;
Error := EventBuf[4] and $0F;
....................... y sigue
En la linea en rojo me da el error de compilación:
/home/heppy/Downloads/bluetooth/wiimotetools.pas(311,5) Error: Fields cannot appear after a method or property definition, start a new visibility section first
Por más que lo miro y lo remiro, no encuentro solución.
Gracias y disculpad por el chorizo código.