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

« back to all changes in this revision

Viewing changes to drivers/solis.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
/* solis.c - driver for Microsol Solis UPS hardware
 
2
 
 
3
   Copyright (C) 2004  Silvino B. MagalhĆ£es  <sbm2yk@gmail.com>
 
4
 
 
5
   This program is free software; you can redistribute it and/or modify
 
6
   it under the terms of the GNU General Public License as published by
 
7
   the Free Software Foundation; either version 2 of the License, or
 
8
   (at your option) any later version.
 
9
 
 
10
   This program is distributed in the hope that it will be useful,
 
11
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
   GNU General Public License for more details.
 
14
 
 
15
   You should have received a copy of the GNU General Public License
 
16
   along with this program; if not, write to the Free Software
 
17
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
18
 
 
19
   2004/10/10 - Version 0.10 - Initial release
 
20
   2004/10/20 - Version 0.20 - add Battery information in driver
 
21
   2004/10/26 - Version 0.30 - add commands and test shutdown
 
22
   2004/10/30 - Version 0.40 - add model data structs
 
23
 
 
24
   Microsol contributed with UPS Solis 1.2 HS 1.2 KVA for my tests.
 
25
 
 
26
   http://www.microsol.com.br
 
27
 
 
28
*/
 
29
 
 
30
#define DRV_VERSION "0.40"
 
31
 
 
32
#include <stdio.h>
 
33
#include <time.h>
 
34
#include "main.h"
 
35
#include "serial.h"
 
36
#include "solis.h"
 
37
 
 
38
#define false 0
 
39
#define true 1
 
40
#define ENDCHAR 13      /* replies end with CR */
 
41
/* solis commands */
 
42
#define CMD_UPSCONT 0xCC
 
43
#define CMD_SHUT    0xDD
 
44
#define CMD_SHUTRET 0xDE
 
45
#define CMD_EVENT   0xCE
 
46
#define CMD_DUMP    0xCD
 
47
 
 
48
/* comment out on english language */
 
49
// #define PORTUGUESE
 
50
 
 
51
#ifdef PORTUGUESE
 
52
#define M_UNKN     "ModĆŖlo solis desconhecido\n"
 
53
#define NO_SOLIS   "Solis nĆ£o detectado! abortando ...\n"
 
54
#define UPS_DATE   "Data no UPS %4d/%02d/%02d\n"
 
55
#define SYS_DATE   "Data do Sistema %4d/%02d/%02d dia da semana %s\n"
 
56
#define ERR_PACK   "Pacote errado\n"
 
57
#define NO_EVENT   "NĆ£o hĆ” eventos\n"
 
58
#define UPS_TIME   "Hora interna UPS %0d:%02d:%02d\n"
 
59
#define PRG_DAYS   "Shutdown Programavel Dom  Seg  Ter  Qua  Qui  Sex  Sab\n"
 
60
#define PRG_ONON   "ProgramaĆ§Ć£o shutdown ativa\n"
 
61
#define TIME_OFF   "UPS Hora desligar %02d:%02d\n"
 
62
#define TIME_ON    "UPS Hora ligar %02d:%02d\n"
 
63
#define PRG_ONOF   "ProgramaĆ§Ć£o shutdown desativada\n"
 
64
#else
 
65
#define M_UNKN     "Unknown solis model\n"
 
66
#define NO_SOLIS   "Solis not detected! aborting ...\n"
 
67
#define UPS_DATE   "UPS Date %4d/%02d/%02d\n"
 
68
#define SYS_DATE   "System Date %4d/%02d/%02d day of week %s\n"
 
69
#define ERR_PACK   "Wrong package\n"
 
70
#define NO_EVENT   "No events\n"
 
71
#define UPS_TIME   "UPS internal Time %0d:%02d:%02d\n"
 
72
#define PRG_DAYS   "Programming Shutdown Sun  Mon  Tue  Wed  Thu  fri  Sat\n"
 
73
#define PRG_ONON   "Shutdown programming ative\n"
 
74
#define TIME_OFF   "UPS Time power off %02d:%02d\n"
 
75
#define TIME_ON    "UPS Time power on %02d:%02d\n"
 
76
#define PRG_ONOF   "Shutdown programming not atived\n"
 
77
#endif
 
78
 
 
79
#define FMT_DAYS   "                      %d    %d    %d    %d    %d    %d    %d\n"
 
80
 
 
81
/* print UPS internal variables */
 
82
static void prnInfo( void )
 
83
{
 
84
 
 
85
        int sun=0, mon=0, tue=0, wed=0, thu=0, fri=0, sat=0;
 
86
 
 
87
        printf( UPS_DATE, Year, Month, Day );
 
88
        printf( SYS_DATE, anon, mesn, dian, seman );
 
89
 
 
90
        printf( UPS_TIME, ihour, imin, isec);
 
91
 
 
92
        tue = ( ( DaysOnWeek & 0x40 ) == 0x40 );
 
93
        wed = ( ( DaysOnWeek & 0x20 ) == 0x20 );
 
94
        thu = ( ( DaysOnWeek & 0x10 ) == 0x10 );
 
95
        fri = ( ( DaysOnWeek & 0x08 ) == 0x08 );
 
96
        sat = ( ( DaysOnWeek & 0x04 ) == 0x04 );
 
97
        sun = ( ( DaysOnWeek & 0x02 ) == 0x02 );
 
98
        mon = ( ( DaysOnWeek & 0x01 ) == 0x01 );
 
99
 
 
100
        if( isprogram ){
 
101
                printf( PRG_ONON );
 
102
                printf( TIME_ON, lhour, lmin);
 
103
                printf( TIME_OFF, dhour, dmin);
 
104
                printf( PRG_DAYS );
 
105
                printf( FMT_DAYS, sun, mon, tue, wed, thu, fri, sat);
 
106
        }
 
107
        else
 
108
                printf( PRG_ONOF );
 
109
 
 
110
}
 
111
 
 
112
/* is today shutdown day */
 
113
static int IsToday( unsigned char dweek, int nweek)
 
114
{
 
115
 
 
116
        switch ( nweek )
 
117
        {
 
118
        case 0: // sunday
 
119
                return ( ( ( dweek & 0x02 ) == 0x02 ) );
 
120
        case 1:
 
121
                return ( ( ( dweek & 0x01 ) == 0x01 ) );
 
122
        case 2:
 
123
                return ( ( ( dweek & 0x40 ) == 0x40 ) );
 
124
        case 3:
 
125
                return ( ( ( dweek & 0x20 ) == 0x20 ) );
 
126
        case 4:
 
127
                return ( ( ( dweek & 0x10 ) == 0x10 ) );
 
128
        case 5:
 
129
                return ( ( ( dweek & 0x08 ) == 0x08 ) );
 
130
        case 6: // saturday
 
131
                return ( ( ( dweek & 0x04 ) == 0x04 ) );
 
132
        }
 
133
        return 0;
 
134
}
 
135
 
 
136
static void AutonomyCalc( int iauto ) /* all models */
 
137
{
 
138
        int indice, indd, lim, min, max, inf, sup, indc, bx, ipo =0;
 
139
 
 
140
        bx = bext[iauto];
 
141
        indice = RecPack[3];
 
142
        indd = indice - 139;
 
143
        if( UtilPower > 20 )
 
144
                ipo = ( UtilPower - 51 ) / 100;
 
145
 
 
146
        indc = auton[iauto].maxi;
 
147
 
 
148
        if( ipo > indc )
 
149
                return;
 
150
 
 
151
        min = auton[iauto].minc[ipo];
 
152
        inf = min - 1;
 
153
        max = auton[iauto].maxc[ipo];
 
154
        lim = max - 139;
 
155
        sup = max + 1;
 
156
 
 
157
        if(  UtilPower <= 20 )
 
158
        {
 
159
                Autonomy = 170;
 
160
                maxauto = 170;
 
161
        }
 
162
        else
 
163
        {
 
164
                maxauto = auton[iauto].mm[ipo][lim];
 
165
                if( indice > inf && indice < sup )
 
166
                        Autonomy = auton[iauto].mm[ipo][indd];
 
167
                else
 
168
                {
 
169
                        if(  indice > max ) Autonomy = maxauto;
 
170
                        if(  indice < min ) Autonomy = 0;
 
171
                }
 
172
        }
 
173
 
 
174
        if(  BattExtension > 0 && iauto < 4 )
 
175
                Autonomy = ( Autonomy * ( BattExtension + bx ) * 1.0 / bx );
 
176
 
 
177
}
 
178
 
 
179
static void ScanReceivePack( void )
 
180
{
 
181
        int aux, im, ov = 0;
 
182
 
 
183
        /* model independent data */
 
184
 
 
185
        Year = ( RecPack[ 19 ] & 0x0F ) + BASE_YEAR;
 
186
        Month = ( RecPack[ 19 ] & 0xF0 ) >> 4;
 
187
        Day = ( RecPack[ 18 ] & 0x1F );
 
188
 
 
189
        /*  Days of week in UPS shutdown programming */
 
190
        DaysOnWeek = RecPack[ 17 ];
 
191
 
 
192
        /* time for programming UPS off */
 
193
        dhour = RecPack[15];
 
194
        dmin  = RecPack[16];
 
195
        /* time for programming UPS on */
 
196
        lhour = RecPack[13];
 
197
        lmin  = RecPack[14];
 
198
        /* UPS internal time */
 
199
        ihour = RecPack[11];
 
200
        imin  = RecPack[10];
 
201
        isec  = RecPack[9];
 
202
 
 
203
        if( ( ( 0x01  & RecPack[ 20 ] ) == 0x01 ) )
 
204
                Out220 = 1;
 
205
        CriticBatt = ( ( 0x04  & RecPack[ 20 ] ) == 0x04 );
 
206
        InversorOn = ( ( 0x08 & RecPack[ 20 ] ) == 0x08 );
 
207
        SuperHeat = ( ( 0x10  & RecPack[ 20 ] ) == 0x10 );
 
208
        SourceFail = ( ( 0x20  & RecPack[ 20 ] ) == 0x20 );
 
209
        OverCharge = ( ( 0x80  & RecPack[ 20 ] ) == 0x80 );
 
210
 
 
211
        if( ( ( 0x40  & RecPack[ 20 ] ) == 0x40 ) )
 
212
                InputValue = 1;
 
213
        else
 
214
                InputValue = 0;
 
215
        Temperature = ( 0x7F & RecPack[ 4 ]);
 
216
        if(  ( ( 0x80  & RecPack[ 4 ] ) == 0x80 ) )
 
217
        Temperature = Temperature - 128;
 
218
 
 
219
        /* model dependent data */
 
220
 
 
221
        im = inds[imodel];
 
222
        ov = Out220;
 
223
 
 
224
        if(  RecPack[ 6 ] >= 194 )
 
225
                InVoltage = RecPack[ 6 ] * ctab[imodel].m_involt194[0] + ctab[imodel].m_involt194[1];
 
226
        else
 
227
                InVoltage = RecPack[ 6 ] * ctab[imodel].m_involt193[0] + ctab[imodel].m_involt193[1];
 
228
 
 
229
        BattVoltage = RecPack[ 3 ] * ctab[imodel].m_battvolt[0] + ctab[imodel].m_battvolt[1];
 
230
 
 
231
        NominalPower = nompow[im];
 
232
        if(  SourceFail ) {
 
233
                OutVoltage = RecPack[ 1 ] * ctab[imodel].m_outvolt_i[ov][0] + ctab[imodel].m_outvolt_i[ov][1];
 
234
                OutCurrent = RecPack[ 5 ] * ctab[imodel].m_outcurr_i[ov][0] + ctab[imodel].m_outcurr_i[ov][1];
 
235
                AppPower = ( RecPack[ 5 ] * RecPack[ 1 ] ) * ctab[imodel].m_appp_i[ov][0] + ctab[imodel].m_appp_i[ov][1];
 
236
                UtilPower = ( RecPack[ 7 ] + RecPack[ 8 ] * 256 ) * ctab[imodel].m_utilp_i[ov][0] + ctab[imodel].m_utilp_i[ov][1];
 
237
                InCurrent = 0;
 
238
        }
 
239
        else {
 
240
        OutVoltage = RecPack[ 1 ] * ctab[imodel].m_outvolt_s[ov][0] + ctab[imodel].m_outvolt_s[ov][1];
 
241
        OutCurrent = RecPack[ 5 ] * ctab[imodel].m_outcurr_s[ov][0] + ctab[imodel].m_outcurr_s[ov][1];
 
242
        AppPower = ( RecPack[ 5 ] * RecPack[ 1 ] ) * ctab[imodel].m_appp_s[ov][0] + ctab[imodel].m_appp_s[ov][1];
 
243
        UtilPower = ( RecPack[ 7 ] + RecPack[ 8 ] * 256 ) * ctab[imodel].m_utilp_s[ov][0] + ctab[imodel].m_utilp_s[ov][1];
 
244
        InCurrent = ( ctab[imodel].m_incurr[0] * 1.0 / BattVoltage ) - ( AppPower * 1.0 / ctab[imodel].m_incurr[1] )
 
245
                + OutCurrent *( OutVoltage * 1.0 / InVoltage );
 
246
        }
 
247
 
 
248
        aux = ( RecPack[ 21 ] + RecPack[ 22 ] * 256 );
 
249
        if( aux > 0 )
 
250
                InFreq = ctab[imodel].m_infreq * 1.0 / aux;
 
251
        else
 
252
                InFreq = 0;
 
253
  
 
254
        /* input voltage offset */
 
255
        if( InVoltage < InVolt_offset ) { /* all is equal 30 */
 
256
                InFreq = 0;
 
257
                InVoltage = 0;
 
258
                InCurrent = 0;
 
259
        }
 
260
 
 
261
        /*  app power offset */
 
262
        if( AppPower < ctab[imodel].m_appp_offset ) {
 
263
                AppPower = 0;
 
264
                UtilPower = 0;
 
265
                ChargePowerFactor = 0;
 
266
                OutCurrent = 0;
 
267
        }
 
268
 
 
269
        if( im < 3 )
 
270
                AutonomyCalc( im );
 
271
        else {
 
272
                if(  BattExtension == 80 )
 
273
                        AutonomyCalc( im + 1 );
 
274
                else
 
275
                        AutonomyCalc( im );
 
276
        }
 
277
 
 
278
        /* model independent data */
 
279
 
 
280
        batcharge = ( Autonomy / maxauto ) * 100.0;
 
281
        upscharge = ( AppPower / NominalPower ) * 100.0;
 
282
 
 
283
        if (batcharge > 100.0)
 
284
                batcharge = 100.0;
 
285
   
 
286
        OutFreq = 60;
 
287
        if( !( InversorOn ) ) {
 
288
                OutVoltage = 0;
 
289
                OutFreq = 0;
 
290
        }
 
291
 
 
292
        if(  ( !( SourceFail ) && InversorOn ) )
 
293
                OutFreq = InFreq;
 
294
   
 
295
        if(  AppPower <= 0 ) /* charge pf */
 
296
                ChargePowerFactor = 0;
 
297
        else {
 
298
                if( AppPower == 0 )
 
299
                        ChargePowerFactor = 100;
 
300
                else
 
301
                        ChargePowerFactor = (( UtilPower / AppPower) * 100 );
 
302
        if(  ChargePowerFactor > 100 )
 
303
                ChargePowerFactor = 100;
 
304
        }
 
305
   
 
306
        if( SourceFail && SourceLast ) /* first time failure */
 
307
                FailureFlag = true;
 
308
 
 
309
        /* source return */
 
310
        if( !( SourceFail ) && !( SourceLast ) ) {
 
311
                SourceReturn = true;
 
312
                ser_flush_in(upsfd,"",0);    /* clean port */
 
313
        }
 
314
   
 
315
        if( !( SourceFail ) == SourceLast ) {
 
316
                SourceReturn = false;
 
317
                FailureFlag = false;
 
318
        }
 
319
   
 
320
        SourceLast = !( SourceFail );
 
321
 
 
322
        /* Autonomy */
 
323
   
 
324
        if( ( Autonomy < 5 ) )
 
325
                LowBatt = true;
 
326
        else
 
327
                LowBatt = false;
 
328
                                                                                                                             
 
329
        UpsPowerFactor = 700;
 
330
   
 
331
        /* input 110V or 220v */
 
332
        if(  ( InputValue == 0 ) ) {
 
333
                InDownLim = 75;
 
334
                InUpLim = 150;
 
335
                NomInVolt = 110;
 
336
        }
 
337
        else {
 
338
                InDownLim = 150;
 
339
                InUpLim = 300;
 
340
                NomInVolt = 220;
 
341
        }
 
342
 
 
343
        /* output volage 220V or 110V */
 
344
        if( Out220 ) {
 
345
                OutDownLim = 190;
 
346
                OutUpLim = 250;
 
347
                NomOutVolt = 220;
 
348
        }
 
349
        else {
 
350
                OutDownLim = 100;
 
351
                OutUpLim = 140;
 
352
                NomOutVolt = 110;
 
353
        }
 
354
   
 
355
        if( SourceFail )  /* source status */
 
356
                InputStatus = 2;
 
357
        else
 
358
                InputStatus = 1;
 
359
   
 
360
        if( InversorOn )  /* output status */
 
361
                OutputStatus = 1;
 
362
        else
 
363
                OutputStatus = 2;
 
364
  
 
365
        if( OverCharge )
 
366
                OutputStatus = 3;
 
367
  
 
368
        if( CriticBatt ) /* battery status */
 
369
                BattStatus = 4;
 
370
        else
 
371
                BattStatus = 1;
 
372
   
 
373
        SourceEvents = 0;
 
374
 
 
375
        if( FailureFlag )
 
376
                SourceEvents = 1;
 
377
        if( SourceReturn )
 
378
                SourceEvents = 2;
 
379
   
 
380
        /* verify Inversor */
 
381
        if( Flag_inversor ) {
 
382
                InversorOnLast = InversorOn;
 
383
                Flag_inversor = false;
 
384
        }
 
385
 
 
386
   
 
387
        OutputEvents = 0;
 
388
        if( InversorOn && !( InversorOnLast ) )
 
389
                OutputEvents = 26;
 
390
        if( InversorOnLast && !( InversorOn ) )
 
391
                OutputEvents = 27;
 
392
        InversorOnLast = InversorOn;
 
393
        if( SuperHeat && !( SuperHeatLast ) )
 
394
                OutputEvents = 12;
 
395
        if( SuperHeatLast && !( SuperHeat ) )
 
396
                OutputEvents = 13;
 
397
        SuperHeatLast = SuperHeat;
 
398
        if( OverCharge && !( OverChargeLast ) )
 
399
                OutputEvents = 10;
 
400
        if( OverChargeLast && !( OverCharge ) )
 
401
                OutputEvents = 11;
 
402
        OverChargeLast = OverCharge;
 
403
 
 
404
        BattEvents = 0;
 
405
        CriticBattLast = CriticBatt;
 
406
 
 
407
}
 
408
 
 
409
static void
 
410
CommReceive(const char *bufptr,  int size)
 
411
{
 
412
        int i, CheckSum, i_end;
 
413
 
 
414
        if(  ( size==25 ) )
 
415
                Waiting = 0;
 
416
 
 
417
        switch( Waiting ) {
 
418
        /* normal package */
 
419
        case 0:
 
420
        {
 
421
        if(  size == 25 ) {
 
422
                i_end = 25;
 
423
                for( i = 0 ; i < i_end ; ++i ) {
 
424
                        RecPack[i] = *bufptr;
 
425
                        bufptr++;
 
426
                        }
 
427
            
 
428
                /* CheckSum verify */
 
429
                CheckSum = 0;
 
430
                i_end = 23;
 
431
                for( i = 0 ; i < i_end ; ++i )
 
432
                        CheckSum = RecPack[ i ] + CheckSum;
 
433
                CheckSum = CheckSum % 256;
 
434
                
 
435
                ser_flush_in(upsfd,"",0); /* clean port */
 
436
 
 
437
                /* correct package */
 
438
                if( ( (RecPack[0] & 0xF0) == 0xA0 )
 
439
                        && ( RecPack[ 24 ] == 254 )
 
440
                        && ( RecPack[ 23 ] == CheckSum ) ) {
 
441
 
 
442
                        if(!(detected)) {
 
443
                                SolisModel = (int) (RecPack[0] & 0x0F);
 
444
                                if( SolisModel < 13 )
 
445
                                imodel = SolisModel - 10; /* 10 = 0, 11 = 1 */
 
446
                        else
 
447
                                imodel = SolisModel - 11; /* 13 = 2, 14 = 3, 15 = 4 */
 
448
                        detected = true;
 
449
                        }
 
450
 
 
451
                        switch( SolisModel )
 
452
                        {
 
453
                        case 10:
 
454
                        case 11:
 
455
                        case 12:
 
456
                        case 13:
 
457
                        case 14:
 
458
                        case 15:
 
459
                        {
 
460
                                ScanReceivePack();
 
461
                                break;
 
462
                        }
 
463
                        default:
 
464
                        {
 
465
                                printf( M_UNKN );
 
466
                                break;
 
467
                        }
 
468
                        }
 
469
                }
 
470
 
 
471
                }
 
472
        
 
473
        break;
 
474
        }
 
475
       
 
476
        case 1:
 
477
        {
 
478
                /* dumping package nothing to do yet */
 
479
                Waiting = 0;
 
480
                break;
 
481
        }
 
482
 
 
483
        }
 
484
 
 
485
        Waiting =0;
 
486
 
 
487
}
 
488
 
 
489
static void getbaseinfo(void)
 
490
{
 
491
        unsigned char  temp[256];
 
492
#ifdef PORTUGUESE
 
493
        char diassemana[7][4]={"Dom", "Seg", "Ter", "Qua", "Qui", "Sex", "Sab"};
 
494
#else
 
495
        char DaysOfWeek[7][4]={"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
 
496
#endif
 
497
        char    mycmd[8]; // , ch;
 
498
        unsigned char Pacote[25];
 
499
        int  i, j=0, tam, tpac=25;
 
500
 
 
501
        time_t *tmt;
 
502
        struct tm *now;
 
503
        tmt  = ( time_t * ) malloc( sizeof( time_t ) );
 
504
        time( tmt );
 
505
        now = localtime( tmt );
 
506
        dian = now->tm_mday;
 
507
        mesn = now->tm_mon+1;
 
508
        anon = now->tm_year+1900;
 
509
        weekn = now->tm_wday;
 
510
 
 
511
#ifdef PORTUGUESE
 
512
        strcpy( seman, diassemana[weekn] );
 
513
#else   
 
514
        strcpy( seman, DaysOfWeek[weekn] );
 
515
#endif
 
516
 
 
517
        if( testvar("battext"))
 
518
                BattExtension = atoi(getval("battext"));
 
519
 
 
520
        if( testvar("prgshut"))
 
521
                isprogram = atoi(getval("prgshut"));
 
522
 
 
523
        /* dummy read attempt to sync - throw it out */
 
524
        sprintf(mycmd,"%c%c",CMD_UPSCONT, ENDCHAR);
 
525
        ser_send(upsfd, mycmd);
 
526
        /* ser_send_char(upsfd, CMD_UPSCONT); // send the character */
 
527
 
 
528
        /* trying detect solis model */
 
529
        while ( ( !detected ) && ( j < 20 ) ) {
 
530
                temp[0] = 0; // flush temp buffer
 
531
                tam = ser_get_buf_len(upsfd, temp, tpac, 3, 0);
 
532
                if( tam == 25 ) {
 
533
                for( i = 0 ; i < tam ; i++ )
 
534
                    Pacote[i] = temp[i];
 
535
                }
 
536
 
 
537
                j++;
 
538
                if( tam == 25)
 
539
                        CommReceive(Pacote, tam);
 
540
                else
 
541
                        CommReceive(temp, tam);
 
542
        } /* while end */
 
543
 
 
544
        if( (!detected) ) {
 
545
                printf( NO_SOLIS );
 
546
                upsdrv_cleanup();
 
547
                exit(0);
 
548
        }
 
549
 
 
550
        switch( SolisModel )
 
551
        {
 
552
        case 10:
 
553
        case 11:
 
554
        case 12:
 
555
                {
 
556
                strcpy(Model, "Solis 1.0");
 
557
                break;
 
558
                }
 
559
        case 13:
 
560
                {
 
561
                strcpy(Model, "Solis 1.5");
 
562
                break;
 
563
                }
 
564
        case 14:
 
565
                {
 
566
                strcpy(Model, "Solis 2.0");
 
567
                break;
 
568
                }
 
569
        case 15:
 
570
                {
 
571
                strcpy(Model, "Solis 3.0");
 
572
                break;
 
573
                }
 
574
        }
 
575
 
 
576
        if( isprogram )
 
577
          {
 
578
            if( dmin < 5 )
 
579
              {
 
580
                if( dhour > 1 )
 
581
                  hourshut = dhour - 1;
 
582
                else
 
583
                  hourshut = 23;
 
584
                minshut = 60 - ( 5 -dmin );
 
585
              }
 
586
            else
 
587
              minshut = dmin - 5;
 
588
          }
 
589
 
 
590
        /* manufacturer */
 
591
        dstate_setinfo("ups.mfr", "%s", "Microsol");
 
592
 
 
593
        dstate_setinfo("ups.model", "%s", Model);
 
594
        dstate_setinfo("input.transfer.low", "%03.1f", InDownLim);
 
595
        dstate_setinfo("input.transfer.high", "%03.1f", InUpLim);
 
596
 
 
597
        dstate_addcmd("shutdown.return");       /* CMD_SHUTRET */
 
598
        dstate_addcmd("shutdown.stayoff");      /* CMD_SHUT */
 
599
 
 
600
        printf("Detected %s on %s\n", dstate_getinfo("ups.model"), device_path);
 
601
 
 
602
        prnInfo();
 
603
 
 
604
}
 
605
 
 
606
static void getupdateinfo(void)
 
607
{
 
608
        unsigned char  temp[256];
 
609
        int tam, isday, hourn, minn;
 
610
 
 
611
        /* time update and programable shutdown block */
 
612
        time_t *tmt;
 
613
        struct tm *now;
 
614
        tmt  = ( time_t * ) malloc( sizeof( time_t ) );
 
615
        time( tmt );
 
616
        now = localtime( tmt );
 
617
        hourn = now->tm_hour;
 
618
        minn = now->tm_min;
 
619
        weekn = now->tm_wday;
 
620
 
 
621
        if( isprogram ) {
 
622
                isday = IsToday( DaysOnWeek, weekn );
 
623
                if( ( dhour == hourshut ) && ( minshut >= dmin ) && isday )
 
624
                        progshut = 1;
 
625
        }       
 
626
 
 
627
        /* programable shutdown end block */
 
628
 
 
629
        pacsize = 25;
 
630
 
 
631
        /* get update package */
 
632
        temp[0] = 0; /* flush temp buffer */
 
633
        tam = ser_get_buf_len(upsfd, temp, pacsize, 3, 0);
 
634
 
 
635
        CommReceive(temp, tam);
 
636
 
 
637
}
 
638
 
 
639
static int instcmd(const char *cmdname, const char *extra)
 
640
{
 
641
 
 
642
        if (!strcasecmp(cmdname, "shutdown.return")) {
 
643
                // shutdown and restart
 
644
                ser_send_char(upsfd, CMD_SHUTRET); // 0xDE
 
645
                // ser_send_char(upsfd, ENDCHAR);
 
646
                return STAT_INSTCMD_HANDLED;
 
647
        }
 
648
        
 
649
        if (!strcasecmp(cmdname, "shutdown.stayoff")) {
 
650
                // shutdown now (one way)
 
651
                ser_send_char(upsfd, CMD_SHUT); // 0xDD
 
652
                // ser_send_char(upsfd, ENDCHAR);
 
653
                return STAT_INSTCMD_HANDLED;
 
654
        }
 
655
 
 
656
        upslogx(LOG_NOTICE, "instcmd: unknown command [%s]", cmdname);
 
657
        return STAT_INSTCMD_UNKNOWN;
 
658
 
 
659
}
 
660
 
 
661
void upsdrv_initinfo(void)
 
662
{
 
663
        getbaseinfo();
 
664
 
 
665
        upsh.instcmd = instcmd;
 
666
        dstate_setinfo("driver.version.internal", "%s", DRV_VERSION);
 
667
}
 
668
 
 
669
void upsdrv_updateinfo(void)
 
670
{
 
671
 
 
672
        getupdateinfo(); /* new package for updates */
 
673
 
 
674
        dstate_setinfo("output.voltage", "%03.1f", OutVoltage);
 
675
        dstate_setinfo("input.voltage", "%03.1f", InVoltage);
 
676
        dstate_setinfo("battery.voltage", "%02.1f", BattVoltage);
 
677
        dstate_setinfo("battery.charge", "%03.1f", batcharge);
 
678
 
 
679
        status_init();
 
680
 
 
681
        if (!SourceFail )
 
682
                status_set("OL");               /* on line */
 
683
        else
 
684
                status_set("OB");               /* on battery */
 
685
        
 
686
        if (Autonomy < 5 )
 
687
                status_set("LB");               /* low battery */
 
688
 
 
689
        if( progshut )
 
690
                status_set("LB");               /* low battery but is a force shutdown */
 
691
        
 
692
        status_commit();
 
693
        
 
694
        dstate_setinfo("ups.temperature", "%2.2f", Temperature);
 
695
        dstate_setinfo("input.frequency", "%2.1f", InFreq);
 
696
        dstate_setinfo("ups.load", "%03.1f", upscharge);
 
697
 
 
698
        dstate_dataok();
 
699
 
 
700
}
 
701
 
 
702
/* power down the attached load immediately */
 
703
void upsdrv_shutdown(void)
 
704
{
 
705
 
 
706
        /* basic idea: find out line status and send appropriate command */
 
707
        /* on battery: send normal shutdown, ups will return by itself on utility */
 
708
        /* on line: send shutdown+return, ups will cycle and return soon */
 
709
 
 
710
        if (!SourceFail) {    /* on line */
 
711
 
 
712
                printf("On line, sending shutdown+return command...\n");
 
713
                ser_send_char(upsfd, CMD_SHUTRET );
 
714
                /* ser_send_char(upsfd, ENDCHAR); */
 
715
        }
 
716
        else {
 
717
                printf("On battery, sending normal shutdown command...\n");
 
718
                ser_send_char(upsfd, CMD_SHUT);
 
719
                /* ser_send_char(upsfd, ENDCHAR); */
 
720
        }
 
721
        
 
722
}
 
723
 
 
724
void upsdrv_help(void)
 
725
{
 
726
 
 
727
        printf("\nSolis options\n");
 
728
        printf(" Battery Extension\n");
 
729
        printf("  battext = 80\n");
 
730
        printf(" Programable power off\n");
 
731
        printf("  prgshut = 1  (activate programable power off)\n");
 
732
        printf(" Uses Solis Monitor for setting date-time power off\n");
 
733
  
 
734
}
 
735
 
 
736
void upsdrv_makevartable(void)
 
737
{
 
738
 
 
739
        addvar(VAR_VALUE, "battext", "Battery Extension (0-80)min");
 
740
        addvar(VAR_VALUE, "prgshut", "Programable power off (0-1)");
 
741
 
 
742
}
 
743
 
 
744
void upsdrv_banner(void)
 
745
{
 
746
        printf("Network UPS Tools - Microsol Solis UPS driver %s (%s)\n", 
 
747
                DRV_VERSION, UPS_VERSION);
 
748
        printf("by Silvino Magalhaes for Microsol - sbm2yk@gmail.com\n\n");
 
749
}
 
750
 
 
751
void upsdrv_initups(void)
 
752
{
 
753
        upsfd = ser_open(device_path);
 
754
        ser_set_speed(upsfd, device_path, B9600);
 
755
}
 
756
 
 
757
void upsdrv_cleanup(void)
 
758
{
 
759
        ser_close(upsfd, device_path);
 
760
}