12
12
#define _XOPEN_SOURCE 500
13
13
14
14
#include <assert.h>
15
- //#include <ctype.h>
15
+ #include <confuse.h>
16
+ #include <curl/curl.h>
17
+ #include <ctype.h>
18
+ #include <stdlib.h>
19
+ #include <string.h>
20
+ #include <libxml/parser.h>
21
+ #include <libxml/tree.h>
16
22
//#include <errno.h>
17
23
//#include <stddef.h>
18
24
//#include <stdint.h>
19
- //#include <stdio.h>
20
- #include <stdlib.h>
21
- #include <string.h>
25
+
22
26
//#include <dirent.h>
23
27
//
24
- #include <confuse.h>
28
+
25
29
//#include <fcntl.h>
26
30
//#include <sys/stat.h>
27
31
//#include <unistd.h>
32
36
#include "error.h"
33
37
#include "timer.h"
34
38
35
- #define LABEE_DEFAULT_SAMPLING_INTERVAL 100000000L // 100ms
39
+ // Confuse CFG options
40
+ #define LABEE_HOSTNAME_CFG "hostname"
41
+ #define LABEE_NODELIST_FILENAME_CFG "nodelist_file"
42
+ #define LABEE_DEFAULT_NODELIST_FILENAME "./nodelist"
43
+ #define LABEE_STATUS_CFG "disabled"
44
+ #define LABEE_DEFAULT_STATUS cfg_false
45
+ #define LABEE_SAMPLING_INTERVAL_CFG "sampling_interval"
46
+ #define LABEE_DEFAULT_SAMPLING_INTERVAL 150000000L // 150ms
47
+ #define LABEE_API_URL_CFG "api_url"
48
+ #define LABEE_API_USER_CFG "user"
49
+ #define LABEE_API_PASSWD_CFG "password"
50
+ #define LABEE_DEFAULT_API_URL "http://10.11.12.242/REST/node"
51
+
52
+ #define LABEE_NODE_ID "id"
53
+ #define LABEE_DEFAULT_POWER_ATTR "actualPowerUsage"
54
+ #define LABEE_POWER_ATTR_CFG "power_attribute"
55
+
56
+ #define LABEE_NODELIST_DELIM ","
36
57
37
58
struct emlDriver labee_driver ;
38
59
60
+ struct xml_content {
61
+ char * content ;
62
+ size_t length ;
63
+ };
64
+
65
+
66
+ char * trimwhitespace (char * str ) {
67
+ char * end ;
68
+
69
+ // Trim leading space
70
+ while (isspace ((unsigned char )* str )) str ++ ;
71
+
72
+ if (* str == 0 ) // All spaces?
73
+ return str ;
74
+
75
+ // Trim trailing space
76
+ end = str + strlen (str ) - 1 ;
77
+ while (end > str && isspace ((unsigned char )* end )) end -- ;
78
+
79
+ // Write new null terminator character
80
+ end [1 ] = '\0' ;
81
+
82
+ return str ;
83
+ }
84
+
85
+
86
+ static size_t store_partial_content (void * content , size_t size ,
87
+ size_t nmemb , struct xml_content * s ) {
88
+ size_t new_length = s -> length + size * nmemb ;
89
+ s -> content = realloc (s -> content , new_length + 1 );
90
+ memcpy (s -> content + s -> length , content , size * nmemb );
91
+ s -> length = new_length ;
92
+ s -> content [s -> length ] = '\0' ;
93
+ return size * nmemb ;
94
+ }
95
+
96
+
97
+ static enum emlError get_xml (struct xml_content * xc ) {
98
+ enum emlError err = EML_SUCCESS ;
99
+ char * labee_api_url = cfg_getstr (labee_driver .config , LABEE_API_URL_CFG );
100
+ char * api_user = cfg_getstr (labee_driver .config , LABEE_API_USER_CFG );
101
+ char * api_passwd = cfg_getstr (labee_driver .config , LABEE_API_PASSWD_CFG );
102
+ CURLcode res ;
103
+
104
+ CURL * curl = curl_easy_init ();
105
+
106
+ if (curl ) {
107
+ curl_easy_setopt (curl , CURLOPT_URL , labee_api_url );
108
+ curl_easy_setopt (curl , CURLOPT_USERNAME , api_user );
109
+ curl_easy_setopt (curl , CURLOPT_PASSWORD , api_passwd );
110
+
111
+ struct curl_slist * list = 0 ;
112
+ list = curl_slist_append (list , "Content-type: application/xml" );
113
+
114
+ curl_easy_setopt (curl , CURLOPT_WRITEDATA , (void * )xc );
115
+ curl_easy_setopt (curl , CURLOPT_WRITEFUNCTION , store_partial_content );
116
+ res = curl_easy_perform (curl );
117
+
118
+ if (res != CURLE_OK ) {
119
+ snprintf (labee_driver .failed_reason , sizeof (labee_driver .failed_reason ),
120
+ "obtain_xml(): %s, %s " , labee_api_url , curl_easy_strerror (res ));
121
+ err = EML_NETWORK_ERROR ;
122
+ }
123
+
124
+ curl_easy_cleanup (curl );
125
+ }
126
+ return err ;
127
+ }
128
+
129
+
130
+ void init_xml (struct xml_content * * xc ) {
131
+ (* xc ) = malloc (sizeof (struct xml_content ));
132
+ (* xc )-> content = malloc (1 );
133
+ (* xc )-> content [0 ] = '\0' ;
134
+ (* xc )-> length = 0 ;
135
+ }
136
+
137
+
138
+ void free_xml (struct xml_content * xc ) {
139
+ if (xc ) {
140
+ free (xc -> content );
141
+ xc -> length = 0 ;
142
+ free (xc );
143
+ }
144
+ }
145
+
39
146
40
147
static enum emlError init (cfg_t * const config ) {
41
148
assert (!labee_driver .initialized );
42
149
assert (config );
43
150
labee_driver .config = config ;
44
151
45
152
enum emlError err ;
46
-
47
- // TODO Check if the API is up
153
+ // Check that the API is working
154
+ struct xml_content * xc ;
155
+ init_xml (& xc );
156
+ err = get_xml (xc );
157
+ free_xml (xc );
48
158
49
- // FUnction that generates error code
159
+ // Function that generates error code
50
160
if (err != EML_SUCCESS )
51
161
goto err_free ;
52
162
@@ -73,41 +183,135 @@ static enum emlError init(cfg_t* const config) {
73
183
}
74
184
75
185
76
- static enum emlError shutdown () {
186
+ // We were using shutdown of the sake of consistency between all drivers
187
+ // but it produces a conflict with a shutdown function used in curl.
188
+ // It has been changed as it does not affect any behaviour.
189
+ static enum emlError labee_shutdown () {
77
190
assert (labee_driver .initialized );
78
191
79
192
labee_driver .initialized = 0 ;
80
193
81
194
return EML_SUCCESS ;
82
195
}
83
196
197
+
198
+ static enum emlError obtain_hostname_rest_reference (char * * ref ) {
199
+ char * nodelist_filename = cfg_getstr (labee_driver .config , LABEE_NODELIST_FILENAME_CFG );
200
+ char * hostname = cfg_getstr (labee_driver .config , LABEE_HOSTNAME_CFG );
201
+ char buffer [BUFSIZ ];
202
+ enum emlError err = EML_BAD_CONFIG ;
203
+
204
+ FILE * fp = fopen (nodelist_filename , "r" );
205
+ while (fscanf (fp , "%s" , buffer ) != EOF ) {
206
+ char * tok1 = strtok (buffer , LABEE_NODELIST_DELIM );
207
+ char * tok2 = strtok (0 , LABEE_NODELIST_DELIM );
208
+ tok2 = trimwhitespace (tok2 );
209
+
210
+ if (!strcmp (tok2 , hostname )) {
211
+ err = EML_SUCCESS ;
212
+ (* ref ) = malloc (sizeof (tok1 ));
213
+ strcpy (* ref , tok1 );
214
+ break ;
215
+ }
216
+ }
217
+ fclose (fp );
218
+ return err ;
219
+ }
220
+
221
+
222
+ enum emlError get_power_from_xml (long long unsigned * power ,
223
+ struct xml_content * xc ) {
224
+ xmlDocPtr doc ;
225
+ xmlChar * id ;
226
+ xmlChar * chr_power ;
227
+ char * ref ;
228
+ enum emlError err ;
229
+ const xmlChar * label_id = xmlCharStrdup (LABEE_NODE_ID );
230
+ const xmlChar * label_powerusage = xmlCharStrdup (
231
+ cfg_getstr (labee_driver .config , LABEE_POWER_ATTR_CFG )
232
+ );
233
+
234
+ err = obtain_hostname_rest_reference (& ref );
235
+ if (err != EML_SUCCESS )
236
+ return err ;
237
+
238
+ // The document being in memory, it have no base per RFC 2396,
239
+ // and the "noname.xml" argument will serve as its base.
240
+ doc = xmlReadMemory (xc -> content , xc -> length , "noname.xml" , NULL , 0 );
241
+ if (!doc )
242
+ return EML_SENSOR_MEASUREMENT_ERROR ;
243
+
244
+ xmlNodePtr cur = xmlDocGetRootElement (doc );
245
+ cur = cur -> children ;
246
+ while (cur != NULL ) {
247
+ id = xmlGetProp (cur , label_id );
248
+ if (!strcmp ((char * ) id , ref )) {
249
+ xmlFree (id );
250
+ chr_power = xmlGetProp (cur , label_powerusage );
251
+ break ;
252
+ }
253
+ xmlFree (id );
254
+ cur = cur -> next ;
255
+ }
256
+
257
+ // EML_SI_MEGA is applied since the measurement offers enough precision
258
+ (* power ) = atof ((char * ) chr_power ) * EML_SI_MEGA ;
259
+
260
+ xmlFreeDoc (doc );
261
+ free (ref );
262
+ return EML_SUCCESS ;
263
+ }
264
+
265
+
84
266
static enum emlError measure (size_t devno , unsigned long long * values ) {
85
267
assert (labee_driver .initialized );
86
268
assert (devno < labee_driver .ndevices ); // Shouldn't be more than one anyways
87
269
88
- enum emlError err ;
270
+ enum emlError err = EML_SUCCESS ;
271
+ unsigned long long power ;
89
272
90
- values [0 ] = millitimestamp ();
91
- const long sampling_interval = cfg_getint (labee_driver .config , "sampling_interval" );
92
- unsigned long long power = 1 / sampling_interval ;
273
+ struct xml_content * xc ;
274
+ init_xml (& xc );
275
+ err = get_xml (xc );
276
+ if (err != EML_SUCCESS )
277
+ goto err_free ;
93
278
94
- //TODO parse xml from rest api apply average proportionally to interval
95
- values [labee_driver .default_props -> inst_energy_field * DATABLOCK_SIZE ] = power ;
279
+ err = get_power_from_xml (& power , xc );
280
+ if (err != EML_SUCCESS )
281
+ goto err_free ;
282
+
283
+ values [0 ] = nanotimestamp ();
284
+ values [labee_driver .default_props -> inst_power_field * DATABLOCK_SIZE ] = power ;
285
+
286
+ free_xml (xc );
96
287
return EML_SUCCESS ;
288
+
289
+ err_free :
290
+ if (labee_driver .failed_reason [0 ] == '\0' )
291
+ strncpy (labee_driver .failed_reason , emlErrorMessage (err ),
292
+ sizeof (labee_driver .failed_reason ) - 1 );
293
+ free_xml (xc );
294
+ return err ;
97
295
}
98
296
99
297
// default measurement properties for this driver
100
298
static struct emlDataProperties default_props = {
101
- .time_factor = EML_SI_MILLI ,
102
- .energy_factor = EML_SI_MICRO , // Measurement is in J, but to store on a long, it is multiplied by EML_SI_MEGA
103
- .power_factor = EML_SI_MICRO , // Measurement is in W, same principle, with EML_SI_MEGA
104
- .inst_energy_field = 1 ,
105
- .inst_power_field = 2 ,
299
+ .time_factor = EML_SI_NANO ,
300
+ .energy_factor = EML_SI_MICRO ,
301
+ .power_factor = EML_SI_MICRO , // The unit is in W, so it is saved multiplied by EML_SI_MEGA.
302
+ .inst_energy_field = 0 ,
303
+ .inst_power_field = 1 ,
106
304
};
107
305
108
306
static cfg_opt_t cfgopts [] = {
109
- CFG_BOOL ("disabled" , cfg_false , CFGF_NONE ),
110
- CFG_INT ("sampling_interval" , LABEE_DEFAULT_SAMPLING_INTERVAL , CFGF_NONE ),
307
+ CFG_BOOL (LABEE_STATUS_CFG , LABEE_DEFAULT_STATUS , CFGF_NONE ),
308
+ CFG_INT (LABEE_SAMPLING_INTERVAL_CFG , LABEE_DEFAULT_SAMPLING_INTERVAL , CFGF_NONE ),
309
+ CFG_STR (LABEE_API_URL_CFG , LABEE_DEFAULT_API_URL , CFGF_NONE ),
310
+ CFG_STR (LABEE_HOSTNAME_CFG , "" , CFGF_NONE ),
311
+ CFG_STR (LABEE_NODELIST_FILENAME_CFG , "./nodelist" , CFGF_NONE ),
312
+ CFG_STR (LABEE_API_USER_CFG , "" , CFGF_NONE ),
313
+ CFG_STR (LABEE_API_PASSWD_CFG , "" , CFGF_NONE ),
314
+ CFG_STR (LABEE_POWER_ATTR_CFG , LABEE_DEFAULT_POWER_ATTR , CFGF_NONE ),
111
315
CFG_END ()
112
316
};
113
317
@@ -121,6 +325,6 @@ struct emlDriver labee_driver = {
121
325
.config = NULL ,
122
326
123
327
.init = & init ,
124
- .shutdown = & shutdown ,
328
+ .shutdown = & labee_shutdown ,
125
329
.measure = & measure ,
126
330
};
0 commit comments