RocketLogger  1.1
web.c
Go to the documentation of this file.
1 
31 #include <stdint.h>
32 
33 #include <sys/ipc.h>
34 #include <sys/shm.h>
35 
36 #include "pru.h"
37 #include "sem.h"
38 #include "types.h"
39 
40 #include "web.h"
41 
46 struct web_shm* web_create_shm(void) {
47 
48  int shm_id = shmget(SHMEM_DATA_KEY, sizeof(struct web_shm),
49  IPC_CREAT | SHMEM_PERMISSIONS);
50  if (shm_id == -1) {
51  rl_log(ERROR, "In create_web_shm: failed to get shared data memory id; "
52  "%d message: %s",
53  errno, strerror(errno));
54  return NULL;
55  }
56  struct web_shm* web_data = (struct web_shm*)shmat(shm_id, NULL, 0);
57 
58  if (web_data == (void*)-1) {
59  rl_log(ERROR, "In create_web_shm: failed to map shared data memory; %d "
60  "message: %s",
61  errno, strerror(errno));
62  return NULL;
63  }
64 
65  return web_data;
66 }
67 
72 struct web_shm* web_open_shm(void) {
73 
74  int shm_id =
75  shmget(SHMEM_DATA_KEY, sizeof(struct web_shm), SHMEM_PERMISSIONS);
76  if (shm_id == -1) {
77  rl_log(ERROR, "In create_web_shm: failed to get shared data memory id; "
78  "%d message: %s",
79  errno, strerror(errno));
80  return NULL;
81  }
82  struct web_shm* web_data = (struct web_shm*)shmat(shm_id, NULL, 0);
83 
84  if (web_data == (void*)-1) {
85  rl_log(ERROR, "In create_web_shm: failed to map shared data memory; %d "
86  "message: %s",
87  errno, strerror(errno));
88  return NULL;
89  }
90 
91  return web_data;
92 }
93 
100 void web_buffer_reset(struct ringbuffer* buffer, int element_size, int length) {
101  buffer->element_size = element_size;
102  buffer->length = length;
103  buffer->filled = 0;
104  buffer->head = 0;
105 }
106 
112 void web_buffer_add(struct ringbuffer* buffer, int64_t* data) {
113  memcpy((buffer->data) +
114  buffer->head * buffer->element_size / sizeof(int64_t),
115  data, buffer->element_size);
116  if (buffer->filled < buffer->length) {
117  buffer->filled++;
118  }
119  buffer->head = (buffer->head + 1) % buffer->length;
120 }
121 
128 int64_t* web_buffer_get(struct ringbuffer* buffer, int num) {
129  int pos = ((int)buffer->head + (int)buffer->length - 1 - num) %
130  (int)buffer->length;
131 
132  return buffer->data + pos * buffer->element_size / sizeof(int64_t);
133 }
134 
142 void web_merge_currents(uint8_t* valid, int64_t* dest, int64_t* src,
143  struct rl_conf* conf) {
144 
145  int ch_in = 0;
146  int ch_out = 0;
147 
148  if (conf->channels[I1H_INDEX] == CHANNEL_ENABLED &&
149  conf->channels[I1L_INDEX] == CHANNEL_ENABLED) {
150  if (valid[0] == 1) {
151  dest[ch_out++] = src[++ch_in];
152  } else {
153  dest[ch_out++] = src[ch_in++] * H_L_SCALE;
154  }
155  ch_in++;
156  } else if (conf->channels[I1H_INDEX] == CHANNEL_ENABLED) {
157  dest[ch_out++] = src[ch_in++] * H_L_SCALE;
158  } else if (conf->channels[I1L_INDEX] == CHANNEL_ENABLED) {
159  dest[ch_out++] = src[ch_in++];
160  }
161  if (conf->channels[V1_INDEX] == CHANNEL_ENABLED) {
162  dest[ch_out++] = src[ch_in++];
163  }
164  if (conf->channels[V2_INDEX] == CHANNEL_ENABLED) {
165  dest[ch_out++] = src[ch_in++];
166  }
167 
168  if (conf->channels[I2H_INDEX] == CHANNEL_ENABLED &&
169  conf->channels[I2L_INDEX] == CHANNEL_ENABLED) {
170  if (valid[1] == 1) {
171  dest[ch_out++] = src[++ch_in];
172  } else {
173  dest[ch_out++] = src[ch_in++] * H_L_SCALE;
174  }
175  ch_in++;
176  } else if (conf->channels[I2H_INDEX] == CHANNEL_ENABLED) {
177  dest[ch_out++] = src[ch_in++] * H_L_SCALE;
178  } else if (conf->channels[I2L_INDEX] == CHANNEL_ENABLED) {
179  dest[ch_out++] = src[ch_in++];
180  }
181 
182  if (conf->channels[V3_INDEX] == CHANNEL_ENABLED) {
183  dest[ch_out++] = src[ch_in++];
184  }
185  if (conf->channels[V4_INDEX] == CHANNEL_ENABLED) {
186  dest[ch_out++] = src[ch_in++];
187  }
188 }
189 
200 void web_handle_data(struct web_shm* web_data_ptr, int sem_id,
201  void* buffer_addr, uint32_t sample_data_size,
202  uint32_t samples_count,
203  struct time_stamp* timestamp_realtime,
204  struct rl_conf* conf) {
205 
206  // count channels
207  int num_bin_channels = 0;
208  if (conf->digital_inputs == DIGITAL_INPUTS_ENABLED) {
209  num_bin_channels = NUM_DIGITAL_INPUTS;
210  }
211 
212  int num_channels = count_channels(conf->channels);
213 
214  // AVERAGE DATA //
215 
216  // averaged data (for web and low rates)
217  uint32_t avg_length[WEB_RING_BUFFER_COUNT] = {
218  samples_count / BUFFER1_SIZE, samples_count / BUFFER10_SIZE,
219  samples_count / BUFFER100_SIZE};
220  int64_t avg_data[WEB_RING_BUFFER_COUNT][NUM_CHANNELS];
221  uint32_t bin_avg_data[WEB_RING_BUFFER_COUNT][NUM_DIGITAL_INPUTS];
222  uint8_t avg_valid[WEB_RING_BUFFER_COUNT]
223  [NUM_I_CHANNELS] = {{1, 1}, {1, 1}, {1, 1}};
224 
225  memset(avg_data, 0, sizeof(int64_t) * num_channels * WEB_RING_BUFFER_COUNT);
226  memset(bin_avg_data, 0,
227  sizeof(uint32_t) * num_bin_channels * WEB_RING_BUFFER_COUNT);
228 
229  // WEB DATA //
230 
231  // data for webserver
233  [web_data_ptr->num_channels];
234 
235  // HANDLE BUFFER //
236  for (uint32_t i = 0; i < samples_count; i++) {
237 
238  // channel data variables
239  uint32_t bin_data;
240 
241  // read binary channels
242  uint8_t bin_adc1 = (*((int8_t*)(buffer_addr)));
243  uint8_t bin_adc2 = (*((int8_t*)(buffer_addr + 1)));
244 
245  buffer_addr += PRU_DIG_SIZE;
246 
247  // read and scale values (if channel selected)
248  int ch = 0;
249  for (int j = 0; j < NUM_CHANNELS; j++) {
250  if (conf->channels[j] == CHANNEL_ENABLED) {
251  int32_t adc_value;
252  if (sample_data_size == 4) {
253  adc_value =
254  *((int32_t*)(buffer_addr + sample_data_size * j));
255  } else {
256  adc_value =
257  *((int16_t*)(buffer_addr + sample_data_size * j));
258  }
259 
260  int32_t channel_value =
261  (int32_t)((adc_value + calibration.offsets[j]) *
262  calibration.scales[j]);
263  avg_data[BUF1_INDEX][ch] += channel_value;
264 
265  ch++;
266  }
267  }
268  buffer_addr += NUM_CHANNELS * sample_data_size;
269 
270  // BINARY CHANNELS //
271 
272  // mask and combine digital inputs, if requestet
273  int bin_channel_pos;
274  if (conf->digital_inputs == DIGITAL_INPUTS_ENABLED) {
275  bin_data = ((bin_adc1 & BINARY_MASK) >> 1) |
276  ((bin_adc2 & BINARY_MASK) << 2);
277  bin_channel_pos = NUM_DIGITAL_INPUTS;
278  // average digital inputs
279  int32_t MASK = 1;
280  for (int j = 0; j < num_bin_channels; j++) {
281  if ((bin_data & MASK) > 0) {
282  bin_avg_data[BUF1_INDEX][j] += 1;
283  }
284  MASK = MASK << 1;
285  }
286  } else {
287  bin_channel_pos = 0;
288  }
289 
290  // mask and combine valid info
291  uint8_t valid1 = (~bin_adc1) & VALID_MASK;
292  uint8_t valid2 = (~bin_adc2) & VALID_MASK;
293 
294  if (conf->channels[I1L_INDEX] == CHANNEL_ENABLED) {
295  bin_data = bin_data | (valid1 << bin_channel_pos);
296  bin_channel_pos++;
297  }
298  if (conf->channels[I2L_INDEX] == CHANNEL_ENABLED) {
299  bin_data = bin_data | (valid2 << bin_channel_pos);
300  bin_channel_pos++;
301  }
302 
303  // average valid info
304  for (int j = 0; j <= BUF100_INDEX; j++) {
305  avg_valid[j][0] = avg_valid[j][0] & valid1;
306  avg_valid[j][1] = avg_valid[j][1] & valid2;
307  }
308 
309  // HANDLE AVERAGE DATA //
310 
311  // buffer 1s/div
312  if ((i + 1) % avg_length[BUF1_INDEX] == 0) {
313 
314  // average channel data
315  for (int j = 0; j < num_channels; j++) {
316  avg_data[BUF1_INDEX][j] /= avg_length[BUF1_INDEX];
317  avg_data[BUF10_INDEX][j] += avg_data[BUF1_INDEX][j];
318  }
319 
320  // merge_currents (for web)
321  web_merge_currents(avg_valid[BUF1_INDEX],
322  &web_data[BUF1_INDEX][i / avg_length[BUF1_INDEX]]
323  [num_bin_channels],
324  avg_data[BUF1_INDEX], conf);
325 
326  // average bin channels
327  for (int j = 0; j < num_bin_channels; j++) {
328 
329  bin_avg_data[BUF10_INDEX][j] += bin_avg_data[BUF1_INDEX][j];
330 
331  // store bin channels for web
332  if (bin_avg_data[BUF1_INDEX][j] >=
333  (avg_length[BUF1_INDEX] / 2)) {
334  web_data[BUF1_INDEX][i / avg_length[BUF1_INDEX]][j] = 1;
335  } else {
336  web_data[BUF1_INDEX][i / avg_length[BUF1_INDEX]][j] = 0;
337  }
338  }
339 
340  // reset values
341  memset(avg_data[BUF1_INDEX], 0, sizeof(int64_t) * num_channels);
342  memset(bin_avg_data[BUF1_INDEX], 0,
343  sizeof(uint32_t) * num_bin_channels);
344  avg_valid[BUF1_INDEX][0] = 1;
345  avg_valid[BUF1_INDEX][1] = 1;
346  }
347 
348  // buffer 10
349  if ((i + 1) % avg_length[BUF10_INDEX] == 0) {
350 
351  // average
352  for (int j = 0; j < num_channels; j++) {
353  avg_data[BUF10_INDEX][j] /=
354  (avg_length[BUF10_INDEX] / avg_length[BUF1_INDEX]);
355  avg_data[BUF100_INDEX][j] += avg_data[BUF10_INDEX][j];
356  }
357 
358  // merge_currents (for web)
359  web_merge_currents(avg_valid[BUF10_INDEX],
360  &web_data[BUF10_INDEX]
361  [i / avg_length[BUF10_INDEX]]
362  [num_bin_channels],
363  avg_data[BUF10_INDEX], conf);
364 
365  // average bin channels
366  for (int j = 0; j < num_bin_channels; j++) {
367 
368  bin_avg_data[BUF100_INDEX][j] += bin_avg_data[BUF10_INDEX][j];
369 
370  // store bin channels for web
371  if (bin_avg_data[BUF10_INDEX][j] >=
372  (avg_length[BUF10_INDEX] / 2)) {
373  web_data[BUF10_INDEX][i / avg_length[BUF10_INDEX]][j] = 1;
374  } else {
375  web_data[BUF10_INDEX][i / avg_length[BUF10_INDEX]][j] = 0;
376  }
377  }
378 
379  // reset values
380  memset(avg_data[BUF10_INDEX], 0, sizeof(int64_t) * num_channels);
381  memset(bin_avg_data[BUF10_INDEX], 0,
382  sizeof(uint32_t) * num_bin_channels);
383  avg_valid[BUF10_INDEX][0] = 1;
384  avg_valid[BUF10_INDEX][1] = 1;
385  }
386 
387  // buffer 100
388  if ((i + 1) % avg_length[BUF100_INDEX] == 0) {
389 
390  // average
391  for (int j = 0; j < num_channels; j++) {
392  avg_data[BUF100_INDEX][j] /=
393  (avg_length[BUF100_INDEX] / avg_length[BUF10_INDEX]);
394  }
395 
396  // merge_currents (for web)
397  web_merge_currents(avg_valid[BUF100_INDEX],
398  &web_data[BUF100_INDEX]
399  [i / avg_length[BUF100_INDEX]]
400  [num_bin_channels],
401  avg_data[BUF100_INDEX], conf);
402 
403  // store bin channels for web
404  for (int j = 0; j < num_bin_channels; j++) {
405 
406  if (bin_avg_data[BUF100_INDEX][j] >=
407  (avg_length[BUF100_INDEX] / 2)) {
408  web_data[BUF100_INDEX][i / avg_length[BUF100_INDEX]][j] = 1;
409  } else {
410  web_data[BUF100_INDEX][i / avg_length[BUF100_INDEX]][j] = 0;
411  }
412  }
413  }
414  }
415 
416  // WRITE WEB DATA //
417 
418  // get shared memory access
419  if (wait_sem(sem_id, DATA_SEM, SEM_WRITE_TIME_OUT) == TIME_OUT) {
420  // disable webserver and continue running
421  conf->enable_web_server = 0;
423  rl_log(WARNING, "semaphore failure. Webserver disabled");
424  } else {
425 
426  // write time
427  web_data_ptr->time =
428  timestamp_realtime->sec * 1000 + timestamp_realtime->nsec / 1000000;
429 
430  // write data to ring buffer
431  web_buffer_add(&web_data_ptr->buffer[BUF1_INDEX],
432  &web_data[BUF1_INDEX][0][0]);
433  web_buffer_add(&web_data_ptr->buffer[BUF10_INDEX],
434  &web_data[BUF10_INDEX][0][0]);
435  web_buffer_add(&web_data_ptr->buffer[BUF100_INDEX],
436  &web_data[BUF100_INDEX][0][0]);
437 
438  // release shared memory
439  set_sem(sem_id, DATA_SEM, 1);
440  }
441 }
#define TIME_OUT
Definition: types.h:76
struct ringbuffer buffer[WEB_RING_BUFFER_COUNT]
Array of ring buffers for different time scales.
Definition: web.h:100
int offsets[NUM_CHANNELS]
Channel offsets (in bit)
Definition: types.h:304
#define SHMEM_DATA_KEY
Key for web shared memory (used for creation)
Definition: types.h:95
#define NUM_DIGITAL_INPUTS
Number of RocketLogger digital channels.
Definition: types.h:109
struct web_shm * web_create_shm(void)
Definition: web.c:46
double scales[NUM_CHANNELS]
Channel scalings.
Definition: types.h:306
#define BINARY_MASK
Mask for binary inputs read from PRU.
Definition: pru.h:149
#define V1_INDEX
Definition: types.h:230
#define V4_INDEX
Definition: types.h:235
#define BUF10_INDEX
Index of 10s/div buffer.
Definition: web.h:45
struct rl_status status
Current status of RocketLogger.
Definition: rl_server.c:70
#define V2_INDEX
Definition: types.h:231
int64_t sec
Seconds in UNIX time (UTC)
Definition: util.h:46
struct web_shm * web_open_shm(void)
Definition: web.c:72
#define BUFFER1_SIZE
Size of 1s/div buffer.
Definition: web.h:59
void rl_log(rl_log_type type, const char *format,...)
Definition: log.c:38
void web_buffer_add(struct ringbuffer *buffer, int64_t *data)
Definition: web.c:112
#define BUFFER10_SIZE
Size of 10s/div buffer.
Definition: web.h:61
int set_sem(int sem_id, int sem_num, int val)
Definition: sem.c:123
uint32_t num_channels
Number of channels sampled.
Definition: web.h:98
int wait_sem(int sem_id, int sem_num, int time_out)
Definition: sem.c:87
int digital_inputs
En-/disable digital inputs.
Definition: types.h:264
int64_t data[NUM_WEB_CHANNELS *NUM_WEB_POINTS]
Data array.
Definition: web.h:88
int enable_web_server
En-/disable plots on web interface.
Definition: types.h:266
int sem_id
ID of semaphore set.
Definition: rl_server.c:52
#define DATA_SEM
Number of data semaphore in set (manages access to shared memory data)
Definition: types.h:322
#define BUF100_INDEX
Index of 100s/div buffer.
Definition: web.h:47
rl_state state
State.
Definition: types.h:284
#define I2L_INDEX
Definition: types.h:233
#define VALID_MASK
Mask for valid bit read from PRU.
Definition: pru.h:147
struct web_shm * web_data
Pointer to shared memory data.
Definition: rl_server.c:54
void web_buffer_reset(struct ringbuffer *buffer, int element_size, int length)
Definition: web.c:100
#define NUM_I_CHANNELS
Maximum number of RocketLogger current channels.
Definition: types.h:105
Definition: types.h:246
uint32_t filled
Number of elements in buffer.
Definition: web.h:84
#define NUM_CHANNELS
Maximum number of RocketLogger channels.
Definition: types.h:103
#define CHANNEL_ENABLED
Channel sampling enabled.
Definition: types.h:222
#define SHMEM_PERMISSIONS
Permissions for shared memory.
Definition: types.h:97
Warning.
Definition: types.h:200
#define BUFFER100_SIZE
Size of 100s/div buffer.
Definition: web.h:63
#define I1H_INDEX
Definition: types.h:228
#define PRU_DIG_SIZE
Size of PRU digital information in bytes.
Definition: types.h:113
void web_handle_data(struct web_shm *web_data_ptr, int sem_id, void *buffer_addr, uint32_t sample_data_size, uint32_t samples_count, struct time_stamp *timestamp_realtime, struct rl_conf *conf)
Definition: web.c:200
Running.
Definition: types.h:141
int channels[NUM_CHANNELS]
Channels to sample.
Definition: types.h:260
#define BUF1_INDEX
Index of 1s/div buffer.
Definition: web.h:43
int64_t time
Time stamp of most recent datum (in UNIX time, UTC)
Definition: web.h:96
uint32_t head
Current position (in elements)
Definition: web.h:86
#define WEB_RING_BUFFER_COUNT
Number of ring buffers in shared memory.
Definition: web.h:41
Definition: web.h:94
Error.
Definition: types.h:199
int64_t nsec
Nanoseconds.
Definition: util.h:48
#define H_L_SCALE
Current high-low scale difference.
Definition: web.h:73
uint32_t element_size
Size of buffer element.
Definition: web.h:80
#define V3_INDEX
Definition: types.h:234
#define SEM_WRITE_TIME_OUT
Time out time in seconds, waiting on semaphore write.
Definition: types.h:317
uint32_t length
Size of buffer in elements.
Definition: web.h:82
#define I2H_INDEX
Definition: types.h:232
Definition: web.h:78
int count_channels(int channels[NUM_CHANNELS])
Definition: util.c:79
void web_merge_currents(uint8_t *valid, int64_t *dest, int64_t *src, struct rl_conf *conf)
Definition: web.c:142
int64_t * web_buffer_get(struct ringbuffer *buffer, int num)
Definition: web.c:128
int8_t num_channels
Number of channels sampled.
Definition: rl_server.c:67
#define I1L_INDEX
Definition: types.h:229
#define DIGITAL_INPUTS_ENABLED
Digital input sampling ensabled.
Definition: types.h:241
struct rl_calibration calibration
Calibration data.
Definition: types.h:334