Line data Source code
1 : /********************************************************************\
2 :
3 : Name: mscbdev.c
4 : Created by: Stefan Ritt
5 :
6 : Contents: MSCB Device Driver.
7 :
8 : $Id$
9 :
10 : \********************************************************************/
11 :
12 : #include <stdio.h>
13 : #include <stdlib.h>
14 : #include <stdarg.h>
15 : #include <string.h>
16 : #include "midas.h"
17 : #include "mscb.h"
18 : #include "mstrlcpy.h"
19 :
20 : extern void mfe_error(const char *error);
21 :
22 : /*---- globals -----------------------------------------------------*/
23 :
24 : /* MSCB node address / channel mapping */
25 :
26 : typedef struct {
27 : char mscb_device[256];
28 : char pwd[32];
29 : int debug;
30 : int retries;
31 : int pause;
32 : int *mscb_address;
33 : unsigned char *mscb_index;
34 : int *var_size;
35 : float *var_cache;
36 : char *label;
37 : } MSCBDEV_SETTINGS;
38 :
39 : typedef struct {
40 : MSCBDEV_SETTINGS mscbdev_settings;
41 : INT fd;
42 : INT num_channels;
43 : } MSCBDEV_INFO;
44 :
45 : /*---- device driver routines --------------------------------------*/
46 :
47 0 : void addr_changed(HNDLE, HNDLE, void *arg)
48 : {
49 : INT i, status;
50 : MSCB_INFO_VAR var_info;
51 : MSCBDEV_INFO *info;
52 :
53 0 : info = (MSCBDEV_INFO *) arg;
54 :
55 : /* get info about MSCB channels */
56 0 : if (info->num_channels > 20)
57 0 : printf("\n");
58 0 : for (i = 0; i < info->num_channels; i++) {
59 0 : if (info->num_channels > 20) {
60 0 : printf("Channel %d\r", i);
61 0 : fflush(stdout);
62 : }
63 0 : status = mscb_info_variable(info->fd, info->mscbdev_settings.mscb_address[i],
64 0 : info->mscbdev_settings.mscb_index[i], &var_info);
65 0 : if (status == MSCB_SUCCESS) {
66 0 : if (var_info.flags & MSCBF_FLOAT)
67 0 : info->mscbdev_settings.var_size[i] = -1;
68 : else
69 0 : info->mscbdev_settings.var_size[i] = var_info.width;
70 0 : mstrlcpy(info->mscbdev_settings.label+i*16, var_info.name, 16);
71 : } else {
72 0 : info->mscbdev_settings.var_size[i] = 0;
73 0 : cm_msg(MERROR, "addr_changed", "Cannot read from address %d at submaster %s",
74 0 : info->mscbdev_settings.mscb_address[i], info->mscbdev_settings.mscb_device);
75 0 : return;
76 : }
77 : }
78 0 : if (info->num_channels > 20)
79 0 : printf("\n");
80 : }
81 :
82 : /*----------------------------------------------------------------------------*/
83 :
84 : /* the init function creates a ODB record which contains the
85 : settings and initialized it variables as well as the bus driver */
86 :
87 : typedef INT(func_t) (INT cmd, ...);
88 :
89 0 : INT mscbdev_init(HNDLE hkey, MSCBDEV_INFO **pinfo, INT channels, func_t *)
90 : {
91 : int i, status, size;
92 : HNDLE hDB, hsubkey;
93 : MSCBDEV_INFO *info;
94 :
95 : /* allocate info structure */
96 0 : info = (MSCBDEV_INFO*) calloc(1, sizeof(MSCBDEV_INFO));
97 0 : *pinfo = info;
98 0 : info->mscbdev_settings.mscb_address = (int*) calloc(channels, sizeof(INT));
99 0 : info->mscbdev_settings.mscb_index = (unsigned char*) calloc(channels, sizeof(INT));
100 0 : info->mscbdev_settings.var_size = (int*) calloc(channels, sizeof(INT));
101 0 : info->mscbdev_settings.var_cache = (float*) calloc(channels, sizeof(float));
102 0 : info->mscbdev_settings.label = (char*) calloc(channels, 16);
103 0 : for (i = 0; i < channels; i++)
104 0 : info->mscbdev_settings.var_cache[i] = (float) ss_nan();
105 :
106 0 : cm_get_experiment_database(&hDB, NULL);
107 :
108 : /* create settings record */
109 0 : size = sizeof(info->mscbdev_settings.mscb_device);
110 0 : strcpy(info->mscbdev_settings.mscb_device, "usb0");
111 0 : status = db_get_value(hDB, hkey, "MSCB Device", &info->mscbdev_settings.mscb_device, &size, TID_STRING, TRUE);
112 0 : if (status != DB_SUCCESS)
113 0 : return FE_ERR_ODB;
114 :
115 0 : size = sizeof(info->mscbdev_settings.pwd);
116 0 : info->mscbdev_settings.pwd[0] = 0;
117 0 : status = db_get_value(hDB, hkey, "MSCB Pwd", &info->mscbdev_settings.pwd, &size, TID_STRING, TRUE);
118 0 : if (status != DB_SUCCESS)
119 0 : return FE_ERR_ODB;
120 :
121 0 : size = sizeof(info->mscbdev_settings.debug);
122 0 : info->mscbdev_settings.debug = 0;
123 0 : status = db_get_value(hDB, hkey, "MSCB Debug", &info->mscbdev_settings.debug, &size, TID_INT32, TRUE);
124 0 : if (status != DB_SUCCESS)
125 0 : return FE_ERR_ODB;
126 :
127 0 : size = sizeof(info->mscbdev_settings.pause);
128 0 : info->mscbdev_settings.pause = 0;
129 0 : status = db_get_value(hDB, hkey, "MSCB Pause", &info->mscbdev_settings.pause, &size, TID_INT32, TRUE);
130 0 : if (status != DB_SUCCESS)
131 0 : return FE_ERR_ODB;
132 :
133 0 : size = sizeof(info->mscbdev_settings.retries);
134 0 : info->mscbdev_settings.retries = 10;
135 0 : status = db_get_value(hDB, hkey, "MSCB Retries", &info->mscbdev_settings.retries, &size, TID_INT, TRUE);
136 0 : if (status != DB_SUCCESS)
137 0 : return FE_ERR_ODB;
138 :
139 0 : size = sizeof(INT) * channels;
140 0 : db_get_value(hDB, hkey, "MSCB Address", info->mscbdev_settings.mscb_address, &size, TID_INT, TRUE);
141 0 : db_find_key(hDB, hkey, "MSCB Address", &hsubkey);
142 0 : size = sizeof(INT) * channels;
143 0 : db_set_data(hDB, hsubkey, info->mscbdev_settings.mscb_address, size, channels, TID_INT);
144 0 : db_open_record(hDB, hsubkey, info->mscbdev_settings.mscb_address, size, MODE_READ, addr_changed, info);
145 :
146 0 : size = sizeof(BYTE) * channels;
147 0 : db_get_value(hDB, hkey, "MSCB Index", info->mscbdev_settings.mscb_index, &size, TID_BYTE, TRUE);
148 0 : db_find_key(hDB, hkey, "MSCB Index", &hsubkey);
149 0 : size = sizeof(BYTE) * channels;
150 0 : db_set_data(hDB, hsubkey, info->mscbdev_settings.mscb_index, size, channels, TID_BYTE);
151 0 : db_open_record(hDB, hsubkey, info->mscbdev_settings.mscb_index, size, MODE_READ, addr_changed, info);
152 :
153 : // execute periodic tasks since mscb_init can take a while
154 0 : cm_periodic_tasks();
155 :
156 : /* initialize info structure */
157 0 : info->num_channels = channels;
158 :
159 0 : info->fd = mscb_init(info->mscbdev_settings.mscb_device, sizeof(info->mscbdev_settings.mscb_device),
160 0 : info->mscbdev_settings.pwd, info->mscbdev_settings.debug);
161 0 : if (info->fd < 0) {
162 0 : cm_msg(MERROR, "mscbdev_init", "Cannot connect to MSCB device \"%s\"", info->mscbdev_settings.mscb_device);
163 0 : return FE_ERR_HW;
164 : }
165 :
166 : /* set number of retries */
167 0 : mscb_set_eth_max_retry(info->fd, info->mscbdev_settings.retries);
168 :
169 : /* set communication pause */
170 0 : mscb_set_eth_pause(info->fd, info->mscbdev_settings.pause);
171 :
172 : /* write back device */
173 0 : status = db_set_value(hDB, hkey, "Device", &info->mscbdev_settings.mscb_device,
174 : sizeof(info->mscbdev_settings.mscb_device), 1, TID_STRING);
175 0 : if (status != DB_SUCCESS)
176 0 : return FE_ERR_ODB;
177 :
178 : /* read initial variable sizes */
179 0 : addr_changed(0, 0, info);
180 :
181 0 : return FE_SUCCESS;
182 : }
183 :
184 : /*----------------------------------------------------------------------------*/
185 :
186 0 : INT mscbdev_exit(MSCBDEV_INFO * info)
187 : {
188 : /* close MSCB bus */
189 0 : if (info) {
190 0 : mscb_exit(info->fd);
191 0 : free(info->mscbdev_settings.mscb_address);
192 0 : free(info->mscbdev_settings.mscb_index);
193 0 : free(info->mscbdev_settings.var_size);
194 0 : free(info);
195 : }
196 :
197 0 : return FE_SUCCESS;
198 : }
199 :
200 : /*----------------------------------------------------------------------------*/
201 :
202 0 : INT mscbdev_set(MSCBDEV_INFO * info, INT channel, float value)
203 : {
204 : INT value_int;
205 :
206 0 : if (info->mscbdev_settings.var_size[channel] == -1) {
207 : /* channel is "float" */
208 0 : mscb_write(info->fd, info->mscbdev_settings.mscb_address[channel],
209 0 : info->mscbdev_settings.mscb_index[channel], &value, sizeof(float));
210 : } else {
211 : /* channel is int */
212 0 : value_int = (INT) value;
213 0 : mscb_write(info->fd, info->mscbdev_settings.mscb_address[channel],
214 0 : info->mscbdev_settings.mscb_index[channel], &value_int,
215 0 : info->mscbdev_settings.var_size[channel]);
216 : }
217 :
218 0 : return FE_SUCCESS;
219 : }
220 :
221 : /*----------------------------------------------------------------------------*/
222 :
223 0 : INT mscbdev_read_all(MSCBDEV_INFO * info)
224 : {
225 : int i, j, status, i_start, i_stop, v_start, v_stop, addr, size;
226 : unsigned char buffer[256], *pbuf;
227 : static DWORD last_error = 0;
228 :
229 : /* find consecutive ranges in variables */
230 0 : v_start = v_stop = 0;
231 0 : i_start = i_stop = info->mscbdev_settings.mscb_index[0];
232 0 : addr = info->mscbdev_settings.mscb_address[0];
233 :
234 0 : for (i = 1; i <= info->num_channels; i++) {
235 0 : if (i == info->num_channels || // read last chunk
236 0 : i_stop - i_start >= 60 || // not more than 60 vars (->240 bytes)
237 0 : info->mscbdev_settings.mscb_address[i] != addr || // if at different address
238 0 : info->mscbdev_settings.mscb_index[i] != i_stop + 1) { // if non-consecutive index
239 :
240 : /* complete range found, so read it */
241 0 : size = sizeof(buffer);
242 0 : if (i_start == i_stop) {
243 : /* read single value (bug in old mscbmain.c) */
244 0 : status = mscb_read(info->fd, addr, i_start, buffer, &size);
245 0 : if (info->mscbdev_settings.var_size[v_start] == -1)
246 0 : DWORD_SWAP(buffer);
247 : } else {
248 0 : status = mscb_read_range(info->fd, addr, i_start, i_stop, buffer, &size);
249 : }
250 :
251 0 : if (status != MSCB_SUCCESS) {
252 : /* only produce error once every minute */
253 0 : if (ss_time() - last_error >= 60) {
254 0 : last_error = ss_time();
255 : char str[512];
256 0 : sprintf(str, "Read error submaster %s address %d", info->mscbdev_settings.mscb_device, addr);
257 0 : mfe_error(str);
258 : }
259 0 : for (j = v_start; j <= v_stop; j++)
260 0 : info->mscbdev_settings.var_cache[j] = (float) ss_nan();
261 0 : return FE_ERR_HW;
262 : }
263 :
264 : /* interprete buffer */
265 0 : pbuf = buffer;
266 0 : for (j = v_start; j <= v_stop; j++) {
267 0 : if (info->mscbdev_settings.var_size[j] == -1) {
268 0 : DWORD_SWAP(pbuf);
269 0 : info->mscbdev_settings.var_cache[j] = *((float *) pbuf);
270 0 : pbuf += sizeof(float);
271 0 : } else if (info->mscbdev_settings.var_size[j] == 4) {
272 0 : DWORD_SWAP(pbuf);
273 0 : info->mscbdev_settings.var_cache[j] = (float) *((unsigned int *) pbuf);
274 0 : pbuf += sizeof(unsigned int);
275 0 : } else if (info->mscbdev_settings.var_size[j] == 2) {
276 0 : WORD_SWAP(pbuf);
277 0 : info->mscbdev_settings.var_cache[j] = (float) *((unsigned short *) pbuf);
278 0 : pbuf += sizeof(unsigned short);
279 : } else {
280 0 : info->mscbdev_settings.var_cache[j] = (float) *((unsigned char *) pbuf);
281 0 : pbuf += sizeof(unsigned char);
282 : }
283 : }
284 :
285 0 : if (i < info->num_channels) {
286 0 : v_start = v_stop = i;
287 0 : i_start = i_stop = info->mscbdev_settings.mscb_index[i];
288 0 : addr = info->mscbdev_settings.mscb_address[i];
289 : }
290 0 : } else {
291 0 : i_stop++;
292 0 : v_stop++;
293 : }
294 :
295 : }
296 :
297 0 : return FE_SUCCESS;
298 : }
299 :
300 : /*----------------------------------------------------------------------------*/
301 :
302 0 : INT mscbdev_get(MSCBDEV_INFO * info, INT channel, float *pvalue)
303 : {
304 : INT status;
305 :
306 : /* check if value was previously read by mscbhvr_read_all() */
307 0 : if (!ss_isnan(info->mscbdev_settings.var_cache[channel])) {
308 0 : *pvalue = info->mscbdev_settings.var_cache[channel];
309 0 : info->mscbdev_settings.var_cache[channel] = (float) ss_nan();
310 0 : return FE_SUCCESS;
311 : }
312 :
313 0 : status = mscbdev_read_all(info);
314 0 : *pvalue = info->mscbdev_settings.var_cache[channel];
315 0 : info->mscbdev_settings.var_cache[channel] = (float) ss_nan();
316 :
317 0 : return status;
318 : }
319 :
320 : /*----------------------------------------------------------------------------*/
321 :
322 0 : INT mscbdev_get_label(MSCBDEV_INFO * info, INT channel, char *name)
323 : {
324 :
325 0 : mstrlcpy(name, info->mscbdev_settings.label+channel*16, NAME_LENGTH);
326 0 : name[8] = 0;
327 0 : return MSCB_SUCCESS;
328 :
329 : /*
330 : int status;
331 : MSCB_INFO_VAR var_info;
332 :
333 : status = mscb_info_variable(info->fd, info->mscbdev_settings.mscb_address[channel],
334 : info->mscbdev_settings.mscb_index[channel], &var_info);
335 : if (status == MSCB_SUCCESS) {
336 : mstrlcpy(name, var_info.name, NAME_LENGTH);
337 : name[8] = 0;
338 : }
339 :
340 : return status;
341 : */
342 : }
343 :
344 : /*---- device driver entry point -----------------------------------*/
345 :
346 0 : INT mscbdev(INT cmd, ...)
347 : {
348 : va_list argptr;
349 : HNDLE hKey;
350 : INT channel, status;
351 : float value, *pvalue;
352 : MSCBDEV_INFO *info;
353 : char *name;
354 :
355 0 : va_start(argptr, cmd);
356 0 : status = FE_SUCCESS;
357 :
358 0 : switch (cmd) {
359 0 : case CMD_INIT: {
360 0 : hKey = va_arg(argptr, HNDLE);
361 0 : MSCBDEV_INFO **pinfo = va_arg(argptr, MSCBDEV_INFO**);
362 0 : channel = va_arg(argptr, INT);
363 0 : va_arg(argptr, DWORD);
364 0 : func_t* bd = va_arg(argptr, func_t *);
365 0 : status = mscbdev_init(hKey, pinfo, channel, bd);
366 0 : break;
367 : }
368 0 : case CMD_EXIT:
369 0 : info = va_arg(argptr, MSCBDEV_INFO *);
370 0 : status = mscbdev_exit(info);
371 0 : break;
372 :
373 0 : case CMD_SET:
374 0 : info = va_arg(argptr, MSCBDEV_INFO *);
375 0 : channel = va_arg(argptr, INT);
376 0 : value = (float) va_arg(argptr, double); // floats are passed as double
377 0 : status = mscbdev_set(info, channel, value);
378 0 : break;
379 :
380 0 : case CMD_GET:
381 : case CMD_GET_DIRECT:
382 0 : info = va_arg(argptr, MSCBDEV_INFO *);
383 0 : channel = va_arg(argptr, INT);
384 0 : pvalue = va_arg(argptr, float *);
385 0 : status = mscbdev_get(info, channel, pvalue);
386 0 : break;
387 :
388 0 : case CMD_GET_LABEL:
389 0 : info = va_arg(argptr, MSCBDEV_INFO *);
390 0 : channel = va_arg(argptr, INT);
391 0 : name = va_arg(argptr, char *);
392 0 : status = mscbdev_get_label(info, channel, name);
393 0 : break;
394 :
395 0 : case CMD_GET_DEMAND_DIRECT:
396 0 : info = va_arg(argptr, MSCBDEV_INFO *);
397 0 : channel = va_arg(argptr, INT);
398 0 : pvalue = va_arg(argptr, float *);
399 0 : status = mscbdev_get(info, channel, pvalue);
400 0 : break;
401 :
402 0 : default:
403 0 : break;
404 : }
405 :
406 0 : va_end(argptr);
407 :
408 0 : return status;
409 : }
410 :
411 : /*------------------------------------------------------------------*/
|