1
/* $Id: plugin_huawei.c 870 2008-04-10 14:55:23Z michux $
2
* $URL: https://ssl.bulix.org/svn/lcd4linux/trunk/plugin_huawei.c $
4
* plugin plugin_huawei. Copyright (C) 2010 Jar <jar@pcuf.fi>
6
* Huawei E220 3G modem statistics via /dev/ttyUSB* user interface. It may (or may not) work well
7
* with other Huawei 3G USB modems too (which uses PPP interface between modem and computer), like
8
* E160, E169, E226, E272, E230 etc. Since they all seem to use same kind of set AT commands and
9
* responses. Tested with Huawei E220, E160E and Vodafone Huawei K3565.
11
* Thanks to Mikko <vmj@linuxbox.fi> for contributing the scan_uint() function and some other code.
13
* Based on sample plugin which is
14
* Copyright (C) 2003 Michael Reinelt <michael@reinelt.co.at>
15
* Copyright (C) 2004, 2005, 2006, 2007, 2008 The LCD4Linux Team <lcd4linux-devel@users.sourceforge.net>
18
* This file is part of LCD4Linux.
20
* LCD4Linux is free software; you can redistribute it and/or modify
21
* it under the terms of the GNU General Public License as published by
22
* the Free Software Foundation; either version 2, or (at your option)
25
* LCD4Linux is distributed in the hope that it will be useful,
26
* but WITHOUT ANY WARRANTY; without even the implied warranty of
27
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28
* GNU General Public License for more details.
30
* You should have received a copy of the GNU General Public License
31
* along with this program; if not, write to the Free Software
32
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
37
/* define the include files you need */
40
#include <stdio.h> /* standard buffered input/output */
41
#include <stdlib.h> /* standard library definitions */
42
#include <stdarg.h> /* for va_start et al */
43
#include <string.h> /* string operations */
44
#include <unistd.h> /* read(), close() */
45
#include <fcntl.h> /* open() */
46
#include <termios.h> /* tcflush() */
47
#include <sys/types.h> /* data types */
48
#include <sys/stat.h> /* stat structure */
49
#include <sys/time.h> /* timeval structure */
50
#include <errno.h> /* system error numbers */
53
/* these should always be included */
63
#define PORT "/dev/ttyUSB1" /* default port */
64
#define BAUDRATE B38400 /* default baudrate */
65
#define SEND_BUFFER_SIZE 128 /* send buffer size */
66
#define RECV_BUFFER_SIZE 256 /* receive buffer size */
67
#define MIN_INTERVAL 100 /* minimum query interval 100 ms */
70
#define INIT_STRING "ATE1 ^CURC=0;^DSFLOWCLR" /* disable unsolicited report codes and reset DS traffic
71
* with local echo enabled
73
#define QUALITY "ATE1 +CSQ" /* signal quality query with local echo enabled */
74
#define SYSINFO "ATE1 ^SYSINFO" /* network access query with local echo enabled */
75
#define MANUF "ATE1 +GMI" /* manufacturer query with local echo enabled */
76
#define MODEL "ATE1 +GMM" /* model query with local echo enabled */
77
#define FWVER "ATE1 +CGMR" /* firmware version query with local echo enabled */
78
#define FLOWREPORT "ATE1 ^DSFLOWQRY" /* DS traffic query with local echo enabled */
79
#define OPERATOR "ATE1 +COPS=3,0;+COPS?" /* gsm/umts operator query (3=set format only, 0=long alphanum. string)
80
* with local echo enabled
83
static char name[] = "plugin_huawei.c";
85
static char *sub_system_mode[] = {
86
"NO CONN", /* no service */
88
"GPRS", /* 2.5G/GPRS */
89
"EDGE", /* 2.75G/EDGE */
90
"WCDMA", /* 3G/UMTS */
91
"HSDPA", /* 3.5G/UMTS */
92
"HSUPA", /* 3.5G/UMTS */
93
"HSPA", /* HSDPA+HSUPA */
97
static int fd = -2; /* serial fd */
98
static char *port = NULL; /* serial device */
100
/* signal strength query */
101
static unsigned int rssi = 0; /* relative rssi 0...31 */
102
static unsigned int ber = 0; /* ber (bit error rate, not supported) */
104
/* manufacturer query */
105
static char manuf[32] = ""; /* manufacturer */
108
static char model[32] = ""; /* model */
110
/* fw version query */
111
static char fwver[32] = ""; /* firmware version */
113
/* gsm/umts operator query */
114
static char operator[64] = ""; /* current gsm/umts network operator */
116
/* DS traffic report query */
117
static unsigned long int last_ds_time = 0; /* last DS connection time [s] */
118
static unsigned long long int last_tx_flow = 0; /* last DS transmiting trafic [Bytes] */
119
static unsigned long long int last_rx_flow = 0; /* last DS receiving trafic [Bytes] */
120
static unsigned long int total_ds_time = 0; /* total DS connection time [s] */
121
static unsigned long long int total_tx_flow = 0; /* total transmitting DS traffic [Bytes] */
122
static unsigned long long int total_rx_flow = 0; /* total receiving DS traffic [Bytes] */
124
static double calc_tx_rate = 0; /* calculated tx rate */
125
static double calc_rx_rate = 0; /* calculated rx rate */
127
/* system information query */
128
static unsigned int status = 0; /* system service state */
129
static unsigned int domain = 0; /* system service domain */
130
static unsigned int roaming_status = 0; /* roaming status */
131
static unsigned int mode = 0; /* system mode */
132
static unsigned int sim_state = 0; /* SIM card state */
133
static unsigned int reserved = 0; /* reserved, E618 used it to indicate the simlock state */
134
static unsigned int sub_mode = 0; /* system sub mode */
136
static int debug = 0; /* enable debug messages */
139
static int age_diff(struct timeval prev_age)
144
gettimeofday(&now, NULL);
145
diff = (now.tv_sec - prev_age.tv_sec) * 1000 + (now.tv_usec - prev_age.tv_usec) / 1000;
150
static int scan_uint(const char *str, unsigned int nargs, ...)
152
unsigned int wall = 0;
153
unsigned int i = 0; /* number of parsed numbers */
154
unsigned int *a = NULL; /* pointer to currently parsed number (type
155
must be that of the actual arguments) */
157
/* initialize the argument list */
159
va_start(argv, nargs);
162
/* initialize to first argument */
163
a = va_arg(argv, unsigned int *);
164
/* initialize it to zero */
168
/* loop through the argument list and the string */
169
while (str && *str && wall < 1024) {
181
/* intent: multiply current value of 'a' with 10 and add
182
numeric value of character str) */
184
*a = ((*a) * 10) + ((*str) - '0');
190
/* proceed to next argument */
191
a = va_arg(argv, unsigned int *);
192
/* initialize it to zero */
195
/* this was the last number to parse */
196
/* (comma indicates that there are more) */
201
/* ignore any unknown characters */
205
/* proceed to next character */
210
/* fill any extraneous arguments with zero */
211
if (str && !(*str) && i < nargs - 1) {
213
for (j++; j < nargs; j++) {
214
a = va_arg(argv, unsigned int *);
219
/* finalize the argument list */
222
/* return the number of parsed numbers */
223
return (int) (i > 0) ? i + 1 : i;
226
static int huawei_port_exists(const char *device)
229
struct stat stat_ptr;
231
/* check the device is present */
232
ret = stat(device, &stat_ptr);
236
/* check the device is character device */
237
return (S_ISCHR(stat_ptr.st_mode));
240
static void huawei_read_port(void)
244
/* port can be defined via env variable */
245
if ((test = getenv("HUAWEI_PORT"))) {
248
info("%s: Using HUAWEI_PORT=%s from env variable for user interface device", name, port);
256
static int huawei_configure_port(void)
259
struct termios options;
262
fd = open(port, O_RDWR | O_NOCTTY | O_NDELAY);
264
error("%s: ERROR: Problem opening %s. Try using the HUAWEI_PORT env variable (export HUAWEI_PORT=/dev/ttyUSB*)",
269
/* enable blocking behavior with timeout */
270
ret = fcntl(fd, F_SETFL, 0);
272
error("%s: ERROR: Problem setting file descriptor status flags %i", name, fd);
278
/* get the current options */
279
ret = tcgetattr(fd, &options);
281
error("%s: ERROR: Problem getting terminal attributes %s", name, port);
288
options.c_cflag |= (CS8 | CLOCAL | CREAD);
289
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
290
options.c_iflag &= ~(IGNBRK | BRKINT | IGNPAR | IGNCR | INLCR | ICRNL |
291
IUCLC | IXANY | IXON | IXOFF | INPCK | ISTRIP);
292
options.c_oflag = 0; /* raw output */
293
options.c_cc[VMIN] = 0;
294
options.c_cc[VTIME] = 1; /* 0.1 second timeout */
296
/* set the input baud rate to BAUDRATE */
297
ret = cfsetispeed(&options, BAUDRATE);
299
error("%s: ERROR: Problem setting input baud rate %s", name, port);
305
/* set the output baud rate to BAUDRATE */
306
ret = cfsetospeed(&options, BAUDRATE);
308
error("%s: ERROR: Problem setting output baud rate %s", name, port);
314
/* set the options */
315
ret = tcsetattr(fd, TCSANOW, &options);
317
error("%s: ERROR: Problem setting terminal attributes %s", name, port);
323
/* flush input and output buffers */
324
ret = tcflush(fd, TCIFLUSH);
326
error("%s: ERROR: Problem flushing input and output buffers %s", name, port);
335
static int huawei_send(const char *cmd)
338
char buf[SEND_BUFFER_SIZE];
340
sprintf(buf, "%s\r", cmd);
344
bytes = write(fd, buf, len);
346
/* force null termination */
352
if (bytes < 0 && errno != EAGAIN) {
353
error("%s: ERROR: Writing to device %s failed: %s", name, port, strerror(errno));
355
} else if (bytes != len) {
356
error("%s: ERROR: Partial write when writing to device %s", name, port);
360
/* remove trailing CR */
361
while (bytes > 0 && buf[bytes - 1] == '\r') {
366
debug("DEBUG: <-Send bytes=%i, send buf=%s", bytes, buf);
371
static char *huawei_receive(void)
373
int run, count, bytes;
375
static char buf[RECV_BUFFER_SIZE];
377
/* skip the plain NL's and CR's (<CR><LF><CR><LF> makes max. 4 pcs. of them) and re-read */
378
for (run = 0; run < 4; run++) {
380
/* pointer to the current position in the buffer */
383
/* set count to buffer size */
384
count = RECV_BUFFER_SIZE;
386
/* Read until a NL or a CR is encountered. If 'buf' fills up before newline is seen,
387
* exit the loop when there's still room for zero termination (count == 1).
390
bytes = read(fd, c, 1);
392
if (*c == '\n' || *c == '\r' || (bytes < 0 && errno != EAGAIN))
400
/* force null termination */
403
/* now we have data (when buf len > 0), exit from for-loop and return the data to caller */
404
if (strlen(buf) > 0 || (bytes < 0 && errno != EAGAIN))
408
if (bytes < 0 && errno != EAGAIN) {
409
error("%s: ERROR: Reading from device %s failed: %s", name, port, strerror(errno));
413
/* print bytes read and buffer data when debuging enabled */
415
debug("DEBUG: ->Received bytes=%i, receive buf=%s", (int) strlen(buf), buf);
420
static int huawei_recv_error(const char *msg)
422
if (strstr(msg, "ERROR") != NULL || strncmp(msg, "NO CARRIER", 10) == 0 ||
423
strncmp(msg, "COMMAND NOT SUPPORT", 19) == 0 || strncmp(msg, "TOO MANY PARAMETERS", 19) == 0)
429
static char *huawei_send_receive(const char *cmd)
431
int run, bytes_send, recv_seq;
433
static char reply[RECV_BUFFER_SIZE];
435
/* send command to modem */
436
bytes_send = huawei_send(cmd);
438
/* start with an empty reply */
441
if (bytes_send > 0) {
445
/* receive modem responses (currently handle only 3 lines of responses:
446
* request->reply->ok|error)
448
for (run = 0; run < 3; run++) {
450
tmp = huawei_receive();
453
if (strncmp(cmd, INIT_STRING, strlen(INIT_STRING)) == 0) {
455
/* waiting local echo back after the init string has been sent */
456
if (recv_seq == 0 && strncmp(tmp, INIT_STRING, strlen(INIT_STRING)) == 0) {
460
/* waiting "OK" after local echo has been received */
461
else if (recv_seq == 1 && strncmp(tmp, "OK", 2) == 0) {
462
strncpy(reply, tmp, sizeof(reply) - 1);
466
/* waiting possible "ERROR" after local echo has been received */
467
else if (recv_seq == 1 && huawei_recv_error(tmp) == 1) {
468
strncpy(reply, tmp, sizeof(reply) - 1);
475
/* waiting local echo back after the cmd has been sent */
476
if (recv_seq == 0 && strncmp(tmp, cmd, strlen(cmd)) == 0) {
480
/* waiting data (but not "OK" or "ERROR") after local echo has been received */
481
else if (recv_seq == 1 && strlen(tmp) > 0 && huawei_recv_error(tmp) == 0) {
483
strncpy(reply, tmp, sizeof(reply) - 1);
486
/* waiting "OK" after data has been received */
487
else if (recv_seq == 2 && strncmp(tmp, "OK", 2) == 0) {
491
/* waiting possible "ERROR" after local echo has been received */
492
else if (recv_seq == 1 && huawei_recv_error(tmp) == 1) {
493
strncpy(reply, tmp, sizeof(reply) - 1);
503
static int huawei_configured(void)
505
int port_exists, ret, bytes;
506
static int connected = -1, configured = 0;
509
/* re-read port because device name may change during plugin execution */
512
/* check the device exists before reading on it */
513
port_exists = huawei_port_exists(port);
515
/* modem removed event */
516
if (port_exists < 1 && (connected == -1 || connected == 1)) {
517
info("%s: Modem doesn't exists or has been removed, device %s is to be closed", name, port);
521
error("%s: ERROR: Error when closing device %s after modem removal, ret=%i", name, port, ret);
528
/* modem inserted event */
529
if (port_exists > 0 && (connected == -1 || connected == 0)) {
530
info("%s: Modem has been inserted, device %s will be opened", name, port);
532
ret = huawei_configure_port();
536
debug("DEBUG: Device %s configured successfully, fd=%i", port, ret);
538
error("%s: ERROR: Device %s configuring failure->retrying..., ret=%i", name, port, ret);
543
/* init variables to zero (except tx/rx total flows) when device disconnected */
544
if (connected == 0) {
556
strcpy(operator, "");
560
/* modem initialization */
561
if (connected == 1 && configured != 1) {
562
buf = huawei_send_receive(INIT_STRING);
565
if (strncmp(buf, "OK", 2) == 0) {
567
info("%s: Modem user inerface succesfully initialized to: \'%s\'", name, INIT_STRING);
570
error("%s: ERROR: Invalid or empty response: \'%s\' received for: \'%s\'", name, buf, INIT_STRING);
577
static void huawei_read_quality(const char *cmd)
582
buf = huawei_send_receive(cmd);
585
if (strncmp(buf, "+CSQ: ", 6) == 0) {
587
/* Returns relative signal strength (RSSI) and ber (not supported by modems).
594
* 2 to 30 -109 dBm to -53 dBm
596
* 99 unknown or unmeasurable
599
if (scan_uint(buf + 6, 2, &rssi, &ber) != 2)
600
error("%s: ERROR: Cannot parse all +CSQ: data fields, some data may be wrong or missing", name);
603
debug("DEBUG: Relative rssi value: %u", rssi);
605
error("%s: ERROR: Invalid or empty response: \'%s\' received for: \'%s\'", name, buf, cmd);
610
static void huawei_read_sysinfo(const char *cmd)
615
buf = huawei_send_receive(cmd);
618
if (strncmp(buf, "^SYSINFO:", 9) == 0) {
620
/* Returns system information.
622
* ^SYSINFO:2,3,0,5,1,,4
623
* status,domain,roaming_status,mode,SIM state,reserved,sub_mode
626
if (scan_uint(buf + 9, 7, &status, &domain, &roaming_status, &mode, &sim_state, &reserved, &sub_mode) != 7)
627
error("%s: ERROR: Cannot parse all ^SYSINFO: data fields, some data may be wrong or missing", name);
630
debug("DEBUG: Sub mode value: %u", sub_mode);
632
error("%s: ERROR: Invalid or empty response: \'%s\' received for: \'%s\'", name, buf, cmd);
637
static void huawei_read_manuf(const char *cmd)
642
buf = huawei_send_receive(cmd);
645
/* accept all but "ERROR" */
646
if (bytes > 0 && huawei_recv_error(buf) == 0) {
648
/* Returns manufacturer string.
652
strncpy(manuf, buf, sizeof(manuf) - 1);
655
debug("DEBUG: Manufacturer string: %s", manuf);
657
error("%s: ERROR: Invalid or empty response: \'%s\' received for: \'%s\'", name, buf, cmd);
662
static void huawei_read_model(const char *cmd)
667
buf = huawei_send_receive(cmd);
670
/* accept all but "ERROR" */
671
if (bytes > 0 && huawei_recv_error(buf) == 0) {
673
/* Returns model string.
677
strncpy(model, buf, sizeof(model) - 1);
680
debug("DEBUG: Model string: %s", model);
682
error("%s: ERROR: Invalid or empty response: \'%s\' received for: \'%s\'", name, buf, cmd);
687
static void huawei_read_fwver(const char *cmd)
692
buf = huawei_send_receive(cmd);
695
/* accept all but "ERROR" */
696
if (bytes > 0 && huawei_recv_error(buf) == 0) {
698
/* Returns firmware version string.
702
strncpy(fwver, buf, sizeof(fwver) - 1);
705
debug("DEBUG: Firmware version string: %s", fwver);
707
error("%s: ERROR: Invalid or empty response: \'%s\' received for: \'%s\'", name, buf, cmd);
712
static void huawei_read_operator(const char *cmd)
714
int bytes, i, pos = 0, copy = 0;
717
buf = huawei_send_receive(cmd);
720
if (strncmp(buf, "+COPS:", 6) == 0) {
722
/* Returns operator string.
724
* +COPS: 0,0,"vodafone ES",2
725
* reg_mode,format,operator string (based on format),network access type
728
/* parse "operator string" */
729
for (i = 6; i <= bytes; i++) {
730
if (buf[i] == '\"' && copy == 0) {
733
} else if ((buf[i] == '\"') && copy == 1)
736
if (copy == 1 && strlen(operator) < sizeof(operator) - 1) {
737
operator[pos] = buf[i];
743
debug("DEBUG: Operator version string: \'%s\'", operator);
745
error("%s: ERROR: Invalid or empty response: \'%s\' received for: \'%s\'", name, buf, cmd);
750
static void huawei_read_flowreport(const char *cmd)
754
static unsigned long long int prev_tx_flow = 0, prev_rx_flow = 0;
755
static unsigned long int prev_ds_time = 0;
757
buf = huawei_send_receive(cmd);
760
if (strncmp(buf, "^DSFLOWQRY:", 11) == 0) {
762
/* Returns flow report.
764
* ^DSFLOWQRY:00000E8E,0000000000333ACC,000000000A93E9AD,007B3514,000000007C0E5F69,00000007AD1AE9C6
765
* last_ds_time,last_rx_flow ,last_tx_flow ,total_ds_time,total_tx_flow,total_rx_flow
768
if (sscanf(buf + 11, "%lX,%LX,%LX,%lX,%LX,%LX", &last_ds_time, &last_tx_flow, &last_rx_flow, &total_ds_time,
769
&total_tx_flow, &total_rx_flow) != 6)
770
error("%s: ERROR: Cannot parse all ^DSFLOWQRY: data fields, some data may be wrong or missing", name);
772
/* ^DSFLOWQRY: lacks tx_rate and rx_rate values (^DSFLOWRPT has them), we try to calculate them here.
773
* Values comes at 2s interval.
776
/* tx_rate calculation */
777
if (last_ds_time >= prev_ds_time + 2 && last_tx_flow > prev_tx_flow)
778
calc_tx_rate = ((double) (last_tx_flow - prev_tx_flow)) / ((double) (last_ds_time - prev_ds_time));
779
else if (last_ds_time >= prev_ds_time + 2 && last_tx_flow == prev_tx_flow)
782
/* rx_rate calculation */
783
if (last_ds_time >= prev_ds_time + 2 && last_rx_flow > prev_rx_flow)
784
calc_rx_rate = ((double) (last_rx_flow - prev_rx_flow)) / ((double) (last_ds_time - prev_ds_time));
785
else if (last_ds_time >= prev_ds_time + 2 && last_rx_flow == prev_rx_flow)
788
/* previous values */
789
prev_tx_flow = last_tx_flow;
790
prev_rx_flow = last_rx_flow;
791
prev_ds_time = last_ds_time;
794
debug("DEBUG: Last DS connection time [s]: %lu", last_ds_time);
795
debug("DEBUG: Last DS transmiting traffic [bytes]: %llu", last_tx_flow);
796
debug("DEBUG: Last DS receiving traffic [bytes]: %llu", last_rx_flow);
797
debug("DEBUG: Total DS connection time [s]: %lu", total_ds_time);
798
debug("DEBUG: Total DS transmiting trafic [bytes]: %llu", total_tx_flow);
799
debug("DEBUG: Total DS receiving trafic [bytes]: %llu", total_rx_flow);
800
debug("DEBUG: Calculated tx rate [bytes/s]: %lf", calc_tx_rate);
801
debug("DEBUG: Calculated rx rate [bytes/s]: %lf", calc_rx_rate);
805
error("%s: ERROR: Invalid or empty response: \'%s\' received for: \'%s\'", name, buf, cmd);
810
static void my_quality(RESULT * result, RESULT * arg1)
813
static struct timeval prev_age;
816
age = age_diff(prev_age);
818
if (age < 0 || age >= MIN_INTERVAL) {
819
gettimeofday(&prev_age, NULL);
821
if (huawei_configured() == 1)
822
huawei_read_quality(QUALITY);
825
/* Note: R2S stands for 'Result to String' */
826
if (strncmp(R2S(arg1), "%", 1) == 0) {
827
/* scale rssi 0...31 to 0..100% value */
828
if (rssi > 0 && rssi < 32)
829
value = (double) rssi *100 / 31;
833
} else if (strncmp(R2S(arg1), "dbm", 3) == 0) {
834
/* scale rssi 0...31 to -113 dBm...-51 dBm value */
835
if (rssi > 0 && rssi < 32)
836
value = ((double) rssi * 2) - 113;
840
} else if (strncmp(R2S(arg1), "rssi", 4) == 0) {
841
/* pass through relative rssi 0...31 value */
842
if (rssi > 0 && rssi < 32)
843
value = (double) rssi;
848
error("%s: ERROR: Argument for huawei::quality() is missing, give: '%%'|'dbm'|'rssi'", name);
853
SetResult(&result, R_NUMBER, &value);
858
static void my_mode(RESULT * result, RESULT * arg1)
861
static struct timeval prev_age;
863
char *value_str, *mode_str;
865
age = age_diff(prev_age);
867
if (age < 0 || age >= MIN_INTERVAL) {
868
gettimeofday(&prev_age, NULL);
870
if (huawei_configured() == 1)
871
huawei_read_sysinfo(SYSINFO);
874
if (strncmp(R2S(arg1), "text", 4) == 0) {
875
/* sub modes 8 and 9 are unknown */
879
/* start with an empty string */
880
value_str = strdup("");
883
mode_str = sub_system_mode[sub_mode];
885
/* allocate memory for value */
886
value_str = realloc(value_str, strlen(mode_str) + 1);
888
/* write mode string to value */
889
strcat(value_str, mode_str);
892
SetResult(&result, R_STRING, value_str);
894
/* free local string */
897
} else if (strncmp(R2S(arg1), "number", 6) == 0) {
898
value_num = (double) mode;
901
SetResult(&result, R_NUMBER, &value_num);
904
error("%s: ERROR: Argument for huawei::mode() is missing, give: 'text'|'number'", name);
909
SetResult(&result, R_NUMBER, &value_num);
915
static void my_manuf(RESULT * result)
918
static struct timeval prev_age;
921
age = age_diff(prev_age);
923
if (age < 0 || age >= MIN_INTERVAL) {
924
gettimeofday(&prev_age, NULL);
926
if (huawei_configured() == 1)
927
huawei_read_manuf(MANUF);
930
/* start with an empty string */
931
value_str = strdup("");
933
/* allocate memory for value */
934
value_str = realloc(value_str, strlen(manuf) + 1);
936
/* write mode string to value */
937
strcat(value_str, manuf);
940
SetResult(&result, R_STRING, value_str);
942
/* free local string */
948
static void my_model(RESULT * result)
951
static struct timeval prev_age;
954
age = age_diff(prev_age);
956
if (age < 0 || age >= MIN_INTERVAL) {
957
gettimeofday(&prev_age, NULL);
959
if (huawei_configured() == 1)
960
huawei_read_model(MODEL);
963
/* start with an empty string */
964
value_str = strdup("");
966
/* allocate memory for value */
967
value_str = realloc(value_str, strlen(model) + 1);
969
/* write mode string to value */
970
strcat(value_str, model);
973
SetResult(&result, R_STRING, value_str);
975
/* free local string */
981
static void my_fwver(RESULT * result)
984
static struct timeval prev_age;
987
age = age_diff(prev_age);
989
if (age < 0 || age >= MIN_INTERVAL) {
990
gettimeofday(&prev_age, NULL);
992
if (huawei_configured() == 1)
993
huawei_read_fwver(FWVER);
996
/* start with an empty string */
997
value_str = strdup("");
999
/* allocate memory for value */
1000
value_str = realloc(value_str, strlen(fwver) + 1);
1002
/* write mode string to value */
1003
strcat(value_str, fwver);
1006
SetResult(&result, R_STRING, value_str);
1008
/* free local string */
1014
static void my_operator(RESULT * result)
1017
static struct timeval prev_age;
1020
age = age_diff(prev_age);
1022
if (age < 0 || age >= MIN_INTERVAL) {
1023
gettimeofday(&prev_age, NULL);
1025
if (huawei_configured() == 1)
1026
huawei_read_operator(OPERATOR);
1029
/* start with an empty string */
1030
value_str = strdup("");
1032
/* allocate memory for value */
1033
value_str = realloc(value_str, strlen(operator) + 1);
1035
/* write mode string to value */
1036
strcat(value_str, operator);
1039
SetResult(&result, R_STRING, value_str);
1041
/* free local string */
1047
static void my_flowreport(RESULT * result, RESULT * arg1)
1050
unsigned int days, hours, mins, secs;
1053
static struct timeval prev_age;
1055
age = age_diff(prev_age);
1057
if (age < 0 || age >= MIN_INTERVAL) {
1058
gettimeofday(&prev_age, NULL);
1060
if (huawei_configured() == 1)
1061
huawei_read_flowreport(FLOWREPORT);
1064
if (strncmp(R2S(arg1), "uptime", 6) == 0) {
1066
days = last_ds_time / 86400;
1067
hours = (last_ds_time / 3600) - (days * 24);
1068
mins = (last_ds_time / 60) - (days * 1440) - (hours * 60);
1069
secs = last_ds_time % 60;
1072
sprintf(value_str, "%u days %02u:%02u:%02u", days, hours, mins, secs);
1074
sprintf(value_str, "%02u:%02u:%02u", hours, mins, secs);
1076
/* store result: days, hours, mins, secs */
1077
SetResult(&result, R_STRING, value_str);
1082
if (strncmp(R2S(arg1), "uptime_seconds", 14) == 0) {
1083
/* uptime in seconds */
1084
value_num = (double) last_ds_time;
1086
/* store result: seconds */
1087
SetResult(&result, R_NUMBER, &value_num);
1092
if (strncmp(R2S(arg1), "tx_rate", 7) == 0) {
1093
/* tx data in Bytes/s */
1094
value_num = calc_tx_rate;
1097
SetResult(&result, R_NUMBER, &value_num);
1102
if (strncmp(R2S(arg1), "rx_rate", 7) == 0) {
1103
/* rx data in Bytes/s */
1104
value_num = calc_rx_rate;
1107
SetResult(&result, R_NUMBER, &value_num);
1112
if (strncmp(R2S(arg1), "total_tx", 8) == 0) {
1113
/* total rx data in Bytes */
1114
value_num = (double) total_tx_flow;
1117
SetResult(&result, R_NUMBER, &value_num);
1122
if (strncmp(R2S(arg1), "total_rx", 8) == 0) {
1123
/* total rx data in Bytes */
1124
value_num = (double) total_rx_flow;
1127
SetResult(&result, R_NUMBER, &value_num);
1133
("%s: ERROR: Argument for huawei::flowreport() is missing, give: 'uptime'|'uptime_seconds'|'tx_rate'|'rx_rate'|'total_tx'|'total_rx')",
1138
SetResult(&result, R_NUMBER, &value_num);
1143
/* plugin initialization. MUST NOT be declared 'static'! */
1144
int plugin_init_huawei(void)
1146
/* register our functions */
1147
AddFunction("huawei::quality", 1, my_quality);
1148
AddFunction("huawei::mode", 1, my_mode);
1149
AddFunction("huawei::model", 0, my_model);
1150
AddFunction("huawei::manuf", 0, my_manuf);
1151
AddFunction("huawei::fwver", 0, my_fwver);
1152
AddFunction("huawei::operator", 0, my_operator);
1153
AddFunction("huawei::flowreport", 1, my_flowreport);
1158
void plugin_exit_huawei(void)
1162
/* close file descriptor */
1166
error("%s: ERROR: Device %s closing failure on plugin_exit, %i", name, port, ret);