Skip to content

Instantly share code, notes, and snippets.

@lbfalvy
Last active August 11, 2023 18:47
Show Gist options
  • Save lbfalvy/64f635db3194432630d219d92e2e4e45 to your computer and use it in GitHub Desktop.
Save lbfalvy/64f635db3194432630d219d92e2e4e45 to your computer and use it in GitHub Desktop.
Solution for the coursework in COM3023 "Internet of Things" at the University of Surrey. I have no idea if the transfer function is correct
#include "contiki.h"
#include "dev/light-sensor.h"
#include <stdio.h>
// buffer size
// this has to be comptime constant
#define BUFSIZE 12
// threshold for aggregating the whole buffer into one value
static double FULL_AGG_THRESH = 100.0;
// threshold for aggregating every 4 samples
static double AGG_4_THRESH = 600.0;
// The meaning of the above values was not specified in the coursework brief
// with respect to the variable buffer size, so I guessed. I had to guess
// a lot actually during these 3 years because no coursework brief in the
// entire course demonstrated the meaning of any task with more than one
// value of the other variable config options mandated by the same brief.
// Shallow imitation of the cross-language ubiquitous hard-crashing assert
void assert(int b, char* message) {
if (!b) {
printf("Assertion failed: %s\n", message);
exit(-1);
}
}
/* ================ Helpers ================ */
// these are in math.h but I couldn't find how to edit CFLAGS
double fmin(double a, double b) { if(a < b){ return a; }else{ return b; }};
double fmax(double a, double b) { if(a < b){ return b; }else{ return a; }};
double sqrt(double x) {
if (x == 1) return 1;
if (x < 0) x = -x;
double lb = fmin(1.0, x);
double ub = fmax(1.0, x);
double eps = 0.001;
double guess, error;
do {
guess = (lb + ub) / 2;
double guess2 = guess * guess;
if (guess2 < x) {
lb = guess;
error = x / guess2;
} else { // x <= guess2
ub = guess;
error = guess2 / x;
}
} while (eps < error - 1);
return guess;
}
// Find the number of decimal digits in a nonnegative integer
int oom(int x) {
assert(0 <= x, "oom only supports natural numbers");
if (x == 0) return 1;
int ret = 0;
while (0 < x) {
x = x / 10;
ret++;
}
return ret;
}
// Find the n-th digit of a double.
// 0 is the 1s digit, positive indices move left of the decimal point
char nth_digit(double f, int digit) {
while (digit != 0) { // could also use pow
if (digit < 0) { f *= 10; digit++; }
else { f /= 10; digit--; }
}
assert(0 <= f, "nth_digit only supports positive numbers");
return '0' + ((long)f % 10l);
}
// convert a floating point number to string.
// Return the leftover buffer
char* f2str(char* buffer, char* end, double f, int decimals) {
char* cur = buffer;
if (f == 0) {
*(cur++) = '0';
if (cur < end) *cur = 0;
return cur;
}
if (f < 0) {
*(cur++) = '-';
f = -f;
}
int i = oom(f) - 1;
while (0 <= i && cur < end) *(cur++) = nth_digit(f, i--);
assert(i == -1, "Overflowed buffer while writing double to string");
if (decimals == 0 || ((double)(int)f == f)) {
*cur = 0;
return cur;
}
if (cur < end && 0 < decimals) *(cur++) = '.';
while (-i < decimals && cur < end) *(cur++) = nth_digit(f, i--);
if (cur < end) *cur = 0; // cut buffer short if needed
while (*--cur == '0') *cur = 0; // erase trailing zeros
if (*--cur == '.') *cur = 0; // erase the dot if all decimals were zeros
return cur+1; // return cursor immediately after last failed test above
}
// Obtain light sensor data in lumen
double light_lx(void) {
double val2voltage = 1.5 / 4096.0; // mote characteristics
double voltage2current = 1.0/100000.0; // resistance
double current2lx = 0.625*1e6*1000.0; // see the datasheet
double transfer = val2voltage * voltage2current * current2lx;
double sensor_value = light_sensor.value(LIGHT_SENSOR_PHOTOSYNTHETIC);
return sensor_value * transfer;
}
// Algebraic mean
double fmean(int c, double* v) {
double sum = 0; int i = 0;
while (i < c) sum += v[i++];
return sum / (double)c;
}
// Standard deviation
double fstddev(int c, double* v) {
double mean = fmean(c, v);
double sqsum = 0; int i = 0;
while (i < c) sqsum += pow(v[i++] - mean, 2);
return sqrt(sqsum / (double)c);
}
static char fstrbuf[32];
// Deal with a full buffer
void process_data(double buffer[]) {
int i, agg = 1;
double dev = fstddev(BUFSIZE, buffer);
if (dev < FULL_AGG_THRESH) agg = BUFSIZE;
else if (dev < AGG_4_THRESH) agg = 4;
int reportc = BUFSIZE/agg;
double reportv[reportc];
for (i = 0; i < reportc; i++) reportv[i] = fmean(agg, buffer+(i*agg));
printf("B = [");
for (i = 0; i < BUFSIZE - 1; i++) printf("%d, ", (int)buffer[i]);
printf("%d]\n", (int)buffer[BUFSIZE - 1]);
f2str(fstrbuf, fstrbuf+31, dev, 2);
printf("StdDev = %s\n", fstrbuf);
printf("Aggregation = %d-into-1\n", agg);
printf("X = [");
for (i = 0; i < reportc; i++) {
f2str(fstrbuf, fstrbuf+31, reportv[i], 2);
printf("%s", fstrbuf);
if (i + 1 < reportc) printf(",");
}
printf("]\n");
}
int i = 0;
double buffer[BUFSIZE];
/*---------------------------------------------------------------------------*/
PROCESS(hello_world_process, "Hello world process");
AUTOSTART_PROCESSES(&hello_world_process);
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(hello_world_process, ev, data)
{
static struct etimer timer;
PROCESS_BEGIN();
etimer_set(&timer, CLOCK_CONF_SECOND/2);
SENSORS_ACTIVATE(light_sensor);
while(1) {
// this apparently declares a jump target,
// otherwise the buffer could be local state
PROCESS_WAIT_EVENT_UNTIL(ev=PROCESS_EVENT_TIMER);
buffer[i++] = light_lx();
if (BUFSIZE <= i) {
i = 0;
process_data(buffer);
}
etimer_reset(&timer);
}
PROCESS_END();
}
/*---------------------------------------------------------------------------*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment