/* File: SensorWrapper.h Author: J. Ian Lindsay Date: 2013.11.28 Copyright 2016 Manuvr, Inc Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. This class is a generic interface to a sensor. That sensor might measure many things. */ #ifndef __SENSOR_WRAPPER_INCLUDE_H #define __SENSOR_WRAPPER_INCLUDE_H #include #include #include "StringBuilder.h" #include "cbor-cpp/cbor.h" #include "CppPotpourri.h" #include "AbstractPlatform.h" #include "EnumeratedTypeCodes.h" class SensorWrapper; /* * We have the option of directing a datum to autoreport under certain conditions. * When such a datum becomes dirty, the SensorWrapper class can call a provided * callback with the entire sensor wrapper as an argument. */ typedef void (*SensorCallBack) (SensorWrapper*); /* Flags for an individual piece of data from a sensor. */ #define SENSE_DATUM_FLAG_HARDWARE 0x8000 // The proximate basis of the data is hardware. #define SENSE_DATUM_FLAG_IS_PROXIED 0x4000 // This datum belongs to another sensor. #define SENSE_DATUM_FLAG_REPORT_MASK 0x3800 // Reporting behavior bits. #define SENSE_DATUM_FLAG_DIRTY 0x0004 // This data was updated since it was last read. #define SENSE_DATUM_FLAG_MEM_ALLOC 0x0002 // Any memory needed for this datum is allocated. #define SENSE_DATUM_FLAG_IS_ACTIVE 0x0001 // Do we care to collect data? #define SENSE_DATUM_FLAG_PRELOAD_MASK 0xC000 // What flags are blown away by preload. /* Flags for the sensor itself. */ #define MANUVR_SENSOR_FLAG_DEVICE_PRESENT 0x0001 // Part was found. #define MANUVR_SENSOR_FLAG_PINS_CONFIGURED 0x0002 // Low-level pin setup is complete. #define MANUVR_SENSOR_FLAG_INITIALIZED 0x0004 // Registers are initialized. #define MANUVR_SENSOR_FLAG_ENABLED 0x0008 // Device is measuring. #define MANUVR_SENSOR_FLAG_CALIBRATED 0x1000 /* Sensors can automatically report their values. */ enum class SensorParameter : uint8_t { UNDEFINED = 0, AUTOGAIN = 1, // 0 or 1 SAMPLE_PERIOD = 7 // milliseconds }; /* Sensors can automatically report their values. */ enum class SensorReporting : uint8_t { OFF = 0, NEW_VALUE = 1, EVERY_READ = 2, THRESHOLD = 3, RESERVED_0 = 4, RESERVED_1 = 5, RESERVED_2 = 6, RESERVED_3 = 7 }; /* These are possible error codes. */ enum class SensorError : int8_t { DATA_UPDATED = 1, // There was no error, and fresh data. NO_ERROR = 0, // There was no error. ABSENT = -1, // We failed to talk to the sensor. OUT_OF_MEMORY = -2, // Couldn't allocate memory for some sensor-related task. WRONG_IDENTITY = -3, // Some sensors come with ID markers in them. If we get one wrong, this happens. NOT_LOCAL = -4, // If we try to read or change parameters of a sensor that isn't attached to us. INVALID_PARAM_ID = -5, // If we try to read or change a sensor parameter that isn't supported. INVALID_PARAM = -6, // If we try to set a sensor parameter to something invalid for an existing register. NOT_CALIBRATED = -7, // If we try to read a sensor that is uncalibrated. Not all sensors require this. INVALID_DATUM = -8, // If we try to do an operation on a datum that doesn't exist for this sensor. UNHANDLED_TYPE = -9, // Issued when we ask for a string conversion that we don't support. NULL_POINTER = -10, // What happens when we try to do I/O on a null pointer. BUS_ERROR = -11, // If there was some generic bus error that we otherwise can't pinpoint. BUS_ABSENT = -12, // If the requested bus is not accessible. REG_NOT_WRITABLE = -13, // If we try to write to a read-only register. REG_NOT_DEFINED = -14, // If we try to do I/O on a non-existent register. DATA_EXHAUSTED = -15, // If we try to poll sensor data faster than the sensor can produce it. BAD_TYPE_CONVERT = -16, // If we ask the class to convert types in a way that isn't possible. MISSING_CONF = -17, // If we ask the sensor class to perform an operation on parameters that it doesn't have. NOT_INITIALIZED = -18, // Tried to do something that requires an initialization that hasn't happened. UNIMPLEMENTED = -19, // The requested action was valid, but unimplemented. UNDEFINED_ERR = -128, // }; /* This struct allows us to not replicate const data in precious memory. */ typedef struct sense_datum_def_t { const char* const desc; // A brief description of the datum for humans. const TCode type_id; // The type of the data member. const SIUnit units; // Real-world units that this datum measures. const uint16_t flgs; // Flags to preload into the datum. } DatumDef; /* * This class helps us present and manage the unique data that comes out of each sensor. * Every instance of SensorWrapper should have at least one of these defined for it. */ class SensorDatum { public: const DatumDef* def; // A brief description of the datum for humans. /* Declaration of obligatory overrides. */ virtual void printDebug(StringBuilder*) =0; virtual SensorError printValue(StringBuilder*) =0; virtual SensorError serializeCBOR(StringBuilder*) =0; virtual SensorError serializeRaw(uint8_t*, uint32_t) =0; /* Inline accessors */ inline uint32_t lastUpdate() { return _last_update; }; inline bool isProxied() { return (_flags & SENSE_DATUM_FLAG_IS_PROXIED); }; inline bool mem_ready() { return (_flags & SENSE_DATUM_FLAG_MEM_ALLOC); }; inline bool hardware() { return (_flags & SENSE_DATUM_FLAG_HARDWARE); }; inline bool dirty() { return (_flags & SENSE_DATUM_FLAG_DIRTY); }; inline SensorReporting autoreport() { return ((SensorReporting) (_flags & SENSE_DATUM_FLAG_REPORT_MASK)); }; protected: SensorDatum(const DatumDef* DEF) : def(DEF) {}; //~SensorDatum(); inline void dirty(bool x) { _flags = (x) ? (_flags | SENSE_DATUM_FLAG_DIRTY) : (_flags & ~SENSE_DATUM_FLAG_DIRTY); if (x) _last_update = millis(); }; private: uint16_t _flags = 0; uint32_t _last_update = 0; }; class SensorWrapper { public: /* Declaration of obligatory overrides. */ virtual SensorError init() =0; // Initialize the sensor. virtual SensorError poll() =0; // Polls the class. virtual SensorError reset() =0; // Reset the sensor. virtual SensorError enable(bool) =0; // Should the sensor be enabled? virtual void printDebug(StringBuilder*) =0; virtual SensorError serialize(cbor::encoder*) =0; virtual SensorError serialize(uint8_t*, uint32_t) =0; /* Inline accessors */ inline bool pinsConfigured() { return _sensor_flag(MANUVR_SENSOR_FLAG_PINS_CONFIGURED); }; inline bool devFound() { return _sensor_flag(MANUVR_SENSOR_FLAG_DEVICE_PRESENT); }; inline bool isInitialized() { return _sensor_flag(MANUVR_SENSOR_FLAG_INITIALIZED); }; inline bool isEnabled() { return _sensor_flag(MANUVR_SENSOR_FLAG_ENABLED); }; inline bool isCalibrated() { return _sensor_flag(MANUVR_SENSOR_FLAG_CALIBRATED); }; inline const char* sensorName() { return _name; }; /* Static functions */ static const char* errorString(SensorError); static void printSensorBasicInfo(SensorWrapper*, StringBuilder*); protected: //SensorCallBack ar_callback = nullptr; // The pointer to the callback function used for autoreporting. SensorWrapper(const char*); SensorWrapper(const char*, const char*); ~SensorWrapper(); /* Inline accessors */ inline void pinsConfigured(bool x) { _sensor_set_flag(MANUVR_SENSOR_FLAG_PINS_CONFIGURED, x); }; inline void devFound(bool x) { _sensor_set_flag(MANUVR_SENSOR_FLAG_DEVICE_PRESENT, x); }; inline void isInitialized(bool x) { _sensor_set_flag(MANUVR_SENSOR_FLAG_INITIALIZED, x); }; inline void isEnabled(bool x) { _sensor_set_flag(MANUVR_SENSOR_FLAG_ENABLED, x); }; inline void isCalibrated(bool x) { _sensor_set_flag(MANUVR_SENSOR_FLAG_CALIBRATED, x); }; /* Flag manipulation inlines */ inline uint16_t _sensor_flags() { return _flags; }; inline bool _sensor_flag(uint16_t _flag) { return (_flags & _flag); }; inline void _sensor_clear_flag(uint16_t _flag) { _flags &= ~_flag; }; inline void _sensor_set_flag(uint16_t _flag) { _flags |= _flag; }; inline void _sensor_set_flag(uint16_t _flag, bool nu) { if (nu) _flags |= _flag; else _flags &= ~_flag; }; private: const char* _name; // This is the name of the sensor. uint16_t _flags = 0; // Holds elementary state and capability info. }; #endif // __SENSOR_WRAPPER_INCLUDE_H