Line data Source code
1 : /********************************************************************\
2 :
3 : Name: device_driver.c
4 : Created by: Stefan Ritt
5 :
6 : Contents: The system part of the MIDAS frontend.
7 :
8 : \********************************************************************/
9 :
10 : #include <stdio.h>
11 : #include <assert.h>
12 : #include "midas.h"
13 : #include "msystem.h"
14 :
15 0 : static int sc_thread(void *info)
16 : {
17 0 : DEVICE_DRIVER *device_drv = (DEVICE_DRIVER*)info;
18 : int i, status, cmd;
19 0 : int current_channel = 0;
20 0 : int current_priority_channel = 0;
21 : float value;
22 : int *last_update;
23 : unsigned int current_time;
24 : DWORD last_time;
25 :
26 0 : ss_thread_set_name(std::string("SC:")+ *device_drv->pequipment_name);
27 :
28 0 : last_update = (int*)calloc(device_drv->channels, sizeof(int));
29 0 : for (i=0 ; i<device_drv->channels ; i++)
30 0 : last_update[i] = ss_millitime() - 20000;
31 0 : last_time = ss_millitime();
32 :
33 : // call CMD_START of device driver
34 0 : device_drv->dd(CMD_START, device_drv->dd_info, 0, NULL);
35 :
36 : // initialize setting to NAN in order not to trigger an immediate write
37 0 : for (i = 0; i < device_drv->channels; i++)
38 0 : device_drv->mt_buffer->channel[i].variable[CMD_SET] = (float) ss_nan();
39 :
40 0 : int skip = 0;
41 : do {
42 :
43 : // only operate if enabled
44 0 : if (device_drv->pequipment->enabled) {
45 :
46 : /* read one channel from device, skip if time limit is set */
47 :
48 : /* limit data rate if defined in equipment list */
49 0 : if (device_drv->pequipment && device_drv->pequipment->event_limit && current_channel == 0) {
50 0 : if (ss_millitime() - last_time < (DWORD) device_drv->pequipment->event_limit) {
51 0 : skip = 1;
52 : } else {
53 0 : skip = 0;
54 0 : last_time = ss_millitime();
55 : }
56 : }
57 :
58 0 : if (!skip) {
59 0 : for (cmd = CMD_GET_FIRST; cmd <= CMD_GET_LAST; cmd++) {
60 0 : value = (float) ss_nan();
61 0 : status = device_drv->dd(cmd, device_drv->dd_info, current_channel, &value);
62 :
63 0 : ss_mutex_wait_for(device_drv->mutex, 1000);
64 0 : device_drv->mt_buffer->channel[current_channel].variable[cmd] = value;
65 0 : device_drv->mt_buffer->status = status;
66 0 : ss_mutex_release(device_drv->mutex);
67 : }
68 0 : device_drv->mt_buffer->channel[current_channel].n_read++;
69 : }
70 :
71 : /* switch to next channel in next loop */
72 0 : current_channel = (current_channel + 1) % device_drv->channels;
73 :
74 : /* check for priority channel */
75 0 : if (device_drv->flags & DF_PRIORITY_READ) {
76 0 : current_time = ss_millitime();
77 0 : i = (current_priority_channel + 1) % device_drv->channels;
78 0 : while (!(current_time - last_update[i] < 10000)) {
79 0 : i = (i + 1) % device_drv->channels;
80 0 : if (i == current_priority_channel) {
81 : /* non found, so finish */
82 0 : break;
83 : }
84 : }
85 :
86 : /* updated channel found, so read it additionally */
87 0 : if (current_time - last_update[i] < 10000) {
88 0 : current_priority_channel = i;
89 :
90 0 : for (cmd = CMD_GET_FIRST; cmd <= CMD_GET_LAST; cmd++) {
91 0 : status = device_drv->dd(cmd, device_drv->dd_info, i, &value);
92 :
93 0 : ss_mutex_wait_for(device_drv->mutex, 1000);
94 0 : device_drv->mt_buffer->channel[i].variable[cmd] = value;
95 0 : device_drv->mt_buffer->status = status;
96 0 : ss_mutex_release(device_drv->mutex);
97 : }
98 : }
99 : }
100 :
101 : // copy potential set value to get/get_demand buffers to avoid old value there to be copied to ODB
102 0 : for (i = 0; i < device_drv->channels; i++) {
103 :
104 0 : for (cmd = CMD_SET_FIRST; cmd <= CMD_SET_LAST; cmd++) {
105 0 : if (!ss_isnan(device_drv->mt_buffer->channel[i].variable[cmd])) {
106 0 : ss_mutex_wait_for(device_drv->mutex, 1000);
107 0 : value = device_drv->mt_buffer->channel[i].variable[cmd];
108 0 : ss_mutex_release(device_drv->mutex);
109 :
110 0 : if (cmd == CMD_SET) {
111 0 : ss_mutex_wait_for(device_drv->mutex, 1000);
112 0 : device_drv->mt_buffer->channel[i].variable[CMD_GET] = value;
113 0 : device_drv->mt_buffer->channel[i].variable[CMD_GET_DEMAND] = value;
114 0 : ss_mutex_release(device_drv->mutex);
115 : }
116 : }
117 : }
118 : }
119 :
120 : /* check if anything to write to device */
121 0 : for (i = 0; i < device_drv->channels; i++) {
122 :
123 0 : for (cmd = CMD_SET_FIRST; cmd <= CMD_SET_LAST; cmd++) {
124 0 : if (!ss_isnan(device_drv->mt_buffer->channel[i].variable[cmd])) {
125 0 : ss_mutex_wait_for(device_drv->mutex, 1000);
126 0 : value = device_drv->mt_buffer->channel[i].variable[cmd];
127 0 : device_drv->mt_buffer->channel[i].variable[cmd] = (float) ss_nan();
128 0 : ss_mutex_release(device_drv->mutex);
129 :
130 0 : status = device_drv->dd(cmd, device_drv->dd_info, i, value);
131 0 : device_drv->mt_buffer->status = status;
132 0 : if (cmd == CMD_SET)
133 0 : last_update[i] = ss_millitime();
134 : }
135 : }
136 : }
137 : } // enabled
138 :
139 0 : ss_sleep(10); // don't eat all CPU
140 :
141 0 : } while (device_drv->stop_thread == 0);
142 :
143 0 : free(last_update);
144 :
145 : /* signal stopped thread */
146 0 : device_drv->stop_thread = 2;
147 :
148 0 : return SUCCESS;
149 : }
150 :
151 : /*------------------------------------------------------------------*/
152 :
153 0 : INT device_driver(DEVICE_DRIVER * device_drv, INT cmd, ...)
154 : {
155 : va_list argptr;
156 : HNDLE hKey;
157 : INT channel, status, i, j;
158 : float value, *pvalue;
159 : char *name, *label;
160 :
161 0 : va_start(argptr, cmd);
162 0 : status = FE_SUCCESS;
163 :
164 : /* don't execute command if driver is disabled */
165 0 : if (!device_drv->enabled)
166 0 : return FE_PARTIALLY_DISABLED;
167 :
168 0 : switch (cmd) {
169 0 : case CMD_INIT:
170 0 : hKey = va_arg(argptr, HNDLE);
171 :
172 0 : if (device_drv->flags & DF_MULTITHREAD) {
173 0 : status = device_drv->dd(CMD_INIT, hKey, &device_drv->dd_info,
174 : device_drv->channels, device_drv->flags,
175 : device_drv->bd);
176 :
177 0 : if (status == FE_SUCCESS && (device_drv->flags & DF_MULTITHREAD)) {
178 : /* create inter-thread data exchange buffers */
179 0 : device_drv->mt_buffer = (DD_MT_BUFFER *) calloc(1, sizeof(DD_MT_BUFFER));
180 0 : device_drv->mt_buffer->n_channels = device_drv->channels;
181 0 : device_drv->mt_buffer->channel = (DD_MT_CHANNEL *) calloc(device_drv->channels, sizeof(DD_MT_CHANNEL));
182 0 : assert(device_drv->mt_buffer->channel);
183 :
184 : /* initialize n_read for all channels */
185 0 : for (i=0 ; i<device_drv->channels ; i++)
186 0 : device_drv->mt_buffer->channel[i].n_read = 0;
187 :
188 : /* set all get values to NaN */
189 0 : for (i=0 ; i<device_drv->channels ; i++)
190 0 : for (j=CMD_GET_FIRST ; j<=CMD_GET_LAST ; j++)
191 0 : device_drv->mt_buffer->channel[i].variable[j] = (float) ss_nan();
192 :
193 : /* set all set values to NaN */
194 0 : for (i=0 ; i<device_drv->channels ; i++)
195 0 : for (j=CMD_SET_FIRST ; j<=CMD_SET_LAST ; j++)
196 0 : device_drv->mt_buffer->channel[i].variable[j] = (float)ss_nan();
197 :
198 : /* get default names for this driver already now */
199 0 : for (i = 0; i < device_drv->channels; i++) {
200 0 : device_drv->dd(CMD_GET_LABEL, device_drv->dd_info, i,
201 0 : device_drv->mt_buffer->channel[i].label);
202 : }
203 : /* create semaphore */
204 0 : status = ss_mutex_create(&device_drv->mutex, FALSE);
205 0 : if (status != SS_CREATED && status != SS_SUCCESS)
206 0 : return FE_ERR_DRIVER;
207 0 : status = FE_SUCCESS;
208 : }
209 : } else {
210 0 : status = device_drv->dd(CMD_INIT, hKey, &device_drv->dd_info,
211 : device_drv->channels, device_drv->flags,
212 : device_drv->bd);
213 : }
214 0 : break;
215 :
216 0 : case CMD_START:
217 0 : if (device_drv->flags & DF_MULTITHREAD && device_drv->mt_buffer != NULL) {
218 : /* create dedicated thread for this device */
219 0 : device_drv->mt_buffer->thread_id = ss_thread_create(sc_thread, device_drv);
220 : }
221 0 : break;
222 :
223 0 : case CMD_CLOSE:
224 : /* signal all threads to stop */
225 0 : if (device_drv->flags & DF_MULTITHREAD && device_drv->mt_buffer != NULL)
226 0 : device_drv->stop_thread = 1;
227 0 : break;
228 :
229 0 : case CMD_STOP:
230 0 : if (device_drv->flags & DF_MULTITHREAD && device_drv->mt_buffer != NULL) {
231 0 : if (device_drv->stop_thread == 0)
232 0 : device_drv->stop_thread = 1;
233 :
234 : /* wait for max. 10 seconds until thread has gracefully stopped */
235 0 : for (i = 0; i < 1000; i++) {
236 0 : if (device_drv->stop_thread == 2)
237 0 : break;
238 0 : ss_sleep(10);
239 : }
240 :
241 : /* if timeout expired, kill thread */
242 0 : if (i == 1000)
243 0 : ss_thread_kill(device_drv->mt_buffer->thread_id);
244 :
245 0 : ss_mutex_delete(device_drv->mutex);
246 0 : free(device_drv->mt_buffer->channel);
247 0 : free(device_drv->mt_buffer);
248 : }
249 0 : break;
250 :
251 0 : case CMD_EXIT:
252 0 : status = device_drv->dd(CMD_EXIT, device_drv->dd_info);
253 0 : break;
254 :
255 0 : case CMD_SET_LABEL:
256 0 : channel = va_arg(argptr, INT);
257 0 : label = va_arg(argptr, char *);
258 0 : status = device_drv->dd(CMD_SET_LABEL, device_drv->dd_info, channel, label);
259 0 : break;
260 :
261 0 : case CMD_GET_LABEL:
262 0 : channel = va_arg(argptr, INT);
263 0 : name = va_arg(argptr, char *);
264 0 : status = device_drv->dd(CMD_GET_LABEL, device_drv->dd_info, channel, name);
265 0 : break;
266 :
267 0 : default:
268 :
269 0 : if (cmd >= CMD_SET_FIRST && cmd <= CMD_SET_LAST) {
270 :
271 : /* transfer data to sc_thread for SET commands */
272 0 : channel = va_arg(argptr, INT);
273 0 : value = (float) va_arg(argptr, double); // floats are passed as double
274 0 : if (device_drv->flags & DF_MULTITHREAD) {
275 0 : ss_mutex_wait_for(device_drv->mutex, 1000);
276 0 : device_drv->mt_buffer->channel[channel].variable[cmd] = value;
277 0 : status = device_drv->mt_buffer->status;
278 0 : ss_mutex_release(device_drv->mutex);
279 : } else {
280 0 : status = device_drv->dd(cmd, device_drv->dd_info, channel, value);
281 : }
282 :
283 0 : } else if (cmd >= CMD_GET_FIRST && cmd <= CMD_GET_LAST) {
284 :
285 : /* transfer data from sc_thread for GET commands */
286 0 : channel = va_arg(argptr, INT);
287 0 : pvalue = va_arg(argptr, float *);
288 0 : if (device_drv->flags & DF_MULTITHREAD) {
289 0 : ss_mutex_wait_for(device_drv->mutex, 1000);
290 0 : *pvalue = device_drv->mt_buffer->channel[channel].variable[cmd];
291 0 : status = device_drv->mt_buffer->status;
292 0 : if (device_drv->mt_buffer->channel[channel].n_read < 1)
293 0 : status = FE_NOT_YET_READ;
294 0 : ss_mutex_release(device_drv->mutex);
295 : } else
296 0 : status = device_drv->dd(cmd, device_drv->dd_info, channel, pvalue);
297 :
298 : } else {
299 :
300 : /* all remaining commands which are passed directly to the device driver */
301 0 : channel = va_arg(argptr, INT);
302 0 : pvalue = va_arg(argptr, float *);
303 0 : status = device_drv->dd(cmd, device_drv->dd_info, channel, pvalue);
304 : }
305 :
306 0 : break;
307 : }
308 :
309 0 : va_end(argptr);
310 0 : return status;
311 : }
312 :
313 : /* emacs
314 : * Local Variables:
315 : * tab-width: 8
316 : * c-basic-offset: 3
317 : * indent-tabs-mode: nil
318 : * End:
319 : */
|