~ubuntu-branches/ubuntu/saucy/nut/saucy

« back to all changes in this revision

Viewing changes to drivers/newhidups.c

  • Committer: Bazaar Package Importer
  • Author(s): Reinhard Tartler
  • Date: 2005-07-20 19:48:50 UTC
  • mto: (16.1.1 squeeze)
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: james.westby@ubuntu.com-20050720194850-oo61wjr33rrx2mre
Tags: upstream-2.0.2
ImportĀ upstreamĀ versionĀ 2.0.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* newhidups.c - New prototype HID UPS driver for Network UPS Tools
 
1
/* newhidups.c - Driver for serial/USB HID UPS units
2
2
 * 
3
 
 * Copyright (C) 2003-2004
4
 
 * Arnaud Quette <arnaud.quette@free.fr> && <arnaud.quette@mgeups.com>
 
3
 * Copyright (C) 2003 - 2005
 
4
 *   Arnaud Quette <arnaud.quette@free.fr> && <arnaud.quette@mgeups.com>
 
5
 *   John Stamp <kinsayder@hotmail.com>
5
6
 *
6
7
 * This program is sponsored by MGE UPS SYSTEMS - opensource.mgeups.com
7
8
 *
25
26
#include "newhidups.h"
26
27
 
27
28
/* include all known hid2nut lookup tables */
28
 
#include "mgehid.h"
 
29
#include "mge-hid.h"
 
30
#include "apc-hid.h"
29
31
 
30
 
/* pointer to the good HidNut lookup table */
 
32
/* pointer to the good lookup tables */
31
33
static hid_info_t *hid_ups;
 
34
static models_name_t *model_names;
32
35
 
33
36
/* Global vars */
34
37
static HIDDevice *hd;
 
38
static MatchFlags flg;
35
39
static int offdelay = DEFAULT_OFFDELAY;
36
40
static int ondelay = DEFAULT_ONDELAY;
 
41
static int pollfreq = DEFAULT_POLLFREQ;
 
42
static int ups_status = 0;
 
43
static bool data_has_changed = FALSE; /* for SEMI_STATIC data polling */
 
44
static time_t lastpoll; /* Timestamp the last polling */
37
45
 
38
46
/* support functions */
 
47
static int instcmd(const char *cmdname, const char *extradata);
39
48
static int setvar(const char *varname, const char *val);
40
 
static hid_info_t *find_info(const char *varname);
 
49
static hid_info_t *find_nut_info(const char *varname);
 
50
static hid_info_t *find_hid_info(const char *hidname);
41
51
static char *hu_find_infoval(info_lkp_t *hid2info, long value);
42
 
static char *format_model_name(char *iProduct, char *iModel);
 
52
static char *get_model_name(char *iProduct, char *iModel);
 
53
static void process_status_info(char *nutvalue);
 
54
static void ups_status_set(void);
 
55
static void identify_ups ();
 
56
static bool hid_ups_walk(int mode);
 
57
static void reconnect_ups(void);
43
58
 
44
59
/* ---------------------------------------------
45
60
 * driver functions implementations
46
61
 * --------------------------------------------- */
47
62
void upsdrv_shutdown(void)
48
63
{
49
 
  char delay[6];
50
 
 
51
 
  /* 1) set DelayBeforeStartup */
52
 
  if (getval ("ondelay"))
53
 
    ondelay = atoi (getval ("ondelay"));
54
 
 
55
 
  //  HIDSetItemValue(find_info("ups.delay.start")->hidpath, ondelay);
56
 
  sprintf(&delay[0], "%i", ondelay);
57
 
  if (setvar("ups.delay.start", &delay[0])!= STAT_SET_HANDLED)
58
 
    fatalx("Shutoff command failed (setting ondelay)");
59
 
 
60
 
  /* 2) set DelayBeforeShutdown */
61
 
  if (getval ("offdelay"))
62
 
    offdelay = atoi (getval ("offdelay"));
63
 
  
64
 
  //HIDSetItemValue(find_info("ups.delay.shutdown")->hidpath, offdelay);
65
 
  sprintf(&delay[0], "%i", offdelay);
66
 
  if (setvar("ups.delay.shutdown", &delay[0])!= STAT_SET_HANDLED)
67
 
    fatalx("Shutoff command failed (setting offdelay)");
 
64
        char delay[7];
 
65
 
 
66
        /* Retrieve user defined delay settings */
 
67
        if ( getval(HU_VAR_ONDELAY) )
 
68
                ondelay = atoi( getval(HU_VAR_ONDELAY) );
 
69
 
 
70
        if ( getval(HU_VAR_OFFDELAY) )
 
71
                offdelay = atoi( getval(HU_VAR_OFFDELAY) );
 
72
 
 
73
        /* Apply specific method(s) */
 
74
        switch (hd->VendorID)
 
75
        {
 
76
                case APC:
 
77
                        /* FIXME: the data (or command) should appear in
 
78
                         * the hid2nut table, so that it can be autodetected
 
79
                         * upon startup, and then calable through setvar()
 
80
                         * or instcmd(), ie below
 
81
                         */
 
82
 
 
83
                        /* From apcupsd, usb.c/killpower() */
 
84
                        /* 1) APCBattCapBeforeStartup */
 
85
                        /* 2) BackUPS Pro => */
 
86
        
 
87
                        /* Misc method B */
 
88
                        upsdebugx(2, "upsdrv_shutdown: APC ForceShutdown style shutdown.\n");
 
89
                        if (instcmd("shutdown.return", NULL) != STAT_INSTCMD_HANDLED)
 
90
                                upsdebugx(2, "ForceShutdown command failed");
 
91
 
 
92
 
 
93
                /* Don't "break" as the general method might also be supported! */;
 
94
                case MGE_UPS_SYSTEMS:
 
95
                default:
 
96
                        /* 1) set DelayBeforeStartup */
 
97
                        sprintf(&delay[0], "%i", ondelay);
 
98
                        if (setvar("ups.delay.start", &delay[0])!= STAT_SET_HANDLED)
 
99
                                fatalx("Shutoff command failed (setting ondelay)");
 
100
                        
 
101
                        /* 2) set DelayBeforeShutdown */
 
102
                        sprintf(&delay[0], "%i", offdelay);
 
103
                        if (setvar("ups.delay.shutdown", &delay[0])!= STAT_SET_HANDLED)
 
104
                                fatalx("Shutoff command failed (setting offdelay)");
 
105
                break;
 
106
        }
68
107
}
69
108
 
70
109
/* process instant command and take action. */
71
110
static int instcmd(const char *cmdname, const char *extradata)
72
111
{
73
 
  hid_info_t *hidups_item;
74
 
 
75
 
  /* 1) retrieve and check netvar & item_path */        
76
 
  hidups_item = find_info(cmdname);
77
 
 
78
 
  if (hidups_item == NULL || hidups_item->info_type == NULL ||
79
 
      !(hidups_item->hidflags & HU_FLAG_OK))
80
 
    {
81
 
      upsdebugx(2, "instcmd: info element unavailable %s\n", cmdname);
82
 
      /* TODO: manage items handled "manually" */
83
 
      return STAT_INSTCMD_UNKNOWN;
84
 
    }
85
 
 
86
 
  /* Checking if item is an instant command */
87
 
  if (!hidups_item->hidflags & HU_TYPE_CMD) {
88
 
    upsdebugx(2, "instcmd: %s is not an instant command\n", cmdname);
89
 
    return STAT_INSTCMD_UNKNOWN;
90
 
  }
91
 
 
92
 
  /* Actual variable setting */
93
 
  if (HIDSetItemValue(hidups_item->hidpath, atol(hidups_item->dfl))) {
94
 
 
95
 
    upsdebugx(3, "SUCCEED\n");
96
 
    return STAT_INSTCMD_HANDLED;
97
 
  }
98
 
  else
99
 
    upsdebugx(3, "FAILED\n"); /* TODO: HANDLED but FAILED, not UNKNOWN! */
100
 
 
101
 
  /* TODO: to be completed */
102
 
  return STAT_INSTCMD_UNKNOWN;
 
112
        hid_info_t *hidups_item;
 
113
        
 
114
        upsdebugx(2, "entering instcmd(%s, %s)\n", cmdname, extradata);
 
115
 
 
116
        /* Retrieve and check netvar & item_path */     
 
117
        hidups_item = find_nut_info(cmdname);
 
118
        
 
119
        /* Check validity of the found the item */
 
120
        if (hidups_item == NULL || hidups_item->info_type == NULL ||
 
121
                !(hidups_item->hidflags & HU_FLAG_OK))
 
122
        {
 
123
                upsdebugx(2, "instcmd: info element unavailable %s\n", cmdname);
 
124
                /* TODO: manage items handled "manually" */
 
125
                return STAT_INSTCMD_UNKNOWN;
 
126
        }
 
127
 
 
128
        /* Check if the item is an instant command */
 
129
        if (!hidups_item->hidflags & HU_TYPE_CMD)
 
130
        {
 
131
                upsdebugx(2, "instcmd: %s is not an instant command\n", cmdname);
 
132
                return STAT_INSTCMD_UNKNOWN;
 
133
        }
 
134
        
 
135
        /* Actual variable setting */
 
136
        if (HIDSetItemValue(hidups_item->hidpath, atol(hidups_item->dfl)))
 
137
        {
 
138
                upsdebugx(3, "SUCCEED\n");
 
139
                /* Set the status so that SEMI_STATIC vars are polled */
 
140
                data_has_changed = TRUE;
 
141
                return STAT_INSTCMD_HANDLED;
 
142
        }
 
143
        else
 
144
                upsdebugx(3, "FAILED\n"); /* TODO: HANDLED but FAILED, not UNKNOWN! */
 
145
        
 
146
        /* TODO: to be completed */
 
147
        return STAT_INSTCMD_UNKNOWN;
103
148
}
104
149
 
105
 
/* set r/w INFO_ element to a value. */
 
150
/* set r/w variable to a value. */
106
151
static int setvar(const char *varname, const char *val)
107
152
{
108
 
  hid_info_t *hidups_item;
109
 
 
110
 
  upsdebugx(2, "============== entering setvar(%s, %s) ==============\n", varname, val);
111
 
 
112
 
  /* 1) retrieve and check netvar & item_path */        
113
 
  hidups_item = find_info(varname);
114
 
 
115
 
  if (hidups_item == NULL || hidups_item->info_type == NULL ||
116
 
      !(hidups_item->hidflags & HU_FLAG_OK))
117
 
    {
118
 
      upsdebugx(2, "setvar: info element unavailable %s\n", varname);
119
 
      return STAT_SET_UNKNOWN;
120
 
    }
121
 
 
122
 
  /* Checking item writability and HID Path */
123
 
  if (!hidups_item->info_flags & ST_FLAG_RW) {
124
 
    upsdebugx(2, "setvar: not writable %s\n", varname);
125
 
    return STAT_SET_UNKNOWN;
126
 
  }
127
 
 
128
 
  /* handle server side variable */
129
 
  if (hidups_item->hidflags & HU_FLAG_ABSENT) {
130
 
    upsdebugx(2, "setvar: setting server side variable %s\n", varname);
131
 
    dstate_setinfo(hidups_item->info_type, val);
132
 
    return STAT_SET_HANDLED;
133
 
  } else {
134
 
    /* SHUT_FLAG_ABSENT is the only case of HID Path == NULL */
135
 
    if (hidups_item->hidpath == NULL) {
136
 
      upsdebugx(2, "setvar: ID Path is NULL for %s\n", varname);
137
 
      return STAT_SET_UNKNOWN;
138
 
    }
139
 
  }
140
 
 
141
 
  /* Actual variable setting */
142
 
  if (HIDSetItemValue(hidups_item->hidpath, atol(val))) {
143
 
 
144
 
    /* TODO: GetValue(hidups_item->hidpath) to ensure success */
145
 
    upsdebugx(3, "SUCCEED\n");
146
 
    /* Delay a bit not to flood the device */
147
 
    sleep(1);
148
 
    return STAT_SET_HANDLED;
149
 
  }
150
 
  else
151
 
    upsdebugx(3, "FAILED\n"); /* TODO: HANDLED but FAILED, not UNKNOWN! */
152
 
 
153
 
  return STAT_SET_UNKNOWN;
154
 
}
155
 
 
156
 
void upsdrv_help(void) { /* TODO: to be completed */ }
 
153
        hid_info_t *hidups_item;
 
154
        
 
155
        upsdebugx(2, "entering setvar(%s, %s)\n", varname, val);
 
156
        
 
157
        /* 1) retrieve and check netvar & item_path */  
 
158
        hidups_item = find_nut_info(varname);
 
159
        
 
160
        if (hidups_item == NULL || hidups_item->info_type == NULL ||
 
161
                !(hidups_item->hidflags & HU_FLAG_OK))
 
162
        {
 
163
                upsdebugx(2, "setvar: info element unavailable %s\n", varname);
 
164
                return STAT_SET_UNKNOWN;
 
165
        }
 
166
 
 
167
        /* Checking item writability and HID Path */
 
168
        if (!hidups_item->info_flags & ST_FLAG_RW)
 
169
        {
 
170
                upsdebugx(2, "setvar: not writable %s\n", varname);
 
171
                return STAT_SET_UNKNOWN;
 
172
        }
 
173
 
 
174
        /* handle server side variable */
 
175
        if (hidups_item->hidflags & HU_FLAG_ABSENT)
 
176
        {
 
177
                upsdebugx(2, "setvar: setting server side variable %s\n", varname);
 
178
                dstate_setinfo(hidups_item->info_type, "%s", val);
 
179
                return STAT_SET_HANDLED;
 
180
        }
 
181
        else
 
182
        {
 
183
                /* SHUT_FLAG_ABSENT is the only case of HID Path == NULL */
 
184
                if (hidups_item->hidpath == NULL)
 
185
                {
 
186
                        upsdebugx(2, "setvar: ID Path is NULL for %s\n", varname);
 
187
                        return STAT_SET_UNKNOWN;
 
188
                }
 
189
        }
 
190
 
 
191
        /* Actual variable setting */
 
192
        if (HIDSetItemValue(hidups_item->hidpath, atol(val)))
 
193
        {
 
194
                /* FIXME: GetValue(hidups_item->hidpath) to ensure success on non volatile */
 
195
                upsdebugx(3, "SUCCEED\n");
 
196
                /* Delay a bit not to flood the device */
 
197
                sleep(1);
 
198
                /* Set the status so that SEMI_STATIC vars are polled */
 
199
                data_has_changed = TRUE;
 
200
                return STAT_SET_HANDLED;
 
201
        }
 
202
        else
 
203
                upsdebugx(3, "FAILED\n"); /* FIXME: HANDLED but FAILED, not UNKNOWN! */
 
204
        
 
205
        return STAT_SET_UNKNOWN;
 
206
}
 
207
 
 
208
void upsdrv_help(void)
 
209
{
 
210
  /* FIXME: to be completed */
 
211
}
157
212
 
158
213
void upsdrv_makevartable(void) 
159
214
{
160
 
  char temp [128];
161
 
  
162
 
  /* add command line/conf variables */
163
 
  sprintf(temp, "Set shutdown delay, in seconds (default=%d).",
164
 
          DEFAULT_OFFDELAY);
165
 
  addvar (VAR_VALUE, "offdelay", temp);
166
 
  
167
 
  sprintf(temp, "Set startup delay, in ten seconds units for MGE (default=%d).",
168
 
          DEFAULT_ONDELAY);
169
 
  addvar (VAR_VALUE, "ondelay", temp);
170
 
  
171
 
  /* TODO: getval (Mfr, Prod, Idx) */
 
215
        char temp [MAX_STRING_SIZE];
 
216
        
 
217
        sprintf(temp, "Set shutdown delay, in seconds (default=%d).",
 
218
                DEFAULT_OFFDELAY);
 
219
        addvar (VAR_VALUE, HU_VAR_OFFDELAY, temp);
 
220
        
 
221
        sprintf(temp, "Set startup delay, in ten seconds units for MGE (default=%d).",
 
222
                DEFAULT_ONDELAY);
 
223
        addvar (VAR_VALUE, HU_VAR_ONDELAY, temp);
 
224
        
 
225
        sprintf(temp, "Set polling frequency, in seconds, to reduce USB flow (default=%i).",
 
226
                DEFAULT_POLLFREQ);
 
227
        addvar(VAR_VALUE, HU_VAR_POLLFREQ, temp);
 
228
        
 
229
        /* FIXME: autodetection values (Mfr, Product, Index, ...) */
172
230
}
173
231
 
174
232
void upsdrv_banner(void)
175
233
{
176
 
  printf("Network UPS Tools: New HID UPS driver %s (%s)\n\n",
177
 
         DRIVER_VERSION, UPS_VERSION);
178
 
 
179
 
  experimental_driver = 1;
 
234
        printf("Network UPS Tools: New USB/HID UPS driver %s (%s)\n\n",
 
235
                DRIVER_VERSION, UPS_VERSION);
180
236
}
181
237
 
182
 
/* TODO: merge {init,update}info in hidups_walk() */
183
238
void upsdrv_updateinfo(void) 
184
239
{
185
 
  hid_info_t *item;
186
 
  float value;
187
 
  char *nutvalue;
188
 
 
189
 
  upsdebugx(1, "Updating...\n");
190
 
 
191
 
  /* clear status buffer before begining */
192
 
  status_init();
193
 
 
194
 
  /* Process pending events (HID notifications on Interrupt pipe) */
195
 
  /* TODO: process "HIDItem HIDGetNextEvent(HIDDevice *dev);" */
196
 
 
197
 
  /* Device data walk ----------------------------- */
198
 
  for ( item = hid_ups ; item->info_type != NULL ; item++ ) {
199
 
 
200
 
    if ((item->hidflags & HU_FLAG_ABSENT)
201
 
        || (item->hidflags & HU_TYPE_CMD))
202
 
      continue;
203
 
    
204
 
    if (item->hidflags & HU_FLAG_OK) {
205
 
      
206
 
      /* TODO: 3 tryes before giving up (needed when OnBattery!) */
207
 
      if ((value = HIDGetItemValue(item->hidpath)) != -2 ) {
208
 
 
209
 
        /* deal with status items */
210
 
        if (!strncmp(item->info_type, "ups.status", 10)) {
211
 
          
212
 
          nutvalue = hu_find_infoval(item->hid2info, (long)value);
213
 
          if (nutvalue != NULL)   
214
 
            status_set(nutvalue);
215
 
 
216
 
        } else { /* standard items */
217
 
          /* need lookup'ed translation */
218
 
          if (item->hid2info != NULL) {
219
 
            nutvalue = hu_find_infoval(item->hid2info, (long)value);
220
 
            if (nutvalue != NULL)
221
 
              dstate_setinfo(item->info_type, item->dfl, nutvalue);
222
 
          }
223
 
          else
224
 
            dstate_setinfo(item->info_type, item->dfl, value);
225
 
 
226
 
          dstate_dataok(); /* atomic "commit" call */
 
240
        hid_info_t *item;
 
241
        char *nutvalue;
 
242
        int retcode, evtCount = 0;
 
243
        HIDItem *eventsList[10];
 
244
 
 
245
        upsdebugx(1, "upsdrv_updateinfo...");
 
246
 
 
247
 
 
248
        /* FIXME: check for device availability */
 
249
        /* to set datastale! */
 
250
        if (hd == NULL)
 
251
          {
 
252
                upsdebugx(1, "\n=>Got to reconnect!\n");
 
253
                reconnect_ups();
 
254
          }
 
255
 
 
256
        /* Only do a full update (polling) every pollfreq 
 
257
         * or upon data change (ie setvar/instcmd) */
 
258
        if ( (time(NULL) <= (lastpoll + pollfreq))
 
259
                 && (data_has_changed != TRUE) )
 
260
          {
 
261
                /* Wait for HID notifications on Interrupt pipe */
 
262
                if ((evtCount = HIDGetEvents(NULL, eventsList)) > 0)
 
263
                  {
 
264
                        upsdebugx(1, "\n=>Got %i HID Objects...", evtCount);
 
265
                        
 
266
                        /* Process pending events (HID notifications on Interrupt pipe) */
 
267
                        while (evtCount > 0)
 
268
                          {
 
269
                                /* Check if we are asked to stop (reactivity++) */
 
270
                                if (exit_flag != 0)
 
271
                                  return;
 
272
 
 
273
                                upsdebugx(3, "Object: %s = %ld", 
 
274
                                                  eventsList[evtCount-1]->Path,
 
275
                                                  eventsList[evtCount-1]->Value);
 
276
                                
 
277
                                if ((item = find_hid_info(eventsList[evtCount-1]->Path)) != NULL)
 
278
                                  {
 
279
                                        /* Does it need value lookup? */
 
280
                                        if (item->hid2info != NULL)
 
281
                                          {
 
282
                                                nutvalue = hu_find_infoval(item->hid2info, (long)eventsList[evtCount-1]->Value);
 
283
                                                if (nutvalue != NULL)
 
284
                                                  {
 
285
                                                        upsdebugx(2, "%s = %s", item->info_type,nutvalue);
 
286
                                                        
 
287
                                                        /* Is it ups.status? */
 
288
                                                        if (!strncmp(item->info_type, "ups.status", 10))
 
289
                                                          {
 
290
                                                                /* bitwise status to process it globally */
 
291
                                                                process_status_info(nutvalue);
 
292
                                                                ups_status_set();
 
293
                                                          }
 
294
                                                        else
 
295
                                                          dstate_setinfo(item->info_type, item->dfl, nutvalue);
 
296
                                                  }
 
297
                                                /* FIXME: else => revert the status, ie -LB == reset LB... */
 
298
                                          }
 
299
                                        else
 
300
                                          upsdebugx(2, "%s = %ld", item->info_type, eventsList[evtCount-1]->Value);
 
301
                                  }
 
302
                                free(eventsList[evtCount-1]);
 
303
                                evtCount--;
 
304
                          }
 
305
                        dstate_dataok();
 
306
                  }
 
307
                else
 
308
                  retcode = evtCount; /* propagate error code */
 
309
 
 
310
                /* Quick poll on main ups.status data */
 
311
                hid_ups_walk(HU_WALKMODE_QUICK_UPDATE);
 
312
          }
 
313
        else /* Polling update */
 
314
          {
 
315
                hid_ups_walk(HU_WALKMODE_FULL_UPDATE);
 
316
          }
 
317
 
 
318
        /* Reset SEMI_STATIC flag */
 
319
        data_has_changed = FALSE;
 
320
}
 
321
 
 
322
 
 
323
/* Process status info globally to avoid inconsistencies */
 
324
static void process_status_info(char *nutvalue)
 
325
{
 
326
        status_lkp_t *status_item;
 
327
 
 
328
        upsdebugx(2, "process_status_info: %s\n", nutvalue);
 
329
 
 
330
        for (status_item = status_info; status_item->status_value != 0 ; status_item++)
 
331
        {
 
332
                if (!strcasecmp(status_item->status_str, nutvalue))
 
333
                {
 
334
                        switch (status_item->status_value)
 
335
                        {
 
336
                                case STATUS_OL: /* clear OB, set OL */
 
337
                                        ups_status &= ~STATUS_OB;
 
338
                                        ups_status |= STATUS_OL;
 
339
                                break;
 
340
                                case STATUS_OB: /* clear OL, set OB */
 
341
                                        ups_status &= ~STATUS_OL;
 
342
                                        ups_status |= STATUS_OB;
 
343
                                break;
 
344
                                case STATUS_LB: /* set LB */ /* FIXME: ?clear OL? */
 
345
                                        ups_status |= STATUS_LB;   /* else, put in default! */ 
 
346
                                break;
 
347
                                case STATUS_CHRG: /* clear DISCHRG, set CHRG */
 
348
                                        ups_status &= ~STATUS_DISCHRG;
 
349
                                        ups_status |= STATUS_CHRG;
 
350
                                break;
 
351
                                case STATUS_DISCHRG: /* clear CHRG, set DISCHRG */
 
352
                                        ups_status &= ~STATUS_CHRG;
 
353
                                        ups_status |= STATUS_DISCHRG;
 
354
                                break;
 
355
                                /* FIXME: to be checked */
 
356
                                default: /* CAL, TRIM, BOOST, OVER, RB, BYPASS, OFF */
 
357
                                        ups_status |= status_item->status_value;
 
358
                                        /* FIXME: When do we reset these? */
 
359
                                break;
 
360
                        }
 
361
                }
227
362
        }
228
 
      } else {
229
 
        dstate_datastale();
230
 
      }
231
 
    }
232
 
  }
233
 
  /* Commit the status buffer */
234
 
  status_commit();
235
363
}
236
364
 
237
365
void upsdrv_initinfo(void)
238
366
{
239
 
  hid_info_t *item;
240
 
  float value;
241
 
  char *nutvalue;
242
 
 
243
 
  /* identify unit: fill ups.{mfr, model, serial} */
244
 
  dstate_setinfo("ups.mfr", hd->Vendor);
245
 
  dstate_setinfo("ups.model", format_model_name(hd->Product, NULL));
246
 
  dstate_setinfo("ups.serial", (hd->Serial != NULL)?hd->Serial:"unknown");
247
 
 
248
 
  /* TODO: load lookup file (WARNING: should be in initups()
249
 
     because of -k segfault (=> not calling upsdrv_initinfo())
250
 
  */
251
 
 
252
 
  /* clear status buffer before begining */
253
 
  status_init();
254
 
 
255
 
  /* Device capabilities enumeration ----------------------------- */
256
 
  for ( item = hid_ups ; item->info_type != NULL ; item++ ) {
257
 
 
258
 
    /* Avoid redundancy when multiple defines (RO/RW)
259
 
     * Not applicable to "ups.status" items!
260
 
     */
261
 
    if ((dstate_getinfo(item->info_type) != NULL)
262
 
        && (strncmp(item->info_type, "ups.status", 10))) { 
263
 
      item->hidflags &= ~HU_FLAG_OK;
264
 
      continue;
265
 
    }
266
 
        
267
 
    /* Special case for handling instant commands */
268
 
    if (item->hidflags & HU_TYPE_CMD) {
269
 
      /* Check actual availability */
270
 
      if (HIDGetItemValue(item->hidpath) != -2 ) {
271
 
        dstate_addcmd(item->info_type);
272
 
      }
273
 
      continue;
274
 
    }
275
 
 
276
 
    /* Special case for handling server side variables */
277
 
    if (item->hidflags & HU_FLAG_ABSENT) {
278
 
      dstate_setinfo(item->info_type, item->dfl);
279
 
      dstate_setflags(item->info_type, item->info_flags);
280
 
      /* disable reading now => needed?!
281
 
         item->shut_flags &= ~HU_FLAG_OK;*/
282
 
    } else {
283
 
      /* TODO: 3 tryes before giving up (needed when OnBattery!) */
284
 
      if ((value = HIDGetItemValue(item->hidpath)) != -2 ) {
285
 
        
286
 
        item->hidflags &= HU_FLAG_OK;
287
 
 
288
 
        /* deal with status items */
289
 
        if (!strncmp(item->info_type, "ups.status", 10)) {
290
 
          nutvalue = hu_find_infoval(item->hid2info, (long)value);
291
 
          if (nutvalue != NULL)
292
 
            status_set(nutvalue);
293
 
 
294
 
        } else { /* standard items */
295
 
          /* need lookup'ed translation */
296
 
          if (item->hid2info != NULL) {
297
 
            nutvalue = hu_find_infoval(item->hid2info, (long)value);
298
 
            if (nutvalue != NULL)
299
 
              dstate_setinfo(item->info_type, item->dfl, nutvalue);
300
 
          }
301
 
          else
302
 
            dstate_setinfo(item->info_type, item->dfl, value);
303
 
 
304
 
          /* TODO: verify setability/RW with (hData.Attribute != ATTR_DATA_CST) */
305
 
          dstate_setflags(item->info_type, item->info_flags);
306
 
        }
307
 
 
308
 
        /* Set max length for strings */
309
 
        if (item->info_flags & ST_FLAG_STRING)
310
 
          dstate_setaux(item->info_type, item->info_len);
311
 
 
312
 
        dstate_dataok(); /* atomic call */
313
 
      }
314
 
      else {
315
 
        /* invalidate item */
316
 
        item->hidflags &= ~HU_FLAG_OK;
317
 
      }
318
 
    }
319
 
  }
320
 
 
321
 
  /* Commit the status buffer */
322
 
  status_commit();
323
 
 
324
 
  /* install handlers */
325
 
  upsh.new_setvar = setvar;
326
 
  upsh.new_instcmd = instcmd;
 
367
        /* identify unit: fill ups.{mfr, model, serial} */
 
368
        identify_ups ();
 
369
 
 
370
        /* TODO: load lookup file (WARNING: should be in initups()
 
371
        because of -k segfault (=> not calling upsdrv_initinfo())
 
372
        */
 
373
 
 
374
        /* Device capabilities enumeration */
 
375
        hid_ups_walk(HU_WALKMODE_INIT);
 
376
 
 
377
        /* install handlers */
 
378
        upsh.setvar = setvar;
 
379
        upsh.instcmd = instcmd;
327
380
}
328
381
 
329
382
void upsdrv_initups(void)
330
383
{
331
 
  MatchFlags flg;
332
 
  
333
 
  /* Search for the first UPS, no matter Mfr or exact product */
334
 
  /* TODO: add vartable for VID, PID, Idx => getval*/
335
 
  flg.VendorID = MGE_UPS_SYSTEMS; /* limiting to MGE is enough for now! */
336
 
  flg.ProductID = ANY;
337
 
  flg.UsageCode = hid_lookup_usage("UPS");
338
 
  flg.Index = 0x0;
339
 
  
340
 
  if ((hd = HIDOpenDevice(device_path, &flg)) == NULL)
341
 
    fatalx("No USB/HID UPS found");
342
 
  else
343
 
    upslogx(1, "Detected an UPS: %s/%s\n", hd->Vendor, hd->Product);
344
 
 
345
 
  /* See initinfo for WARNING */
346
 
  switch (hd->VendorID)
347
 
    {
348
 
    case MGE_UPS_SYSTEMS:
349
 
      hid_ups = hid_mge;
350
 
      break; 
351
 
    case APC:
352
 
    default:
353
 
      fatalx("Manufacturer not supported. Contact driver author <arnaud.quette@free.fr>");
354
 
      /* TODO: call dump_tree() */
355
 
      break;       
356
 
    }
 
384
        /* Search for the first supported UPS, no matter Mfr or exact product */
 
385
        if ((hd = HIDOpenDevice(device_path, &flg, MODE_OPEN)) == NULL)
 
386
                fatalx("No USB/HID UPS found");
 
387
        else
 
388
                upslogx(1, "Detected an UPS: %s/%s\n", hd->Vendor, hd->Product);
 
389
 
 
390
        /* See initinfo for WARNING */
 
391
        switch (hd->VendorID)
 
392
        {
 
393
                case MGE_UPS_SYSTEMS:
 
394
                        hid_ups = hid_mge;
 
395
                        model_names = mge_models_names;
 
396
                break;
 
397
                case APC:
 
398
                        hid_ups = hid_apc;
 
399
                        model_names = apc_models_names;
 
400
                        HIDDumpTree(NULL);
 
401
                break;
 
402
                case MUSTEK:
 
403
                case TRIPPLITE:
 
404
                case UNITEK:
 
405
                default:
 
406
                        upslogx(1, "Manufacturer not supported!");
 
407
                        upslogx(1, "Contact the driver author <arnaud.quette@free.fr / @mgeups.com> with the below information");
 
408
                        HIDDumpTree(NULL);
 
409
                        fatalx("Aborting");
 
410
                break;
 
411
        }
 
412
 
 
413
        /* init polling frequency */
 
414
        if ( getval(HU_VAR_POLLFREQ) )
 
415
                pollfreq = atoi ( getval(HU_VAR_POLLFREQ) );
357
416
}
358
417
 
359
418
void upsdrv_cleanup(void)
360
419
{
361
 
  if (hd != NULL)
362
 
    HIDCloseDevice(hd);
 
420
        if (hd != NULL)
 
421
                HIDCloseDevice(hd);
363
422
}
364
423
 
365
424
/**********************************************************************
366
425
 * Support functions
367
426
 *********************************************************************/
368
427
 
369
 
/* find info element definition in my info array. */
370
 
static hid_info_t *find_info(const char *varname)
 
428
void identify_ups ()
 
429
{
 
430
        char *string;
 
431
        char *ptr1, *ptr2, *str;
 
432
        char *finalname = NULL;
 
433
        float appPower;
 
434
 
 
435
        upsdebugx (2, "entering identify_ups(0x%04x, 0x%04x)\n", 
 
436
                           hd->VendorID, /*FIXME: iManufacturer? */
 
437
                           hd->iProduct);
 
438
 
 
439
        switch (hd->VendorID)
 
440
        {
 
441
                case MGE_UPS_SYSTEMS:
 
442
                        /* Get iModel and iProduct strings */
 
443
                        if ((string = HIDGetItemString("UPS.PowerSummary.iModel")) != NULL)
 
444
                                finalname = get_model_name(hd->Product, string);
 
445
                        else
 
446
                        {
 
447
                                /* Try with ConfigApparentPower */
 
448
                                if (HIDGetItemValue("UPS.Flow.[4].ConfigApparentPower", &appPower) != 0 )
 
449
                                {
 
450
                                        string = xmalloc(16);
 
451
                                        sprintf(string, "%i", (int)appPower);
 
452
                                        finalname = get_model_name(hd->Product, string);
 
453
                                        free (string);
 
454
                                }
 
455
                                else
 
456
                                finalname = hd->Product;
 
457
                        }
 
458
                break;
 
459
                case APC:
 
460
                        /* FIXME?: what is the path "UPS.APC_UPS_FirmwareRevision"? */
 
461
                        str = hd->Product;
 
462
                        ptr1 = strstr(str, "FW:");
 
463
                        if (ptr1)
 
464
                        {
 
465
                                *(ptr1 - 1) = '\0';
 
466
                                ptr1 += strlen("FW:");
 
467
                                ptr2 = strstr(ptr1, "USB FW:");
 
468
                                if (ptr2)
 
469
                                {
 
470
                                        *(ptr2 - 1) = '\0';
 
471
                                        ptr2 += strlen("USB FW:");
 
472
                                        dstate_setinfo("ups.firmware.aux", "%s", ptr2);
 
473
                                }
 
474
                                dstate_setinfo("ups.firmware", "%s", ptr1);
 
475
                        }
 
476
                        finalname = str;
 
477
                        break;
 
478
                default: /* Nothing to do */
 
479
                break;
 
480
        }
 
481
 
 
482
        /* Actual information setting */
 
483
        dstate_setinfo("ups.mfr", "%s", hd->Vendor);
 
484
        dstate_setinfo("ups.model", "%s", finalname);
 
485
        dstate_setinfo("ups.serial", "%s", (hd->Serial != NULL)?hd->Serial:"unknown");
 
486
}
 
487
 
 
488
/* walk ups variables and set elements of the info array. */
 
489
static bool hid_ups_walk(int mode)
 
490
{
 
491
        hid_info_t *item;
 
492
        float value;
 
493
        char *nutvalue;
 
494
        int retcode = 0;
 
495
 
 
496
        /* 3 modes: HU_WALKMODE_INIT, HU_WALKMODE_QUICK_UPDATE and HU_WALKMODE_FULL_UPDATE */
 
497
        
 
498
        /* Device data walk ----------------------------- */
 
499
        for ( item = hid_ups ; item->info_type != NULL ; item++ )
 
500
          {
 
501
                /* Check if we are asked to stop (reactivity++) */
 
502
                if (exit_flag != 0)
 
503
                  return TRUE;
 
504
 
 
505
                /* filter data according to mode */
 
506
                switch (mode)
 
507
                  {
 
508
                        /* Device capabilities enumeration */
 
509
                  case HU_WALKMODE_INIT:
 
510
                        {               
 
511
                          /* Avoid redundancy when multiple defines (RO/RW)
 
512
                           * Not applicable to "ups.status" items! */
 
513
                          if ((dstate_getinfo(item->info_type) != NULL)
 
514
                                  && (strncmp(item->info_type, "ups.status", 10)))
 
515
                                {
 
516
                                  item->hidflags &= ~HU_FLAG_OK;
 
517
                                  continue;
 
518
                                }
 
519
 
 
520
                          /* Check instant commands availability */
 
521
                          if (item->hidflags & HU_TYPE_CMD)
 
522
                                {
 
523
                                  if (HIDGetItemValue(item->hidpath, &value) == 1 )
 
524
                                        dstate_addcmd(item->info_type);
 
525
 
 
526
                                  continue;
 
527
                                }
 
528
                          /* Special case for handling server side variables */
 
529
                          if (item->hidflags & HU_FLAG_ABSENT)
 
530
                                {
 
531
                                  /* Check if exists (if necessary) before creation */
 
532
                                  if (item->hidpath != NULL)
 
533
                                        {
 
534
                                          if ((retcode = HIDGetItemValue(item->hidpath, &value)) != 1 )
 
535
                                                continue;
 
536
                                        }
 
537
                                  else
 
538
                                        {
 
539
                                          /* Simply set the default value */
 
540
                                          dstate_setinfo(item->info_type, "%s", item->dfl);
 
541
                                          dstate_setflags(item->info_type, item->info_flags);
 
542
                                          continue;
 
543
                                        }
 
544
                        
 
545
                                  dstate_setinfo(item->info_type, "%s", item->dfl);
 
546
                                  dstate_setflags(item->info_type, item->info_flags);
 
547
 
 
548
                                  /* Set max length for strings, if needed */
 
549
                                  if (item->info_flags & ST_FLAG_STRING)
 
550
                                        dstate_setaux(item->info_type, item->info_len);
 
551
                        
 
552
                                  /* disable reading now 
 
553
                                         item->shut_flags &= ~SHUT_FLAG_OK;*/
 
554
                                }
 
555
                        }
 
556
                        break; 
 
557
                  case HU_WALKMODE_QUICK_UPDATE:
 
558
                        {
 
559
                          /* Quick update only deals with status! */
 
560
                          if ( !(item->hidflags & HU_FLAG_QUICK_POLL))
 
561
                                continue;
 
562
                        }
 
563
                        break; 
 
564
                  default:
 
565
                  case HU_WALKMODE_FULL_UPDATE:
 
566
                        {
 
567
                          /* These doesn't need polling after initinfo() */
 
568
                          if ((item->hidflags & HU_FLAG_ABSENT)
 
569
                                  || (item->hidflags & HU_TYPE_CMD)
 
570
                                  || (item->hidflags & HU_FLAG_STATIC)
 
571
                                  /* These need to be polled after user changes (setvar / instcmd) */
 
572
                                  || ( (item->hidflags & HU_FLAG_SEMI_STATIC) && (data_has_changed == FALSE) ) ) 
 
573
                                /* FIXME: external condition might change these, ie pushing the HW On/Off button! */
 
574
                                continue;
 
575
                        }
 
576
                        break; 
 
577
                  }
 
578
 
 
579
                /* Standard variables */
 
580
                /* skip elements we shouldn't process / show. */
 
581
                if ( ( (mode == HU_WALKMODE_QUICK_UPDATE) || (mode == HU_WALKMODE_FULL_UPDATE) )
 
582
                         && !(item->hidflags & HU_FLAG_OK) )
 
583
                  continue;
 
584
 
 
585
                if ((retcode = HIDGetItemValue(item->hidpath, &value)) == 1 )
 
586
                  {
 
587
                        /* deal with status items */
 
588
                        if (!strncmp(item->info_type, "ups.status", 10))
 
589
                          {
 
590
                                nutvalue = hu_find_infoval(item->hid2info, (long)value);
 
591
                                if (nutvalue != NULL)
 
592
                                  {
 
593
                                        /* bitwise status to process it globally */
 
594
                                        process_status_info(nutvalue);
 
595
                                        ups_status_set();
 
596
                                  }
 
597
                          }
 
598
                        else /* standard items */
 
599
                          {
 
600
                                /* need lookup'ed translation? */
 
601
                                if (item->hid2info != NULL)
 
602
                                  {
 
603
                                        nutvalue = hu_find_infoval(item->hid2info, (long)value);
 
604
                                        if (nutvalue != NULL)
 
605
                                          dstate_setinfo(item->info_type, item->dfl, nutvalue);
 
606
                                  }
 
607
                                else
 
608
                                  dstate_setinfo(item->info_type, item->dfl, value);
 
609
                                
 
610
                                if (mode == HU_WALKMODE_INIT)
 
611
                                  {
 
612
                                        /* TODO: verify setability/RW with (hData.Attribute != ATTR_DATA_CST) */
 
613
                                        dstate_setflags(item->info_type, item->info_flags);
 
614
                                  }
 
615
                          }
 
616
                        if (mode == HU_WALKMODE_INIT)
 
617
                          {
 
618
                                /* Set max length for strings */
 
619
                                if (item->info_flags & ST_FLAG_STRING)
 
620
                                  dstate_setaux(item->info_type, item->info_len);
 
621
                          }
 
622
 
 
623
                        /* atomic call */
 
624
/*                      dstate_dataok(); */
 
625
 
 
626
                        /* store timestamp */
 
627
/*                      lastpoll = time(NULL); */
 
628
                  }
 
629
                else
 
630
                  {
 
631
                        if ( (retcode == -EPERM) || (retcode == -EPIPE)
 
632
                                 || (retcode == -ENODEV) || (retcode == -EACCES) )
 
633
                          break;
 
634
                        else {
 
635
                          /* atomic call */
 
636
                          dstate_dataok();
 
637
                        }
 
638
 
 
639
                        if (mode == HU_WALKMODE_INIT)
 
640
                          {
 
641
                                /* invalidate item */
 
642
                                item->hidflags &= ~HU_FLAG_OK;
 
643
                          }
 
644
                  }
 
645
          } /* end for */
 
646
 
 
647
        if (mode == HU_WALKMODE_FULL_UPDATE)
 
648
          {
 
649
                /* store timestamp */
 
650
                lastpoll = time(NULL);
 
651
          }
 
652
 
 
653
        /* Reserved values: -1/-10 for nul delay, -2 can't get value */
 
654
        /* device has been disconnected, try to reconnect */
 
655
        if ( (retcode == -EPERM) || (retcode == -EPIPE)
 
656
                 || (retcode == -ENODEV) || (retcode == -EACCES) )
 
657
          {
 
658
                hd = NULL;
 
659
                reconnect_ups();
 
660
          }
 
661
        else {
 
662
          /* atomic call */
 
663
          dstate_dataok();
 
664
        }
 
665
 
 
666
  return TRUE;
 
667
}
 
668
 
 
669
static void reconnect_ups(void)
 
670
{
 
671
  if (hd == NULL)
 
672
        {         
 
673
          upsdebugx(2, "==================================================");
 
674
          upsdebugx(2, "= device has been disconnected, try to reconnect =");
 
675
          upsdebugx(2, "==================================================");
 
676
          
 
677
          /* Not really useful as the device is no more reachable */
 
678
          HIDCloseDevice(NULL);
 
679
          
 
680
          if ((hd = HIDOpenDevice(device_path, &flg, MODE_REOPEN)) == NULL)
 
681
                dstate_datastale();
 
682
        }
 
683
}
 
684
 
 
685
/* Process the whole ups.status */
 
686
static void ups_status_set(void)
 
687
{
 
688
        /* clear status buffer before begining */
 
689
        status_init();
 
690
  
 
691
        if (ups_status & STATUS_CAL)
 
692
          status_set("CAL");            /* calibration */
 
693
        if (ups_status & STATUS_TRIM)
 
694
          status_set("TRIM");           /* SmartTrim */
 
695
        if (ups_status & STATUS_BOOST)
 
696
          status_set("BOOST");  /* SmartBoost */
 
697
        if (ups_status & STATUS_OL)
 
698
          status_set("OL");             /* on line */
 
699
        if (ups_status & STATUS_OB)
 
700
          status_set("OB");             /* on battery */
 
701
        if (ups_status & STATUS_OVER)
 
702
          status_set("OVER");           /* overload */
 
703
        if (ups_status & STATUS_LB)
 
704
          status_set("LB");             /* low battery */
 
705
        if (ups_status & STATUS_RB)
 
706
          status_set("RB");             /* replace batt */
 
707
        if (ups_status & STATUS_BYPASS)
 
708
          status_set("BYPASS"); /* on bypass */   
 
709
        if (ups_status & STATUS_CHRG)
 
710
          status_set("CHRG");           /* charging */
 
711
        if (ups_status & STATUS_DISCHRG)
 
712
          status_set("DISCHRG");        /* discharging */         
 
713
        if ( (ups_status & STATUS_OFF) || (ups_status == 0) )
 
714
          status_set("OFF");
 
715
        
 
716
        /* Commit the status buffer */
 
717
        status_commit();
 
718
}
 
719
 
 
720
/* find info element definition in info array
 
721
 * by NUT varname.
 
722
 */
 
723
static hid_info_t *find_nut_info(const char *varname)
371
724
{
372
725
  hid_info_t *hidups_item;
373
726
 
376
729
      return hidups_item;
377
730
  }
378
731
 
379
 
  upsdebugx(2, "find_info: unknown info type: 0x%x\n", varname);
 
732
  upsdebugx(2, "find_nut_info: unknown info type: %s\n", varname);
 
733
  return NULL;
 
734
}
 
735
 
 
736
/* find info element definition in info array
 
737
 * by HID varname.
 
738
 */
 
739
static hid_info_t *find_hid_info(const char *hidname)
 
740
{
 
741
  hid_info_t *hidups_item;
 
742
 
 
743
  for (hidups_item = hid_ups; hidups_item->info_type != NULL ; hidups_item++) {
 
744
 
 
745
        /* Skip NULL HID path (server side vars) */
 
746
        if (hidups_item->hidpath == NULL)
 
747
          continue;
 
748
        
 
749
    if (!strcasecmp(hidups_item->hidpath, hidname))
 
750
      return hidups_item;
 
751
  }
 
752
 
 
753
  upsdebugx(2, "find_hid_info: unknown variable: %s\n", hidname);
380
754
  return NULL;
381
755
}
382
756
 
383
757
/* find the HID Item value matching that NUT value */
384
 
static long hu_find_valinfo(info_lkp_t *hid2info, char* value)
 
758
/* useful for set with value lookup... */
 
759
/* static long hu_find_valinfo(info_lkp_t *hid2info, char* value)
385
760
{
386
761
  info_lkp_t *info_lkp;
387
762
  
389
764
         (strcmp(info_lkp->nut_value, "NULL")); info_lkp++) {
390
765
    
391
766
    if (!(strcmp(info_lkp->nut_value, value))) {
392
 
      upsdebugx(3, "hu_find_valinfo: found %s (value: %d)\n",
 
767
      upsdebugx(3, "hu_find_valinfo: found %s (value: %s)\n",
393
768
                info_lkp->nut_value, value);
394
769
      
395
770
      return info_lkp->hid_value;
397
772
  }
398
773
  upsdebugx(3, "hu_find_valinfo: no matching HID value for this INFO_* value (%s)", value);
399
774
  return -1;
400
 
}
 
775
} */
401
776
 
402
777
/* find the NUT value matching that HID Item value */
403
778
static char *hu_find_infoval(info_lkp_t *hid2info, long value)
410
785
         (strcmp(info_lkp->nut_value, "NULL")); info_lkp++) {
411
786
    
412
787
    if (info_lkp->hid_value == value) {
413
 
      upsdebugx(3, "hu_find_infoval: found %s (value: %d)\n",
 
788
      upsdebugx(3, "hu_find_infoval: found %s (value: %ld)\n",
414
789
                info_lkp->nut_value, value);
415
790
      
416
791
      return info_lkp->nut_value;
417
792
    }
418
793
  }
419
 
  upsdebugx(3, "hu_find_infoval: no matching INFO_* value for this HID value (%d)\n", value);
 
794
  upsdebugx(3, "hu_find_infoval: no matching INFO_* value for this HID value (%ld)\n", value);
420
795
  return NULL;
421
796
}
422
797
 
423
798
/* All the logic for formatting finely the UPS model name */
424
 
static char *format_model_name(char *iProduct, char *iModel)
 
799
char *get_model_name(char *iProduct, char *iModel)
425
800
{
426
801
  models_name_t *model = NULL;
427
 
  char *new_name = NULL;
428
802
 
429
 
  upsdebugx(2, "Searching for %s\n", iProduct);
 
803
  upsdebugx(2, "get_model_name(%s, %s)\n", iProduct, iModel);
430
804
 
431
805
  /* Search for formatting rules */
432
 
  for ( model = models_names ; model->VendorID != 0x0 ; model++ ) {
433
 
    if(model->VendorID == hd->VendorID) {
434
 
      if ((iProduct != NULL) && (!strncmp(iProduct, model->basename, model->size))) {
435
 
        upsdebugx(2, "Found %s\n", model->finalname);
436
 
        break;
437
 
      }
438
 
      else
439
 
        continue;
440
 
    }
441
 
    else
442
 
      continue;
443
 
  }
 
806
  for ( model = model_names ; model->iProduct != NULL ; model++ )
 
807
        {
 
808
          upsdebugx(2, "comparing with: %s", model->finalname);
 
809
          /* FIXME: use comp_size if not -1 */
 
810
          if ( (!strncmp(iProduct, model->iProduct, strlen(model->iProduct)))
 
811
                   && (!strncmp(iModel, model->iModel, strlen(model->iModel))) )
 
812
                {
 
813
                  upsdebugx(2, "Found %s\n", model->finalname);
 
814
                  break;
 
815
                }
 
816
        }
 
817
  /* FIXME: if we end up with model->iProduct == NULL
 
818
   * then process name in a generic way (not yet supported models!)
 
819
   */
 
820
  return model->finalname;
 
821
}
444
822
 
445
 
  /* Process data */
446
 
  switch (model->VendorID)
447
 
    {
448
 
    case MGE_UPS_SYSTEMS:
449
 
      if (!strncmp(iProduct, "ELLIPSE", 7)) {      
450
 
        if (HIDGetItemValue(model->data2) != -2)
451
 
          sprintf(iProduct, "%s %i", model->finalname, 
452
 
                  (int)HIDGetItemValue(model->data2));
453
 
        else
454
 
          sprintf(iProduct, model->finalname);
455
 
      } else {
456
 
        if (HIDGetItemString(model->data2) != NULL)
457
 
          sprintf(iProduct, "%s %s", model->finalname, 
458
 
                  HIDGetItemString(model->data2)+model->d2_offset);
459
 
        else
460
 
          sprintf(iProduct, model->finalname);
461
 
      }
462
 
      new_name = iProduct;
463
 
      break; 
464
 
    case APC:
465
 
      /* TODO: finish this code, use data2 as an strstr() */
466
 
    default:
467
 
      new_name = "Generic USB UPS";
468
 
    }
469
 
  return new_name;
470
 
}