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