1 module marscamera_c_interface;
2 /+
3  + Minimised code for reproducing PyD segfaults from threading.
4  +
5  + Author: Michael Walsh
6  +/
7 import core.exception: AssertError;
8 
9 import std.concurrency: spawn, Tid, thisTid, send, receive, receiveTimeout, OwnerTerminated, register, locate;
10 import std.datetime: dur;
11 import std.stdio;
12 
13 shared string last_error = "";
14 
15 bool connected = false;
16 
17 
18 int _acquire(int exposure_time_ms);
19 int _get_image(uint* matrix); // 65536 length
20 int _camera_close();
21 
22 void __attach() {
23     import core.thread;
24     thread_attachThis();
25 }
26 
27 void __detach() {
28     import core.thread;
29     thread_detachThis();
30 }
31 
32 
33 //acquire
34 void message_handler1(Tid thr, string cmd, float var1) {
35 	if (cmd == "acquire") {
36 		int ret = _acquire(var1);
37 		send!(string, int)(thr, cmd, ret);
38 	}
39 }
40 
41 
42 //get_image, close
43 void message_handler5(Tid thr, string cmd) {
44 	if (cmd == "get_image") {
45 		uint[65536] image;
46 		uint* tmp = cast(uint*)image;
47 		int ret = _get_image(tmp);
48 		send!(string, int, uint[65536])(thr, cmd, ret, image);
49 	} else if (cmd == "camera_close") {
50 		int ret = _camera_close();
51 		if (ret) {
52 			connected = false;
53 		}
54 		send!(string, int)(thr, cmd, ret);
55 	}
56 }
57 
58 
59 void listener(Tid t) {
60 	send(t, "find", 1);
61 	while (connected) {
62 		receive(&message_handler1,  // (Tid, string, float)
63 			&message_handler5,
64 			(OwnerTerminated s) {connected = false;}); // (Tid, string)
65 	}
66 }
67 
68 void _camera_find(Tid t, string ip_address) {
69 	try {
70 		connected = true;
71 		listener(t);
72 	} catch (Exception e) {
73 		last_error = e.msg.idup;
74 	} catch (AssertError e) {
75 		last_error = "Assertion error" ~ e.msg.idup;
76 	}
77 
78 }
79 
80 int camera_find(string ip) {
81 	scope(failure) {last_error = "Exception in camera_find"; return 0;}
82 	if (locate("listener") == Tid.init) {
83 		Tid listener_thread = spawn(&_camera_find, thisTid(), ip);
84 		register("listener", listener_thread);
85 		int ret = -1;
86 		receiveTimeout(dur!"msecs"(5000),
87 			       (string s, int _ret) {
88 				       assert(s == "find");
89 				       ret = _ret;
90 			       });
91 		if (ret == -1) {
92 			last_error = "Timeout on camera find";
93 			return 1;
94 		} else {
95 			return ret;
96 		}
97 	} else {
98 		last_error = "camera_find exception: camera already connected";
99 		return 0;
100 	}
101 }
102 
103 
104 int _acquire(float exposure_time_ms) {
105 	//The real version of this code acquires on the camera, which has approximately 500 ms of delay.
106 	return 1;
107 }
108 
109 int acquire(float exposure_time_ms) {
110 	try {
111 		auto listener_thread = locate("listener");
112 		if (listener_thread != Tid.init) {
113 			send!(Tid, string, float)(listener_thread, thisTid(), "acquire", exposure_time_ms);
114 			int ret = -1;
115                         /*
116 			receiveTimeout(dur!"msecs"(3000),
117 				       (string s, int _ret) {
118 					       assert(s == "acquire");
119 					       ret = _ret;
120 				       });
121                                        */
122 			if (ret == -1) {
123 				last_error = "Timeout on receive response";
124 				return 1;
125 			} else {
126 				return ret;
127 			}
128 		} else {
129 			last_error = "Camera not initialised with 'find'";
130 			return 0;
131 		}
132 	} catch (Exception e) {
133 		last_error = e.msg.idup;
134 		return 0;
135 	} catch (AssertError e) {
136 		last_error = "Assertion error" ~ e.msg.idup;
137 		return 0;
138 	}
139 }
140 
141 int _get_image(uint *matrix) {
142 	// The real version of this code overwrites *matrix with a 65536-long array of data.
143 	return 1;
144 }
145 
146 extern(C) int get_image(uint *matrix) {
147 	auto listener_thread = locate("listener");
148 	if (listener_thread != Tid.init) {
149 		send!(Tid, string)(listener_thread, thisTid(), "get_image");
150 		int ret = -1;
151 		receiveTimeout(dur!"msecs"(1000),
152 			       (string s, int _ret, uint[65536] _matrix) {
153 				       assert(s == "get_image");
154 				       foreach (i; 0..65536) {
155 					       matrix[i] = _matrix[i];
156 				       }
157 				       ret = _ret;
158 			       });
159 		if (ret == -1) {
160 			last_error = "get_image: Timeout on receive response";
161 			return 0;
162 		} else {
163 			return ret;
164 		}
165 	} else {
166 		last_error = "Camera not initialised with 'find'";
167 		return 0;
168 	}
169 }
170 
171 int _camera_close() {
172 	// The real version of this code closes the socket connection.
173 	return 1;
174 }
175 
176 int camera_close() {
177 	auto listener_thread = locate("listener");
178 	if (listener_thread != Tid.init) {
179 		send!(Tid, string)(listener_thread, thisTid(), "camera_close");
180 		int ret = -1;
181 		receiveTimeout(dur!"msecs"(1000),
182 			       (string s, int _ret) {
183 				       assert(s == "camera_close");
184 				       ret = _ret;
185 			       });
186 		if (ret == -1) {
187 			last_error = "camera_close: Timeout on receive response";
188 			return 0;
189 		} else {
190 			return ret;
191 		}
192 	} else {
193 		last_error = "Camera not initialised with 'find'";
194 		return 0;
195 	}
196 }
197 
198 void __throw_last_error() {
199 	throw new Exception(last_error);
200 }
201 
202 /+
203  + Code used for the PyD interface.
204  +/
205 
206 void __camera_find(string ip_address) {
207 	scope(failure) 	__throw_last_error();
208 	if (!camera_find(ip_address)) {
209 		__throw_last_error();
210 	}
211 }
212 
213 void __camera_close() {
214 	scope(failure) 	__throw_last_error();
215 	if (!camera_close()) {
216 		__throw_last_error();
217 	}
218 }
219 
220 void __acquire(float exposure_time_ms) {
221 	scope(failure) 	__throw_last_error();
222 	if (!acquire(exposure_time_ms)) {
223 		__throw_last_error();
224 	}
225 }
226 
227 uint[65536] __get_image() {
228 	scope(failure) {
229             __throw_last_error();
230         }
231 	uint[65536] matrix;
232 	if (!get_image(cast(uint*)matrix)) {
233 		//__throw_last_error();
234 	}
235 	return matrix;
236 }