RocketLogger  1.1.4
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];
222  uint32_t bin_avg_data[WEB_RING_BUFFER_COUNT][NUM_DIGITAL_INPUTS];
223  uint8_t avg_valid[WEB_RING_BUFFER_COUNT]
224  [NUM_I_CHANNELS] = {{1, 1}, {1, 1}, {1, 1}};
225 
226  memset(avg_data, 0, sizeof(int64_t) * num_channels * WEB_RING_BUFFER_COUNT);
227  memset(bin_avg_data, 0,
228  sizeof(uint32_t) * num_bin_channels * WEB_RING_BUFFER_COUNT);
229 
230  // WEB DATA //
231 
232  // data for webserver
234  [web_data_ptr->num_channels];
235 
236  // HANDLE BUFFER //
237  for (uint32_t i = 0; i < samples_count; i++) {
238 
239  // channel data variables
240  uint32_t bin_data;
241 
242  // read binary channels
243  uint8_t bin_adc1 = (*((int8_t*)(buffer_addr)));
244  uint8_t bin_adc2 = (*((int8_t*)(buffer_addr + 1)));
245 
246  buffer_addr += PRU_DIG_SIZE;
247 
248  // read and scale values (if channel selected)
249  int ch = 0;
250  for (int j = 0; j < NUM_CHANNELS; j++) {
251  if (conf->channels[j] == CHANNEL_ENABLED) {
252  int32_t adc_value;
253  if (sample_data_size == 4) {
254  adc_value =
255  *((int32_t*)(buffer_addr + sample_data_size * j));
256  } else {
257  adc_value =
258  *((int16_t*)(buffer_addr + sample_data_size * j));
259  }
260 
261  int32_t channel_value =
262  (int32_t)((adc_value + calibration.offsets[j]) *
263  calibration.scales[j]);
264  avg_data[BUF1_INDEX][ch] += channel_value;
265 
266  ch++;
267  }
268  }
269  buffer_addr += NUM_CHANNELS * sample_data_size;
270 
271  // BINARY CHANNELS //
272 
273  // mask and combine digital inputs, if requestet
274  int bin_channel_pos;
275  if (conf->digital_inputs == DIGITAL_INPUTS_ENABLED) {
276  bin_data = ((bin_adc1 & BINARY_MASK) >> 1) |
277  ((bin_adc2 & BINARY_MASK) << 2);
278  bin_channel_pos = NUM_DIGITAL_INPUTS;
279  // average digital inputs
280  int32_t MASK = 1;
281  for (int j = 0; j < num_bin_channels; j++) {
282  if ((bin_data & MASK) > 0) {
283  bin_avg_data[BUF1_INDEX][j] += 1;
284  }
285  MASK = MASK << 1;
286  }
287  } else {
288  bin_channel_pos = 0;
289  }
290 
291  // mask and combine valid info
292  uint8_t valid1 = (~bin_adc1) & VALID_MASK;
293  uint8_t valid2 = (~bin_adc2) & VALID_MASK;
294 
295  if (conf->channels[I1L_INDEX] == CHANNEL_ENABLED) {
296  bin_data = bin_data | (valid1 << bin_channel_pos);
297  bin_channel_pos++;
298  }
299  if (conf->channels[I2L_INDEX] == CHANNEL_ENABLED) {
300  bin_data = bin_data | (valid2 << bin_channel_pos);
301  bin_channel_pos++;
302  }
303 
304  // average valid info
305  for (int j = 0; j <= BUF100_INDEX; j++) {
306  avg_valid[j][0] = avg_valid[j][0] & valid1;
307  avg_valid[j][1] = avg_valid[j][1] & valid2;
308  }
309 
310  // HANDLE AVERAGE DATA //
311 
312  // buffer 1s/div
313  if ((i + 1) % avg_length[BUF1_INDEX] == 0) {
314 
315  // average channel data
316  for (int j = 0; j < num_channels; j++) {
317  avg_data[BUF1_INDEX][j] /= avg_length[BUF1_INDEX];
318  avg_data[BUF10_INDEX][j] += avg_data[BUF1_INDEX][j];
319  }
320 
321  // merge_currents (for web)
322  web_merge_currents(avg_valid[BUF1_INDEX],
323  &web_data[BUF1_INDEX][i / avg_length[BUF1_INDEX]]
324  [num_bin_channels],
325  avg_data[BUF1_INDEX], conf);
326 
327  // average bin channels
328  for (int j = 0; j < num_bin_channels; j++) {
329 
330  bin_avg_data[BUF10_INDEX][j] += bin_avg_data[BUF1_INDEX][j];
331 
332  // store bin channels for web
333  if (bin_avg_data[BUF1_INDEX][j] >=
334  (avg_length[BUF1_INDEX] / 2)) {
335  web_data[BUF1_INDEX][i / avg_length[BUF1_INDEX]][j] = 1;
336  } else {
337  web_data[BUF1_INDEX][i / avg_length[BUF1_INDEX]][j] = 0;
338  }
339  }
340 
341  // reset values
342  memset(avg_data[BUF1_INDEX], 0, sizeof(int64_t) * num_channels);
343  memset(bin_avg_data[BUF1_INDEX], 0,
344  sizeof(uint32_t) * num_bin_channels);
345  avg_valid[BUF1_INDEX][0] = 1;
346  avg_valid[BUF1_INDEX][1] = 1;
347  }
348 
349  // buffer 10
350  if ((i + 1) % avg_length[BUF10_INDEX] == 0) {
351 
352  // average
353  for (int j = 0; j < num_channels; j++) {
354  avg_data[BUF10_INDEX][j] /=
355  (avg_length[BUF10_INDEX] / avg_length[BUF1_INDEX]);
356  avg_data[BUF100_INDEX][j] += avg_data[BUF10_INDEX][j];
357  }
358 
359  // merge_currents (for web)
360  web_merge_currents(avg_valid[BUF10_INDEX],
361  &web_data[BUF10_INDEX]
362  [i / avg_length[BUF10_INDEX]]
363  [num_bin_channels],
364  avg_data[BUF10_INDEX], conf);
365 
366  // average bin channels
367  for (int j = 0; j < num_bin_channels; j++) {
368 
369  bin_avg_data[BUF100_INDEX][j] += bin_avg_data[BUF10_INDEX][j];
370 
371  // store bin channels for web
372  if (bin_avg_data[BUF10_INDEX][j] >=
373  (avg_length[BUF10_INDEX] / 2)) {
374  web_data[BUF10_INDEX][i / avg_length[BUF10_INDEX]][j] = 1;
375  } else {
376  web_data[BUF10_INDEX][i / avg_length[BUF10_INDEX]][j] = 0;
377  }
378  }
379 
380  // reset values
381  memset(avg_data[BUF10_INDEX], 0, sizeof(int64_t) * num_channels);
382  memset(bin_avg_data[BUF10_INDEX], 0,
383  sizeof(uint32_t) * num_bin_channels);
384  avg_valid[BUF10_INDEX][0] = 1;
385  avg_valid[BUF10_INDEX][1] = 1;
386  }
387 
388  // buffer 100
389  if ((i + 1) % avg_length[BUF100_INDEX] == 0) {
390 
391  // average
392  for (int j = 0; j < num_channels; j++) {
393  avg_data[BUF100_INDEX][j] /=
394  (avg_length[BUF100_INDEX] / avg_length[BUF10_INDEX]);
395  }
396 
397  // merge_currents (for web)
398  web_merge_currents(avg_valid[BUF100_INDEX],
399  &web_data[BUF100_INDEX]
400  [i / avg_length[BUF100_INDEX]]
401  [num_bin_channels],
402  avg_data[BUF100_INDEX], conf);
403 
404  // store bin channels for web
405  for (int j = 0; j < num_bin_channels; j++) {
406 
407  if (bin_avg_data[BUF100_INDEX][j] >=
408  (avg_length[BUF100_INDEX] / 2)) {
409  web_data[BUF100_INDEX][i / avg_length[BUF100_INDEX]][j] = 1;
410  } else {
411  web_data[BUF100_INDEX][i / avg_length[BUF100_INDEX]][j] = 0;
412  }
413  }
414  }
415  }
416 
417  // WRITE WEB DATA //
418 
419  // get shared memory access
420  if (wait_sem(sem_id, DATA_SEM, SEM_WRITE_TIME_OUT) == TIME_OUT) {
421  // disable webserver and continue running
422  conf->enable_web_server = 0;
424  rl_log(WARNING, "semaphore failure. Webserver disabled");
425  } else {
426 
427  // write time
428  web_data_ptr->time =
429  timestamp_realtime->sec * 1000 + timestamp_realtime->nsec / 1000000;
430 
431  // write data to ring buffer
432  web_buffer_add(&web_data_ptr->buffer[BUF1_INDEX],
433  &web_data[BUF1_INDEX][0][0]);
434  web_buffer_add(&web_data_ptr->buffer[BUF10_INDEX],
435  &web_data[BUF10_INDEX][0][0]);
436  web_buffer_add(&web_data_ptr->buffer[BUF100_INDEX],
437  &web_data[BUF100_INDEX][0][0]);
438 
439  // release shared memory
440  set_sem(sem_id, DATA_SEM, 1);
441  }
442 }
#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