IrDA.pbi

Share your advanced PureBasic knowledge/code with the community.
User avatar
HeX0R
Addict
Addict
Posts: 992
Joined: Mon Sep 20, 2004 7:12 am
Location: Hell

IrDA.pbi

Post by HeX0R »

This is an include to use IrDA devices (I only tested serial Irda adapters).
Supported os are windows and linux, macos shouldn't be a big deal either, this is just a little socket-action.

Remark:
It is only one connection at once allowed, but this should be enough anyway.
I was too lazy to add multi connections support.

Code: Select all

;*******************************************
;*
;*   Filename:     IrDA.pbi
;*   Version:      V1.0.0
;*   Date:         31.07.2015
;*   Author:       HeX0R
;*                 http://hex0rs.coderbu.de
;*
;*   License:      BEER-WARE
;*                 Thomas 'HeX0R' Milz wrote this file. As long as you retain this notice you
;*                 can do whatever you want with this stuff. If we meet some day, and you think
;*                 this stuff is worth it, you can buy me a beer in return.
;*                                                               HeX0R@coderbu.de
;*
;*   OS:           [x] Windows
;*                 [x] Linux
;*                 [ ] MacOS (someone needs to add the correct api calls and constants)
;*
;*   Description:  This is an include to use IrDA adapters
;*                 I only needed it for serial IrDA adapters, don't know if others will work also
;*
;*   useful links: [win]   https://msdn.microsoft.com/de-de/library/windows/desktop/ms738544%28v=vs.85%29.aspx
;*                 [linux] http://lxr.free-electrons.com/source/include/uapi/linux/irda.h#L124
;*
;*
;*   Usage
;*   Please have a look at the comments and at the example at the bottom of the code.
;*
;*
;*******************************************

DeclareModule IrDA
	
	Declare Init()
	Declare ExamineIrdaDevices()
	Declare NextIrdaDevice()
	Declare.s GetIrdaDeviceName()
	Declare GetIrdaDeviceID()
	Declare FinishExamineIrda()
	Declare Connect(DeviceID)
	Declare Disconnect()
	Declare SendData(*Buffer, BufferLen)
	Declare ReceiveData(*Buffer, BufferLen)
	Declare IsDataAvailable()
	Declare GetSockID()
	Declare GetLastError()
	
	CompilerSelect #PB_Compiler_OS
		CompilerCase #PB_OS_Windows
			
			;Error Handling
			#ERROR_NONE                     = #ERROR_SUCCESS
			#ERROR_NO_INIT_NETWORK          = #WSANOTINITIALISED
			#ERROR_NETWORK_DOWN             = #WSAENETDOWN
			#ERROR_NO_IRDA_SUPPORT          = #WSAEAFNOSUPPORT
			#ERROR_NO_MORE_DEVICES          = #WSAEMFILE
			#ERROR_ADDRESS_IN_USE           = #WSAEADDRINUSE
			#ERROR_NO_MEMORY                = #WSAENOBUFS
			#ERROR_PROTOCOL_NOT_SUPPORTED   = #WSAEPROTONOSUPPORT
			#ERROR_PROTOCOLTYPE_WRONG       = #WSAEPROTOTYPE
			#ERROR_NOT_YET_CONNECTED        = 1
			#ERROR_SOCKET_ALREADY_CONNECTED = #WSAEISCONN
			#ERROR_NO_EXAMINE_IRDA_DEVICES  = 2
			#ERROR_TIMED_OUT                = #WSAETIMEDOUT
			#ERROR_INVALID_SOCKET           = #INVALID_SOCKET
			
			

		CompilerCase #PB_OS_Linux
	
			;Error Handling
			;Errors
			#EAGAIN            = 11
			#EACCES            = 13
			#EAFNOSUPPORT      = 97
			#EINVAL            = 22
			#EMFILE            = 24
			#ENFILE            = 23
			#ENOBUFS           = 105
			#ENOMEM            = 12
			#EPROTONOSUPPORT   = 93
			
			#ERROR_NONE                     = 0
			#ERROR_NO_INIT_NETWORK          = -4
			#ERROR_NETWORK_DOWN             = 0
			#ERROR_NO_IRDA_SUPPORT          = #EAGAIN
			#ERROR_NO_MORE_DEVICES          = -2
			#ERROR_ADDRESS_IN_USE           = 0
			#ERROR_NO_MEMORY                = #ENOBUFS
			#ERROR_PROTOCOL_NOT_SUPPORTED   = #EINVAL
			#ERROR_PROTOCOLTYPE_WRONG       = #EACCES
			#ERROR_NOT_YET_CONNECTED        = -5
			#ERROR_SOCKET_ALREADY_CONNECTED = 0
			#ERROR_NO_EXAMINE_IRDA_DEVICES  = -3
			#ERROR_TIMED_OUT                = 0
			#ERROR_INVALID_SOCKET           = -1
			

	CompilerEndSelect
	
EndDeclareModule

Module IrDa
	
	CompilerSelect #PB_Compiler_OS
		CompilerCase #PB_OS_Windows
			
			Procedure __GetLastError()
				ProcedureReturn WSAGetLastError_()
			EndProcedure
			
			Structure SOCKADDR_IRDA
				irdaAddressFamily.w
				irdaDeviceID.l
				irdaServiceName.b[25]
			EndStructure

			Structure IRDA_DEVICE_INFO
				irdaDeviceID.l
				irdaDeviceName.b[22]
				Reserved.b[2]
			EndStructure

			Structure DEVICELIST
				numDevice.l
				Device.IRDA_DEVICE_INFO[0]
			EndStructure
			#AF_IRDA = 26
			#PF_IRDA = #AF_IRDA

			#SOL_IRLMP            = $00FF;

			#IRLMP_ENUMDEVICES    = $00000010;
			#IRLMP_IAS_SET        = $00000011;
			#IRLMP_IAS_QUERY      = $00000012;
			#IRLMP_SEND_PDU_LEN   = $00000013;
			#IRLMP_EXCLUSIVE_MODE = $00000014;
			#IRLMP_IRLPT_MODE     = $00000015;
			#IRLMP_9WIRE_MODE     = $00000016;
			#IRLMP_TINYTP_MODE    = $00000017;
			#IRLMP_PARAMETERS     = $00000018;
			#IRLMP_DISCOVERY_MODE = $00000019;

			#IAS_ATTRIB_NO_CLASS  = $00000010;
			#IAS_ATTRIB_NO_ATTRIB = $00000000;
			#IAS_ATTRIB_INT       = $00000001;
			#IAS_ATTRIB_OCTETSEQ  = $00000002;
			#IAS_ATTRIB_STR       = $00000003;

			#IAS_MAX_USER_STRING  = 256;
			#IAS_MAX_OCTET_STRING = 1024;
			#IAS_MAX_CLASSNAME    = 64;
			#IAS_MAX_ATTRIBNAME   = 256;

		CompilerCase #PB_OS_Linux
	
			ImportC ""
  			errno_location() As "__errno_location"
  		EndImport
  		
  		Procedure __GetLastError()
  			ProcedureReturn PeekL(errno_location())
  		EndProcedure

  		#AF_IRDA           = 23
  		#FIONREAD          = $541B
			#SOL_IRLMP         = 266
			#SOL_IRDA          = 266
			#IRLMP_ENUMDEVICES = 1
			#SOCK_STREAM       = 1

			Structure SOCKADDR_IRDA
				irdaAddressFamily.w
				sir_lsap_sel.b
				irdaDeviceID.l
				irdaServiceName.b[25]
			EndStructure
			
			Structure IRDA_DEVICE_INFO
				saddr.l
				irdaDeviceID.l
				irdaDeviceName.b[22]
				charset.b
				hints.b[2]
			EndStructure
			
			Structure DEVICELIST
				numDevice.l
				Device.IRDA_DEVICE_INFO[0]
			EndStructure
	CompilerEndSelect
	
	InitNetwork()
	EnableExplicit
	
	Global DestSockAddr.SOCKADDR_IRDA
	Global *pDevList.DEVICELIST
	Global Socket, DeviceNum, LastError
	
	Procedure Init()
		;Always use Init first and also check the result
		;After a Disconnect() you need to call Init() again before you can use Connect()!!
		
		LastError                      = #ERROR_NONE
		DestSockAddr\irdaAddressFamily = #AF_IRDA
		DestSockAddr\irdaDeviceID      = 0
		PokeS(@DestSockAddr\irdaServiceName[0], "SampleIrDAService", -1, #PB_Ascii)
	
		Socket = SOCKET_(#AF_IRDA, #SOCK_STREAM, 0)
		If Socket = #ERROR_INVALID_SOCKET
			Socket    = 0
			LastError = __GetLastError()
			ProcedureReturn #False
		EndIf
		
		ProcedureReturn Socket
	EndProcedure
	
	Procedure ExamineIrdaDevices()
		;Start examination of Irda Devices
		
		Protected pDevListLen
		
		LastError = #ERROR_NONE
		If Socket = 0
			LastError = #ERROR_NO_INIT_NETWORK
			ProcedureReturn #False
		EndIf
		*pDevList           = AllocateMemory(4096)
		*pDevList\numDevice = 0
		pDevListLen         = MemorySize(*pDevList)
		
		If getsockopt_(Socket, #SOL_IRLMP, #IRLMP_ENUMDEVICES, *pDevList, @pDevListLen) = #ERROR_INVALID_SOCKET
			LastError = __GetLastError()
			ProcedureReturn #False
		EndIf
		
		If *pDevList\numDevice = 0
			LastError = #ERROR_NO_MORE_DEVICES
			Debug "No IRDA devices were discovered or cached"	
			ProcedureReturn #False
		EndIf
		DeviceNum = 0
		
		ProcedureReturn #True
	EndProcedure
	
	Procedure NextIrdaDevice()
		;Lets examine the next Irda device
		
		LastError = #ERROR_NONE
		If Socket = 0
			LastError = #ERROR_NO_INIT_NETWORK
			ProcedureReturn #False
		ElseIf *pDevList = 0
			LastError = #ERROR_NO_EXAMINE_IRDA_DEVICES
			ProcedureReturn #False
		ElseIf *pDevList\numDevice = 0
			Lasterror = #ERROR_NO_MORE_DEVICES
			ProcedureReturn #False
		EndIf
		
		DeviceNum + 1
		If DeviceNum > *pDevList\numDevice
			Lasterror = #ERROR_NO_MORE_DEVICES
			ProcedureReturn #False
		EndIf
		
		ProcedureReturn #True
	EndProcedure
	
	Procedure.s GetIrdaDeviceName()
		;this is th current DeviceName
		
		LastError = #ERROR_NONE
		If Socket = 0
			LastError = #ERROR_NO_INIT_NETWORK
			ProcedureReturn ""
		ElseIf *pDevList = 0
			LastError = #ERROR_NO_EXAMINE_IRDA_DEVICES
			ProcedureReturn ""
		ElseIf *pDevList\numDevice < DeviceNum
			Lasterror = #ERROR_NO_MORE_DEVICES
			ProcedureReturn ""
		EndIf
		
		ProcedureReturn PeekS(@*pDevList\Device[DeviceNum - 1]\irdaDeviceName[0], -1, #PB_Ascii)
	EndProcedure
	
	Procedure GetIrdaDeviceID()
		;this is the current examined DeviceID
		
		LastError = #ERROR_NONE
		If Socket = 0
			LastError = #ERROR_NO_INIT_NETWORK
			ProcedureReturn #False
		ElseIf *pDevList = 0
			LastError = #ERROR_NO_EXAMINE_IRDA_DEVICES
			ProcedureReturn #False
		ElseIf *pDevList\numDevice < DeviceNum
			Lasterror = #ERROR_NO_MORE_DEVICES
			ProcedureReturn #False
		EndIf
		
		ProcedureReturn *pDevList\Device[DeviceNum - 1]\irdaDeviceID
	EndProcedure
	
	Procedure FinishExamineIrda()
		;Finish examination previously started with ExamineIrdaDevices()
		
		LastError = #ERROR_NONE
		If Socket = 0
			LastError = #ERROR_NO_INIT_NETWORK
			ProcedureReturn #False
		EndIf
		If *pDevList
			FreeMemory(*pDevList)
			*pDevList = 0
		EndIf
		DeviceNum = 0
		
	EndProcedure
	
	Procedure Connect(DeviceID)
		;Connect to the IrDA Decide #DeviceID
		;You can get the Device ID with the examine procedures:
		;ExamineDevices(), NextIrdaDevice(), GetIrdaDeviceID(), GetIrdaDeviceName(), FinishExamineIrda()
		
		LastError = #ERROR_NONE
		If Socket = 0
			LastError = #ERROR_NO_INIT_NETWORK
			ProcedureReturn #False
		ElseIf DestSockAddr\irdaDeviceID <> 0
			LastError = #ERROR_SOCKET_ALREADY_CONNECTED
			ProcedureReturn #False
		EndIf
		DestSockAddr\irdaDeviceID = DeviceID
		If connect_(Socket, @DestSockAddr, SizeOf(SOCKADDR_IRDA)) = #ERROR_INVALID_SOCKET
			DestSockAddr\irdaDeviceID = 0
			LastError                 = __GetLastError()
			ProcedureReturn #False
		EndIf
		
		ProcedureReturn #True
	EndProcedure
	
	Procedure Disconnect()
		;IF YOU WANT TO REOPEN A IRDA SOCKET, RECALL INIT()!!
		;A SIMPLE CONNECT() WILL NOT BE ENOUGH!
		
		LastError = #ERROR_NONE
		If Socket = 0
			LastError = #ERROR_NO_INIT_NETWORK
		Else
			CompilerSelect #PB_Compiler_OS
				CompilerCase #PB_OS_Windows
					If closesocket_(Socket) = #ERROR_INVALID_SOCKET
						LastError = __GetLastError()
					EndIf
				CompilerCase #PB_OS_Linux
					If close_(Socket) = #ERROR_INVALID_SOCKET
						LastError = __GetLastError()
					EndIf
			CompilerEndSelect
		EndIf
		
		Socket                    = 0
		DestSockAddr\irdaDeviceID = 0
		
		ProcedureReturn #True
	EndProcedure
	
	Procedure SendData(*Buffer, BufferLen)
		;send data in *Buffer via IrDA
		
		Protected Length
		
		LastError = #ERROR_NONE
		If Socket = 0
			LastError = #ERROR_NO_INIT_NETWORK
			ProcedureReturn #False
		ElseIf DestSockAddr\irdaDeviceID = 0
			LastError = #ERROR_NOT_YET_CONNECTED
			ProcedureReturn #False
		EndIf
		
		Length = send_(Socket, *Buffer, BufferLen, 0)
		If Length = #ERROR_INVALID_SOCKET
			LastError = __GetLastError()
		EndIf
		
		ProcedureReturn Length
	EndProcedure
	
	Procedure IsDataAvailable()
		;Checks if data is available and will then return the amount of data waiting.
		;similar to AvailableSerialPortInput
		
		Protected Length
	
		If Socket = 0
			LastError = #ERROR_NO_INIT_NETWORK
			ProcedureReturn -1
		ElseIf DestSockAddr\irdaDeviceID = 0
			LastError = #ERROR_NOT_YET_CONNECTED
			ProcedureReturn -1
		EndIf
		
		CompilerSelect #PB_Compiler_OS
			CompilerCase #PB_OS_Windows
				ioctlsocket_(Socket, #FIONREAD, @Length)
			CompilerCase #PB_OS_Linux
				ioctl_(Socket, #FIONREAD, @Length)
		CompilerEndSelect
	
		ProcedureReturn Length
	EndProcedure	

	Procedure ReceiveData(*Buffer, BufferLen)
		;Receive data from the IrDA into *Buffer
		;Will return the length it has been received.
		
		Protected Length
		
		LastError = #ERROR_NONE
		If Socket = 0
			LastError = #ERROR_NO_INIT_NETWORK
			ProcedureReturn #False
		ElseIf DestSockAddr\irdaDeviceID = 0
			LastError = #ERROR_NOT_YET_CONNECTED
			ProcedureReturn #False
		EndIf
		
		Length = recv_(Socket, *Buffer, BufferLen, 0)
		If Length = #ERROR_INVALID_SOCKET
			LastError = __GetLastError()
		EndIf
		
		ProcedureReturn Length
	EndProcedure
	
	Procedure GetSockID()
		;Get the os handle of our socket
		
		If Socket = 0
			LastError = #ERROR_NO_INIT_NETWORK
			ProcedureReturn #False
		EndIf
		
		ProcedureReturn Socket
	EndProcedure
	
	Procedure GetLastError()
		
		ProcedureReturn LastError
	EndProcedure
	
EndModule
	


;Example Code


CompilerIf #PB_Compiler_IsMainFile
	
	Procedure.s ParseErrorMessages()
		Protected Error, Result.s
		
		Select IrDA::GetLastError()
			Case IRDA::#ERROR_NONE
				Result = "There were no error!"
			Case IRDA::#ERROR_NO_INIT_NETWORK
				Result = "It seems you have network problems or didn't call IRDA::Init()!"
			Case IRDA::#ERROR_NETWORK_DOWN
				Result = "Network down!"
			Case IRDA::#ERROR_NO_IRDA_SUPPORT
				Result = "Check that the local computer has an infrared device and a device driver is installed!"
			Case IRDA::#ERROR_NO_MORE_DEVICES
				Result = "No (more) IrDA deviced found"
			Case IRDA::#ERROR_ADDRESS_IN_USE
				Result = "The Socket seems to be in use!"
			Case IRDA::#ERROR_NO_MEMORY
				Result = "Memory problems!"
			Case IRDA::#ERROR_PROTOCOL_NOT_SUPPORTED
				Result = "The protocol is not supported?!"
			Case IRDA::#ERROR_PROTOCOLTYPE_WRONG
				Result = "Wrong protocol type!"
			Case IRDA::#ERROR_NOT_YET_CONNECTED
				Result = "The socket is not connected!"
			Case IRDA::#ERROR_SOCKET_ALREADY_CONNECTED
				Result = "This socket is already connected!"
			Case IRDA::#ERROR_NO_EXAMINE_IRDA_DEVICES
				Result = "You didn't call IRDA::ExamineIrdaDevices() first!"
			Case IRDA::#ERROR_TIMED_OUT
				Result = "Request timed out!"
		EndSelect
		
		ProcedureReturn Result
	EndProcedure
		
	Procedure main()
		Protected i
		
		If IrDA::Init() = #False
			Debug "Init failed!"
			Debug ParseErrorMessages()
			ProcedureReturn
		EndIf

		If IrDa::ExamineIrdaDevices()
			While IrDA::NextIrdaDevice()
				Debug IrDA::GetIrdaDeviceName()
				Debug IrDA::GetIrdaDeviceID()
				i = IrDA::GetIrdaDeviceID() ;<- keep the first device in mind
			Wend
			IrDA::FinishExamineIrda()
	
			If IrDA::Connect(i)
				Debug "ok"
				Debug IrDA::Disconnect()
			Else
				Debug "Connection failed!"
				Debug ParseErrorMessages()
			EndIf
		Else
			Debug "Examination failed!"
			Debug ParseErrorMessages()
		EndIf
	EndProcedure
	
	main()
CompilerEndIf
juror
Enthusiast
Enthusiast
Posts: 228
Joined: Mon Jul 09, 2007 4:47 pm
Location: Courthouse

Re: IrDA.pbi

Post by juror »

Nice one
HeX0R wrote:If we meet some day, and you think
;* this stuff is worth it, you can buy me a beer in return.
;* HeX0R@coderbu.de
HeX0R
Joined: Mon Sep 20, 2004 1:12 am
Posts: 352
Location: Hell

I'm sure I'll see you. Hope there's a bar ;)
User avatar
HeX0R
Addict
Addict
Posts: 992
Joined: Mon Sep 20, 2004 7:12 am
Location: Hell

Re: IrDA.pbi

Post by HeX0R »

juror wrote:I'm sure I'll see you. Hope there's a bar ;)
Sure, but I fear they won't have any cold drinks ;)
Post Reply