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 }