1 /*
2  * This file is part of the OpenKinect Project. http://www.openkinect.org
3  *
4  * Copyright (c) 2010 individual OpenKinect contributors. See the CONTRIB file
5  * for details.
6  *
7  * This code is licensed to you under the terms of the Apache License, version
8  * 2.0, or, at your option, the terms of the GNU General Public License,
9  * version 2.0. See the APACHE20 and GPL2 files for the text of the licenses,
10  * or the following URLs:
11  * http://www.apache.org/licenses/LICENSE-2.0
12  * http://www.gnu.org/licenses/gpl-2.0.txt
13  *
14  * If you redistribute this file in source form, modified or unmodified, you
15  * may:
16  *   1) Leave this header intact and distribute it under the same terms,
17  *      accompanying it with the APACHE20 and GPL20 files, or
18  *   2) Delete the Apache 2.0 clause and accompany it with the GPL2 file, or
19  *   3) Delete the GPL v2 clause and accompany it with the APACHE20 file
20  * In all cases you must keep the copyright notice intact and include a copy
21  * of the CONTRIB file.
22  *
23  * Binary distributions must follow the binary distribution requirements of
24  * either License.
25  */
26 
27 #pragma once
28 
29 #include <libfreenect.h>
30 #include <stdexcept>
31 #include <map>
32 #include <pthread.h>
33 
34 namespace Freenect {
35 	class Noncopyable {
36 	  public:
Noncopyable()37 		Noncopyable() {}
~Noncopyable()38 		~Noncopyable() {}
39 	  private:
40 		Noncopyable( const Noncopyable& );
41 		const Noncopyable& operator=( const Noncopyable& );
42 	};
43 
44 	class FreenectTiltState {
45 	  friend class FreenectDevice;
FreenectTiltState(freenect_raw_tilt_state * _state)46 		FreenectTiltState(freenect_raw_tilt_state *_state):
47 			m_state(_state), m_code(_state->tilt_status)
48 		{}
49 	  public:
getAccelerometers(double * x,double * y,double * z)50 		void getAccelerometers(double* x, double* y, double* z) {
51 			freenect_get_mks_accel(m_state, x, y, z);
52 		}
getTiltDegs()53 		double getTiltDegs() {
54 			return freenect_get_tilt_degs(m_state);
55 		}
56 	  public:
57 		freenect_tilt_status_code m_code;
58 	  private:
59 		freenect_raw_tilt_state *m_state;
60 	};
61 
62 	class FreenectDevice : Noncopyable {
63 	  public:
FreenectDevice(freenect_context * _ctx,int _index)64 		FreenectDevice(freenect_context *_ctx, int _index) {
65 			if(freenect_open_device(_ctx, &m_dev, _index) < 0) throw std::runtime_error("Cannot open Kinect");
66 			freenect_set_user(m_dev, this);
67 			freenect_set_video_format(m_dev, FREENECT_VIDEO_RGB);
68 			freenect_set_depth_format(m_dev, FREENECT_DEPTH_11BIT);
69 			freenect_set_depth_callback(m_dev, freenect_depth_callback);
70 			freenect_set_video_callback(m_dev, freenect_video_callback);
71 		}
~FreenectDevice()72 		~FreenectDevice() {
73 			if(freenect_close_device(m_dev) < 0) throw std::runtime_error("Cannot shutdown Kinect");
74 		}
startVideo()75 		void startVideo() {
76 			if(freenect_start_video(m_dev) < 0) throw std::runtime_error("Cannot start RGB callback");
77 		}
stopVideo()78 		void stopVideo() {
79 			if(freenect_stop_video(m_dev) < 0) throw std::runtime_error("Cannot stop RGB callback");
80 		}
startDepth()81 		void startDepth() {
82 			if(freenect_start_depth(m_dev) < 0) throw std::runtime_error("Cannot start depth callback");
83 		}
stopDepth()84 		void stopDepth() {
85 			if(freenect_stop_depth(m_dev) < 0) throw std::runtime_error("Cannot stop depth callback");
86 		}
setTiltDegrees(double _angle)87 		void setTiltDegrees(double _angle) {
88 			if(freenect_set_tilt_degs(m_dev, _angle) < 0) throw std::runtime_error("Cannot set angle in degrees");
89 		}
setLed(freenect_led_options _option)90 		void setLed(freenect_led_options _option) {
91 			if(freenect_set_led(m_dev, _option) < 0) throw std::runtime_error("Cannot set led");
92 		}
updateState()93 		void updateState() {
94 			if (freenect_update_tilt_state(m_dev) < 0) throw std::runtime_error("Cannot update device state");
95 		}
getState() const96 		FreenectTiltState getState() const {
97 			return FreenectTiltState(freenect_get_tilt_state(m_dev));
98 		}
99 		// Do not call directly even in child
100 		virtual void VideoCallback(void *video, uint32_t timestamp) = 0;
101 		// Do not call directly even in child
102 		virtual void DepthCallback(void *depth, uint32_t timestamp) = 0;
103 	  private:
104 		freenect_device *m_dev;
freenect_depth_callback(freenect_device * dev,void * depth,uint32_t timestamp)105 		static void freenect_depth_callback(freenect_device *dev, void *depth, uint32_t timestamp) {
106 			FreenectDevice* device = static_cast<FreenectDevice*>(freenect_get_user(dev));
107 			device->DepthCallback(depth, timestamp);
108 		}
freenect_video_callback(freenect_device * dev,void * video,uint32_t timestamp)109 		static void freenect_video_callback(freenect_device *dev, void *video, uint32_t timestamp) {
110 			FreenectDevice* device = static_cast<FreenectDevice*>(freenect_get_user(dev));
111 			device->VideoCallback(video, timestamp);
112 		}
113 	};
114 
115 	template <class T>class Freenect : Noncopyable {
116 	  public:
Freenect()117 		Freenect() : m_stop(false) {
118 			if(freenect_init(&m_ctx, NULL) < 0) throw std::runtime_error("Cannot initialize freenect library");
119 			if(pthread_create(&m_thread, NULL, pthread_callback, (void*)this) != 0) throw std::runtime_error("Cannot initialize freenect thread");
120 		}
~Freenect()121 		~Freenect() {
122 			for(typename std::map<int, T*>::iterator it = m_devices.begin() ; it != m_devices.end() ; ++it) {
123 				delete it->second;
124 			}
125 			m_stop = true;
126 			pthread_join(m_thread, NULL);
127 			if(freenect_shutdown(m_ctx) < 0) throw std::runtime_error("Cannot cleanup freenect library");
128 		}
createDevice(int _index)129 		T& createDevice(int _index) {
130 			m_devices.insert(std::make_pair<int, T*>(_index, new T(m_ctx, _index)));
131 			return *(m_devices[_index]);
132 		}
deleteDevice(int _index)133 		void deleteDevice(int _index) {
134 			m_devices.erase(_index);
135 		}
deviceCount()136 		int deviceCount() {
137 			return freenect_num_devices(m_ctx);
138 		}
139 		// Do not call directly, thread runs here
operator ()()140 		void operator()() {
141 			while(!m_stop) {
142 				if(freenect_process_events(m_ctx) < 0) throw std::runtime_error("Cannot process freenect events");
143 			}
144 		}
pthread_callback(void * user_data)145 		static void *pthread_callback(void *user_data) {
146 			Freenect<T>* freenect = static_cast<Freenect<T>*>(user_data);
147 			(*freenect)();
148 			return NULL;
149 		}
150 	  private:
151 		freenect_context *m_ctx;
152 		volatile bool m_stop;
153 		pthread_t m_thread;
154 		std::map<int, T*> m_devices;
155 	};
156 
157 }
158 
159