PageRenderTime 43ms CodeModel.GetById 15ms app.highlight 24ms RepoModel.GetById 1ms app.codeStats 0ms

/src/ois/src/extras/LIRC/OISLIRCFactoryCreator.cpp

https://bitbucket.org/cabalistic/ogredeps/
C++ | 405 lines | 285 code | 66 blank | 54 comment | 84 complexity | ddf1f73b81f34e515a24700bb837b0fa MD5 | raw file
  1#include "OISConfig.h"
  2#ifdef OIS_LIRC_SUPPORT
  3/*
  4The zlib/libpng License
  5
  6Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com)
  7
  8This software is provided 'as-is', without any express or implied warranty. In no event will
  9the authors be held liable for any damages arising from the use of this software.
 10
 11Permission is granted to anyone to use this software for any purpose, including commercial 
 12applications, and to alter it and redistribute it freely, subject to the following
 13restrictions:
 14
 15    1. The origin of this software must not be misrepresented; you must not claim that 
 16		you wrote the original software. If you use this software in a product, 
 17		an acknowledgment in the product documentation would be appreciated but is 
 18		not required.
 19
 20    2. Altered source versions must be plainly marked as such, and must not be 
 21		misrepresented as being the original software.
 22
 23    3. This notice may not be removed or altered from any source distribution.
 24*/
 25#include "OISLIRCFactoryCreator.h"
 26#include "OISException.h"
 27#include <assert.h>
 28#include <stdlib.h>
 29
 30#ifdef OIS_WIN32_PLATFORM
 31#  pragma warning (disable : 4996)
 32#  pragma warning (disable : 4267)
 33#  pragma warning (disable : 4554)
 34#  pragma warning (disable : 4996)
 35#  define _WIN32_WINNT 0x0500
 36#endif
 37#include <boost/asio.hpp>
 38#include <boost/bind.hpp>
 39#include <boost/thread.hpp>
 40
 41#include <istream>
 42#include <sstream>
 43
 44using namespace OIS;
 45
 46//---------------------------------------------------------------------------------//
 47class LIRCFactoryCreator::BoostWrapper
 48{
 49public:
 50	LIRCFactoryCreator::BoostWrapper() : mSocket(mIOService), mThreadHandler(0)
 51	{
 52	}
 53
 54	//TCP stuff
 55	boost::asio::io_service mIOService;
 56	boost::asio::ip::tcp::socket mSocket;
 57
 58	//Thread Stuff
 59	//! Boost thread execution object (only alive when at least 1 lirc is alive)
 60	boost::thread *mThreadHandler;
 61		
 62	//! Gaurds access to the active lirc list
 63	boost::mutex mLircListMutex;
 64
 65};
 66
 67//---------------------------------------------------------------------------------//
 68LIRCFactoryCreator::LIRCFactoryCreator() :
 69	mConnected(false),
 70	mThreadRunning(false),
 71	mCount(0),
 72	mWrapped(0)
 73{
 74	mWrapped = new BoostWrapper();
 75
 76	mIP   = (getenv("OIS_LIRC_IP") != 0) ? getenv("OIS_LIRC_IP") : "127.0.0.1";
 77	mPort = (getenv("OIS_LIRC_PORT") != 0) ? getenv("OIS_LIRC_PORT") : "8765";
 78
 79	try
 80	{
 81		enableConnection(true);
 82		discoverRemotes();
 83	}
 84	catch(...)
 85	{
 86		mCount = 0;
 87	}
 88
 89	//Regardless of if there is remotes or not, we will close the conenction now.
 90	enableConnection(false);
 91}
 92
 93//---------------------------------------------------------------------------------//
 94LIRCFactoryCreator::~LIRCFactoryCreator()
 95{
 96	enableConnectionThread(false);
 97	enableConnection(false);
 98
 99	delete mWrapped;
100}
101
102//---------------------------------------------------------------------------------//
103void LIRCFactoryCreator::discoverRemotes()
104{
105	//http://www.lirc.org/html/technical.html#applications
106	mCount = 0;
107
108	mWrapped->mSocket.write_some(boost::asio::buffer("LIST\n"));
109
110	boost::asio::streambuf buffer;
111
112	//Read all remotes
113	bool start = false;
114	bool data = false;
115	for(;;)
116	{
117		boost::asio::read_until(mWrapped->mSocket, buffer, '\n');
118
119		std::istream str(&buffer);
120		std::string res;
121		str >> res;
122
123		if( res == "" )				//If nothing left, we are done
124			break;
125		else if( res == "ERROR" )	//If any errors, we leave immediately
126			return;
127		else if( res == "END" )		//We have reached the end block
128			start = false;
129		else if( res == "DATA" )	//After Data will be a list of remote names
130		{
131			start = true;
132			data = true;
133			continue;
134		}
135
136		//Have we  gotten the DATA word yet?
137		if( start == false )
138			continue;
139
140		if( data ) //How many?
141			mCount = atoi(res.c_str());
142		else //What follows should now be a list of remote names
143			mUnusedRemotes.push_back(res);
144
145		data = false;
146	}
147
148	//Read information about each remote
149	boost::asio::streambuf buffer2;
150	for( int i = 0; i < mCount; ++i )
151	{
152		std::ostringstream istr;
153		istr << "LIST " << mUnusedRemotes[i] << "\n";
154		
155		mWrapped->mSocket.write_some(boost::asio::buffer(istr.str()));
156		RemoteInfo information;
157		int buttonCount = 0;
158
159		start = data = false;
160		
161		for(;;)
162		{
163			boost::asio::read_until(mWrapped->mSocket, buffer, '\n');
164
165			std::istream str(&buffer);
166			std::string res;
167			str >> res;
168
169			if( res == "" )				//If nothing left, we are done
170				break;
171			else if( res == "ERROR" )	//If error, bail out
172				return;
173			else if( res == "END" )		//We have reached the end block
174				start = false;
175			else if( res == "DATA" )	//After Data will be button count
176			{
177				start = true;
178				data = true;
179				continue;
180			}
181
182			//Have we  gotten the DATA word yet?
183			if( start == false )
184				continue;
185
186			if( data ) //After button count, there will be a list of button names
187				information.buttons = atoi(res.c_str());
188			else
189				information.buttonMap[res] = buttonCount++;
190
191			data = false;
192		}
193
194		mJoyStickInformation[mUnusedRemotes[i]] = information;
195	}
196}
197
198//---------------------------------------------------------------------------------//
199void LIRCFactoryCreator::enableConnection(bool enable, bool blocking)
200{
201	if( enable == true && mConnected == false )
202	{
203		boost::asio::ip::tcp::resolver resolver(mWrapped->mIOService);
204		boost::asio::ip::tcp::resolver::query query(mIP, mPort);
205		boost::asio::ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
206		boost::asio::ip::tcp::resolver::iterator end;
207
208		//Connect (trying all found connections - ip4/ip6)
209		boost::asio::error result = boost::asio::error::host_not_found;
210		while (result && endpoint_iterator != end)
211		{
212			mWrapped->mSocket.close();
213			mWrapped->mSocket.connect(*endpoint_iterator++, boost::asio::assign_error(result));
214		}
215
216		if (result != boost::asio::error::success)
217			throw (result);
218
219		if( blocking == false )
220		{
221			mWrapped->mSocket.io_control(boost::asio::socket_base::non_blocking_io(true));
222		}
223
224		mConnected = true;
225	}
226	else if( enable == false )
227	{
228		mWrapped->mSocket.close();
229		mConnected = false;
230	}
231}
232
233//---------------------------------------------------------------------------------//
234void LIRCFactoryCreator::enableConnectionThread(bool enable)
235{
236	if( enable == true && mThreadRunning == false )
237	{
238		mThreadRunning = true;
239		mWrapped->mThreadHandler = new boost::thread(boost::bind(&LIRCFactoryCreator::threadUpdate, this));
240	}
241	else if( enable == false && mThreadRunning == true )
242	{
243		mThreadRunning = false;
244		mWrapped->mThreadHandler->join();
245		delete mWrapped->mThreadHandler;
246		mWrapped->mThreadHandler = 0;
247	}
248}
249
250//---------------------------------------------------------------------------------//
251void LIRCFactoryCreator::threadUpdate()
252{
253	boost::xtime timer;
254	boost::asio::streambuf buffer;
255	std::istream stream(&buffer);
256	std::string code, repeat, button, remote;
257
258
259	while( mThreadRunning )
260	{
261		try
262		{
263			while(  mWrapped->mSocket.in_avail() > 0 )
264			{
265				boost::asio::read_until(mWrapped->mSocket, buffer, '\n');
266				
267				stream >> code;   //64 bit value, ignorable
268				stream >> repeat; //Repeat rate starting at zero (we ignore, for now)
269				stream >> button; //Button name
270				stream >> remote; //Remote name
271
272				{	//Lock object, find out which remote sent event
273					boost::mutex::scoped_lock arrayLock(mWrapped->mLircListMutex);
274					std::map<std::string, LIRCControl*>::iterator i = mUpdateRemotes.find(remote);
275					if( i != mUpdateRemotes.end() )
276					{
277						i->second->queueButtonPressed(button);
278					}
279				}
280			}
281		}
282		catch(...)
283		{	//Hmm, what should we do if we get a socket error here.. Ignore it I suppose,
284		}	//and wait till the used remote objects get shutdown. We could try to 
285			//reconnect, but how do we know if we will even get the same remotes.
286
287		boost::xtime_get(&timer, boost::TIME_UTC);
288		timer.nsec += 300000000; // 100 000 000 ~= .3 sec
289		boost::thread::sleep(timer);
290	}
291}
292
293//---------------------------------------------------------------------------------//
294DeviceList LIRCFactoryCreator::freeDeviceList()
295{
296	DeviceList list;
297	for( std::vector<std::string>::iterator i = mUnusedRemotes.begin(); i != mUnusedRemotes.end(); ++i )
298		list.insert(std::make_pair(OISJoyStick, *i));
299
300	return list;
301}
302
303//---------------------------------------------------------------------------------//
304int LIRCFactoryCreator::totalDevices(Type iType)
305{
306	if( iType == OISJoyStick )
307		return mCount;
308	else
309		return 0;
310}
311
312//---------------------------------------------------------------------------------//
313int LIRCFactoryCreator::freeDevices(Type iType)
314{
315	if( iType == OISJoyStick )
316		return (int)mUnusedRemotes.size();
317	else
318		return 0;
319}
320
321//---------------------------------------------------------------------------------//
322bool LIRCFactoryCreator::vendorExist(Type iType, const std::string & vendor)
323{
324	if( iType == OISJoyStick && std::find(mUnusedRemotes.begin(), mUnusedRemotes.end(), vendor) != mUnusedRemotes.end() )
325		return true;
326	else
327		return false;
328}
329
330//---------------------------------------------------------------------------------//
331Object* LIRCFactoryCreator::createObject(InputManager* creator, Type iType, bool bufferMode, const std::string & vendor)
332{
333	if( mUnusedRemotes.size() > 0 )
334	{
335		std::vector<std::string>::iterator remote = mUnusedRemotes.end();
336		if( vendor == "" )
337			remote = mUnusedRemotes.begin();
338		else
339			remote = std::find(mUnusedRemotes.begin(), mUnusedRemotes.end(), vendor);
340
341		if( remote != mUnusedRemotes.end() )
342		{
343			//Make sure connection is established
344			enableConnection(true, false);
345
346			//Make sure connection thread is alive
347			enableConnectionThread(true);
348
349			//Create device
350			LIRCControl *obj = new LIRCControl(creator, 0, bufferMode, this, mJoyStickInformation[*remote]);
351
352			//Add to used list, and then remove from unused list
353			{
354				boost::mutex::scoped_lock arrayLock(mWrapped->mLircListMutex);
355				mUpdateRemotes[*remote] = obj;
356			}
357			mUnusedRemotes.erase(remote);
358
359			return obj;
360		}
361	}
362	
363	OIS_EXCEPT(E_InputDeviceNonExistant, "No Device found which matches description!");
364}
365
366//---------------------------------------------------------------------------------//
367void LIRCFactoryCreator::destroyObject(Object* obj)
368{
369	if( obj == 0 )
370		return;
371
372	int remotes_alive = 0;
373
374	{	//Scope lock
375		boost::mutex::scoped_lock arrayLock(mWrapped->mLircListMutex);
376
377		//Find object
378		std::map<std::string, LIRCControl*>::iterator i = mUpdateRemotes.begin(), e = mUpdateRemotes.end();
379		bool found = false;
380		for(; i != e; ++i)
381		{
382			if( i->second == obj )
383			{
384				found = true;
385				break;
386			}
387		}
388
389		if( found == false )
390			OIS_EXCEPT(E_General, "Device not found in LIRC remote collection!");
391
392		//Move from used to unused list
393		mUnusedRemotes.push_back(i->first);
394		mUpdateRemotes.erase(i);
395		
396		delete obj;
397
398		remotes_alive = (int)mUpdateRemotes.size();
399	}
400
401	//Destroy thread if no longer in use (we do this after unlocking mutex!)
402	if( remotes_alive == 0 )
403		enableConnectionThread(false);
404}
405#endif