-- Remote I/O Server Dispatcher for Raspberry Pi LPC1114 I/O Processor -- Expansion Board device commands -- Copyright (C)2019-2021, Philip Munts, President, Munts AM Corp. -- -- Redistribution and use in source and binary forms, with or without -- modification, are permitted provided that the following conditions are met: -- -- * Redistributions of source code must retain the above copyright notice, -- this list of conditions and the following disclaimer. -- -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -- POSSIBILITY OF SUCH DAMAGE. WITH Interfaces; WITH Logging.libsimpleio; WITH Message64; WITH Messaging; WITH RemoteIO.Dispatch; WITH RemoteIO.Executive; WITH SPI_Agent.Commands; WITH SPI_Agent.Messages; WITH SPI_Agent.Pins; WITH errno; USE TYPE Interfaces.Integer_32; USE TYPE Interfaces.Unsigned_32; USE TYPE Messaging.Byte; PACKAGE BODY RemoteIO.Device_SPIAgent IS -- Information string for DEVICE_INFO_REQUEST infostring : CONSTANT String := "LPC1114 I/O Processor SPI Agent"; -- Minimal binding to libspiagent.so PRAGMA Link_With("-lspiagent"); PROCEDURE open (server : String; error : OUT Interfaces.Unsigned_32); PRAGMA Import(C, open, "spiagent_open"); PROCEDURE command (command : IN SPI_Agent.Messages.SPIAGENT_COMMAND_MSG_t; response : OUT SPI_Agent.Messages.SPIAGENT_RESPONSE_MSG_t; error : OUT Interfaces.Integer_32); PRAGMA Import(C, command, "spiagent_command"); -- Query available abstract devices PROCEDURE Present (Self : IN OUT DispatcherSubclass; cmd : Message64.Message; resp : OUT Message64.message) IS BEGIN resp(0) := MessageTypes'Pos(DEVICE_PRESENT_RESPONSE); resp(1) := cmd(1); resp(2 .. 63) := (OTHERS => 0); resp(3) := 16#80#; -- Device 0 present END Present; -- Query abstract device information string PROCEDURE Info (Self : IN OUT DispatcherSubclass; cmd : Message64.Message; resp : OUT Message64.message) IS num : Natural; BEGIN resp(0) := MessageTypes'Pos(DEVICE_INFO_RESPONSE); resp(1) := cmd(1); resp(2 .. 63) := (OTHERS => 0); -- Extract the channel number parameter num := RemoteIO.ChannelNumber(cmd(2)); IF num >= RemoteIO.ChannelNumber'Last THEN resp(2) := errno.EINVAL; RETURN; END IF; IF num /= 0 THEN resp(2) := errno.ENODEV; RETURN; END IF; -- Copy the information string to the response buffer FOR i IN infostring'Range LOOP resp(2 + i) := Messaging.Byte(Character'Pos(infostring(i))); END LOOP; END; -- Execute an abstract device operation PROCEDURE Operation (Self : IN OUT DispatcherSubclass; cmd : Message64.Message; resp : OUT Message64.message) IS num : Natural; scmd : SPI_Agent.Messages.SPIAGENT_COMMAND_MSG_t; sresp : SPI_Agent.Messages.SPIAGENT_RESPONSE_MSG_t; error : Interfaces.Integer_32; BEGIN resp(0) := MessageTypes'Pos(DEVICE_OPERATION_RESPONSE); resp(1) := cmd(1); resp(2 .. 63) := (OTHERS => 0); -- Extract the channel number parameter num := RemoteIO.ChannelNumber(cmd(2)); IF num >= RemoteIO.ChannelNumber'Last THEN resp(2) := errno.EINVAL; RETURN; END IF; IF num /= 0 THEN resp(2) := errno.ENODEV; RETURN; END IF; -- Build SPI Agent command message scmd.Command := Interfaces.Unsigned_32(cmd(3))*16777216 OR Interfaces.Unsigned_32(cmd(4))*65536 OR Interfaces.Unsigned_32(cmd(5))*256 OR Interfaces.Unsigned_32(cmd(6)); scmd.Pin := Interfaces.Unsigned_32(cmd(7))*16777216 OR Interfaces.Unsigned_32(cmd(8))*65536 OR Interfaces.Unsigned_32(cmd(9))*256 OR Interfaces.Unsigned_32(cmd(10)); scmd.Data := Interfaces.Unsigned_32(cmd(11))*16777216 OR Interfaces.Unsigned_32(cmd(12))*65536 OR Interfaces.Unsigned_32(cmd(13))*256 OR Interfaces.Unsigned_32(cmd(14)); -- Dispatch SPI Agent command message command(scmd, sresp, error); -- Handle errors IF error /= 0 THEN resp(2) := Messaging.Byte(error); RETURN; END IF; IF sresp.Error /= 0 THEN resp(2) := Messaging.Byte(sresp.Error); RETURN; END IF; -- Copy response data resp(3) := Messaging.Byte(sresp.Command / 16777216); resp(4) := Messaging.Byte(sresp.Command / 65536 MOD 256); resp(5) := Messaging.Byte(sresp.Command / 256 MOD 256); resp(6) := Messaging.Byte(sresp.Command MOD 256); resp(7) := Messaging.Byte(sresp.Pin / 16777216); resp(8) := Messaging.Byte(sresp.Pin / 65536 MOD 256); resp(9) := Messaging.Byte(sresp.Pin / 256 MOD 256); resp(10) := Messaging.Byte(sresp.Pin MOD 256); resp(11) := Messaging.Byte(sresp.Data / 16777216); resp(12) := Messaging.Byte(sresp.Data / 65536 MOD 256); resp(13) := Messaging.Byte(sresp.Data / 256 MOD 256); resp(14) := Messaging.Byte(sresp.Data MOD 256); resp(15) := Messaging.Byte(sresp.Error / 16777216); resp(16) := Messaging.Byte(sresp.Error / 65536 MOD 256); resp(17) := Messaging.Byte(sresp.Error / 256 MOD 256); resp(18) := Messaging.Byte(sresp.Error MOD 256); END Operation; -- Create Remote I/O Protocol command dispatcher object FUNCTION Create (executor : IN OUT RemoteIO.Executive.Executor) RETURN Dispatcher IS Self : Dispatcher; BEGIN Self := NEW DispatcherSubclass'(NULL RECORD); executor.Register(DEVICE_PRESENT_REQUEST, RemoteIO.Dispatch.Dispatcher(Self)); executor.Register(DEVICE_INFO_REQUEST, RemoteIO.Dispatch.Dispatcher(Self)); executor.Register(DEVICE_OPERATION_REQUEST, RemoteIO.Dispatch.Dispatcher(Self)); RETURN Self; END Create; -- Dispatch Remote I/O Protocol commands PROCEDURE Dispatch (Self : IN OUT DispatcherSubclass; cmd : Message64.Message; resp : OUT Message64.Message) IS msgtype : MessageTypes; BEGIN msgtype := MessageTypes'Val(cmd(0)); CASE msgtype IS WHEN DEVICE_PRESENT_REQUEST => Present(Self, cmd, resp); WHEN DEVICE_INFO_REQUEST => Info(Self, cmd, resp); WHEN DEVICE_OPERATION_REQUEST => Operation(Self, cmd, resp); WHEN OTHERS => Logging.libsimpleio.Error("Unexected message type: " & MessageTypes'Image(msgtype)); END CASE; END Dispatch; error : Interfaces.Unsigned_32; BEGIN open("ioctl://localhost", error); IF (error /= 0) AND (error /= errno.EBUSY) THEN RAISE Program_Error WITH "Cannot initialize libsimpleio"; END IF; END RemoteIO.Device_SPIAgent;