diff options
Diffstat (limited to 'util')
| -rw-r--r-- | util/README.md | 72 | ||||
| -rw-r--r-- | util/util.c | 366 | ||||
| -rw-r--r-- | util/util.h | 77 | 
3 files changed, 515 insertions, 0 deletions
| diff --git a/util/README.md b/util/README.md new file mode 100644 index 0000000..bda72c8 --- /dev/null +++ b/util/README.md @@ -0,0 +1,72 @@ +# brnkl-util + +Small collection of helper functions required by some of our open source code + +## File I/O + +Functions to handle boilerplate when reading and writing from files. + +```c +le_result_t ioutil_readIntFromFile(const char* path, int* value); +le_result_t ioutil_readDoubleFromFile(const char* filePath, double* value); +le_result_t ioutil_writeToFile(const char* path, +                               void* value, +                               size_t size, +                               size_t count); + +le_result_t ioutil_appendToFile(const char* path, +                                void* value, +                                size_t size, +                                size_t count); + +``` + +## General + +Collection of unsorted helper functions + +```c +uint64_t GetCurrentTimestamp(void); +time_t util_getMTime(char* path); +int util_getUnixDatetime(); +le_result_t util_flattenRes(le_result_t* res, int nRes); +bool util_fileExists(const char* path); +bool util_alreadyMounted(const char* devPath); +void* util_find(Functional* f); +void util_listDir(const char* dir, char* dest, size_t size); +``` + +## GPIO (Linux SysFS) + +Provides API calls for all functionality supported by the Linux SysFS GPIO interface + +```c +le_result_t gpio_exportPin(char* pin); +le_result_t gpio_unexportPin(char* pin); +void getGpioPath(char* outputStr, char* pin, char* subDir); +le_result_t gpio_setDirection(char* pin, char* direction); +le_result_t gpio_setInput(char* pin); +le_result_t gpio_setOutput(char* pin); +le_result_t gpio_setActiveState(char* pin, bool isActiveLow); +le_result_t gpio_isActive(char* pin, bool* isActive); +le_result_t gpio_setValue(char* pin, bool state); +le_result_t gpio_setLow(char* pin); +le_result_t gpio_setHigh(char* pin); +le_result_t gpio_setPull(char* pin, char* pull); +le_result_t gpio_pullDown(char* pin); +le_result_t gpio_pullUp(char* pin); +``` + +## Serial + +Handler boilerplate for reading and writing to a serial port + +```c +int fd_openSerial(const char* device, int baud); +speed_t fd_convertBaud(int baud); +int fd_puts(const int fd, const char* s); +int fd_getChar(const int fd); +void fd_flush(const int fd); +int fd_dataAvail(int fd, int* data); +void fd_flushInput(const int fd); +``` diff --git a/util/util.c b/util/util.c new file mode 100644 index 0000000..3042c22 --- /dev/null +++ b/util/util.c @@ -0,0 +1,366 @@ +#include "util.h" +#include "legato.h" +#include <termios.h> + +le_result_t readFromFile(const char* path, +                         void* value, +                         int (*scanCallback)(FILE* f, void* val)) { +  FILE* f = fopen(path, "r"); +  if (f == NULL) { +    LE_WARN("Couldn't open '%s' - %m", path); +    return LE_IO_ERROR; +  } +  int numScanned = scanCallback(f, value); +  if (numScanned != 1) +    return LE_FORMAT_ERROR; +  fclose(f); +  return LE_OK; +} + +int scanIntCallback(FILE* f, void* value) { +  int* val = value; +  return fscanf(f, "%d", val); +} + +int scanDoubleCallback(FILE* f, void* value) { +  double* val = value; +  return fscanf(f, "%lf", val); +} + +le_result_t ioutil_readIntFromFile(const char* path, int* value) { +  return readFromFile(path, value, scanIntCallback); +} + +le_result_t ioutil_readDoubleFromFile(const char* path, double* value) { +  return readFromFile(path, value, scanDoubleCallback); +} + +le_result_t writeToFile(const char* path, +                        void* value, +                        size_t size, +                        size_t count, +                        const char* openMode) { +  FILE* f = fopen(path, openMode); +  if (f == NULL) { +    LE_WARN("Failed to open %s for writing", path); +    return LE_IO_ERROR; +  } +  fwrite(value, size, count, f); +  fflush(f); +  fclose(f); +  return LE_OK; +} + +le_result_t ioutil_writeToFile(const char* path, +                               void* value, +                               size_t size, +                               size_t count) { +  return writeToFile(path, value, size, count, "w"); +} + +le_result_t ioutil_appendToFile(const char* path, +                                void* value, +                                size_t size, +                                size_t count) { +  return writeToFile(path, value, size, count, "a"); +} + +le_result_t util_flattenRes(le_result_t* res, int nRes) { +  for (int i = 0; i < nRes; i++) { +    if (res[i] != LE_OK) +      return res[i]; +  } +  return LE_OK; +} + +int util_getUnixDatetime() { +  struct timeval tv; +  gettimeofday(&tv, NULL); +  return tv.tv_sec; +} + +/** + * Get the last modified datetime + * of the file at path + */ +time_t util_getMTime(char* path) { +  struct stat st; +  if (stat(path, &st) != 0) +    return -1; +  else +    return st.st_mtime; +} + +bool util_fileExists(const char* path) { +  struct stat st; +  return stat(path, &st) == 0; +} + +bool util_alreadyMounted(const char* devPath) { +  char content[2048]; +  FILE* f = fopen("/proc/mounts", "r"); +  if (f == NULL) { +    return false; +  } +  fread(content, sizeof(char), sizeof(content), f); +  // if this ref is non-null, we found a match +  return strstr(content, devPath) != NULL; +} + +uint64_t GetCurrentTimestamp(void) { +  struct timeval tv; +  gettimeofday(&tv, NULL); +  uint64_t utcMilliSec = +      (uint64_t)(tv.tv_sec) * 1000 + (uint64_t)(tv.tv_usec) / 1000; +  return utcMilliSec; +} + +// TODO verify this is working +le_result_t gpio_exportPin(char* pin) { +  int len = strlen(pin); +  return ioutil_writeToFile("/sys/class/gpio/export", &pin, sizeof(char), len); +} + +le_result_t gpio_unexportPin(char* pin) { +  int len = strlen(pin); +  return ioutil_writeToFile("/sys/class/gpio/unexport", &pin, sizeof(char), +                            len); +} + +void getGpioPath(char* outputStr, char* pin, char* subDir) { +  sprintf(outputStr, "/sys/class/gpio/gpio%s/%s", pin, subDir); +} + +le_result_t gpio_setDirection(char* pin, char* direction) { +  char path[100]; +  getGpioPath(path, pin, "direction"); +  return ioutil_writeToFile(path, direction, sizeof(char), strlen(direction)); +} + +le_result_t gpio_setPull(char* pin, char* pull) { +  char path[100]; +  getGpioPath(path, pin, "pull"); +  return ioutil_writeToFile(path, pull, sizeof(char), strlen(pull)); +} + +le_result_t gpio_pullDown(char* pin) { +  return gpio_setPull(pin, "down"); +} + +le_result_t gpio_pullUp(char* pin) { +  return gpio_setPull(pin, "up"); +} + +le_result_t gpio_setInput(char* pin) { +  return gpio_setDirection(pin, "in"); +} + +le_result_t gpio_setOutput(char* pin) { +  return gpio_setDirection(pin, "out"); +} + +le_result_t gpio_setActiveState(char* pin, bool isActiveLow) { +  // Any non zero value toggles the existing value +  // so we must read the existing value first +  char path[100]; +  int isActiveLowSet; +  getGpioPath(path, pin, "active_low"); +  le_result_t readRes = ioutil_readIntFromFile(path, &isActiveLowSet); +  le_result_t writeRes = LE_OK; +  if (isActiveLow != isActiveLowSet) { +    writeRes = ioutil_writeToFile(path, "1", sizeof(char), 1); +  } +  return readRes == LE_OK && writeRes == LE_OK ? LE_OK : LE_FAULT; +} + +le_result_t gpio_isActive(char* pin, bool* isActive) { +  char path[50]; +  getGpioPath(path, pin, "value"); +  int val; +  le_result_t readRes = ioutil_readIntFromFile(path, &val); +  *isActive = val; +  return readRes; +} + +le_result_t gpio_setValue(char* pin, bool state) { +  char path[50]; +  getGpioPath(path, pin, "value"); +  char* strState = state ? "1" : "0"; +  return ioutil_writeToFile(path, &strState, sizeof(char), strlen(strState)); +} + +le_result_t gpio_setLow(char* pin) { +  return gpio_setValue(pin, LOW); +} + +le_result_t gpio_setHigh(char* pin) { +  return gpio_setValue(pin, HIGH); +} + +void* util_find(Functional* f) { +  f->args.i = 0; +  while (f->args.i < f->n) { +    if (f->callback(&f->args)) { +      return f->derefCallback(f->args.i, f->args.arr); +    } +    f->args.i++; +  } +  return NULL; +} + +void util_listDir(const char* dir, char* dest, size_t size) { +  struct dirent* de; +  char toConcat[1024]; +  DIR* dr = opendir(dir); +  if (dr == NULL) +    return; +  while ((de = readdir(dr)) != NULL) { +    if (de->d_name[0] != '.') { +      snprintf(toConcat, size, "%s,", de->d_name); +      strncat(dest, toConcat, size); +    } +  } +  closedir(dr); +} + +/** + * Convert an integer baud rate to a speed_t + */ +speed_t fd_convertBaud(int baud) { +  speed_t b; +  switch (baud) { +    case 50: +      b = B50; +      break; +    case 75: +      b = B75; +      break; +    case 110: +      b = B110; +      break; +    case 134: +      b = B134; +      break; +    case 150: +      b = B150; +      break; +    case 200: +      b = B200; +      break; +    case 300: +      b = B300; +      break; +    case 600: +      b = B600; +      break; +    case 1200: +      b = B1200; +      break; +    case 1800: +      b = B1800; +      break; +    case 2400: +      b = B2400; +      break; +    case 9600: +      b = B9600; +      break; +    case 19200: +      b = B19200; +      break; +    case 38400: +      b = B38400; +      break; +    case 57600: +      b = B57600; +      break; +    case 115200: +      b = B115200; +      break; +    case 230400: +      b = B230400; +      break; +    case 921600: +      b = B921600; +      break; +    default: +      b = -2; +  } +  return b; +} + +/** + * Open a serial connection on device + * + * Lifted from here + * https://github.com/WiringPi/WiringPi/blob/master/wiringPi/wiringSerial.c + */ +int fd_openSerial(const char* device, int baud) { +  struct termios options; +  speed_t binaryBaud = fd_convertBaud(baud); +  int status, fd; +  if ((fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK)) == -1) +    return -1; +  fcntl(fd, F_SETFL, O_RDWR); +  tcgetattr(fd, &options); +  cfmakeraw(&options); +  cfsetispeed(&options, binaryBaud); +  cfsetospeed(&options, binaryBaud); + +  options.c_cflag |= (CLOCAL | CREAD); +  options.c_cflag &= ~PARENB; +  options.c_cflag &= ~CSTOPB; +  options.c_cflag &= ~CSIZE; +  options.c_cflag |= CS8; +  options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); +  options.c_oflag &= ~OPOST; + +  options.c_cc[VMIN] = 0; +  options.c_cc[VTIME] = 10;  // Ten seconds (100 deciseconds) + +  tcsetattr(fd, TCSANOW | TCSAFLUSH, &options); + +  ioctl(fd, TIOCMGET, &status); + +  status |= TIOCM_DTR; +  status |= TIOCM_RTS; + +  ioctl(fd, TIOCMSET, &status); +  usleep(10000);  // 10mS +  return fd; +} + +int fd_puts(const int fd, const char* s) { +  return write(fd, s, strlen(s)); +} + +int fd_getChar(const int fd) { +  uint8_t x; + +  if (read(fd, &x, 1) != 1) +    return -1; + +  return ((int)x) & 0xFF; +} + +void fd_flush(const int fd) { +  // tcflush(fd, TCIOFLUSH); +  tcdrain(fd); +} + +void fd_flushInput(const int fd) { +  tcflush(fd, TCIFLUSH); +} + +int fd_dataAvail(int fd, int* data) { +  return ioctl(fd, FIONREAD, data); +} + +double util_avgDouble(double* readings, int nReadings) { +  double sum = 0; +  for (int i = 0; i < nReadings; i++) { +    sum += readings[i]; +  } + +  return sum / nReadings; +} diff --git a/util/util.h b/util/util.h new file mode 100644 index 0000000..06ef2fb --- /dev/null +++ b/util/util.h @@ -0,0 +1,77 @@ +#ifndef UTIL_H +#define UTIL_H + +#include "legato.h" +#include <termios.h> + +#define HIGH 1 +#define LOW 0 + +typedef struct { +  int i; +  void* arr; +  void* ctxp; +} FunctionalArgs; + +typedef struct { +  int n;                                   // number of elements in array +  bool (*callback)(FunctionalArgs* args);  // callback applied to arr[i] +  void* (*derefCallback)(int i, void* j);  // callback used to deference arr[i] +  FunctionalArgs args; +} Functional; + +// ioutil +le_result_t readFromFile(const char* path, +                         void* value, +                         int (*scanCallback)(FILE* f, void* val)); +int scanDoubleCallback(FILE* f, void* value); +le_result_t ioutil_readIntFromFile(const char* path, int* value); +le_result_t ioutil_readDoubleFromFile(const char* filePath, double* value); +le_result_t ioutil_writeToFile(const char* path, +                               void* value, +                               size_t size, +                               size_t count); + +le_result_t ioutil_appendToFile(const char* path, +                                void* value, +                                size_t size, +                                size_t count); + +// TODO fix this name (no PascalCase) +uint64_t GetCurrentTimestamp(void); +time_t util_getMTime(char* path); +int util_getUnixDatetime(); +le_result_t util_flattenRes(le_result_t* res, int nRes); +bool util_fileExists(const char* path); +bool util_alreadyMounted(const char* devPath); +double util_avgDouble(double* readings, int nReadings); + +// TODO verify this is working +le_result_t gpio_exportPin(char* pin); +le_result_t gpio_unexportPin(char* pin); +void getGpioPath(char* outputStr, char* pin, char* subDir); +le_result_t gpio_setDirection(char* pin, char* direction); +le_result_t gpio_setInput(char* pin); +le_result_t gpio_setOutput(char* pin); +le_result_t gpio_setActiveState(char* pin, bool isActiveLow); +le_result_t gpio_isActive(char* pin, bool* isActive); +le_result_t gpio_setValue(char* pin, bool state); +le_result_t gpio_setLow(char* pin); +le_result_t gpio_setHigh(char* pin); +le_result_t gpio_setPull(char* pin, char* pull); +le_result_t gpio_pullDown(char* pin); +le_result_t gpio_pullUp(char* pin); + +void* util_find(Functional* f); + +void util_listDir(const char* dir, char* dest, size_t size); + +int fd_openSerial(const char* device, int baud); +speed_t fd_convertBaud(int baud); +int fd_puts(const int fd, const char* s); +int fd_getChar(const int fd); +void fd_flush(const int fd); +int fd_dataAvail(int fd, int* data); +void fd_flushInput(const int fd); + +#endif | 
