unit DIOExports;

interface

uses
	Winapi.Windows,
	Core;

function DIO_Configure(uClientRef: TClientRef; pDataBytes: TPUInt32; pData: TPUInt8; pDirection: TPUInt8): TWinErrCode; cdecl;
function DIO_ReadDirection(uClientRef: TClientRef; pDataBytes: TPUInt32; pData: TPUInt8): TWinErrCode; cdecl;
function DIO_WriteAll(uClientRef: TClientRef; pDataBytes: TPUInt32; pData: TPUInt8): TWinErrCode; cdecl;
//function DIO_Write1(uClientRef: TClientRef; BitIndex: TSInt32; bNewValue: ByteBool): TWinErrCode; cdecl;
//function DIO_WriteMasked(uClientRef: TClientRef; pDataMaskBytes: TPUInt32; pDataMask: TPUInt8; pDataBytes: TSInt32; pData: TPUInt8): TWinErrCode; cdecl;
function DIO_ReadAll(uClientRef: TClientRef; pDataBytes: TPUInt32; pData: TPUInt8): TWinErrCode; cdecl;





implementation

uses
	Math,
	CoreDataMessages, ENetDataItems;

const
	DIOTarLen = 4; //In raw data bytes, each of which is 2 bytes in the packet.



function DIO_Configure(uClientRef: TClientRef; pDataBytes: TPUInt32; pData: TPUInt8; pDirection: TPUInt8): TWinErrCode; cdecl;
var
	ThisClient: TRefClient;
	DataBuf, DirectionBuf: TUInt32;
	Msg: TMessageItem;

begin
	Result := VerifyClientRef(uClientRef);
	if Result <> ERROR_SUCCESS then Exit;

	ThisClient := Pointer(uClientRef);

	try
		DataBuf := 0;
		DirectionBuf := 0;
		try
			pDataBytes^ := Min(pDataBytes^, SizeOf(DataBuf)); //Relies on SizeOf(DataBuf) = SizeOf(DirectionBuf).
			Move(pData^, DataBuf, pDataBytes^);
			Move(pDirection^, DirectionBuf, pDataBytes^);
		except
			Result := ERROR_NOACCESS;
			Exit;
		end;

		Msg := TMessageItem.Create;
		Msg.MID := MIDMixed;
		with TWriteRegDataItem(Msg.AddNewDataItem(TWriteRegDataItem)) do begin
			RegOff := $3C;
			RegData := DirectionBuf;
			RegDataSize := rds32;
		end;
		with TWriteRegDataItem(Msg.AddNewDataItem(TWriteRegDataItem)) do begin
			RegOff := $40;
			RegData := DataBuf;
			RegDataSize := rds32;
		end;

		Result := ThisClient.SendReceiveMsgAndExpectOK(Msg);

		Msg.Free;
	except
		Result := ERROR_INTERNAL_ERROR;
	end;
end;

function DIO_ReadDirection(uClientRef: TClientRef; pDataBytes: TPUInt32; pData: TPUInt8): TWinErrCode; cdecl;
var
	ThisClient: TRefClient;
	DataBytes: TSInt32;
	Msg: TMessageItem;

begin
	Result := VerifyClientRef(uClientRef);
	if Result <> ERROR_SUCCESS then begin
		try pDataBytes^ := 0; except end;
		Exit;
	end;

	ThisClient := Pointer(uClientRef);

	try
		try
			DataBytes := pDataBytes^;
		except
			Result := ERROR_BAD_LENGTH;
			try pDataBytes^ := 0; except end;
			Exit;
		end;

		try
			pDataBytes^ := 0;
			FillChar(pData^, DataBytes, 0);
		except
			Result := ERROR_NOACCESS;
			Exit;
		end;

		Msg := TMessageItem.Create;
		try
			Msg.MID := MIDMixed;
			with TReadRegDataItem(Msg.AddNewDataItem(TReadRegDataItem)) do begin
				RegOff := $3C;
			end;

			Result := ThisClient.SendReceiveMsgAndExpectOK(Msg);
			if Result <> ERROR_SUCCESS then Exit;

			with TReadRegReplyDataItem(Msg.DataItem[0]) do begin
				if RegDataSize = rds32 then
					DataBytes := Min(4, DataBytes)
				else
					DataBytes := Min(1, DataBytes)
				;
				try
					Move(RegData, pData^, DataBytes);
				except
					Result := ERROR_NOACCESS;
					DataBytes := 0;
				end;
			end;
		finally
			Msg.Free;
		end;

		pDataBytes^ := DataBytes;
	except
		Result := ERROR_INTERNAL_ERROR;
	end;
end;

function DIO_WriteAll(uClientRef: TClientRef; pDataBytes: TPUInt32; pData: TPUInt8): TWinErrCode; cdecl;
var
	ThisClient: TRefClient;
	DataBuf: TUInt32;
	Msg: TMessageItem;

begin
	Result := VerifyClientRef(uClientRef);
	if Result <> ERROR_SUCCESS then Exit;

	ThisClient := Pointer(uClientRef);

	try
		DataBuf := 0;
		try
			pDataBytes^ := Min(pDataBytes^, SizeOf(DataBuf));
			Move(pData^, DataBuf, pDataBytes^);
		except
			Result := ERROR_NOACCESS;
			Exit;
		end;

		Msg := TMessageItem.Create;
		try
			Msg.MID := MIDMixed;
			with TWriteRegDataItem(Msg.AddNewDataItem(TWriteRegDataItem)) do begin
				RegOff := $40;
				RegData := DataBuf;
				RegDataSize := rds32;
			end;

			Result := ThisClient.SendReceiveMsgAndExpectOK(Msg);
		finally
			Msg.Free;
		end;
	except
		Result := ERROR_INTERNAL_ERROR;
	end;
end;

function DIO_ReadAll(uClientRef: TClientRef; pDataBytes: TPUInt32; pData: TPUInt8): TWinErrCode; cdecl;
var
	ThisClient: TRefClient;
	DataBytes: TSInt32;
	Msg: TMessageItem;

begin
	Result := VerifyClientRef(uClientRef);
	if Result <> ERROR_SUCCESS then begin
		try pDataBytes^ := 0; except end;
		Exit;
	end;

	ThisClient := Pointer(uClientRef);

	try
		try
			DataBytes := pDataBytes^;
		except
			Result := ERROR_BAD_LENGTH;
			try pDataBytes^ := 0; except end;
			Exit;
		end;

		try
			pDataBytes^ := 0;
			FillChar(pData^, DataBytes, 0);
		except
			Result := ERROR_NOACCESS;
			Exit;
		end;

		Msg := TMessageItem.Create;
		try
			Msg.MID := MIDMixed;
			with TReadRegDataItem(Msg.AddNewDataItem(TReadRegDataItem)) do begin
				RegOff := $44;
			end;

			Result := ThisClient.SendReceiveMsgAndExpectOK(Msg);
			if Result <> ERROR_SUCCESS then Exit;

			with TReadRegReplyDataItem(Msg.DataItem[0]) do begin
				if RegDataSize = rds32 then
					DataBytes := Min(4, DataBytes)
				else
					DataBytes := Min(1, DataBytes)
				;
				try
					Move(RegData, pData^, DataBytes);
				except
					Result := ERROR_NOACCESS;
					DataBytes := 0;
				end;
			end;
		finally
			Msg.Free;
		end;

		pDataBytes^ := DataBytes;
	except
		Result := ERROR_INTERNAL_ERROR;
	end;
end;

end.