{"action":"created","comment":{"url":"https://api.github.com/repos/ArduSat/ArdusatSDK/pulls/comments/65389607","id":65389607,"diff_hunk":"@@ -453,266 +257,1212 @@ const char * valuesToCSV(const char *sensorName, unsigned long timestamp, int nu\n   return _getOutBuf();\n }\n \n-// Define a version of a ToCSV function that uses the default name for that\n-// sensor type\n-#define _DEFAULT_SENSOR_NAME_TO_CSV_FXN(NAME) \\\n-  const char * NAME ## ToCSV( NAME ## _t &input) { \\\n-    char sensor[50]; \\\n-    strcpy_P(sensor, NAME ## _sensor_name); \\\n-    return NAME ## ToCSV ( sensor, input ); \\\n+/*\n+ * Internal helper to build the JSON string at the proper point in the output buffer\n+ * with the correct values and labels\n+ */\n+int _writeJSONValue(char *buf, const char *sensor_name, const char *unit, float value) {\n+  char num [32];\n+  char format_str[80];\n+  // inexact estimate on the number of characters the value will take up...\n+  if (strlen(sensor_name) + strlen(unit) + 10 + _output_buf_len > OUTPUT_BUF_SIZE) {\n+    return -1;\n   }\n+  dtostrf(value, 4, 2, num);\n+  strcpy_P(format_str, json_format);\n+  _output_buf_len += sprintf(buf, format_str,\n+\t\t\t     JSON_PREFIX, sensor_name, unit, num,\n+\t\t\t     calculateCheckSum(sensor_name, 1, value), JSON_SUFFIX);\n+  return _output_buf_len;\n+}\n \n-_DEFAULT_SENSOR_NAME_TO_CSV_FXN(acceleration)\n-const char * accelerationToCSV(const char *sensorName, acceleration_t & input) {\n-  _headerToCSV(&(input.header), sensorName);\n-\n-  dtostrf(input.x, 2, 3, _getOutBuf() + _output_buf_len);\n-  _output_buf_len = strlen(_getOutBuf());\n-  _getOutBuf()[_output_buf_len++] = CSV_SEPARATOR;\n+/*\n+ * Internal helper to build 3 JSON strings back to back since there are so many sensors\n+ * that report 3 values\n+ */\n+const char * _tripleValueToJSON(const char *sensorName, int labelLength, unsigned char unit,\n+             char *labelA, float valueA, char *labelB, float valueB, char *labelC, float valueC) {\n+  int nameLength = strlen(sensorName);\n+  char nameBuf[nameLength + labelLength];\n+  _resetOutBuf();\n \n-  dtostrf(input.y, 2, 3, _getOutBuf() + _output_buf_len);\n-  _output_buf_len = strlen(_getOutBuf());\n-  _getOutBuf()[_output_buf_len++] = CSV_SEPARATOR;\n+  sprintf(nameBuf, labelA, sensorName);\n+  _writeJSONValue(&_getOutBuf()[_output_buf_len], nameBuf, unit_to_str(unit), valueA);\n \n-  dtostrf(input.z, 2, 3, _getOutBuf() + _output_buf_len);\n-  _output_buf_len = strlen(_getOutBuf());\n+  sprintf(nameBuf, labelB, sensorName);\n+  _writeJSONValue(&_getOutBuf()[_output_buf_len], nameBuf, unit_to_str(unit), valueB);\n \n-  _add_checksum_to_csv_buffer(sensorName, 3, input.x, input.y, input.z);\n-  _getOutBuf()[_output_buf_len++] = '\\n';\n+  sprintf(nameBuf, labelC, sensorName);\n+  _writeJSONValue(&_getOutBuf()[_output_buf_len], nameBuf, unit_to_str(unit), valueC);\n   return _getOutBuf();\n }\n \n-_DEFAULT_SENSOR_NAME_TO_CSV_FXN(magnetic)\n-const char * magneticToCSV(const char *sensorName, magnetic_t & input) {\n-  _headerToCSV(&(input.header), sensorName);\n-\n-  dtostrf(input.x, 2, 3, _getOutBuf() + _output_buf_len);\n-  _output_buf_len = strlen(_getOutBuf());\n-  _getOutBuf()[_output_buf_len++] = CSV_SEPARATOR;\n-\n-  dtostrf(input.y, 2, 3, _getOutBuf() + _output_buf_len);\n-  _output_buf_len = strlen(_getOutBuf());\n-  _getOutBuf()[_output_buf_len++] = CSV_SEPARATOR;\n-\n-  dtostrf(input.z, 2, 3, _getOutBuf() + _output_buf_len);\n-  _output_buf_len = strlen(_getOutBuf());\n-\n-  _add_checksum_to_csv_buffer(sensorName, 3, input.x, input.y, input.z);\n-  _getOutBuf()[_output_buf_len++] = '\\n';\n-\n+/**\n+ * Creates a JSON string with the appropriate values\n+ *\n+ * @param sensor_name the label to be given to some data\n+ * @param unit the unit of measurement used\n+ * @param value the sensor value\n+ *\n+ * @return the output buffer\n+ */\n+const char * valueToJSON(const char *sensorName, unsigned char unit, float value) {\n+  _resetOutBuf();\n+  _writeJSONValue(_getOutBuf(), sensorName, unit_to_str(unit), value);\n   return _getOutBuf();\n }\n \n-_DEFAULT_SENSOR_NAME_TO_CSV_FXN(temperature)\n-const char * temperatureToCSV(const char *sensorName, temperature_t & input) {\n-  _headerToCSV(&(input.header), sensorName);// warning : resets the internal buffer\n-\n-  dtostrf(input.t, 2, 3, _getOutBuf() + _output_buf_len);\n-  _output_buf_len = strlen(_getOutBuf());\n-\n-  _add_checksum_to_csv_buffer(sensorName, 1, input.t);\n-  _getOutBuf()[_output_buf_len++] = '\\n';\n \n-  return _getOutBuf();\n+/**************************************************************************//**\n+ * @brief   Constructs Acceleration sensor object\n+ * @ingroup acceleration\n+ *\n+ * Example Usage:\n+ * @code\n+ *     Acceleration accel = Acceleration(); // Instantiate sensor object\n+ *     accel.begin();                       // Initialize sensor\n+ *     Serial.println(accel.readToJSON());  // Read and print values in JSON\n+ * @endcode\n+ *****************************************************************************/\n+Acceleration::Acceleration(void) {\n+  Acceleration::sensorId = SENSORID_ADAFRUIT9DOFIMU;\n+  Acceleration::gGain = LSM303_ACCEL_GAIN8G;\n+  Acceleration::header.unit = DATA_UNIT_METER_PER_SECONDSQUARED;\n+  Acceleration::initialized = false;\n }\n \n-_DEFAULT_SENSOR_NAME_TO_CSV_FXN(gyro)\n-const char * gyroToCSV(const char *sensorName, gyro_t & input) {\n-  _headerToCSV(&(input.header), sensorName);// warning : resets the internal buffer\n-\n-  dtostrf(input.x, 2, 3, _getOutBuf() + _output_buf_len);\n-  _output_buf_len = strlen(_getOutBuf());\n-  _getOutBuf()[_output_buf_len++] = CSV_SEPARATOR;\n+Acceleration::~Acceleration() {\n+}\n \n-  dtostrf(input.y, 2, 3, _getOutBuf() + _output_buf_len);\n-  _output_buf_len = strlen(_getOutBuf());\n-  _getOutBuf()[_output_buf_len++] = CSV_SEPARATOR;\n+/**\n+ * @brief   Initializes the sensor with basic configurations\n+ * @ingroup acceleration\n+ *\n+ * @retval true  Successfully initialized\n+ * @retval false Failed to initialize\n+ */\n+boolean Acceleration::begin(void) {\n+  return Acceleration::begin(Acceleration::gGain);\n+}\n \n-  dtostrf(input.z, 2, 3, _getOutBuf() + _output_buf_len);\n-  _output_buf_len = strlen(_getOutBuf());\n+/**\n+ * @brief   Initializes the sensor with advanced configurations\n+ * @ingroup acceleration\n+ *\n+ * @param gGain Advanced configuration for accelerometer's gain\n+ *     - LSM303_ACCEL_GAIN2G\n+ *     - LSM303_ACCEL_GAIN4G\n+ *     - LSM303_ACCEL_GAIN6G\n+ *     - LSM303_ACCEL_GAIN8G (Default)\n+ *     - LSM303_ACCEL_GAIN16G\n+ *\n+ * @retval true  Successfully initialized\n+ * @retval false Failed to initialize\n+ */\n+boolean Acceleration::begin(lsm303_accel_gain_e gain) {\n+  catchSpaceboard();\n+  Acceleration::gGain = gain;\n+  Acceleration::initialized = start_sensor_or_err(acceleration_sensor_name, lsm303_accel_init(gain));\n+  return Acceleration::initialized;\n+}\n \n-  _add_checksum_to_csv_buffer(sensorName, 3, input.x, input.y, input.z);\n-  _getOutBuf()[_output_buf_len++] = '\\n';\n+/**\n+ * @brief   Takes a reading from the sensor\n+ * @ingroup acceleration\n+ */\n+void Acceleration::read(void) {\n+  Acceleration::header.timestamp = millis();\n \n-  return _getOutBuf();\n+  Acceleration::header.sensor_id = Acceleration::sensorId;\n+  lsm303_getAccel(&(Acceleration::x), &(Acceleration::y), &(Acceleration::z));\n }\n \n-_DEFAULT_SENSOR_NAME_TO_CSV_FXN(luminosity)\n-const char * luminosityToCSV(const char *sensorName, luminosity_t & input) {\n-  _headerToCSV(&(input.header), sensorName);// warning : resets the internal buffer\n+/**\n+ * @brief   Takes a reading from the sensor and returns value in CSV format\n+ * @ingroup acceleration\n+ * @param   sensorName The text to display next to the value\n+ */\n+const char * Acceleration::readToCSV(const char * sensorName) {\n+  Acceleration::read();\n+  return Acceleration::toCSV(sensorName);\n+}\n \n-  dtostrf(input.lux, 2, 3, _getOutBuf() + _output_buf_len);\n-  _output_buf_len = strlen(_getOutBuf());\n-  _add_checksum_to_csv_buffer(sensorName, 1, input.lux);\n-  _getOutBuf()[_output_buf_len++] = '\\n';\n+/**\n+ * @brief   Takes a reading from the sensor and returns value in JSON format\n+ * @ingroup acceleration\n+ * @param   sensorName The text to display next to the value\n+ */\n+const char * Acceleration::readToJSON(const char * sensorName) {\n+  Acceleration::read();\n+  return Acceleration::toJSON(sensorName);\n+}\n \n-  return _getOutBuf();\n+/**\n+ * @brief   Returns last read value in CSV format\n+ * @ingroup acceleration\n+ * @param   sensorName The text to display next to the value\n+ */\n+const char * Acceleration::toCSV(const char * sensorName) {\n+  if (Acceleration::initialized)\n+    return valuesToCSV(sensorName, Acceleration::header.timestamp, 3,\n+                       Acceleration::x, Acceleration::y, Acceleration::z);\n+  else\n+    return \"\";\n }\n \n-_DEFAULT_SENSOR_NAME_TO_CSV_FXN(uvlight)\n-const char * uvlightToCSV(const char *sensorName, uvlight_t & input) {\n-  _headerToCSV(&(input.header), sensorName);// warning : resets the internal buffer\n+/**\n+ * @brief   Returns last read value in JSON format\n+ * @ingroup acceleration\n+ * @param   sensorName The text to display next to the value\n+ */\n+const char * Acceleration::toJSON(const char * sensorName) {\n+  if (Acceleration::initialized)\n+    return _tripleValueToJSON(sensorName, 2, Acceleration::header.unit, \"%sX\", Acceleration::x,\n+                             \"%sY\", Acceleration::y, \"%sZ\", Acceleration::z);\n+  else\n+    return \"\";\n+}\n \n-  dtostrf(input.uvindex, 2, 3, _getOutBuf() + _output_buf_len);\n-  _output_buf_len = strlen(_getOutBuf());\n-  _add_checksum_to_csv_buffer(sensorName, 1, input.uvindex);\n-  _getOutBuf()[_output_buf_len++] = '\\n';\n \n-  return _getOutBuf();\n+/**************************************************************************//**\n+ * @brief   Constructs Gyro sensor object\n+ * @ingroup gyro\n+ *\n+ * Example Usage:\n+ * @code\n+ *     Gyro gyro = Gyro();                // Instantiate sensor object\n+ *     gyro.begin();                      // Initialize sensor\n+ *     Serial.println(gyro.readToJSON()); // Read and print values in JSON\n+ * @endcode\n+ *****************************************************************************/\n+Gyro::Gyro(void) {\n+  Gyro::sensorId = SENSORID_ADAFRUIT9DOFIMU;\n+  Gyro::range = 0x20;\n+  Gyro::header.unit = DATA_UNIT_RADIAN_PER_SECOND;\n+  Gyro::initialized = false;\n }\n \n-const char * orientationToCSV(const char *sensorName, orientation_t & input) {\n-  _headerToCSV(&(input.header), sensorName);\n+Gyro::~Gyro() {\n+}\n \n-  dtostrf(input.roll, 2, 3, _getOutBuf() + _output_buf_len);\n-  _output_buf_len = strlen(_getOutBuf());\n-  _getOutBuf()[_output_buf_len++] = CSV_SEPARATOR;\n+/**\n+ * @brief   Initializes the sensor with basic configurations\n+ * @ingroup gyro\n+ *\n+ * @retval true  Successfully initialized\n+ * @retval false Failed to initialize\n+ */\n+boolean Gyro::begin(void) {\n+  return Gyro::begin(Gyro::range);\n+}\n \n-  dtostrf(input.pitch, 2, 3, _getOutBuf() + _output_buf_len);\n-  _output_buf_len = strlen(_getOutBuf());\n-  _getOutBuf()[_output_buf_len++] = CSV_SEPARATOR;\n+/**\n+ * @brief   Initializes the sensor with advanced configurations\n+ * @ingroup gyro\n+ *\n+ * @param range Advanced configuration for gyro's range\n+ * Possible Advanced Configuration Values:\n+ *     - 0x00  (SENSITIVITY_250DPS)\n+ *     - 0x10  (SENSITIVITY_500DPS)\n+ *     - 0x20  (SENSITIVITY_2000DPS) (Default)\n+ *\n+ * @retval true  Successfully initialized\n+ * @retval false Failed to initialize\n+ */\n+boolean Gyro::begin(uint8_t range) {\n+  catchSpaceboard();\n \n-  dtostrf(input.heading, 2, 3, _getOutBuf() + _output_buf_len);\n-  _output_buf_len = strlen(_getOutBuf());\n-  _add_checksum_to_csv_buffer(sensorName, 3, input.roll, input.pitch, input.heading);\n-  _getOutBuf()[_output_buf_len++] = '\\n';\n-  return _getOutBuf();\n+  Gyro::initialized = start_sensor_or_err(gyro_sensor_name, l3gd20h_init(range));\n+  return Gyro::initialized;\n }\n \n-_DEFAULT_SENSOR_NAME_TO_CSV_FXN(pressure)\n-const char * pressureToCSV(const char *sensorName, pressure_t & input) {\n-  _headerToCSV(&(input.header), sensorName);\n-\n-  dtostrf(input.pressure, 2, 3, _getOutBuf() + _output_buf_len);\n-  _output_buf_len = strlen(_getOutBuf());\n-  _add_checksum_to_csv_buffer(sensorName, 1, input.pressure);\n-  _getOutBuf()[_output_buf_len++] = '\\n';\n+/**\n+ * @brief   Takes a reading from the sensor\n+ * @ingroup gyro\n+ */\n+void Gyro::read(void) {\n+  Gyro::header.timestamp = millis();\n \n-  return _getOutBuf();\n+  Gyro::header.sensor_id = Gyro::sensorId;\n+  l3gd20h_getOrientation(&(Gyro::x), &(Gyro::y), &(Gyro::z));\n }\n \n-/*\n- * toJSON output functions\n+/**\n+ * @brief   Takes a reading from the sensor and returns value in CSV format\n+ * @ingroup gyro\n+ * @param   sensorName The text to display next to the value\n  */\n-int _writeJSONValue(char *buf, const char *sensor_name, const char *unit, float value)\n-{\n-  char num [32];\n-  char format_str[80];\n-  // inexact estimate on the number of characters the value will take up...\n-  if (strlen(sensor_name) + strlen(unit) + 10 + _output_buf_len > OUTPUT_BUF_SIZE) {\n-    return -1;\n-  }\n-  dtostrf(value, 4, 2, num);\n-  strcpy_P(format_str, json_format);\n-  _output_buf_len += sprintf(buf, format_str,\n-\t\t\t     JSON_PREFIX, sensor_name, unit, num,\n-\t\t\t     calculateCheckSum(sensor_name, 1, value), JSON_SUFFIX);\n-  return _output_buf_len;\n+const char * Gyro::readToCSV(const char * sensorName) {\n+  Gyro::read();\n+  return Gyro::toCSV(sensorName);\n }\n \n-const char * valueToJSON(const char *sensor_name, unsigned char unit, float value)\n-{\n-  _resetOutBuf();\n-  _writeJSONValue(_getOutBuf(), sensor_name, unit_to_str(unit), value);\n-  return _getOutBuf();\n+/**\n+ * @brief   Takes a reading from the sensor and returns value in JSON format\n+ * @ingroup gyro\n+ * @param   sensorName The text to display next to the value\n+ */\n+const char * Gyro::readToJSON(const char * sensorName) {\n+  Gyro::read();\n+  return Gyro::toJSON(sensorName);\n }\n \n-const char * accelerationToJSON(const char *sensor_name, acceleration_t & acceleration)\n-{\n-  int nameLength = strlen(sensor_name);\n-  char nameBuf[nameLength + 2];\n-  _resetOutBuf();\n+/**\n+ * @brief   Returns last read value in CSV format\n+ * @ingroup gyro\n+ * @param   sensorName The text to display next to the value\n+ */\n+const char * Gyro::toCSV(const char * sensorName) {\n+  if (Gyro::initialized)\n+    return valuesToCSV(sensorName, Gyro::header.timestamp, 3,\n+                       Gyro::x, Gyro::y, Gyro::z);\n+  else\n+    return \"\";\n+}\n \n-  sprintf(nameBuf, \"%sX\", sensor_name);\n-  _writeJSONValue(_getOutBuf(), nameBuf, unit_to_str(acceleration.header.unit),\n-\t\t  acceleration.x);\n-  sprintf(nameBuf, \"%sY\", sensor_name);\n-  _writeJSONValue(&_getOutBuf()[_output_buf_len], nameBuf,\n-\t\t  unit_to_str(acceleration.header.unit), acceleration.y);\n-  sprintf(nameBuf, \"%sZ\", sensor_name);\n-  _writeJSONValue(&_getOutBuf()[_output_buf_len], nameBuf,\n-\t\t  unit_to_str(acceleration.header.unit), acceleration.z);\n-  return _getOutBuf();\n+/**\n+ * @brief   Returns last read value in JSON format\n+ * @ingroup gyro\n+ * @param   sensorName The text to display next to the value\n+ */\n+const char * Gyro::toJSON(const char * sensorName) {\n+  if (Gyro::initialized)\n+    return _tripleValueToJSON(sensorName, 2, Gyro::header.unit, \"%sX\", Gyro::x,\n+                             \"%sY\", Gyro::y, \"%sZ\", Gyro::z);\n+  else\n+    return \"\";\n }\n \n-const char * magneticToJSON(const char *sensor_name, magnetic_t & mag)\n-{\n-  int nameLength = strlen(sensor_name);\n-  char nameBuf[nameLength + 2];\n-  _resetOutBuf();\n \n-  sprintf(nameBuf, \"%sX\", sensor_name);\n-  _writeJSONValue(_getOutBuf(), nameBuf, unit_to_str(mag.header.unit),\n-\t\t  mag.x);\n-  sprintf(nameBuf, \"%sY\", sensor_name);\n-  _writeJSONValue(&_getOutBuf()[_output_buf_len], nameBuf,\n-\t\t  unit_to_str(mag.header.unit), mag.y);\n-  sprintf(nameBuf, \"%sZ\", sensor_name);\n-  _writeJSONValue(&_getOutBuf()[_output_buf_len], nameBuf,\n-\t\t  unit_to_str(mag.header.unit), mag.z);\n-  return _getOutBuf();\n+/**************************************************************************//**\n+ * @brief   Constructs Luminosity sensor object\n+ * @ingroup luminosity\n+ *\n+ * Example Usage:\n+ * @code\n+ *     Luminosity lum = Luminosity();    // Instantiate sensor object\n+ *     lum.begin();                      // Initialize sensor\n+ *     Serial.println(lum.readToJSON()); // Read and print values in JSON\n+ * @endcode\n+ *****************************************************************************/\n+Luminosity::Luminosity(void) {\n+  Luminosity::sensorId = SENSORID_TSL2561;\n+  Luminosity::intTime = TSL2561_INTEGRATIONTIME_13MS;\n+  Luminosity::gain = TSL2561_GAIN_1X;\n+  Luminosity::header.unit = DATA_UNIT_LUX;\n+  Luminosity::initialized = false;\n }\n \n-const char * gyroToJSON(const char *sensor_name, gyro_t & orient)\n-{\n-  int nameLength = strlen(sensor_name);\n-  char nameBuf[nameLength + 8];\n-  _resetOutBuf();\n-\n-  sprintf(nameBuf, \"%sX\", sensor_name);\n-  _writeJSONValue(_getOutBuf(), nameBuf, unit_to_str(orient.header.unit),\n-\t\t  orient.x);\n-  sprintf(nameBuf, \"%sY\", sensor_name);\n-  _writeJSONValue(&_getOutBuf()[_output_buf_len], nameBuf,\n-\t\t  unit_to_str(orient.header.unit), orient.y);\n-  sprintf(nameBuf, \"%sZ\", sensor_name);\n-  _writeJSONValue(&_getOutBuf()[_output_buf_len], nameBuf,\n-\t\t  unit_to_str(orient.header.unit), orient.z);\n-  return _getOutBuf();\n+Luminosity::~Luminosity() {\n }\n \n-const char * temperatureToJSON(const char *sensor_name, temperature_t & temp)\n-{\n-  _resetOutBuf();\n-  _writeJSONValue(_getOutBuf(), sensor_name, unit_to_str(temp.header.unit), temp.t);\n-  return _getOutBuf();\n+/**\n+ * @brief   Initializes the sensor with basic configurations\n+ * @ingroup luminosity\n+ *\n+ * @retval true  Successfully initialized\n+ * @retval false Failed to initialize\n+ */\n+boolean Luminosity::begin(void) {\n+  return Luminosity::begin(Luminosity::intTime, Luminosity::gain);\n }\n \n-const char * luminosityToJSON(const char *sensor_name, luminosity_t & lum)\n-{\n-  _resetOutBuf();\n-  _writeJSONValue(_getOutBuf(), sensor_name, unit_to_str(lum.header.unit), lum.lux);\n-  return _getOutBuf();\n+/**\n+ * @brief   Initializes the sensor with advanced configurations\n+ * @ingroup luminosity\n+ *\n+ * @param intTime Advanced configuration for TSL2561 integration time\n+ *     - TSL2561_INTEGRATIONTIME_13MS (Default)\n+ *     - TSL2561_INTEGRATIONTIME_101MS\n+ *     - TSL2561_INTEGRATIONTIME_402MS\n+ *     \n+ * @param gain Advanced configuration for TSL2561 gain\n+ *     - TSL2561_GAIN_1X (Default)\n+ *     - TSL2561_GAIN_16X\n+ *\n+ * @retval true  Successfully initialized\n+ * @retval false Failed to initialize\n+ */\n+boolean Luminosity::begin(tsl2561IntegrationTime_t intTime, tsl2561Gain_t gain) {\n+  catchSpaceboard();\n+  Luminosity::intTime = intTime;\n+  Luminosity::gain = gain;\n+  Luminosity::initialized = start_sensor_or_err(luminosity_sensor_name, tsl2561_init(intTime, gain));\n+  return Luminosity::initialized;\n }\n \n-const char * uvlightToJSON(const char *sensor_name, uvlight_t & input)\n-{\n-  _resetOutBuf();\n-  _writeJSONValue(_getOutBuf(), sensor_name, unit_to_str(input.header.unit), input.uvindex);\n-  return _getOutBuf();\n+/**\n+ * @brief   Takes a reading from the sensor\n+ * @ingroup luminosity\n+ */\n+void Luminosity::read(void) {\n+  Luminosity::header.timestamp = millis();\n+\n+  Luminosity::header.sensor_id = Luminosity::sensorId;\n+  Luminosity::lux = tsl2561_getLux();\n }\n \n-const char * orientationToJSON(const char *sensor_name, orientation_t & orient)\n-{\n-  int nameLength = strlen(sensor_name);\n-  char nameBuf[nameLength + 8];\n-  _resetOutBuf();\n+/**\n+ * @brief   Takes a reading from the sensor and returns value in CSV format\n+ * @ingroup luminosity\n+ * @param   sensorName The text to display next to the value\n+ */\n+const char * Luminosity::readToCSV(const char * sensorName) {\n+  Luminosity::read();\n+  return Luminosity::toCSV(sensorName);\n+}\n \n-  sprintf(nameBuf, \"%sRoll\", sensor_name);\n-  _writeJSONValue(_getOutBuf(), nameBuf, unit_to_str(orient.header.unit),\n-\t\t  orient.roll);\n-  sprintf(nameBuf, \"%sPitch\", sensor_name);\n-  _writeJSONValue(&_getOutBuf()[_output_buf_len], nameBuf,\n-\t\t  unit_to_str(orient.header.unit), orient.pitch);\n-  sprintf(nameBuf, \"%sHeading\", sensor_name);\n-  _writeJSONValue(&_getOutBuf()[_output_buf_len], nameBuf,\n-\t\t  unit_to_str(orient.header.unit), orient.heading);\n-  return _getOutBuf();\n+/**\n+ * @brief   Takes a reading from the sensor and returns value in JSON format\n+ * @ingroup luminosity\n+ * @param   sensorName The text to display next to the value\n+ */\n+const char * Luminosity::readToJSON(const char * sensorName) {\n+  Luminosity::read();\n+  return Luminosity::toJSON(sensorName);\n }\n \n-const char * pressureToJSON(const char *sensorName, pressure_t & pressure)\n-{\n-  _resetOutBuf();\n-  _writeJSONValue(_getOutBuf(), sensorName, unit_to_str(pressure.header.unit), pressure.pressure);\n-  return _getOutBuf();\n+/**\n+ * @brief   Returns last read value in CSV format\n+ * @ingroup luminosity\n+ * @param   sensorName The text to display next to the value\n+ */\n+const char * Luminosity::toCSV(const char * sensorName) {\n+  if (Luminosity::initialized)\n+    return valueToCSV(sensorName, Luminosity::lux, Luminosity::header.timestamp);\n+  else\n+    return \"\";\n+}\n+\n+/**\n+ * @brief   Returns last read value in JSON format\n+ * @ingroup luminosity\n+ * @param   sensorName The text to display next to the value\n+ */\n+const char * Luminosity::toJSON(const char * sensorName) {\n+  if (Luminosity::initialized)\n+    return valueToJSON(sensorName, Luminosity::header.unit, Luminosity::lux);\n+  else\n+    return \"\";\n+}\n+\n+\n+/**************************************************************************//**\n+ * @brief   Constructs Magnetic sensor object\n+ * @ingroup magnetic\n+ *\n+ * Example Usage:\n+ * @code\n+ *     Magnetic mag = Magnetic();        // Instantiate sensor object\n+ *     mag.begin();                      // Initialize sensor\n+ *     Serial.println(mag.readToJSON()); // Read and print values in JSON\n+ * @endcode\n+ *****************************************************************************/\n+Magnetic::Magnetic(void) {\n+  Magnetic::sensorId = SENSORID_ADAFRUIT9DOFIMU;\n+  Magnetic::gaussScale = LSM303_MAG_SCALE4GAUSS;\n+  Magnetic::header.unit = DATA_UNIT_MICROTESLA;\n+  Magnetic::initialized = false;\n+}\n+\n+Magnetic::~Magnetic() {\n+}\n+\n+/**\n+ * @brief   Initializes the sensor with basic configurations\n+ * @ingroup magnetic\n+ *\n+ * @retval true  Successfully initialized\n+ * @retval false Failed to initialize\n+ */\n+boolean Magnetic::begin(void) {\n+  return Magnetic::begin(Magnetic::gaussScale);\n+}\n+\n+/**\n+ * @brief   Initializes the sensor with advanced configurations\n+ * @ingroup magnetic\n+ *\n+ * @param gaussScale Advanced configuration for magnetometer's scale\n+ *     - LSM303_MAG_SCALE1_3GAUSS\n+ *     - LSM303_MAG_SCALE2GAUSS\n+ *     - LSM303_MAG_SCALE2_5GAUSS\n+ *     - LSM303_MAG_SCALE4GAUSS (Default)\n+ *     - LSM303_MAG_SCALE4_7GAUSS\n+ *     - LSM303_MAG_SCALE5_6GAUSS\n+ *     - LSM303_MAG_SCALE8GAUSS\n+ *     - LSM303_MAG_SCALE12GAUSS\n+ *\n+ * @retval true  Successfully initialized\n+ * @retval false Failed to initialize\n+ */\n+boolean Magnetic::begin(lsm303_mag_scale_e gaussScale) {\n+  catchSpaceboard();\n+  Magnetic::gaussScale = gaussScale;\n+  Magnetic::initialized = start_sensor_or_err(magnetic_sensor_name, lsm303_mag_init(gaussScale));\n+  return Magnetic::initialized;\n+}\n+\n+/**\n+ * @brief   Takes a reading from the sensor\n+ * @ingroup magnetic\n+ */\n+void Magnetic::read(void) {\n+  Magnetic::header.timestamp = millis();\n+\n+  Magnetic::header.sensor_id = Magnetic::sensorId;\n+  lsm303_getMag(&(Magnetic::x), &(Magnetic::y), &(Magnetic::z));\n+}\n+\n+/**\n+ * @brief   Takes a reading from the sensor and returns value in CSV format\n+ * @ingroup magnetic\n+ * @param   sensorName The text to display next to the value\n+ */\n+const char * Magnetic::readToCSV(const char * sensorName) {\n+  Magnetic::read();\n+  return Magnetic::toCSV(sensorName);\n+}\n+\n+/**\n+ * @brief   Takes a reading from the sensor and returns value in JSON format\n+ * @ingroup magnetic\n+ * @param   sensorName The text to display next to the value\n+ */\n+const char * Magnetic::readToJSON(const char * sensorName) {\n+  Magnetic::read();\n+  return Magnetic::toJSON(sensorName);\n+}\n+\n+/**\n+ * @brief   Returns last read value in CSV format\n+ * @ingroup magnetic\n+ * @param   sensorName The text to display next to the value\n+ */\n+const char * Magnetic::toCSV(const char * sensorName) {\n+  if (Magnetic::initialized)\n+    return valuesToCSV(sensorName, Magnetic::header.timestamp, 3,\n+                       Magnetic::x, Magnetic::y, Magnetic::z);\n+  else\n+    return \"\";\n+}\n+\n+/**\n+ * @brief   Returns last read value in JSON format\n+ * @ingroup magnetic\n+ * @param   sensorName The text to display next to the value\n+ */\n+const char * Magnetic::toJSON(const char * sensorName) {\n+  if (Magnetic::initialized)\n+    return _tripleValueToJSON(sensorName, 2, Magnetic::header.unit, \"%sX\", Magnetic::x,\n+                             \"%sY\", Magnetic::y, \"%sZ\", Magnetic::z);\n+  else\n+    return \"\";\n+}\n+\n+\n+/**************************************************************************//**\n+ * @brief   Constructs Orientation calculation object\n+ * @ingroup orientation\n+ *\n+ * Example Usage:\n+ * @code\n+ *     Orientation orient = Orientation();  // Instantiate sensor object\n+ *     orient.begin();                      // Initialize sensor\n+ *     Serial.println(orient.readToJSON()); // Read and print values in JSON\n+ * @endcode\n+ *****************************************************************************/\n+Orientation::Orientation(void) {\n+  Orientation::sensorId = SENSORID_ADAFRUIT9DOFIMU;\n+  Orientation::header.unit = DATA_UNIT_DEGREES;\n+  Orientation::initialized = false;\n+}\n+\n+Orientation::~Orientation() {\n+}\n+\n+/**\n+ * @brief   Creates new Acceleration and Magnetic Sensors to derive orientation\n+ * @ingroup orientation\n+ *\n+ * @retval true  Successfully initialized\n+ * @retval false Failed to initialize\n+ */\n+boolean Orientation::begin(void) {\n+  Acceleration accel;\n+  Magnetic mag;\n+  accel.begin();\n+  mag.begin();\n+  return Orientation::begin(accel, mag);\n+}\n+\n+/**\n+ * @brief   Uses provided Acceleration and Magnetic Sensors to derive orientation\n+ * @ingroup orientation\n+ *\n+ * @param accel Existing Acceleration Sensor to use\n+ * @param mag   Existing Magnetic Sensor to use\n+ *\n+ * @retval true  Successfully initialized\n+ * @retval false Failed to initialize\n+ */\n+boolean Orientation::begin(Acceleration & accel, Magnetic & mag) {\n+  catchSpaceboard();\n+  Orientation::accel = & accel;\n+  Orientation::mag = & mag;\n+  Orientation::initialized = accel.initialized && mag.initialized;\n+  return Orientation::initialized;\n+}\n+\n+/**\n+ * @brief   Takes a reading from the sensor\n+ * @ingroup orientation\n+ */\n+void Orientation::read(void) {\n+  Orientation::accel->read();\n+  Orientation::mag->read();\n+  Orientation::read(*(Orientation::accel), *(Orientation::mag));\n+}\n+\n+/**\n+ * @brief   Takes a reading from the sensor\n+ * @ingroup orientation\n+ *\n+ * @param accel Existing Acceleration Sensor to use\n+ * @param mag   Existing Magnetic Sensor to use\n+ */\n+void Orientation::read(Acceleration & acc, Magnetic & mag) {\n+  float roll;\n+  float pitch;\n+  float heading;\n+  const float PI_F = 3.141592653F;\n+\n+  // Roll is rotation around x-axis (-180 <= roll <= 180)\n+  // Positive roll is clockwise rotation wrt positive x axis\n+  roll = (float) atan2(acc.y, acc.z);\n+\n+  // Pitch is rotation around y-axis (-180 <= pitch <= 180)\n+  // Positive pitch is clockwise rotation wrt positive y axis\n+  if (acc.y * sin(roll) + acc.z * cos(roll) == 0) {\n+    pitch = acc.x > 0 ? (PI_F / 2) : (-PI_F / 2);\n+  } else {\n+    pitch = (float)atan(-acc.x / (acc.y * sin(roll) + acc.z * cos(roll)));\n+  }\n+\n+  // Heading is rotation around z-axis\n+  // Positive heading is clockwise rotation wrt positive z axis\n+  heading = (float)atan2(mag.z * sin(roll) - mag.y * cos(roll),\n+\t\t\t         mag.x * cos(pitch) + mag.y * sin(pitch) * sin(roll) +\n+\t\t\t\t mag.z * sin(pitch) * cos(roll));\n+\n+  // Convert radians to degrees\n+  Orientation::roll = roll * 180 / PI_F;\n+  Orientation::pitch = pitch * 180 / PI_F;\n+  Orientation::heading = heading * 180 / PI_F;\n+\n+  Orientation::header.timestamp = max(acc.header.timestamp, mag.header.timestamp);\n+}\n+\n+/**\n+ * @brief   Takes a reading from the sensor and returns value in CSV format\n+ * @ingroup orientation\n+ * @param   sensorName The text to display next to the value\n+ */\n+const char * Orientation::readToCSV(const char * sensorName) {\n+  Orientation::read();\n+  return Orientation::toCSV(sensorName);\n+}\n+\n+/**\n+ * @brief   Takes a reading from the sensor and returns value in JSON format\n+ * @ingroup orientation\n+ * @param   sensorName The text to display next to the value\n+ */\n+const char * Orientation::readToJSON(const char * sensorName) {\n+  Orientation::read();\n+  return Orientation::toJSON(sensorName);\n+}\n+\n+/**\n+ * @brief   Takes a reading from the sensor and returns value in CSV format\n+ * @ingroup orientation\n+ * @param   sensorName The text to display next to the value\n+ * @param   accel Existing Acceleration Sensor to use\n+ * @param   mag Existing Magnetic Sensor to use\n+ */\n+const char * Orientation::readToCSV(Acceleration & acc, Magnetic & mag, const char * sensorName) {\n+  Orientation::read(acc, mag);\n+  return Orientation::toCSV(sensorName);\n+}\n+\n+/**\n+ * @brief   Takes a reading from the sensor and returns value in JSON format\n+ * @ingroup orientation\n+ * @param   sensorName The text to display next to the value\n+ * @param   accel Existing Acceleration Sensor to use\n+ * @param   mag Existing Magnetic Sensor to use\n+ */\n+const char * Orientation::readToJSON(Acceleration & acc, Magnetic & mag, const char * sensorName) {\n+  Orientation::read(acc, mag);\n+  return Orientation::toJSON(sensorName);\n+}\n+\n+/**\n+ * @brief   Returns last read value in CSV format\n+ * @ingroup orientation\n+ * @param   sensorName The text to display next to the value\n+ */\n+const char * Orientation::toCSV(const char * sensorName) {\n+  if (Orientation::initialized)\n+    return valuesToCSV(sensorName, Orientation::header.timestamp, 3,\n+                       Orientation::roll, Orientation::pitch, Orientation::heading);\n+  else\n+    return \"\";\n+}\n+\n+/**\n+ * @brief   Returns last read value in JSON format\n+ * @ingroup orientation\n+ * @param   sensorName The text to display next to the value\n+ */\n+const char * Orientation::toJSON(const char * sensorName) {\n+  if (Orientation::initialized)\n+    return _tripleValueToJSON(sensorName, 8, Orientation::header.unit, \"%sRoll\", Orientation::roll,\n+                             \"%sPitch\", Orientation::pitch, \"%sHeading\", Orientation::heading);\n+  else\n+    return \"\";\n+}\n+\n+\n+/**************************************************************************//**\n+ * @brief   Constructs Pressure object\n+ * @ingroup pressure\n+ *\n+ * Example Usage:\n+ * @code\n+ *     Pressure press = Pressure();        // Instantiate sensor object\n+ *     press.begin();                      // Initialize sensor\n+ *     Serial.println(press.readToJSON()); // Read and print values in JSON\n+ * @endcode\n+ *****************************************************************************/\n+Pressure::Pressure(void) {\n+  Pressure::sensorId = SENSORID_BMP180;\n+  Pressure::bmp085_mode = BMP085_MODE_ULTRAHIGHRES;\n+  Pressure::header.unit = DATA_UNIT_HECTOPASCAL;\n+  Pressure::initialized = false;\n+}\n+\n+Pressure::~Pressure() {\n+}\n+\n+/**\n+ * @brief   Initializes the sensor with basic configurations\n+ * @ingroup pressure\n+ *\n+ * @retval true  Successfully initialized\n+ * @retval false Failed to initialize\n+ */\n+boolean Pressure::begin(void) {\n+  return Pressure::begin(Pressure::bmp085_mode);\n+}\n+\n+/**\n+ * @brief   Initializes the sensor with advanced configurations\n+ * @ingroup pressure\n+ *\n+ * @param mode Advanced configuration for BMP180's resolution mode\n+ *     - BMP085_MODE_ULTRALOWPOWER\n+ *     - BMP085_MODE_STANDARD\n+ *     - BMP085_MODE_HIGHRES\n+ *     - BMP085_MODE_ULTRAHIGHRES (Default)\n+ *\n+ * @retval true  Successfully initialized\n+ * @retval false Failed to initialize\n+ */\n+boolean Pressure::begin(bmp085_mode_t mode) {\n+  Pressure::bmp085_mode = mode;\n+  Pressure::initialized = start_sensor_or_err(pressure_sensor_name, bmp180_init(mode));\n+\n+  catchSpaceboard();\n+  if (ARDUSAT_SPACEBOARD && !Pressure::initialized) {\n+    _writeUnavailableSensorError(pressure_sensor_name, spaceboard_hardware);\n+    return false;\n+  }\n+\n+  return Pressure::initialized;\n+}\n+\n+/**\n+ * @brief   Takes a reading from the sensor\n+ * @ingroup pressure\n+ */\n+void Pressure::read(void) {\n+  Pressure::header.timestamp = millis();\n+\n+  Pressure::header.sensor_id = Pressure::sensorId;\n+  bmp180_getPressure(&(Pressure::pressure));\n+}\n+\n+/**\n+ * @brief Calculates current altitude given pressure reading and provided pressure at sea level\n+ *\n+ * Equation taken from BMP180 datasheet (page 16):\n+ * http://www.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf\n+ *\n+ * Note that using the equation from wikipedia can give bad results at high\n+ * altitude. See this thread for more information:\n+ * http://forums.adafruit.com/viewtopic.php?f=22&t=58064\n+ *\n+ * @ingroup pressure\n+ * @param   seaLevelPressure Known pressure at sea level in hPa\n+ */\n+float Pressure::altitudeFromSeaLevelPressure(float seaLevelPressure) {\n+  return 44330.0 * (1.0 - pow(Pressure::pressure / seaLevelPressure, 0.1903));\n+}\n+\n+/**\n+ * @brief Calculate the pressure at sea level given current altitude and pressure reading\n+ *\n+ * Equation taken from BMP180 datasheet (page 17):\n+ * http://www.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf\n+ *\n+ * Note that using the equation from wikipedia can give bad results at high\n+ * altitude. See this thread for more information:\n+ * http://forums.adafruit.com/viewtopic.php?f=22&t=58064\n+ *\n+ * @ingroup pressure\n+ * @param   altitude Known altitude in meters\n+ */\n+float Pressure::seaLevelPressureFromAltitude(float altitude) {\n+  return Pressure::pressure / pow(1.0 - (altitude / 44330.0), 5.255);\n+}\n+\n+/**\n+ * @brief   Takes a reading from the sensor and returns value in CSV format\n+ * @ingroup pressure\n+ * @param   sensorName The text to display next to the value\n+ */\n+const char * Pressure::readToCSV(const char * sensorName) {\n+  Pressure::read();\n+  return Pressure::toCSV(sensorName);\n+}\n+\n+/**\n+ * @brief   Takes a reading from the sensor and returns value in JSON format\n+ * @ingroup pressure\n+ * @param   sensorName The text to display next to the value\n+ */\n+const char * Pressure::readToJSON(const char * sensorName) {\n+  Pressure::read();\n+  return Pressure::toJSON(sensorName);\n+}\n+\n+/**\n+ * @brief   Returns last read value in CSV format\n+ * @ingroup pressure\n+ * @param   sensorName The text to display next to the value\n+ */\n+const char * Pressure::toCSV(const char * sensorName) {\n+  if (Pressure::initialized)\n+    return valueToCSV(sensorName, Pressure::pressure, Pressure::header.timestamp);\n+  else\n+    return \"\";\n+}\n+\n+/**\n+ * @brief   Returns last read value in JSON format\n+ * @ingroup pressure\n+ * @param   sensorName The text to display next to the value\n+ */\n+const char * Pressure::toJSON(const char * sensorName) {\n+  if (Pressure::initialized)\n+    return valueToJSON(sensorName, Pressure::header.unit, Pressure::pressure);\n+  else\n+    return \"\";\n+}\n+\n+\n+/**************************************************************************//**\n+ * @brief   Constructs RGBLight sensor object, default uses TCS34725 sensor\n+ * @ingroup rgblight\n+ *\n+ * @param   sensor_id Specifies which RGB sensor to use: TCS34725 or ISL29125\n+ *     - SENSORID_TCS34725\n+ *     - SENSORID_ISL29125\n+ *\n+ * Example Usage:\n+ * @code\n+ *     RGBLight rgb = RGBLight(SENSORID_ISL29125); // Instantiate sensor object\n+ *     rgb.begin();                                // Initialize sensor\n+ *     Serial.println(rgb.readToJSON());           // Read and print values in JSON\n+ * @endcode\n+ *****************************************************************************/\n+RGBLight::RGBLight(sensor_id_t sensor_id) {\n+  RGBLight::sensorId = sensor_id;\n+  RGBLight::islIntensity = CFG1_10KLUX;\n+  RGBLight::tcsIt = TCS34725_INTEGRATIONTIME_154MS;\n+  RGBLight::tcsGain = TCS34725_GAIN_1X;\n+  RGBLight::header.unit = DATA_UNIT_LUX;\n+  RGBLight::initialized = false;\n+}\n+\n+RGBLight::~RGBLight() {\n+}\n+\n+/**\n+ * @brief   Initializes the sensor with basic configurations\n+ * @ingroup rgblight\n+ *\n+ * @retval true  Successfully initialized\n+ * @retval false Failed to initialize\n+ */\n+boolean RGBLight::begin(void) {\n+  return RGBLight::begin(RGBLight::islIntensity, RGBLight::tcsIt, RGBLight::tcsGain);\n+}\n+\n+/**\n+ * @brief   Initializes the sensor with advanced configurations\n+ * @ingroup rgblight\n+ *\n+ * @param islIntensity Advanced configuration for ISL29125 intensity\n+ *     - CFG1_375LUX\n+ *     - CFG1_10KLUX (Default)\n+ *\n+ * @retval true  Successfully initialized\n+ * @retval false Failed to initialize\n+ */\n+boolean RGBLight::begin(uint8_t islIntensity) {\n+  if (RGBLight::sensorId == SENSORID_ISL29125)\n+    return RGBLight::begin(islIntensity, RGBLight::tcsIt, RGBLight::tcsGain);\n+  else\n+    return RGBLight::begin();\n+}\n+\n+/**\n+ * @brief   Initializes the sensor with advanced configurations\n+ * @ingroup rgblight\n+ *\n+ * @param tcsIt Advanced configuration for TCS34725 integration time\n+ *     - TCS34725_INTEGRATIONTIME_2_4MS\n+ *     - TCS34725_INTEGRATIONTIME_24MS\n+ *     - TCS34725_INTEGRATIONTIME_50MS\n+ *     - TCS34725_INTEGRATIONTIME_101MS\n+ *     - TCS34725_INTEGRATIONTIME_154MS (Default)\n+ *     - TCS34725_INTEGRATIONTIME_700MS\n+ *\n+ * @param tcsGain Advanced configuration for TCS34725 gain\n+ *     - TCS34725_GAIN_1X (Default)\n+ *     - TCS34725_GAIN_4X\n+ *     - TCS34725_GAIN_16X\n+ *     - TCS34725_GAIN_60X\n+ *\n+ * @retval true  Successfully initialized\n+ * @retval false Failed to initialize\n+ */\n+boolean RGBLight::begin(tcs34725IntegrationTime_t tcsIt, tcs34725Gain_t tcsGain) {\n+  if (RGBLight::sensorId == SENSORID_TCS34725)\n+    return RGBLight::begin(RGBLight::islIntensity, tcsIt, tcsGain);\n+  else\n+    return RGBLight::begin();\n+}\n+\n+/**\n+ * Private function to initialize RGBLight sensor\n+ */\n+boolean RGBLight::begin(uint8_t islIntensity, tcs34725IntegrationTime_t tcsIt, tcs34725Gain_t tcsGain) {\n+  RGBLight::islIntensity = islIntensity;\n+  RGBLight::tcsIt = tcsIt;\n+  RGBLight::tcsGain = tcsGain;\n+\n+  if (RGBLight::sensorId == SENSORID_ISL29125)\n+    RGBLight::initialized = start_sensor_or_err(rgblight_sensor_name,\n+                                                isl29125_init(islIntensity));\n+  else if (RGBLight::sensorId == SENSORID_TCS34725)\n+    RGBLight::initialized = start_sensor_or_err(rgblight_sensor_name,\n+                                                tcs34725_init(tcsIt, tcsGain));\n+\n+  catchSpaceboard();\n+  if (!ARDUSAT_SPACEBOARD && !RGBLight::initialized) {\n+    _writeUnavailableSensorError(rgblight_sensor_name, spacekit_hardware);\n+    return false;\n+  }\n+\n+  return RGBLight::initialized;\n+}\n+\n+/**\n+ * @brief   Takes a reading from the sensor\n+ * @ingroup rgblight\n+ */\n+void RGBLight::read(void) {\n+  RGBLight::header.timestamp = millis();\n+  RGBLight::header.sensor_id = RGBLight::sensorId;\n+\n+  if (RGBLight::sensorId == SENSORID_ISL29125)\n+    isl29125_getRGB(&(RGBLight::red), &(RGBLight::green), &(RGBLight::blue));\n+  else if (RGBLight::sensorId == SENSORID_TCS34725)\n+    tcs34725_getRGB(&(RGBLight::red), &(RGBLight::green), &(RGBLight::blue));\n+}\n+\n+/**\n+ * @brief   Takes a reading from the sensor and returns value in CSV format\n+ * @ingroup rgblight\n+ * @param   sensorName The text to display next to the value\n+ */\n+const char * RGBLight::readToCSV(const char * sensorName) {\n+  RGBLight::read();\n+  return RGBLight::toCSV(sensorName);\n+}\n+\n+/**\n+ * @brief   Takes a reading from the sensor and returns value in JSON format\n+ * @ingroup rgblight\n+ * @param   sensorName The text to display next to the value\n+ */\n+const char * RGBLight::readToJSON(const char * sensorName) {\n+  RGBLight::read();\n+  return RGBLight::toJSON(sensorName);\n+}\n+\n+/**\n+ * @brief   Returns last read value in CSV format\n+ * @ingroup rgblight\n+ * @param   sensorName The text to display next to the value\n+ */\n+const char * RGBLight::toCSV(const char * sensorName) {\n+  if (RGBLight::initialized)\n+    return valuesToCSV(sensorName, RGBLight::header.timestamp, 3,\n+                       RGBLight::red, RGBLight::green, RGBLight::blue);\n+  else\n+    return \"\";\n+}\n+\n+/**\n+ * @brief   Returns last read value in JSON format\n+ * @ingroup rgblight\n+ * @param   sensorName The text to display next to the value\n+ */\n+const char * RGBLight::toJSON(const char * sensorName) {\n+  if (RGBLight::initialized)\n+    return _tripleValueToJSON(sensorName, 6, RGBLight::header.unit, \"%sRed\", RGBLight::red,\n+                             \"%sGreen\", RGBLight::green, \"%sBlue\", RGBLight::blue);\n+  else\n+    return \"\";\n+}\n+\n+\n+/**************************************************************************//**\n+ * @brief   Constructs Temperature sensor object, default uses TMP102 sensor\n+ * @ingroup temperature\n+ *\n+ * @param   sensor_id Specifies which Temperature sensor to use: TMP102 or MLX90614\n+ *     - SENSORID_TMP102\n+ *     - SENSORID_MLX90614\n+ *\n+ * Example Usage:\n+ * @code\n+ *     Temperature temp = Temperature(SENSORID_MLX90614); // Instantiate sensor object\n+ *     temp.begin();                                      // Initialize sensor\n+ *     Serial.println(temp.readToJSON());                 // Read and print values in JSON\n+ * @endcode\n+ *****************************************************************************/\n+Temperature::Temperature(sensor_id_t sensor_id) {\n+  Temperature::sensorId = sensor_id;\n+  Temperature::header.unit = DATA_UNIT_DEGREES_CELSIUS;\n+  Temperature::initialized = false;\n+}\n+\n+Temperature::~Temperature() {\n+}\n+\n+/**\n+ * @brief   Initializes the sensor with basic configurations\n+ * @ingroup temperature\n+ *\n+ * @retval true  Successfully initialized\n+ * @retval false Failed to initialize\n+ */\n+boolean Temperature::begin(void) {\n+  catchSpaceboard();\n+  if (Temperature::sensorId == SENSORID_TMP102) {\n+    Temperature::initialized = start_sensor_or_err(temperature_sensor_name, tmp102_init());\n+  } else if (Temperature::sensorId == SENSORID_MLX90614) {\n+    Temperature::initialized = start_sensor_or_err(irtemperature_sensor_name, mlx90614_init());\n+  }\n+  return Temperature::initialized;\n+}\n+\n+/**\n+ * @brief   Takes a reading from the sensor\n+ * @ingroup temperature\n+ */\n+void Temperature::read(void) {\n+  Temperature::header.timestamp = millis();\n+  Temperature::header.sensor_id = Temperature::sensorId;\n+\n+  if (Temperature::sensorId == SENSORID_TMP102)\n+    Temperature::t = tmp102_getTempCelsius();\n+  else if (Temperature::sensorId == SENSORID_MLX90614)\n+    Temperature::t = mlx90614_getTempCelsius();\n+}\n+\n+/**\n+ * @brief   Takes a reading from the sensor and returns value in CSV format\n+ * @ingroup temperature\n+ * @param   sensorName The text to display next to the value\n+ */\n+const char * Temperature::readToCSV(const char * sensorName) {\n+  Temperature::read();\n+  return Temperature::toCSV(sensorName);\n+}\n+\n+/**\n+ * @brief   Takes a reading from the sensor and returns value in JSON format\n+ * @ingroup temperature\n+ * @param   sensorName The text to display next to the value\n+ */\n+const char * Temperature::readToJSON(const char * sensorName) {\n+  Temperature::read();\n+  return Temperature::toJSON(sensorName);\n+}\n+\n+/**\n+ * @brief   Returns last read value in CSV format\n+ * @ingroup temperature\n+ * @param   sensorName The text to display next to the value\n+ */\n+const char * Temperature::toCSV(const char * sensorName) {\n+  if (Temperature::initialized)\n+    return valueToCSV(sensorName, Temperature::t, Temperature::header.timestamp);\n+  else\n+    return \"\";\n+}\n+\n+/**\n+ * @brief   Returns last read value in JSON format\n+ * @ingroup temperature\n+ * @param   sensorName The text to display next to the value\n+ */\n+const char * Temperature::toJSON(const char * sensorName) {\n+  if (Temperature::initialized)\n+    return valueToJSON(sensorName, Temperature::header.unit, Temperature::t);\n+  else\n+    return \"\";\n+}\n+\n+\n+/**************************************************************************//**\n+ * @brief   Constructs UVLight sensor object, default uses ML8511 sensor\n+ * @ingroup uvlight\n+ *\n+ * @param   sensor_id Specifies which UVLight sensor to use: ML8511 or SI1132\n+ *     - SENSORID_ML8511\n+ *     - SENSORID_SI1132\n+ *\n+ * Example Usage:\n+ * @code\n+ *     UVLight uv = UVLight(SENSORID_SI1132); // Instantiate sensor object\n+ *     uv.begin();                            // Initialize sensor\n+ *     Serial.println(uv.readToJSON());       // Read and print values in JSON\n+ * @endcode\n+ *****************************************************************************/\n+UVLight::UVLight(sensor_id_t sensor_id) {\n+  UVLight::sensorId = sensor_id;\n+  UVLight::ML8511_pin = DRIVER_ML8511_UV_PIN;\n+  UVLight::header.unit = DATA_UNIT_MILLIWATT_PER_CMSQUARED;\n+  UVLight::initialized = false;\n+}\n+\n+UVLight::~UVLight() {\n+}\n+\n+/**\n+ * @brief   Initializes the sensor with basic configurations\n+ * @ingroup uvlight\n+ *\n+ * @retval true  Successfully initialized\n+ * @retval false Failed to initialize\n+ */\n+boolean UVLight::begin(void) {\n+  return UVLight::begin(UVLight::ML8511_pin);\n+}\n+\n+/**\n+ * @brief   Initializes the sensor with advanced configurations\n+ * @ingroup uvlight\n+ *\n+ * @param pin The analog pin the ML8511 board uses on the Arduino\n+ *     - DRIVER_ML8511_UV_PIN (A0) (Default)\n+ *\n+ * @retval true  Successfully initialized\n+ * @retval false Failed to initialize\n+ */\n+boolean UVLight::begin(int pin) {\n+  catchSpaceboard();\n+  UVLight::ML8511_pin = pin;\n+  if (UVLight::sensorId == SENSORID_SI1132)\n+    UVLight::initialized = start_sensor_or_err(uvlight_sensor_name, si1132_init());\n+  else if (UVLight::sensorId == SENSORID_ML8511)\n+    UVLight::initialized = start_sensor_or_err(uvlight_sensor_name, ml8511_init());\n+  return UVLight::initialized;\n+}\n+\n+/**\n+ * @brief   Takes a reading from the sensor\n+ * @ingroup uvlight\n+ */\n+void UVLight::read(void) {\n+  UVLight::header.timestamp = millis();\n+\n+  if (UVLight::sensorId == SENSORID_SI1132) {\n+    UVLight::header.sensor_id = SENSORID_SI1132;\n+    UVLight::uvindex = si1132_getUVIndex();\n+  } else if (UVLight::sensorId == SENSORID_ML8511) {\n+    UVLight::header.sensor_id = SENSORID_ML8511;\n+    UVLight::uvindex = ml8511_getUV(UVLight::ML8511_pin);\n+  }\n+}\n+\n+/**\n+ * @brief   Takes a reading from the sensor and returns value in CSV format\n+ * @ingroup uvlight\n+ * @param   sensorName The text to display next to the value\n+ */\n+const char * UVLight::readToCSV(const char * sensorName) {\n+  UVLight::read();\n+  return UVLight::toCSV(sensorName);\n+}\n+\n+/**\n+ * @brief   Takes a reading from the sensor and returns value in JSON format\n+ * @ingroup uvlight\n+ * @param   sensorName The text to display next to the value\n+ */\n+const char * UVLight::readToJSON(const char * sensorName) {\n+  UVLight::read();\n+  return UVLight::toJSON(sensorName);\n+}\n+\n+/**\n+ * @brief   Returns last read value in CSV format\n+ * @ingroup uvlight\n+ * @param   sensorName The text to display next to the value\n+ */\n+const char * UVLight::toCSV(const char * sensorName) {\n+  if (UVLight::initialized)\n+    return valueToCSV(sensorName, UVLight::uvindex, UVLight::header.timestamp);\n+  else\n+    return \"\";\n+}\n+\n+/**\n+ * @brief   Returns last read value in JSON format\n+ * @ingroup uvlight\n+ * @param   sensorName The text to display next to the value\n+ */\n+const char * UVLight::toJSON(const char * sensorName) {\n+  if (UVLight::initialized)","path":"ArdusatSDK.cpp","position":1816,"original_position":1816,"commit_id":"b0800fc8c904cdfb9ad54b19af013c90bc94551d","original_commit_id":"b0800fc8c904cdfb9ad54b19af013c90bc94551d","user":{"login":"bencpeters","id":1310129,"avatar_url":"https://avatars.githubusercontent.com/u/1310129?v=3","gravatar_id":"","url":"https://api.github.com/users/bencpeters","html_url":"https://github.com/bencpeters","followers_url":"https://api.github.com/users/bencpeters/followers","following_url":"https://api.github.com/users/bencpeters/following{/other_user}","gists_url":"https://api.github.com/users/bencpeters/gists{/gist_id}","starred_url":"https://api.github.com/users/bencpeters/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bencpeters/subscriptions","organizations_url":"https://api.github.com/users/bencpeters/orgs","repos_url":"https://api.github.com/users/bencpeters/repos","events_url":"https://api.github.com/users/bencpeters/events{/privacy}","received_events_url":"https://api.github.com/users/bencpeters/received_events","type":"User","site_admin":false},"body":"brackets","created_at":"2016-06-01T15:57:07Z","updated_at":"2016-06-01T15:57:07Z","html_url":"https://github.com/ArduSat/ArdusatSDK/pull/11#discussion_r65389607","pull_request_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/pulls/11","_links":{"self":{"href":"https://api.github.com/repos/ArduSat/ArdusatSDK/pulls/comments/65389607"},"html":{"href":"https://github.com/ArduSat/ArdusatSDK/pull/11#discussion_r65389607"},"pull_request":{"href":"https://api.github.com/repos/ArduSat/ArdusatSDK/pulls/11"}}},"pull_request":{"url":"https://api.github.com/repos/ArduSat/ArdusatSDK/pulls/11","id":55041392,"html_url":"https://github.com/ArduSat/ArdusatSDK/pull/11","diff_url":"https://github.com/ArduSat/ArdusatSDK/pull/11.diff","patch_url":"https://github.com/ArduSat/ArdusatSDK/pull/11.patch","issue_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/issues/11","number":11,"state":"open","locked":false,"title":"Support for new Spaceboard Sensors and better detection of hardware","user":{"login":"samolds","id":1863557,"avatar_url":"https://avatars.githubusercontent.com/u/1863557?v=3","gravatar_id":"","url":"https://api.github.com/users/samolds","html_url":"https://github.com/samolds","followers_url":"https://api.github.com/users/samolds/followers","following_url":"https://api.github.com/users/samolds/following{/other_user}","gists_url":"https://api.github.com/users/samolds/gists{/gist_id}","starred_url":"https://api.github.com/users/samolds/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/samolds/subscriptions","organizations_url":"https://api.github.com/users/samolds/orgs","repos_url":"https://api.github.com/users/samolds/repos","events_url":"https://api.github.com/users/samolds/events{/privacy}","received_events_url":"https://api.github.com/users/samolds/received_events","type":"User","site_admin":false},"body":"Added support for the 3 new spaceboard sensors: ISL29125 (RGB), TCS34725 (RGB), and SI1132 (UV).\r\n\r\nAt this point, this ongoing PR also includes a rewrite of the SDK interface to be more object oriented.","created_at":"2016-01-05T00:28:57Z","updated_at":"2016-06-01T15:57:07Z","closed_at":null,"merged_at":null,"merge_commit_sha":"072fe0c6bdb5402cfbb9b41b45b93c964afaed2b","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/pulls/11/commits","review_comments_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/pulls/11/comments","review_comment_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/pulls/comments{/number}","comments_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/issues/11/comments","statuses_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/statuses/b0800fc8c904cdfb9ad54b19af013c90bc94551d","head":{"label":"ArduSat:spaceboard","ref":"spaceboard","sha":"b0800fc8c904cdfb9ad54b19af013c90bc94551d","user":{"login":"ArduSat","id":1914772,"avatar_url":"https://avatars.githubusercontent.com/u/1914772?v=3","gravatar_id":"","url":"https://api.github.com/users/ArduSat","html_url":"https://github.com/ArduSat","followers_url":"https://api.github.com/users/ArduSat/followers","following_url":"https://api.github.com/users/ArduSat/following{/other_user}","gists_url":"https://api.github.com/users/ArduSat/gists{/gist_id}","starred_url":"https://api.github.com/users/ArduSat/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ArduSat/subscriptions","organizations_url":"https://api.github.com/users/ArduSat/orgs","repos_url":"https://api.github.com/users/ArduSat/repos","events_url":"https://api.github.com/users/ArduSat/events{/privacy}","received_events_url":"https://api.github.com/users/ArduSat/received_events","type":"Organization","site_admin":false},"repo":{"id":24110495,"name":"ArdusatSDK","full_name":"ArduSat/ArdusatSDK","owner":{"login":"ArduSat","id":1914772,"avatar_url":"https://avatars.githubusercontent.com/u/1914772?v=3","gravatar_id":"","url":"https://api.github.com/users/ArduSat","html_url":"https://github.com/ArduSat","followers_url":"https://api.github.com/users/ArduSat/followers","following_url":"https://api.github.com/users/ArduSat/following{/other_user}","gists_url":"https://api.github.com/users/ArduSat/gists{/gist_id}","starred_url":"https://api.github.com/users/ArduSat/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ArduSat/subscriptions","organizations_url":"https://api.github.com/users/ArduSat/orgs","repos_url":"https://api.github.com/users/ArduSat/repos","events_url":"https://api.github.com/users/ArduSat/events{/privacy}","received_events_url":"https://api.github.com/users/ArduSat/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/ArduSat/ArdusatSDK","description":"Ardusat Sensors SDK","fork":false,"url":"https://api.github.com/repos/ArduSat/ArdusatSDK","forks_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/forks","keys_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/keys{/key_id}","collaborators_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/teams","hooks_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/hooks","issue_events_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/issues/events{/number}","events_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/events","assignees_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/assignees{/user}","branches_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/branches{/branch}","tags_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/tags","blobs_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/git/refs{/sha}","trees_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/git/trees{/sha}","statuses_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/statuses/{sha}","languages_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/languages","stargazers_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/stargazers","contributors_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/contributors","subscribers_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/subscribers","subscription_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/subscription","commits_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/commits{/sha}","git_commits_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/git/commits{/sha}","comments_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/comments{/number}","issue_comment_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/issues/comments{/number}","contents_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/contents/{+path}","compare_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/compare/{base}...{head}","merges_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/merges","archive_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/downloads","issues_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/issues{/number}","pulls_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/pulls{/number}","milestones_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/milestones{/number}","notifications_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/labels{/name}","releases_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/releases{/id}","deployments_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/deployments","created_at":"2014-09-16T17:42:33Z","updated_at":"2016-04-16T10:16:08Z","pushed_at":"2016-05-27T21:01:07Z","git_url":"git://github.com/ArduSat/ArdusatSDK.git","ssh_url":"git@github.com:ArduSat/ArdusatSDK.git","clone_url":"https://github.com/ArduSat/ArdusatSDK.git","svn_url":"https://github.com/ArduSat/ArdusatSDK","homepage":null,"size":508,"stargazers_count":15,"watchers_count":15,"language":"C++","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":11,"mirror_url":null,"open_issues_count":2,"forks":11,"open_issues":2,"watchers":15,"default_branch":"master"}},"base":{"label":"ArduSat:master","ref":"master","sha":"b587c06b29a09b4d2f2094b9841d3f2f682799e8","user":{"login":"ArduSat","id":1914772,"avatar_url":"https://avatars.githubusercontent.com/u/1914772?v=3","gravatar_id":"","url":"https://api.github.com/users/ArduSat","html_url":"https://github.com/ArduSat","followers_url":"https://api.github.com/users/ArduSat/followers","following_url":"https://api.github.com/users/ArduSat/following{/other_user}","gists_url":"https://api.github.com/users/ArduSat/gists{/gist_id}","starred_url":"https://api.github.com/users/ArduSat/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ArduSat/subscriptions","organizations_url":"https://api.github.com/users/ArduSat/orgs","repos_url":"https://api.github.com/users/ArduSat/repos","events_url":"https://api.github.com/users/ArduSat/events{/privacy}","received_events_url":"https://api.github.com/users/ArduSat/received_events","type":"Organization","site_admin":false},"repo":{"id":24110495,"name":"ArdusatSDK","full_name":"ArduSat/ArdusatSDK","owner":{"login":"ArduSat","id":1914772,"avatar_url":"https://avatars.githubusercontent.com/u/1914772?v=3","gravatar_id":"","url":"https://api.github.com/users/ArduSat","html_url":"https://github.com/ArduSat","followers_url":"https://api.github.com/users/ArduSat/followers","following_url":"https://api.github.com/users/ArduSat/following{/other_user}","gists_url":"https://api.github.com/users/ArduSat/gists{/gist_id}","starred_url":"https://api.github.com/users/ArduSat/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ArduSat/subscriptions","organizations_url":"https://api.github.com/users/ArduSat/orgs","repos_url":"https://api.github.com/users/ArduSat/repos","events_url":"https://api.github.com/users/ArduSat/events{/privacy}","received_events_url":"https://api.github.com/users/ArduSat/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/ArduSat/ArdusatSDK","description":"Ardusat Sensors SDK","fork":false,"url":"https://api.github.com/repos/ArduSat/ArdusatSDK","forks_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/forks","keys_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/keys{/key_id}","collaborators_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/teams","hooks_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/hooks","issue_events_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/issues/events{/number}","events_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/events","assignees_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/assignees{/user}","branches_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/branches{/branch}","tags_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/tags","blobs_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/git/refs{/sha}","trees_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/git/trees{/sha}","statuses_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/statuses/{sha}","languages_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/languages","stargazers_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/stargazers","contributors_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/contributors","subscribers_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/subscribers","subscription_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/subscription","commits_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/commits{/sha}","git_commits_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/git/commits{/sha}","comments_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/comments{/number}","issue_comment_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/issues/comments{/number}","contents_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/contents/{+path}","compare_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/compare/{base}...{head}","merges_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/merges","archive_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/downloads","issues_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/issues{/number}","pulls_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/pulls{/number}","milestones_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/milestones{/number}","notifications_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/labels{/name}","releases_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/releases{/id}","deployments_url":"https://api.github.com/repos/ArduSat/ArdusatSDK/deployments","created_at":"2014-09-16T17:42:33Z","updated_at":"2016-04-16T10:16:08Z","pushed_at":"2016-05-27T21:01:07Z","git_url":"git://github.com/ArduSat/ArdusatSDK.git","ssh_url":"git@github.com:ArduSat/ArdusatSDK.git","clone_url":"https://github.com/ArduSat/ArdusatSDK.git","svn_url":"https://github.com/ArduSat/ArdusatSDK","homepage":null,"size":508,"stargazers_count":15,"watchers_count":15,"language":"C++","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":11,"mirror_url":null,"open_issues_count":2,"forks":11,"open_issues":2,"watchers":15,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/ArduSat/ArdusatSDK/pulls/11"},"html":{"href":"https://github.com/ArduSat/ArdusatSDK/pull/11"},"issue":{"href":"https://api.github.com/repos/ArduSat/ArdusatSDK/issues/11"},"comments":{"href":"https://api.github.com/repos/ArduSat/ArdusatSDK/issues/11/comments"},"review_comments":{"href":"https://api.github.com/repos/ArduSat/ArdusatSDK/pulls/11/comments"},"review_comment":{"href":"https://api.github.com/repos/ArduSat/ArdusatSDK/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/ArduSat/ArdusatSDK/pulls/11/commits"},"statuses":{"href":"https://api.github.com/repos/ArduSat/ArdusatSDK/statuses/b0800fc8c904cdfb9ad54b19af013c90bc94551d"}}}}
{"actor":{"display_login":"bencpeters"}}