RocketLogger  1.0
file_handling.c
Go to the documentation of this file.
1 
5 #include "file_handling.h"
6 
8 const char* channel_names[NUM_CHANNELS] = {"I1H","I1L","V1","V2","I2H","I2L","V3","V4"};
10 const char* digital_input_names[NUM_DIGITAL_INPUTS] = {"DI1", "DI2", "DI3", "DI4", "DI5", "DI6"};
12 const char* valid_info_names[NUM_I_CHANNELS] = {"I1L_valid", "I2L_valid"};
13 
18 
24 void create_time_stamp(struct time_stamp* time_real, struct time_stamp* time_monotonic) {
25 
26  struct timespec spec_real;
27  struct timespec spec_monotonic;
28 
29  // get time stamp of real-time and monotonic clock
30  int ret1 = clock_gettime(CLOCK_REALTIME, &spec_real);
31  int ret2 = clock_gettime(CLOCK_MONOTONIC_RAW, &spec_monotonic);
32 
33  if( ret1 < 0 || ret2 < 0 ) {
34  rl_log(ERROR, "failed to get time");
35  }
36 
37  // convert to own time stamp
38  time_real->sec = (int64_t) spec_real.tv_sec;
39  time_real->nsec = (int64_t) spec_real.tv_nsec;
40  time_monotonic->sec = (int64_t) spec_monotonic.tv_sec;
41  time_monotonic->nsec = (int64_t) spec_monotonic.tv_nsec;
42 
43 }
44 
45 
50 void get_mac_addr(uint8_t mac_address[MAC_ADDRESS_LENGTH]) {
51 
52  FILE* fp = fopen (MAC_ADDRESS_FILE, "r");
53 
54  int i=0;
55  fscanf(fp, "%x", &mac_address[i]);
56  for(i=1; i<MAC_ADDRESS_LENGTH; i++) {
57  fscanf(fp, ":%x", &mac_address[i]);
58  }
59  fclose(fp);
60 }
61 
67 void setup_lead_in(struct rl_file_lead_in* lead_in, struct rl_conf* conf) {
68 
69  // number channels
70  uint16_t channel_count = count_channels(conf->channels);
71  // number binary channels
72  uint16_t channel_bin_count = 0;
74  channel_bin_count = NUM_DIGITAL_INPUTS;
75  }
76  if(conf->channels[I1L_INDEX] == CHANNEL_ENABLED) {
77  i1l_valid_channel = ++channel_bin_count;
78  }
79  if(conf->channels[I2L_INDEX] == CHANNEL_ENABLED) {
80  i2l_valid_channel = ++channel_bin_count;
81  }
82  // comment length
83  uint32_t comment_length = strlen(RL_FILE_COMMENT) * sizeof(int8_t);
84  // timestamps
85  struct time_stamp time_real;
86  struct time_stamp time_monotonic;
87  create_time_stamp(&time_real, &time_monotonic);
88 
89 
90  // lead_in setup
91  lead_in->magic = RL_FILE_MAGIC;
92  lead_in->file_version = RL_FILE_VERSION;
93  lead_in->header_length = sizeof(struct rl_file_lead_in) + comment_length + (channel_count + channel_bin_count) * sizeof(struct rl_file_channel);
94  lead_in->data_block_size = conf->sample_rate / conf->update_rate;
95  lead_in->data_block_count = 0; // needs to be updated
96  lead_in->sample_count = 0; // needs to be updated
97  lead_in->sample_rate = conf->sample_rate;
98  get_mac_addr(lead_in->mac_address);
99  lead_in->start_time = time_real;
100  lead_in->comment_length = comment_length;
101  lead_in->channel_bin_count = channel_bin_count;
102  lead_in->channel_count = channel_count;
103 
104 }
105 
111 void setup_channels(struct rl_file_header* file_header, struct rl_conf* conf) {
112 
113  int i;
114  int j;
115  int total_channel_count = file_header->lead_in.channel_bin_count + file_header->lead_in.channel_count;
116 
117  // reset channels
118  memset(file_header->channel, 0, total_channel_count * sizeof(struct rl_file_channel));
119 
120  // digital channels
121  j=0;
123  for(i=0; i<NUM_DIGITAL_INPUTS; i++) {
124  file_header->channel[j].unit = RL_UNIT_BINARY;
125  file_header->channel[j].channel_scale = RL_SCALE_NONE;
126  file_header->channel[j].data_size = 0;
127  file_header->channel[j].valid_data_channel = NO_VALID_DATA;
128  strcpy(file_header->channel[j].name, digital_input_names[i]);
129  j++;
130  }
131  }
132 
133  // range valid channels
134  if(conf->channels[I1L_INDEX] == CHANNEL_ENABLED) {
135  file_header->channel[j].unit = RL_UNIT_RANGE_VALID;
136  file_header->channel[j].channel_scale = RL_SCALE_NONE;
137  file_header->channel[j].data_size = 0;
138  file_header->channel[j].valid_data_channel = NO_VALID_DATA;
139  strcpy(file_header->channel[j].name, valid_info_names[0]);
140  j++;
141  }
142  if(conf->channels[I2L_INDEX] == CHANNEL_ENABLED) {
143  file_header->channel[j].unit = RL_UNIT_RANGE_VALID;
144  file_header->channel[j].channel_scale = RL_SCALE_NONE;
145  file_header->channel[j].data_size = 0;
146  file_header->channel[j].valid_data_channel = NO_VALID_DATA;
147  strcpy(file_header->channel[j].name, valid_info_names[1]);
148  j++;
149  }
150 
151  // analog channels
152  for(i=0; i<NUM_CHANNELS; i++) {
153  if(conf->channels[i] == CHANNEL_ENABLED) {
154  // current
155  if(is_current(i)){
156  // low
157  if(is_low_current(i)) {
158  file_header->channel[j].channel_scale = RL_SCALE_TEN_PICO;
159  if(i == I1L_INDEX) {
160  file_header->channel[j].valid_data_channel = i1l_valid_channel;
161  } else {
162  file_header->channel[j].valid_data_channel = i2l_valid_channel;
163  }
164  // high
165  } else {
166  file_header->channel[j].channel_scale = RL_SCALE_NANO;
167  file_header->channel[j].valid_data_channel = NO_VALID_DATA;
168  }
169  file_header->channel[j].unit = RL_UNIT_AMPERE;
170  // voltage
171  } else {
172  file_header->channel[j].unit = RL_UNIT_VOLT;
173  file_header->channel[j].channel_scale = RL_SCALE_TEN_NANO;
174  file_header->channel[j].valid_data_channel = NO_VALID_DATA;
175  }
176  file_header->channel[j].data_size = 4;
177  strcpy(file_header->channel[j].name, channel_names[i]);
178  j++;
179  }
180  }
181 }
182 
188 void setup_header(struct rl_file_header* file_header, struct rl_conf* conf) {
189 
190  // comment
191  char* comment = RL_FILE_COMMENT;
192  file_header->comment = comment;
193 
194  // channels
195  setup_channels(file_header, conf);
196 
197 }
198 
204 void store_header_bin(FILE* data, struct rl_file_header* file_header) {
205 
206  int total_channel_count = file_header->lead_in.channel_bin_count + file_header->lead_in.channel_count;
207 
208  // check if alignment bytes are needed after header comment
209  int comment_length = strlen(file_header->comment);
210  int comment_unaligned_bytes = comment_length % RL_FILE_COMMENT_ALIGNMENT_BYTES;
211  if (comment_unaligned_bytes > 0) {
212  file_header->lead_in.comment_length = comment_length + RL_FILE_COMMENT_ALIGNMENT_BYTES
213  - comment_unaligned_bytes;
214  file_header->lead_in.header_length = sizeof(struct rl_file_lead_in) + file_header->lead_in.comment_length
215  + total_channel_count * sizeof(struct rl_file_channel);
216  }
217 
218  // write lead-in
219  fwrite(&(file_header->lead_in), sizeof(struct rl_file_lead_in), 1, data);
220 
221  // write comment, add zero bytes for proper header alignment if necessary
222  fwrite(file_header->comment, comment_length, 1, data);
223  if (comment_unaligned_bytes > 0) {
224  uint8_t zero_bytes[RL_FILE_COMMENT_ALIGNMENT_BYTES] = { 0 };
225  fwrite(zero_bytes, RL_FILE_COMMENT_ALIGNMENT_BYTES - comment_unaligned_bytes, 1, data);
226  }
227 
228  // write channel information
229  fwrite(file_header->channel, sizeof(struct rl_file_channel), total_channel_count, data);
230 }
231 
237 void store_header_csv(FILE* data, struct rl_file_header* file_header) {
238  // lead-in
239  fprintf(data, "RocketLogger CSV File\n");
240  fprintf(data, "File Version,%u\n", (uint32_t) file_header->lead_in.file_version);
241  fprintf(data, "Block Size,%u\n", (uint32_t) file_header->lead_in.data_block_size);
242  fprintf(data, "Block Count,%-20u\n", (uint32_t) file_header->lead_in.data_block_count);
243  fprintf(data, "Sample Count,%-20llu\n", (uint64_t) file_header->lead_in.sample_count);
244  fprintf(data, "Sample Rate,%u\n", (uint32_t) file_header->lead_in.sample_rate);
245  fprintf(data, "MAC Address,%02x", (uint32_t) file_header->lead_in.mac_address[0]);
246  int i;
247  for(i=1; i<MAC_ADDRESS_LENGTH; i++) {
248  fprintf(data, ":%02x", (uint32_t) file_header->lead_in.mac_address[i]);
249  }
250  fprintf(data, "\n");
251  time_t time = (time_t) file_header->lead_in.start_time.sec;
252  fprintf(data, "Start Time,%s", ctime(&time));
253  fprintf(data, "Comment,%s\n", file_header->comment);
254  fprintf(data, "\n");
255 
256  // channels
257  for(i=0; i<(file_header->lead_in.channel_count + file_header->lead_in.channel_bin_count); i++) {
258  fprintf(data, ",%s", file_header->channel[i].name);
259  switch(file_header->channel[i].channel_scale) {
260  case RL_SCALE_MILLI:
261  fprintf(data, " [m");
262  break;
263  case RL_SCALE_MICRO:
264  fprintf(data, " [u");
265  break;
266  case RL_SCALE_TEN_NANO:
267  fprintf(data, " [10n");
268  break;
269  case RL_SCALE_NANO:
270  fprintf(data, " [n");
271  break;
272  case RL_SCALE_TEN_PICO:
273  fprintf(data, " [10p");
274  break;
275  default:
276  break;
277  }
278  switch(file_header->channel[i].unit) {
279  case RL_UNIT_VOLT:
280  fprintf(data, "V]");
281  break;
282  case RL_UNIT_AMPERE:
283  fprintf(data, "A]");
284  break;
285  default:
286  break;
287  }
288  }
289  fprintf(data, "\n");
290 }
291 
297 void update_header_bin(FILE* data, struct rl_file_header* file_header) {
298 
299  // seek to beginning and rewrite lead_in
300  rewind(data);
301  fwrite(&(file_header->lead_in), sizeof(struct rl_file_lead_in), 1, data);
302  fseek(data, 0, SEEK_END);
303 }
304 
310 void update_header_csv(FILE* data, struct rl_file_header* file_header) {
311  rewind(data);
312  fprintf(data, "RocketLogger CSV File\n");
313  fprintf(data, "File Version,%u\n", (uint32_t) file_header->lead_in.file_version);
314  fprintf(data, "Block Size,%u\n", (uint32_t) file_header->lead_in.data_block_size);
315  fprintf(data, "Block Count,%-20u\n", (uint32_t) file_header->lead_in.data_block_count);
316  fprintf(data, "Sample Count,%-20llu\n", (uint64_t) file_header->lead_in.sample_count);
317  fseek(data, 0, SEEK_END);
318 }
319 
327 void merge_currents(uint8_t* valid, int64_t* dest, int64_t* src, struct rl_conf* conf) {
328 
329  int ch_in = 0;
330  int ch_out = 0;
331 
332 
334  if(valid[0] == 1) {
335  dest[ch_out++] = src[++ch_in];
336  } else {
337  dest[ch_out++] = src[ch_in++]*H_L_SCALE;
338  }
339  ch_in++;
340  } else if(conf->channels[I1H_INDEX] == CHANNEL_ENABLED) {
341  dest[ch_out++] = src[ch_in++]*H_L_SCALE;
342  } else if(conf->channels[I1L_INDEX] == CHANNEL_ENABLED){
343  dest[ch_out++] = src[ch_in++];
344  }
345  if(conf->channels[V1_INDEX] == CHANNEL_ENABLED) {
346  dest[ch_out++] = src[ch_in++];
347  }
348  if(conf->channels[V2_INDEX] == CHANNEL_ENABLED) {
349  dest[ch_out++] = src[ch_in++];
350  }
351 
353  if(valid[1] == 1) {
354  dest[ch_out++] = src[++ch_in];
355  } else {
356  dest[ch_out++] = src[ch_in++]*H_L_SCALE;
357  }
358  ch_in++;
359  } else if(conf->channels[I2H_INDEX] == CHANNEL_ENABLED) {
360  dest[ch_out++] = src[ch_in++]*H_L_SCALE;
361  } else if(conf->channels[I2L_INDEX] == CHANNEL_ENABLED){
362  dest[ch_out++] = src[ch_in++];
363  }
364 
365  if(conf->channels[V3_INDEX] == CHANNEL_ENABLED) {
366  dest[ch_out++] = src[ch_in++];
367  }
368  if(conf->channels[V4_INDEX] == CHANNEL_ENABLED) {
369  dest[ch_out++] = src[ch_in++];
370  }
371 }
372 
383 void handle_data_buffer(FILE* data, void* buffer_addr, uint32_t sample_size, uint32_t samples_buffer, struct rl_conf* conf, int sem_id, struct web_shm* web_data_ptr) {
384 
385  // INIT //
386 
387  uint32_t i;
388  uint32_t j;
389  uint32_t k;
390 
391  // bin channels
392  uint32_t num_bin_channels;
394  num_bin_channels = NUM_DIGITAL_INPUTS;
395  } else {
396  num_bin_channels = 0;
397  }
398 
399  // channels
400  uint32_t num_channels = count_channels(conf->channels);
401 
402  // binary data (for samples)
403  uint32_t bin_data;
404  int32_t channel_data[num_channels];
405  int32_t value = 0;
406 
407  // csv data
408  char channel_data_char[CSV_LINE_LENGTH] = "";
409  char value_char[CSV_VALUE_LENGTH];
410 
411 
412  // TIMESTAMP //
413 
414  // create timestamp
415  struct time_stamp time_real;
416  struct time_stamp time_monotonic;
417  create_time_stamp(&time_real, &time_monotonic);
418 
419  // adjust time with buffer latency
420  time_real.sec -= 1 / conf->update_rate;
421  time_monotonic.sec -= 1 / conf->update_rate;
422 
423  // store timestamp
424  if (conf->file_format == BIN) {
425  fwrite(&time_real, sizeof(struct time_stamp), 1, data);
426  fwrite(&time_monotonic, sizeof(struct time_stamp), 1, data);
427 
428  } else if(conf->file_format == CSV) {
429  time_t t = (time_t) time_real.sec;
430  strcpy(value_char, ctime(&t));
431  value_char[strlen(value_char)-1] = '\0'; // remove \n
432  fprintf(data, "%s", value_char);
433  }
434 
435 
436  // AVERAGE DATA //
437 
438  // averaged data (for web and low rates)
439  uint32_t avg_length[WEB_RING_BUFFER_COUNT] = {samples_buffer / BUFFER1_SIZE, samples_buffer / BUFFER10_SIZE, samples_buffer / BUFFER100_SIZE};
440  int64_t avg_data[WEB_RING_BUFFER_COUNT][num_channels];
441  uint32_t bin_avg_data[WEB_RING_BUFFER_COUNT][num_bin_channels];
442  uint8_t avg_valid[WEB_RING_BUFFER_COUNT][NUM_I_CHANNELS] = {{1,1},{1,1},{1,1}};
443 
444  memset(avg_data, 0, sizeof(int64_t) * num_channels * WEB_RING_BUFFER_COUNT);
445  memset(bin_avg_data, 0, sizeof(uint32_t) * num_bin_channels * WEB_RING_BUFFER_COUNT);
446 
447 
448  // WEB DATA //
449 
450  // data for webserver
451  uint32_t num_web_channels = 0;
452  if(conf->enable_web_server == 1) {
453  num_web_channels = web_data_ptr->num_channels;
454  }
455  int64_t web_data[WEB_RING_BUFFER_COUNT][BUFFER1_SIZE][num_web_channels];
456 
457 
458  // HANDLE BUFFER //
459 
460  for(i=0; i<samples_buffer; i++){
461 
462  // READ //
463 
464  // reset values
465  k = 0;
466  bin_data = 0;
467  strcpy(channel_data_char,"\0");
468 
469 
470  // read binary channels
471  uint8_t bin_adc1 = (*((int8_t *) (buffer_addr)));
472  uint8_t bin_adc2 = (*((int8_t *) (buffer_addr + 1)));
473 
474  buffer_addr += PRU_DIG_SIZE;
475 
476  // read and scale values (if channel selected)
477  for(j=0; j<NUM_CHANNELS; j++) {
478  if(conf->channels[j] == CHANNEL_ENABLED) {
479  if(sample_size == 4) {
480  value = *( (int32_t *) (buffer_addr + sample_size*j) );
481  } else {
482  value = *( (int16_t *) (buffer_addr + sample_size*j) );
483  }
484  channel_data[k] = (int32_t) (( value + calibration.offsets[j] ) * calibration.scales[j]);
485  avg_data[BUF1_INDEX][k] += channel_data[k];
486  k++;
487  }
488  }
489  buffer_addr+=NUM_CHANNELS*sample_size;
490 
491 
492  // BINARY CHANNELS //
493 
494  // mask and combine digital inputs, if requestet
495  uint32_t bin_channel_pos;
497  bin_data = ((bin_adc1 & BINARY_MASK) >> 1) | ((bin_adc2 & BINARY_MASK) << 2);
498  bin_channel_pos = NUM_DIGITAL_INPUTS;
499 
500  // average digital inputs
501  int32_t MASK = 1;
502  for(j=0; j<num_bin_channels; j++) {
503  if((bin_data & MASK) > 0) {
504  bin_avg_data[BUF1_INDEX][j] += 1;
505  }
506  MASK = MASK << 1;
507  }
508 
509  } else {
510  bin_channel_pos = 0;
511  }
512 
513  // mask and combine valid info
514  uint8_t valid1 = (~bin_adc1) & VALID_MASK;
515  uint8_t valid2 = (~bin_adc2) & VALID_MASK;
516 
517  if(conf->channels[I1L_INDEX] == CHANNEL_ENABLED) {
518  bin_data = bin_data | (valid1 << bin_channel_pos);
519  bin_channel_pos++;
520  }
521  if(conf->channels[I2L_INDEX] == CHANNEL_ENABLED) {
522  bin_data = bin_data | (valid2 << bin_channel_pos);
523  bin_channel_pos++;
524  }
525 
526  // average valid info
527  for(j=0; j<=BUF100_INDEX; j++) {
528  avg_valid[j][0] = avg_valid[j][0] & valid1;
529  avg_valid[j][1] = avg_valid[j][1] & valid2;
530  }
531 
532 
533  // HANDLE AVERAGE DATA //
534 
535  if(conf->enable_web_server == 1 || conf->sample_rate < MIN_ADC_RATE) {
536 
537  // buffer 1
538  if((i+1)%avg_length[BUF1_INDEX] == 0) {
539 
540  // average
541  for(j=0; j<num_channels; j++) {
542  avg_data[BUF1_INDEX][j] /= avg_length[BUF1_INDEX];
543  avg_data[BUF10_INDEX][j] += avg_data[BUF1_INDEX][j];
544  }
545 
546  // merge_currents (for web)
547  if(conf->enable_web_server == 1) {
548  merge_currents(avg_valid[BUF1_INDEX], &web_data[BUF1_INDEX][i/avg_length[BUF1_INDEX]][num_bin_channels], avg_data[BUF1_INDEX], conf);
549  }
550  // average bin channels
551  for(j=0; j<num_bin_channels; j++) {
552 
553  bin_avg_data[BUF10_INDEX][j] += bin_avg_data[BUF1_INDEX][j];
554 
555  // store bin channels for web
556  if(conf->enable_web_server == 1) {
557  if(bin_avg_data[BUF1_INDEX][j] >= (avg_length[BUF1_INDEX]/2)) {
558  web_data[BUF1_INDEX][i/avg_length[BUF1_INDEX]][j] = 1;
559  } else {
560  web_data[BUF1_INDEX][i/avg_length[BUF1_INDEX]][j] = 0;
561  }
562  }
563  }
564 
565  // write data to file
566  if(conf->sample_rate == 100) {
567  // binary data
568  if (bin_channel_pos > 0) {
569  if (conf->file_format == BIN) {
570  uint32_t temp_bin = 0;
571  for(j=0; j<num_bin_channels; j++) {
572  temp_bin = temp_bin | ((bin_avg_data[BUF1_INDEX][j] >= (avg_length[BUF1_INDEX]/2)) << j);
573  }
574  if(conf->channels[I1L_INDEX] == CHANNEL_ENABLED) {
575  temp_bin = temp_bin | (avg_valid[BUF1_INDEX][0] << j++);
576  }
577  if(conf->channels[I2L_INDEX] == CHANNEL_ENABLED) {
578  temp_bin = temp_bin | (avg_valid[BUF1_INDEX][1] << j++);
579  }
580 
581  fwrite(&temp_bin, sizeof(uint32_t), 1, data);
582 
583  } else if (conf->file_format == CSV) {
584  for(j=0; j<num_bin_channels; j++) {
585  sprintf(value_char, ", %d", (bin_avg_data[BUF1_INDEX][j] >= (avg_length[BUF1_INDEX]/2)));
586  strcat(channel_data_char,value_char);
587  }
588  if(conf->channels[I1L_INDEX] == CHANNEL_ENABLED) {
589  sprintf(value_char, ", %d", avg_valid[BUF1_INDEX][0]);
590  strcat(channel_data_char,value_char);
591  }
592  if(conf->channels[I2L_INDEX] == CHANNEL_ENABLED) {
593  sprintf(value_char, ", %d", avg_valid[BUF1_INDEX][1]);
594  strcat(channel_data_char,value_char);
595  }
596  }
597  }
598 
599  // channel data
600  if (conf->file_format == BIN) {
601  for(j=0; j<num_channels; j++) {
602  int32_t tmp = (int32_t) avg_data[BUF1_INDEX][j];
603  fwrite(&tmp, sizeof(int32_t), 1, data);
604  }
605  } else if (conf->file_format == CSV) {
606  for(j=0; j < num_channels; j++) {
607  sprintf(value_char,",%d",(int32_t) avg_data[BUF1_INDEX][j]);
608  strcat(channel_data_char, value_char);
609  }
610  strcat(channel_data_char,"\n");
611  fprintf(data, "%s", channel_data_char);
612  }
613  }
614 
615  // reset values
616  memset(avg_data[BUF1_INDEX], 0, sizeof(int64_t) * num_channels);
617  memset(bin_avg_data[BUF1_INDEX], 0, sizeof(uint32_t) * num_bin_channels);
618  avg_valid[BUF1_INDEX][0] = 1;
619  avg_valid[BUF1_INDEX][1] = 1;
620  }
621 
622 
623  // buffer 10
624  if((i+1)%avg_length[BUF10_INDEX] == 0) {
625 
626  // average
627  for(j=0; j<num_channels; j++) {
628  avg_data[BUF10_INDEX][j] /= (avg_length[BUF10_INDEX]/avg_length[BUF1_INDEX]);
629  avg_data[BUF100_INDEX][j] += avg_data[BUF10_INDEX][j];
630  }
631 
632  // merge_currents (for web)
633  if(conf->enable_web_server == 1) {
634  merge_currents(avg_valid[BUF10_INDEX], &web_data[BUF10_INDEX][i/avg_length[BUF10_INDEX]][num_bin_channels], avg_data[BUF10_INDEX], conf);
635  }
636 
637  // average bin channels
638  for(j=0; j<num_bin_channels; j++) {
639 
640  bin_avg_data[BUF100_INDEX][j] += bin_avg_data[BUF10_INDEX][j];
641 
642  // store bin channels for web
643  if(conf->enable_web_server == 1) {
644  if(bin_avg_data[BUF10_INDEX][j] >= (avg_length[BUF10_INDEX]/2)) {
645  web_data[BUF10_INDEX][i/avg_length[BUF10_INDEX]][j] = 1;
646  } else {
647  web_data[BUF10_INDEX][i/avg_length[BUF10_INDEX]][j] = 0;
648  }
649  }
650  }
651 
652  // write data to file
653  if(conf->sample_rate == 10) {
654  // binary data
655  if (bin_channel_pos > 0) {
656  if (conf->file_format == BIN) {
657  uint32_t temp_bin = 0;
658  for(j=0; j<num_bin_channels; j++) {
659  temp_bin = temp_bin | ((bin_avg_data[BUF10_INDEX][j] >= (avg_length[BUF10_INDEX]/2)) << j);
660  }
661  if(conf->channels[I1L_INDEX] == CHANNEL_ENABLED) {
662  temp_bin = temp_bin | (avg_valid[BUF10_INDEX][0] << j++);
663  }
664  if(conf->channels[I2L_INDEX] == CHANNEL_ENABLED) {
665  temp_bin = temp_bin | (avg_valid[BUF10_INDEX][1] << j++);
666  }
667 
668  fwrite(&temp_bin, sizeof(uint32_t), 1, data);
669 
670  } else if (conf->file_format == CSV) {
671  for(j=0; j<num_bin_channels; j++) {
672  sprintf(value_char, ", %d", (bin_avg_data[BUF10_INDEX][j] >= (avg_length[BUF10_INDEX]/2)));
673  strcat(channel_data_char,value_char);
674  }
675  if(conf->channels[I1L_INDEX] == CHANNEL_ENABLED) {
676  sprintf(value_char, ", %d", avg_valid[BUF10_INDEX][0]);
677  strcat(channel_data_char,value_char);
678  }
679  if(conf->channels[I2L_INDEX] == CHANNEL_ENABLED) {
680  sprintf(value_char, ", %d", avg_valid[BUF10_INDEX][1]);
681  strcat(channel_data_char,value_char);
682  }
683  }
684  }
685 
686  // channel data
687  if (conf->file_format == BIN) {
688  for(j=0; j<num_channels; j++) {
689  int32_t tmp = (int32_t) avg_data[BUF10_INDEX][j];
690  fwrite(&tmp, sizeof(int32_t), 1, data);
691  }
692  } else if (conf->file_format == CSV) {
693  for(j=0; j < num_channels; j++) {
694  sprintf(value_char,",%d",(int32_t) avg_data[BUF10_INDEX][j]);
695  strcat(channel_data_char, value_char);
696  }
697  strcat(channel_data_char,"\n");
698  fprintf(data, "%s", channel_data_char);
699  }
700  }
701 
702  // reset values
703  memset(avg_data[BUF10_INDEX], 0, sizeof(int64_t) * num_channels);
704  memset(bin_avg_data[BUF10_INDEX], 0, sizeof(uint32_t) * num_bin_channels);
705  avg_valid[BUF10_INDEX][0] = 1;
706  avg_valid[BUF10_INDEX][1] = 1;
707  }
708 
709 
710  // buffer 100
711  if((i+1)%avg_length[BUF100_INDEX] == 0) {
712 
713  // average
714  for(j=0; j<num_channels; j++) {
715  avg_data[BUF100_INDEX][j] /= (avg_length[BUF100_INDEX]/avg_length[BUF10_INDEX]);
716  }
717 
718  // merge_currents (for web)
719  if(conf->enable_web_server == 1) {
720  merge_currents(avg_valid[BUF100_INDEX], &web_data[BUF100_INDEX][i/avg_length[BUF100_INDEX]][num_bin_channels], avg_data[BUF100_INDEX], conf);
721  }
722 
723  // store bin channels for web
724  if(conf->enable_web_server == 1) {
725  for(j=0; j<num_bin_channels; j++) {
726 
727  if(bin_avg_data[BUF100_INDEX][j] >= (avg_length[BUF100_INDEX]/2)) {
728  web_data[BUF100_INDEX][i/avg_length[BUF100_INDEX]][j] = 1;
729  } else {
730  web_data[BUF100_INDEX][i/avg_length[BUF100_INDEX]][j] = 0;
731  }
732  }
733  }
734 
735  // write data to file
736  if(conf->sample_rate == 1) {
737  // binary data
738  if (bin_channel_pos > 0) {
739  if (conf->file_format == BIN) {
740  uint32_t temp_bin = 0;
741  for(j=0; j<num_bin_channels; j++) {
742  temp_bin = temp_bin | ((bin_avg_data[BUF100_INDEX][j] >= (avg_length[BUF100_INDEX]/2)) << j);
743  }
744  if(conf->channels[I1L_INDEX] == CHANNEL_ENABLED) {
745  temp_bin = temp_bin | (avg_valid[BUF100_INDEX][0] << j++);
746  }
747  if(conf->channels[I2L_INDEX] == CHANNEL_ENABLED) {
748  temp_bin = temp_bin | (avg_valid[BUF100_INDEX][1] << j++);
749  }
750 
751  fwrite(&temp_bin, sizeof(uint32_t), 1, data);
752 
753  } else if (conf->file_format == CSV) {
754  for(j=0; j<num_bin_channels; j++) {
755  sprintf(value_char, ", %d", (bin_avg_data[BUF100_INDEX][j] >= (avg_length[BUF100_INDEX]/2)));
756  strcat(channel_data_char,value_char);
757  }
758  if(conf->channels[I1L_INDEX] == CHANNEL_ENABLED) {
759  sprintf(value_char, ", %d", avg_valid[BUF100_INDEX][0]);
760  strcat(channel_data_char,value_char);
761  }
762  if(conf->channels[I2L_INDEX] == CHANNEL_ENABLED) {
763  sprintf(value_char, ", %d", avg_valid[BUF100_INDEX][1]);
764  strcat(channel_data_char,value_char);
765  }
766  }
767  }
768 
769  // channel data
770  if (conf->file_format == BIN) {
771  for(j=0; j<num_channels; j++) {
772  int32_t tmp = (int32_t) avg_data[BUF100_INDEX][j];
773  fwrite(&tmp, sizeof(int32_t), 1, data);
774  }
775  } else if (conf->file_format == CSV) {
776  for(j=0; j < num_channels; j++) {
777  sprintf(value_char,",%d",(int32_t) avg_data[BUF100_INDEX][j]);
778  strcat(channel_data_char, value_char);
779  }
780  strcat(channel_data_char,"\n");
781  fprintf(data, "%s", channel_data_char);
782  }
783  }
784  }
785  }
786 
787  // WRITE FILE IF HIGH RATE //
788 
789  // write binary channels
790  if(conf->sample_rate >= MIN_ADC_RATE) {
791  if (bin_channel_pos > 0) {
792  if (conf->file_format == BIN) {
793  fwrite(&bin_data, sizeof(uint32_t), 1, data);
794 
795  } else if (conf->file_format == CSV) {
796  int32_t MASK = 1;
797  for(j=0; j<bin_channel_pos; j++) {
798  sprintf(value_char, ", %d", (bin_data & MASK) > 1);
799  strcat(channel_data_char,value_char);
800  MASK = MASK << 1;
801  }
802  }
803  }
804 
805  // store values to file
806  if (conf->file_format == BIN) {
807  fwrite(channel_data, sizeof(int32_t), num_channels, data);
808 
809  } else if (conf->file_format == CSV) {
810  for(j=0; j < num_channels; j++) {
811  sprintf(value_char,",%d",channel_data[j]);
812  strcat(channel_data_char, value_char);
813  }
814  strcat(channel_data_char,"\n");
815  fprintf(data, "%s", channel_data_char);
816  }
817  }
818 
819  }
820 
821 
822  // WRITE WEB DATA //
823  if (conf->enable_web_server == 1) {
824 
825  // get shared memory access
826  if(wait_sem(sem_id, DATA_SEM, SEM_WRITE_TIME_OUT) == TIME_OUT) {
827  // disable webserver and continue running
828  conf->enable_web_server = 0;
830  rl_log(WARNING, "semaphore failure. Webserver disabled");
831  } else {
832 
833  // write time
834  web_data_ptr->time = time_real.sec*1000 + time_real.nsec/1000000;
835 
836  // write data to ring buffer
837  buffer_add(&web_data_ptr->buffer[BUF1_INDEX], &web_data[BUF1_INDEX][0][0]);
838  buffer_add(&web_data_ptr->buffer[BUF10_INDEX], &web_data[BUF10_INDEX][0][0]);
839  buffer_add(&web_data_ptr->buffer[BUF100_INDEX], &web_data[BUF100_INDEX][0][0]);
840 
841  // release shared memory
842  set_sem(sem_id, DATA_SEM, 1);
843 
844  }
845  }
846 }
#define TIME_OUT
Definition: types.h:52
struct ringbuffer buffer[WEB_RING_BUFFER_COUNT]
Array of ring buffers for different time scales.
Definition: web.h:70
int offsets[NUM_CHANNELS]
Channel offsets (in bit)
Definition: types.h:254
int is_low_current(int index)
Definition: util.c:26
#define NUM_DIGITAL_INPUTS
Number of RocketLogger digital channels.
Definition: types.h:84
double scales[NUM_CHANNELS]
Channel scalings.
Definition: types.h:256
void store_header_csv(FILE *data, struct rl_file_header *file_header)
#define V1_INDEX
Definition: types.h:186
uint16_t data_size
Datum size in bytes (for voltage and current)
Definition: rl_file.h:136
#define V4_INDEX
Definition: types.h:191
#define BUF10_INDEX
Index of 10s/div buffer.
Definition: web.h:17
uint16_t header_length
Total size of the header in bytes.
Definition: rl_file.h:92
struct time_stamp start_time
Start time of the measurement in UNIX time, UTC.
Definition: rl_file.h:110
struct rl_file_lead_in lead_in
File header lead in (constant size)
Definition: rl_file.h:151
CSV format.
Definition: types.h:151
#define MAC_ADDRESS_FILE
File to read MAC address.
Definition: types.h:61
struct rl_status status
Current status of RocketLogger.
Definition: rl_server.c:42
void update_header_bin(FILE *data, struct rl_file_header *file_header)
#define V2_INDEX
Definition: types.h:187
void buffer_add(struct ringbuffer *buffer, int64_t *data)
Definition: web.c:67
int64_t sec
Seconds in UNIX time (UTC)
Definition: rl_file.h:73
#define BINARY_MASK
Mask for binary inputs read from PRU.
Definition: file_handling.h:24
int i1l_valid_channel
Global variable to determine i1l valid channel.
Definition: file_handling.c:15
int i2l_valid_channel
Global variable to determine i2l valid channel.
Definition: file_handling.c:17
#define BUFFER1_SIZE
Size of 1s/div buffer.
Definition: web.h:31
#define CSV_VALUE_LENGTH
Max length of a CSV value.
Definition: file_handling.h:32
void rl_log(rl_log_type type, const char *format,...)
Definition: log.c:12
#define BUFFER10_SIZE
Size of 10s/div buffer.
Definition: web.h:33
int set_sem(int sem_id, int sem_num, int val)
Definition: sem.c:85
uint32_t num_channels
Number of channels sampled.
Definition: web.h:68
int wait_sem(int sem_id, int sem_num, int time_out)
Definition: sem.c:52
struct rl_file_channel * channel
Channels definitions (binary and normal)
Definition: rl_file.h:157
int digital_inputs
En-/disable digital inputs.
Definition: types.h:216
uint64_t sample_count
Total sample count.
Definition: rl_file.h:101
uint16_t channel_bin_count
Binary channel count.
Definition: rl_file.h:116
#define RL_FILE_MAGIC
File header magic number (ascii RLD)
Definition: rl_file.h:37
int enable_web_server
En-/disable plots on web interface.
Definition: types.h:218
uint16_t file_version
File version number.
Definition: rl_file.h:89
#define VALID_MASK
Mask for valid bit read from PRU.
Definition: file_handling.h:22
int sem_id
ID of semaphore set.
Definition: rl_server.c:24
Binary format.
Definition: types.h:152
#define CSV_LINE_LENGTH
Max length of a CSV file line.
Definition: file_handling.h:30
#define RL_SCALE_NANO
Definition: rl_file.h:23
#define DATA_SEM
Number of data semaphore in set (manages access to shared memory data)
Definition: types.h:273
#define BUF100_INDEX
Index of 100s/div buffer.
Definition: web.h:19
rl_state state
State.
Definition: types.h:234
#define I2L_INDEX
Definition: types.h:189
#define RL_SCALE_TEN_PICO
Definition: rl_file.h:22
struct web_shm * web_data
Pointer to shared memory data.
Definition: rl_server.c:26
#define NUM_I_CHANNELS
Maximum number of RocketLogger current channels.
Definition: types.h:80
rl_unit unit
Channel unit.
Definition: rl_file.h:130
Definition: types.h:202
Range valid information.
Definition: rl_file.h:65
#define NUM_CHANNELS
Maximum number of RocketLogger channels.
Definition: types.h:78
#define CHANNEL_ENABLED
Channel sampling enabled.
Definition: types.h:178
char * comment
Comment field.
Definition: rl_file.h:154
Warning.
Definition: types.h:168
#define BUFFER100_SIZE
Size of 100s/div buffer.
Definition: web.h:35
#define I1H_INDEX
Definition: types.h:184
#define PRU_DIG_SIZE
Size of PRU digital information in bytes.
Definition: types.h:88
void merge_currents(uint8_t *valid, int64_t *dest, int64_t *src, struct rl_conf *conf)
Running.
Definition: types.h:118
#define NO_VALID_DATA
No additional range valid information available.
Definition: rl_file.h:46
int channels[NUM_CHANNELS]
Channels to sample.
Definition: types.h:212
const char * digital_input_names[NUM_DIGITAL_INPUTS]
Digital input names.
Definition: file_handling.c:10
uint16_t channel_count
Analog channel count.
Definition: rl_file.h:119
#define BUF1_INDEX
Index of 1s/div buffer.
Definition: web.h:15
int64_t time
Time stamp of most recent datum (in UNIX time, UTC)
Definition: web.h:66
#define MAC_ADDRESS_LENGTH
MAC address length in bytes.
Definition: rl_file.h:16
void store_header_bin(FILE *data, struct rl_file_header *file_header)
void setup_channels(struct rl_file_header *file_header, struct rl_conf *conf)
int is_current(int index)
Definition: util.c:13
uint32_t comment_length
Comment length.
Definition: rl_file.h:113
rl_file_format file_format
File format.
Definition: types.h:222
uint32_t magic
File magic constant.
Definition: rl_file.h:86
#define WEB_RING_BUFFER_COUNT
Number of ring buffers in shared memory.
Definition: web.h:13
int update_rate
Data update rate.
Definition: types.h:208
void create_time_stamp(struct time_stamp *time_real, struct time_stamp *time_monotonic)
Definition: file_handling.c:24
uint32_t data_block_size
Size of the data blocks in the file in rows.
Definition: rl_file.h:95
char name[RL_FILE_CHANNEL_NAME_LENGTH]
Channel name/description.
Definition: rl_file.h:142
uint16_t sample_rate
Sampling rate of the measurement.
Definition: rl_file.h:104
Definition: web.h:64
#define RL_FILE_COMMENT
Comment for file header.
Definition: rl_file.h:49
Error.
Definition: types.h:167
int64_t nsec
Nanoseconds.
Definition: rl_file.h:75
#define RL_FILE_VERSION
File format version of current implementation.
Definition: rl_file.h:40
void update_header_csv(FILE *data, struct rl_file_header *file_header)
Voltage.
Definition: rl_file.h:62
int sample_rate
Sampling rate.
Definition: types.h:206
int32_t channel_scale
Channel scale (in power of ten, for voltage and current)
Definition: rl_file.h:133
#define V3_INDEX
Definition: types.h:190
#define SEM_WRITE_TIME_OUT
Time out time in seconds, waiting on semaphore write.
Definition: types.h:268
#define I2H_INDEX
Definition: types.h:188
uint16_t valid_data_channel
Link to channel valid data (for low-range current channels)
Definition: rl_file.h:139
int count_channels(int channels[NUM_CHANNELS])
Definition: util.c:39
#define MIN_ADC_RATE
Minimal ADC sampling rate.
Definition: types.h:108
const char * valid_info_names[NUM_I_CHANNELS]
Valid channel names.
Definition: file_handling.c:12
Current.
Definition: rl_file.h:63
int8_t num_channels
Number of channels sampled.
Definition: rl_server.c:39
#define I1L_INDEX
Definition: types.h:185
uint32_t data_block_count
Number of data blocks stored in the file.
Definition: rl_file.h:98
#define RL_SCALE_MILLI
Definition: rl_file.h:26
#define RL_FILE_COMMENT_ALIGNMENT_BYTES
Comment alignment in bytes.
Definition: rl_file.h:52
void handle_data_buffer(FILE *data, void *buffer_addr, uint32_t sample_size, uint32_t samples_buffer, struct rl_conf *conf, int sem_id, struct web_shm *web_data_ptr)
Binary signal.
Definition: rl_file.h:64
void get_mac_addr(uint8_t mac_address[MAC_ADDRESS_LENGTH])
Definition: file_handling.c:50
#define RL_SCALE_TEN_NANO
Definition: rl_file.h:24
uint8_t mac_address[MAC_ADDRESS_LENGTH]
Instrument ID (mac address)
Definition: rl_file.h:107
void setup_lead_in(struct rl_file_lead_in *lead_in, struct rl_conf *conf)
Definition: file_handling.c:67
#define H_L_SCALE
Current high-low scale difference.
Definition: file_handling.h:27
#define DIGITAL_INPUTS_ENABLED
Digital input sampling ensabled.
Definition: types.h:197
#define RL_SCALE_MICRO
Definition: rl_file.h:25
const char * channel_names[NUM_CHANNELS]
Channel names.
Definition: file_handling.c:8
void setup_header(struct rl_file_header *file_header, struct rl_conf *conf)
struct rl_calibration calibration
Calibration data.
Definition: types.h:284
#define RL_SCALE_NONE
Definition: rl_file.h:27