1use std::ffi::CString;
4use std::mem;
5use std::ptr;
6use libc::{self, c_char, c_void};
7
8use crate::c;
9use crate::error::{TangoResult, TangoError};
10use crate::types::*;
11
12
13pub struct DeviceProxy {
15 ptr: *mut c_void,
16}
17
18impl Drop for DeviceProxy {
19 fn drop(&mut self) {
20 let error_stack = unsafe { c::tango_delete_device_proxy(self.ptr) };
21 if !error_stack.is_null() {
22 drop(TangoError::from_stack(error_stack));
24 }
25 }
26}
27
28impl DeviceProxy {
29 pub fn new(address: &str) -> TangoResult<DeviceProxy> {
34 let mut dev = ptr::null_mut();
35 let address = CString::new(address).unwrap();
36 tango_call!(tango_create_device_proxy,
37 DeviceProxy { ptr: dev },
38 address.as_ptr() as *mut c_char, &mut dev)
39 }
40
41 pub fn get_timeout(&self) -> TangoResult<i32> {
43 let mut res = 0;
44 tango_call!(tango_get_timeout_millis,
45 res,
46 self.ptr, &mut res)
47 }
48
49 pub fn set_timeout(&mut self, timeout: i32) -> TangoResult<()> {
51 tango_call!(tango_set_timeout_millis,
52 (),
53 self.ptr, timeout)
54 }
55
56 pub fn get_source(&self) -> TangoResult<DevSource> {
58 let mut source = 0;
59 tango_call!(tango_get_source,
60 DevSource::from_c(source),
61 self.ptr, &mut source)
62 }
63
64 pub fn set_source(&mut self, source: DevSource) -> TangoResult<()> {
66 tango_call!(tango_set_source,
67 (),
68 self.ptr, source as u32)
69 }
70
71 pub fn lock(&mut self) -> TangoResult<()> {
73 tango_call!(tango_lock, (), self.ptr)
74 }
75
76 pub fn unlock(&mut self) -> TangoResult<()> {
78 tango_call!(tango_unlock, (), self.ptr)
79 }
80
81 pub fn is_locked(&self) -> TangoResult<bool> {
83 let mut res = false;
84 tango_call!(tango_is_locked,
85 res,
86 self.ptr, &mut res)
87 }
88
89 pub fn is_locked_by_me(&self) -> TangoResult<bool> {
91 let mut res = false;
92 tango_call!(tango_is_locked_by_me,
93 res,
94 self.ptr, &mut res)
95 }
96
97 pub fn locking_status(&self) -> TangoResult<String> {
99 let mut resptr = ptr::null_mut();
100 tango_call!(tango_locking_status,
101 unsafe {
102 let res = string_from(resptr);
103 libc::free(resptr as *mut c_void);
104 res
105 },
106 self.ptr, &mut resptr)
107 }
108
109 pub fn command_query(&self, cmd_name: &str) -> TangoResult<CommandInfo> {
111 let c_name = CString::new(cmd_name).unwrap();
112 let mut cmdinfo = unsafe { mem::zeroed() };
113 tango_call!(tango_command_query,
114 unsafe { CommandInfo::from_c(cmdinfo, true) },
115 self.ptr, c_name.as_ptr() as *mut c_char, &mut cmdinfo)
116 }
117
118 pub fn command_list_query(&self) -> TangoResult<Vec<CommandInfo>> {
120 let mut infolist = unsafe { mem::zeroed() };
121 tango_call!(tango_command_list_query, (), self.ptr, &mut infolist)?;
122 let mut res = Vec::with_capacity(infolist.length as usize);
123 unsafe {
124 for i in 0..infolist.length {
125 let cmd_ptr = ptr::read(infolist.sequence.offset(i as isize));
126 res.push(CommandInfo::from_c(cmd_ptr, false));
127 }
128 c::tango_free_CommandInfoList(&mut infolist);
129 }
130 Ok(res)
131 }
132
133 pub fn command_inout(&mut self, cmd_name: &str, argin: CommandData) -> TangoResult<CommandData> {
135 let c_name = CString::new(cmd_name).unwrap();
136 let mut argin = unsafe { argin.into_c() };
137 let mut argout = unsafe { mem::zeroed() };
138 let res = tango_call!(tango_command_inout,
139 unsafe { CommandData::from_c(argout) },
140 self.ptr, c_name.as_ptr() as *mut c_char,
141 &mut argin, &mut argout);
142 unsafe { CommandData::free_c_data(argin) };
143 res
144 }
145
146 pub fn get_attribute_list(&self) -> TangoResult<Vec<String>> {
148 let mut namelist = unsafe { mem::zeroed() };
149 tango_call!(tango_get_attribute_list, (), self.ptr, &mut namelist)?;
150 let mut res = Vec::with_capacity(namelist.length as usize);
151 unsafe {
152 for i in 0..namelist.length {
153 let name = ptr::read(namelist.sequence.offset(i as isize));
154 res.push(string_from(name));
155 }
156 c::tango_free_VarStringArray(&mut namelist);
157 }
158 Ok(res)
159 }
160
161 pub fn get_attribute_config(&self, attr_names: &[&str]) -> TangoResult<Vec<AttributeInfo>> {
163 let mut namelist = unsafe { mem::zeroed::<c::VarStringArray>() };
164 let mut infolist = unsafe { mem::zeroed::<c::AttributeInfoList>() };
165 let mut ptr_vec = Vec::with_capacity(attr_names.len());
166 for name in attr_names {
167 ptr_vec.push(CString::new(*name).unwrap().into_raw());
168 }
169 namelist.length = attr_names.len() as u32;
170 namelist.sequence = ptr_vec.as_mut_ptr();
171 tango_call!(tango_get_attribute_config, (), self.ptr, &mut namelist, &mut infolist)?;
172 let mut res = Vec::with_capacity(infolist.length as usize);
173 unsafe {
174 for i in 0..infolist.length {
175 let info = ptr::read(infolist.sequence.offset(i as isize));
176 res.push(AttributeInfo::from_c(info));
177 }
178 c::tango_free_AttributeInfoList(&mut infolist);
179 for ptr in ptr_vec {
180 drop(CString::from_raw(ptr));
181 }
182 }
183 Ok(res)
184 }
185
186 pub fn attribute_list_query(&self) -> TangoResult<Vec<AttributeInfo>> {
188 let mut infolist = unsafe { mem::zeroed() };
189 tango_call!(tango_attribute_list_query, (), self.ptr, &mut infolist)?;
190 let mut res = Vec::with_capacity(infolist.length as usize);
191 unsafe {
192 for i in 0..infolist.length {
193 let info = ptr::read(infolist.sequence.offset(i as isize));
194 res.push(AttributeInfo::from_c(info));
195 }
196 c::tango_free_AttributeInfoList(&mut infolist);
197 }
198 Ok(res)
199 }
200
201 pub fn read_attribute(&mut self, attr_name: &str) -> TangoResult<AttributeData> {
203 let c_name = CString::new(attr_name).unwrap();
204 let mut data = unsafe { mem::zeroed() };
205 tango_call!(tango_read_attribute,
206 unsafe { AttributeData::from_c(data, true) },
207 self.ptr, c_name.as_ptr() as *mut c_char, &mut data)
208 }
209
210 pub fn write_attribute(&mut self, attr_data: AttributeData) -> TangoResult<()> {
212 let mut data = unsafe { attr_data.into_c() };
213 let res = tango_call!(tango_write_attribute, (),
214 self.ptr, &mut data);
215 unsafe { AttributeData::free_c_data(data) };
216 res
217 }
218
219 pub fn read_attributes(&mut self, attr_names: &[&str]) -> TangoResult<Vec<AttributeData>> {
221 let mut namelist = unsafe { mem::zeroed::<c::VarStringArray>() };
222 let mut datalist = unsafe { mem::zeroed::<c::AttributeDataList>() };
223 let mut ptr_vec = Vec::with_capacity(attr_names.len());
224 for name in attr_names {
225 ptr_vec.push(CString::new(*name).unwrap().into_raw());
226 }
227 namelist.length = attr_names.len() as u32;
228 namelist.sequence = ptr_vec.as_mut_ptr();
229 tango_call!(tango_read_attributes, (), self.ptr, &mut namelist, &mut datalist)?;
230 let mut res = Vec::with_capacity(datalist.length as usize);
231 unsafe {
232 for i in 0..datalist.length {
233 let data = ptr::read(datalist.sequence.offset(i as isize));
234 res.push(AttributeData::from_c(data, false));
235 }
236 c::tango_free_AttributeDataList(&mut datalist);
237 for ptr in ptr_vec {
238 drop(CString::from_raw(ptr));
239 }
240 }
241 Ok(res)
242 }
243
244 pub fn write_attributes(&mut self, attr_data: Vec<AttributeData>) -> TangoResult<()> {
246 let mut datalist = unsafe { mem::zeroed::<c::AttributeDataList>() };
247 let mut ptr_vec = Vec::with_capacity(attr_data.len());
248 datalist.length = attr_data.len() as u32;
249 for data in attr_data {
250 ptr_vec.push(unsafe { data.into_c() });
251 }
252 datalist.sequence = ptr_vec.as_mut_ptr();
253 let res = tango_call!(tango_write_attributes, (),
254 self.ptr, &mut datalist);
255 unsafe {
256 for ptr in ptr_vec {
257 AttributeData::free_c_data(ptr);
258 }
259 }
260 res
261 }
262
263 pub fn get_device_property(&self, prop_list: Vec<DbDatum>) -> TangoResult<Vec<DbDatum>> {
267 let mut db_data = unsafe { mem::zeroed::<c::DbData>() };
268 let mut ptr_vec = Vec::with_capacity(prop_list.len());
269 let mut cstr_vec = Vec::with_capacity(prop_list.len());
270 db_data.length = prop_list.len() as u32;
271 for datum in prop_list {
272 let (datum, cstr) = unsafe { datum.into_c() };
273 ptr_vec.push(datum);
274 cstr_vec.push(cstr);
275 }
276 db_data.sequence = ptr_vec.as_mut_ptr();
277 tango_call!(tango_get_device_property, (), self.ptr, &mut db_data)?;
278 let mut res = Vec::with_capacity(db_data.length as usize);
279 unsafe {
280 for i in 0..db_data.length {
281 let db_datum = ptr::read(db_data.sequence.offset(i as isize));
282 res.push(DbDatum::from_c(db_datum, false));
283 }
284 c::tango_free_DbData(&mut db_data);
285 }
286 Ok(res)
287 }
288
289 pub fn put_device_property(&mut self, prop_list: Vec<DbDatum>) -> TangoResult<()> {
291 let mut db_data = unsafe { mem::zeroed::<c::DbData>() };
292 let mut ptr_vec = Vec::with_capacity(prop_list.len());
293 let mut cstr_vec = Vec::with_capacity(prop_list.len());
294 db_data.length = prop_list.len() as u32;
295 for datum in prop_list {
296 let (datum, cstr) = unsafe { datum.into_c() };
297 ptr_vec.push(datum);
298 cstr_vec.push(cstr);
299 }
300 db_data.sequence = ptr_vec.as_mut_ptr();
301 let res = tango_call!(tango_put_device_property, (),
302 self.ptr, &mut db_data);
303 unsafe {
304 for ptr in ptr_vec {
305 DbDatum::free_c_data(ptr);
306 }
307 }
308 res
309 }
310
311 pub fn delete_device_property(&mut self, prop_list: &[&str]) -> TangoResult<()> {
313 let mut db_data = unsafe { mem::zeroed::<c::DbData>() };
314 let mut ptr_vec = Vec::with_capacity(prop_list.len());
315 let mut cstr_vec = Vec::with_capacity(prop_list.len());
316 db_data.length = prop_list.len() as u32;
317 for prop in prop_list {
318 let datum = DbDatum::name_only(prop);
319 let (datum, cstr) = unsafe { datum.into_c() };
320 ptr_vec.push(datum);
321 cstr_vec.push(cstr);
322 }
323 db_data.sequence = ptr_vec.as_mut_ptr();
324 let res = tango_call!(tango_delete_device_property, (),
325 self.ptr, &mut db_data);
326 unsafe {
327 for ptr in ptr_vec {
328 DbDatum::free_c_data(ptr);
329 }
330 }
331 res
332 }
333}