Line data Source code
1 : /********************************************************************\
2 :
3 : Name: mscbhv4.c
4 : Created by: Stefan Ritt
5 :
6 : Contents: MSCB Mu3e 4-channel High Voltage Device Driver
7 :
8 : $Id: mscbhvr.c 2753 2005-10-07 14:55:31Z ritt $
9 :
10 : \********************************************************************/
11 :
12 : #include <stdio.h>
13 : #include <math.h>
14 : #include <stdarg.h>
15 : #include <string.h>
16 : #include <assert.h>
17 : #include <stdlib.h>
18 : #include "midas.h"
19 : #include "mscb.h"
20 : #include "mfe.h"
21 :
22 : /*---- globals -----------------------------------------------------*/
23 :
24 : typedef struct {
25 : char mscb_device[NAME_LENGTH];
26 : char pwd[NAME_LENGTH];
27 : BOOL debug;
28 : int *address;
29 : int channels;
30 : } MSCBHV4_SETTINGS;
31 :
32 : typedef struct {
33 : unsigned char control;
34 : float u_demand;
35 : float u_meas;
36 : unsigned char enabled;
37 : unsigned char on[4];
38 : float i_meas[4];
39 : bool cached;
40 : } MSCB_NODE_VARS;
41 :
42 : typedef struct {
43 : MSCBHV4_SETTINGS settings;
44 : int fd;
45 : MSCB_NODE_VARS *node_vars;
46 : } MSCBHV4_INFO;
47 :
48 : INT mscbhv4_read_all(MSCBHV4_INFO * info, int i);
49 :
50 : /*---- device driver routines --------------------------------------*/
51 :
52 0 : INT mscbhv4_init(HNDLE hkey, void **pinfo, INT channels, INT(*bd) (INT cmd, ...))
53 : {
54 : int status, size;
55 : HNDLE hDB;
56 : MSCBHV4_INFO *info;
57 : MSCB_INFO node_info;
58 : KEY key;
59 :
60 : /* allocate info structure */
61 0 : info = (MSCBHV4_INFO *) calloc(1, sizeof(MSCBHV4_INFO));
62 0 : info->node_vars = (MSCB_NODE_VARS *) calloc(channels, sizeof(MSCB_NODE_VARS));
63 0 : *pinfo = info;
64 :
65 0 : cm_get_experiment_database(&hDB, NULL);
66 :
67 : // retrieve device name
68 0 : db_get_key(hDB, hkey, &key);
69 :
70 : // create MSCBHV4 settings record
71 0 : size = sizeof(info->settings.mscb_device);
72 0 : info->settings.mscb_device[0] = 0;
73 0 : status = db_get_value(hDB, hkey, "MSCB Device", &info->settings.mscb_device, &size, TID_STRING, TRUE);
74 0 : if (status != DB_SUCCESS)
75 0 : return FE_ERR_ODB;
76 :
77 0 : size = sizeof(info->settings.pwd);
78 0 : info->settings.pwd[0] = 0;
79 0 : status = db_get_value(hDB, hkey, "MSCB Pwd", &info->settings.pwd, &size, TID_STRING, TRUE);
80 0 : if (status != DB_SUCCESS)
81 0 : return FE_ERR_ODB;
82 :
83 0 : info->settings.address = (int*)calloc(sizeof(INT), channels/4);
84 0 : assert(info->settings.address);
85 :
86 0 : int n_nodes = ((channels-1) / 4 + 1);
87 0 : size = n_nodes * sizeof(INT);
88 0 : status = db_get_value(hDB, hkey, "MSCB Address", info->settings.address, &size, TID_INT, FALSE);
89 0 : if (status != DB_SUCCESS)
90 0 : return FE_ERR_ODB;
91 :
92 : // open device on MSCB
93 0 : info->fd = mscb_init(info->settings.mscb_device, NAME_LENGTH, info->settings.pwd, info->settings.debug);
94 0 : if (info->fd < 0) {
95 0 : cm_msg(MERROR, "mscbhv4_init",
96 : "Cannot access MSCB submaster at \"%s\". Check power and connection.",
97 0 : info->settings.mscb_device);
98 0 : return FE_ERR_HW;
99 : }
100 :
101 : // check nodes
102 0 : for (int i=0 ; i<n_nodes ; i++) {
103 0 : status = mscb_info(info->fd, info->settings.address[i], &node_info);
104 0 : if (status != MSCB_SUCCESS) {
105 0 : cm_msg(MERROR, "mscbhv4_init",
106 : "Cannot access HV4 node at address \"%d\". Please check cabling and power.",
107 0 : info->settings.address[0]);
108 0 : return FE_ERR_HW;
109 : }
110 :
111 0 : if (strcmp(node_info.node_name, "HV+") != 0 &&
112 0 : strcmp(node_info.node_name, "HV-") != 0) {
113 0 : cm_msg(MERROR, "mscbhvr_init",
114 : "Found unexpected node \"%s\" at address \"%d\".",
115 0 : node_info.node_name, info->settings.address[i]);
116 0 : return FE_ERR_HW;
117 : }
118 : }
119 :
120 : // read all values from HV4 devices
121 0 : for (int i=0 ; i<channels ; i++) {
122 :
123 0 : if (i % 10 == 0)
124 0 : printf("%s: %d\r", key.name, i);
125 :
126 0 : status = mscbhv4_read_all(info, i);
127 0 : if (status != FE_SUCCESS)
128 0 : return status;
129 : }
130 0 : printf("%s: %d\n", key.name, channels);
131 :
132 0 : return FE_SUCCESS;
133 : }
134 :
135 : /*----------------------------------------------------------------------------*/
136 :
137 0 : INT mscbhv4_read_all(MSCBHV4_INFO * info, int i)
138 : {
139 : int size, status;
140 : unsigned char buffer[256], *pbuf;
141 : char str[256];
142 :
143 0 : if (i % 4 != 0)
144 0 : return FE_SUCCESS;
145 :
146 0 : size = sizeof(buffer);
147 0 : status = mscb_read_range(info->fd, info->settings.address[i/4], 0, 10, buffer, &size);
148 0 : if (status != MSCB_SUCCESS) {
149 0 : sprintf(str, "Error reading MSCB HV4 at \"%s:%d\".",
150 0 : info->settings.mscb_device, info->settings.address[i/4]);
151 0 : mfe_error(str);
152 0 : return FE_ERR_HW;
153 : }
154 :
155 : // decode variables from buffer
156 0 : pbuf = buffer;
157 0 : DWORD_SWAP(pbuf);
158 0 : info->node_vars[i].u_demand = *((float *)pbuf);
159 0 : pbuf += sizeof(float);
160 0 : DWORD_SWAP(pbuf);
161 0 : info->node_vars[i].u_meas = *((float *)pbuf);
162 0 : pbuf += sizeof(float);
163 0 : info->node_vars[i].enabled = *((unsigned char *)pbuf);
164 0 : pbuf += sizeof(char);
165 0 : info->node_vars[i].on[0] = *((unsigned char *)pbuf);
166 0 : pbuf += sizeof(char);
167 0 : info->node_vars[i].on[1] = *((unsigned char *)pbuf);
168 0 : pbuf += sizeof(char);
169 0 : info->node_vars[i].on[2] = *((unsigned char *)pbuf);
170 0 : pbuf += sizeof(char);
171 0 : info->node_vars[i].on[3] = *((unsigned char *)pbuf);
172 0 : pbuf += sizeof(char);
173 0 : DWORD_SWAP(pbuf);
174 0 : info->node_vars[i].i_meas[0] = *((float *)pbuf);
175 0 : pbuf += sizeof(float);
176 0 : DWORD_SWAP(pbuf);
177 0 : info->node_vars[i].i_meas[1] = *((float *)pbuf);
178 0 : pbuf += sizeof(float);
179 0 : DWORD_SWAP(pbuf);
180 0 : info->node_vars[i].i_meas[2] = *((float *)pbuf);
181 0 : pbuf += sizeof(float);
182 0 : DWORD_SWAP(pbuf);
183 0 : info->node_vars[i].i_meas[3] = *((float *)pbuf);
184 0 : pbuf += sizeof(float);
185 :
186 : // mark voltage/current as valid in cache
187 0 : for (int j=i ; j<i+4 ; j++)
188 0 : info->node_vars[j].cached = 1;
189 :
190 0 : return FE_SUCCESS;
191 : }
192 :
193 : /*----------------------------------------------------------------------------*/
194 :
195 0 : INT mscbhv4_exit(MSCBHV4_INFO * info)
196 : {
197 0 : mscb_exit(info->fd);
198 :
199 0 : free(info);
200 :
201 0 : return FE_SUCCESS;
202 : }
203 :
204 : /*----------------------------------------------------------------------------*/
205 :
206 0 : INT mscbhv4_set(MSCBHV4_INFO * info, INT channel, float value)
207 : {
208 0 : int fc = channel / 4 * 4; // first channel of module
209 0 : int mc = channel % 4; // channel in module
210 :
211 0 : if (value == 0) {
212 : // turn channel off
213 0 : unsigned char flag = 0;
214 0 : mscb_write(info->fd, info->settings.address[channel/4], 3+mc, &flag, 1);
215 0 : info->node_vars[channel].u_demand = 0;
216 0 : info->node_vars[fc].on[mc] = 0;
217 : } else {
218 :
219 0 : mscb_write(info->fd, info->settings.address[channel / 4], 0, &value, 4);
220 :
221 : // set demand value of all four channels, since unit only has one demand
222 0 : for (int i = fc; i < fc + 4; i++)
223 0 : if (info->node_vars[i].u_demand != 0)
224 0 : info->node_vars[i].u_demand = value;
225 :
226 0 : if (info->node_vars[fc].on[mc] == 0) {
227 : // turn channel on
228 0 : unsigned char flag = 1;
229 0 : mscb_write(info->fd, info->settings.address[channel/4], 3+mc, &flag, 1);
230 0 : info->node_vars[fc].on[mc] = 1;
231 : }
232 : }
233 :
234 0 : return FE_SUCCESS;
235 : }
236 :
237 : /*----------------------------------------------------------------------------*/
238 :
239 0 : INT mscbhv4_get(MSCBHV4_INFO * info, INT channel, float *pvalue)
240 : {
241 0 : int fc = channel / 4 * 4; // first channel of module
242 :
243 : // check if value was previously read by mscbhvr_read_all()
244 0 : if (info->node_vars[channel].cached) {
245 0 : if (info->node_vars[fc].on[channel % 4] == 0)
246 0 : *pvalue = 0;
247 : else
248 0 : *pvalue = info->node_vars[fc].u_meas;
249 0 : info->node_vars[channel].cached = 0;
250 0 : return FE_SUCCESS;
251 : }
252 :
253 0 : int status = mscbhv4_read_all(info, channel);
254 :
255 0 : if (info->node_vars[fc].on[channel % 4] == 0)
256 0 : *pvalue = 0;
257 : else
258 0 : *pvalue = info->node_vars[fc].u_meas;
259 0 : return status;
260 : }
261 :
262 : /*---- device driver entry point -----------------------------------*/
263 :
264 0 : INT mscbhv4(INT cmd, ...)
265 : {
266 : va_list argptr;
267 : HNDLE hKey;
268 : INT channel, status;
269 : float value, *pvalue;
270 : int *pivalue, i;
271 : INT(*bd)(INT,...);
272 : MSCBHV4_INFO *info;
273 :
274 0 : va_start(argptr, cmd);
275 0 : status = FE_SUCCESS;
276 :
277 0 : switch (cmd) {
278 0 : case CMD_INIT:
279 0 : hKey = va_arg(argptr, HNDLE);
280 0 : info = va_arg(argptr, MSCBHV4_INFO *);
281 0 : channel = va_arg(argptr, INT);
282 0 : bd = va_arg(argptr, INT(*)(INT,...));
283 0 : status = mscbhv4_init(hKey, (void**)info, channel, bd);
284 0 : break;
285 :
286 0 : case CMD_EXIT:
287 0 : info = va_arg(argptr, MSCBHV4_INFO *);
288 0 : status = mscbhv4_exit(info);
289 0 : break;
290 :
291 0 : case CMD_SET:
292 0 : info = va_arg(argptr, MSCBHV4_INFO *);
293 0 : channel = va_arg(argptr, INT);
294 0 : value = (float) va_arg(argptr, double);
295 0 : status = mscbhv4_set(info, channel, value);
296 0 : break;
297 :
298 0 : case CMD_GET:
299 0 : info = va_arg(argptr, MSCBHV4_INFO *);
300 0 : channel = va_arg(argptr, INT);
301 0 : pvalue = va_arg(argptr, float *);
302 0 : status = mscbhv4_get(info, channel, pvalue);
303 0 : break;
304 :
305 0 : case CMD_GET_DEMAND:
306 0 : info = va_arg(argptr, MSCBHV4_INFO *);
307 0 : channel = va_arg(argptr, INT);
308 0 : pvalue = va_arg(argptr, float *);
309 0 : i = channel / 4 * 4;
310 :
311 0 : if (info->node_vars[i].on[channel % 4] == 0)
312 0 : *pvalue = 0;
313 : else
314 0 : *pvalue = info->node_vars[i].u_demand;
315 0 : break;
316 :
317 0 : case CMD_GET_CURRENT:
318 0 : info = va_arg(argptr, MSCBHV4_INFO *);
319 0 : channel = va_arg(argptr, INT);
320 0 : pvalue = va_arg(argptr, float *);
321 0 : i = channel / 4 * 4;
322 0 : *pvalue = info->node_vars[i].i_meas[channel % 4];
323 0 : break;
324 :
325 0 : case CMD_GET_LABEL:
326 : case CMD_SET_LABEL:
327 0 : status = FE_SUCCESS;
328 0 : break;
329 :
330 0 : case CMD_GET_THRESHOLD:
331 0 : info = va_arg(argptr, MSCBHV4_INFO *);
332 0 : channel = va_arg(argptr, INT);
333 0 : pvalue = va_arg(argptr, float *);
334 0 : *pvalue = 0.01f;
335 0 : break;
336 :
337 0 : case CMD_GET_THRESHOLD_CURRENT:
338 0 : info = va_arg(argptr, MSCBHV4_INFO *);
339 0 : channel = va_arg(argptr, INT);
340 0 : pvalue = va_arg(argptr, float *);
341 0 : *pvalue = 0.05f;
342 0 : break;
343 :
344 0 : case CMD_GET_THRESHOLD_ZERO:
345 0 : info = va_arg(argptr, MSCBHV4_INFO *);
346 0 : channel = va_arg(argptr, INT);
347 0 : pvalue = va_arg(argptr, float *);
348 0 : *pvalue = 15;
349 0 : break;
350 :
351 0 : case CMD_GET_STATUS:
352 0 : info = va_arg(argptr, MSCBHV4_INFO *);
353 0 : channel = va_arg(argptr, INT);
354 0 : pivalue = va_arg(argptr, INT *);
355 0 : i = channel / 4 * 4;
356 0 : *pivalue = info->node_vars[i].enabled;
357 0 : break;
358 :
359 0 : case CMD_GET_VOLTAGE_LIMIT:
360 0 : info = va_arg(argptr, MSCBHV4_INFO *);
361 0 : channel = va_arg(argptr, INT);
362 0 : pvalue = va_arg(argptr, float *);
363 0 : *pvalue = 120;
364 0 : break;
365 :
366 0 : case CMD_GET_CURRENT_LIMIT:
367 0 : info = va_arg(argptr, MSCBHV4_INFO *);
368 0 : channel = va_arg(argptr, INT);
369 0 : pvalue = va_arg(argptr, float *);
370 0 : *pvalue = 1.25;
371 0 : break;
372 :
373 0 : case CMD_GET_RAMPDOWN:
374 : case CMD_GET_RAMPUP:
375 : case CMD_GET_TRIP_TIME:
376 : case CMD_GET_TRIP:
377 : case CMD_GET_TEMPERATURE:
378 0 : info = va_arg(argptr, MSCBHV4_INFO *);
379 0 : channel = va_arg(argptr, INT);
380 0 : pivalue = va_arg(argptr, INT *);
381 0 : *pivalue = 0; // not implemented for the moment...
382 0 : status = FE_SUCCESS;
383 0 : break;
384 :
385 0 : case CMD_SET_TRIP_TIME:
386 : case CMD_SET_VOLTAGE_LIMIT:
387 : case CMD_SET_CURRENT_LIMIT:
388 : case CMD_START:
389 : case CMD_STOP:
390 : case CMD_SET_RAMPUP:
391 : case CMD_SET_RAMPDOWN:
392 0 : break;
393 :
394 0 : default:
395 0 : cm_msg(MERROR, "mscbhv4 device driver", "Received unknown command %d", cmd);
396 0 : status = FE_ERR_DRIVER;
397 0 : break;
398 : }
399 :
400 0 : va_end(argptr);
401 :
402 0 : return status;
403 : }
404 :
405 : /*------------------------------------------------------------------*/
|