program ei_eio_i2c_55;
(* This is a companion to ei_eio_serial.ino, which is assumed to be compiled *)
(* with I2C support enabled and to respond to "EI\r" with "EIO\r". MarkMLl. *)
{$mode objfpc}{$H+}
{$assertions on }
uses
Sysutils, BaseUnix, crt;
const
I2C_SLAVE = 1795;
type
responseType= (none, bad, ok);
var
slave: dword= $55;
fd: cint;
scratch: integer;
ei: string[15]= 'EI' + #$0d;
response: string;
(* Convert the Data parameter from a word to a pointer. This should have
lots of sanity checks, i.e. that the IOCTL number is known to be one
that doesn't take a pointer, that the value being cast is actually small
and so on.
*)
function fpIoctl(Handle: cint; Ndx: TIOCtlRequest; Data: dword): cint;
begin
Assert(Ndx = I2C_SLAVE, 'Bad IOCTL number');
Assert(Data < 256, 'Bad IOCTL parameter');
result := BaseUnix.FpIOCtl(Handle, Ndx, pointer(ptruint(Data)))
end { fpIoctl } ;
(* Assume that messages are fixed-format and that we're looking for EIO
followed by stuff.
*)
function getResponse(Handle: cint): responseType;
// Apparently an Arduino I2C message is restricted by buffer length to 32 bytes,
// and a serial message to 64 bytes. This suggests that, assuming text-format
// rather than binary data, individual lines are probably best kept below 32
// characters and possibly when generated zero-padded to precisely 32 bytes even
// if trimmed before being sent as text.
begin
response := '........................'; (* 24 characters *)
Sleep(100); (* Milliseconds *)
if fpRead(Handle, response[1], 24) <> 24 then
if response[1] = '.' then (* No response at all *)
exit(none)
else (* Didn't get to \r *)
exit(bad);
if (Pos('EIO', response) <> 1) or (Pos(#$0d, response) = 0) then
exit(bad) (* Not quite right *)
else begin (* Got it *)
SetLength(response, Pos(#$0d, response) - 1);
exit(ok)
end
end { getResponse } ;
begin
fd := fpOpen('/dev/i2c-1', O_RDWR);
Assert(fd >= 0, 'Open failed');
scratch := fpIoctl(fd, I2C_SLAVE, slave);
Assert(scratch = 0, 'Slave assignment failed');
repeat
case getResponse(fd) of
none: WriteLn('Read timed out');
bad: WriteLn('Read incomplete')
end;
until keypressed;
scratch := fpClose(fd);
Assert(scratch = 0, 'Close failed');
WriteLn('EXIT OK')
end.