diff --git a/CommandAccelStepper/CommandAccelStepper.cpp b/CommandAccelStepper/CommandAccelStepper.cpp index c56299f..d379036 100644 --- a/CommandAccelStepper/CommandAccelStepper.cpp +++ b/CommandAccelStepper/CommandAccelStepper.cpp @@ -195,7 +195,7 @@ void CommandAccelStepper::unrecognized(const char *command) cmdHdl.sendCmdSerial(); } -//Moves the stepper to a specific location +//Moves the stepper to a specific location [i.e. ABSOLUTE MOVE] void CommandAccelStepper::wrapper_moveTo() { CommandAccelStepper* self = (CommandAccelStepper*) globalCommandAccelStepperPt2Object; @@ -218,7 +218,7 @@ void CommandAccelStepper::moveTo() } } -//Moves the stepper x number of steps +//Moves the stepper x number of steps [i.e. RELATIVE MOVE] void CommandAccelStepper::wrapper_move() { CommandAccelStepper* self = (CommandAccelStepper*) globalCommandAccelStepperPt2Object; diff --git a/CommandBME280/CommandBME280.cpp b/CommandBME280/CommandBME280.cpp new file mode 100644 index 0000000..4979107 --- /dev/null +++ b/CommandBME280/CommandBME280.cpp @@ -0,0 +1,243 @@ + +#include "CommandBME280.h" + +void *globalCommandBME280Pt2Object; + +CommandBME280::CommandBME280(){ + BME280 bme280 = BME280(); +} +/** +* register to a CommandManager +*/ +void CommandBME280::registerToCommandManager(CommandManager &cmdMng, const char *command) +{ + cmdMng.addDevice(command, this, wrapper_init, wrapper_handleCommand, wrapper_setHeader, wrapper_update); +} + +/** +* init function to be run once in setup +* we initialize all the callback here +*/ +void CommandBME280::wrapper_init(void *pt2Object) +{ + // explicitly cast to a pointer to Classname + CommandBME280 *self = (CommandBME280 *)pt2Object; + self->init(); +} + +void CommandBME280::init() +{ +#ifdef CommandBME280_DEBUG + Serial.println("Init CommandBME280"); +#endif + + // here register all the commands + // the following is mandatory for the bonjour behavior + cmdHdl.addCommand(BONJOUR_CMD, wrapper_bonjour); + cmdHdl.addCommand(CommandBME280_READ_PRESSURE, wrapper_pressure); + cmdHdl.addCommand(CommandBME280_READ_TEMPERATURE, wrapper_temperature); + cmdHdl.addCommand(CommandBME280_READ_HUMIDITY, wrapper_humidity); + + // the default unrecognized, keep it + cmdHdl.setDefaultHandler(wrapper_unrecognized); + + //Initialize your device first + Serial.begin(115200); + Wire.begin(); + bme280.setI2CAddress(0x76); + + // Prime sensor + if (bme280.beginI2C() != false) + { + #ifdef CommandBME280_DEBUG + Serial.println("Sensor ok!"); + #endif + } + else + { + #ifdef CommandBME280_DEBUG + Serial.println("Cannot connect"); + #endif + } + +} + +/** +* message are redicted here +*/ +void CommandBME280::wrapper_handleCommand(const char *command, void *pt2Object) +{ + // each time the handleCommand is called, it is givben the command and the pointer to the instance that should handle it + globalCommandBME280Pt2Object = pt2Object; + // explicitly cast to a pointer to Classname + CommandBME280 *self = (CommandBME280 *)globalCommandBME280Pt2Object; + + self->handleCommand(command); +} + +void CommandBME280::handleCommand(const char *command) +{ +#ifdef CommandBME280_DEBUG + Serial.print("My pressure sensor received: "); + Serial.println(command); +#endif + + cmdHdl.processString(command); +} + +/** +* set Header for the message that come out of this device +* the wrapper is used by CommandManager +*/ +void CommandBME280::wrapper_setHeader(const char *cmdHeader, void *pt2Object) +{ + // explicitly cast to a pointer to Classname + CommandBME280 *self = (CommandBME280 *)pt2Object; + self->setHeader(cmdHeader); +} + +void CommandBME280::setHeader(const char *cmdHeader) +{ +#ifdef CommandBME280_DEBUG + Serial.print("Set Header CommandBME280 to "); + Serial.println(cmdHeader); +#endif + + cmdHdl.setCmdHeader(cmdHeader); +} + +/** +* update function to be run each loop +*/ +void CommandBME280::wrapper_update(void *pt2Object) +{ + // explicitly cast to a pointer to Classname + CommandBME280 *self = (CommandBME280 *)pt2Object; + self->update(); +} + +// update is empty for pressure sensors +void CommandBME280::update() +{ +} + +/* +* a bonjour behavior enable to know who we are talking to +* change the CommandBME280_BONJOUR_ID and ensure it is unique to your new device +*/ +void CommandBME280::wrapper_bonjour() +{ + // explicitly cast to a pointer to Classname + CommandBME280 *self = (CommandBME280 *)globalCommandBME280Pt2Object; + self->bonjour(); +} + +void CommandBME280::bonjour() +{ +#ifdef CommandBME280_DEBUG + Serial.println("Device received bonjour command"); +#endif + + cmdHdl.initCmd(); + cmdHdl.addCmdString(BONJOUR_CMD); + cmdHdl.addCmdDelim(); + cmdHdl.addCmdString(CommandBME280_BONJOUR_ID); + cmdHdl.addCmdTerm(); + cmdHdl.sendCmdSerial(); +} + +/** +* default unrecognized command and wrapper +* respond a message with heade "?" and the command received as argument +*/ +void CommandBME280::wrapper_unrecognized(const char *command) +{ + // explicitly cast to a pointer to Classname + CommandBME280 *self = (CommandBME280 *)globalCommandBME280Pt2Object; + self->unrecognized(command); +} + +void CommandBME280::unrecognized(const char *command) +{ + cmdHdl.initCmd(); + cmdHdl.addCmdString(UNRECOGNIZED_CMD); + cmdHdl.addCmdDelim(); + cmdHdl.addCmdString(command); + cmdHdl.addCmdTerm(); + cmdHdl.sendCmdSerial(); +} + +/** +* pressure command and wrapper +*/ +void CommandBME280::wrapper_pressure() +{ + // explicitly cast to a pointer to Classname + CommandBME280 *self = (CommandBME280 *)globalCommandBME280Pt2Object; + self->pressure(); +} + +void CommandBME280::pressure() +{ +#ifdef CommandBME280_DEBUG + Serial.println("BME280 received pressure command"); +#endif + + bme280.beginI2C(); + cmdHdl.initCmd(); + cmdHdl.addCmdString(CommandBME280_REPORT_PRESSURE); + cmdHdl.addCmdDelim(); + cmdHdl.addCmdFloat(bme280.readFloatPressure()); + cmdHdl.addCmdTerm(); + cmdHdl.sendCmdSerial(); +} + +/** +* temperature command and wrapper +*/ +void CommandBME280::wrapper_temperature() +{ + // explicitly cast to a pointer to Classname + CommandBME280 *self = (CommandBME280 *)globalCommandBME280Pt2Object; + self->temperature(); +} + +void CommandBME280::temperature() +{ +#ifdef CommandBME280_DEBUG + Serial.println("BME280 received temperature command"); +#endif + + bme280.beginI2C(); + cmdHdl.initCmd(); + cmdHdl.addCmdString(CommandBME280_REPORT_TEMPERATURE); + cmdHdl.addCmdDelim(); + cmdHdl.addCmdFloat(bme280.readTempC()); + cmdHdl.addCmdTerm(); + cmdHdl.sendCmdSerial(); +} + +/** +* humidity command and wrapper +*/ +void CommandBME280::wrapper_humidity() +{ + // explicitly cast to a pointer to Classname + CommandBME280 *self = (CommandBME280 *)globalCommandBME280Pt2Object; + self->humidity(); +} + +void CommandBME280::humidity() +{ +#ifdef CommandBME280_DEBUG + Serial.println("BME280 received humidity command"); +#endif + + bme280.beginI2C(); + cmdHdl.initCmd(); + cmdHdl.addCmdString(CommandBME280_REPORT_HUMIDITY); + cmdHdl.addCmdDelim(); + cmdHdl.addCmdFloat(bme280.readFloatHumidity()); + cmdHdl.addCmdTerm(); + cmdHdl.sendCmdSerial(); +} diff --git a/CommandBME280/CommandBME280.h b/CommandBME280/CommandBME280.h new file mode 100644 index 0000000..d17516b --- /dev/null +++ b/CommandBME280/CommandBME280.h @@ -0,0 +1,77 @@ +#ifndef CommandBME280_h +#define CommandBME280_h + +#if defined(WIRING) && WIRING >= 100 +#include +#elif defined(ARDUINO) && ARDUINO >= 100 +#include +#else + #include +#endif + +#include +#include + +#include + + +#define UNRECOGNIZED_CMD "?" +#define BONJOUR_CMD "BONJOUR" + +// the bonjour id of this device +#define CommandBME280_BONJOUR_ID "BME280" + +// incoming command +#define CommandBME280_READ_PRESSURE "RP" +#define CommandBME280_READ_TEMPERATURE "RT" +#define CommandBME280_READ_HUMIDITY "RH" + +//outgoing command +#define CommandBME280_REPORT_PRESSURE "P" +#define CommandBME280_REPORT_TEMPERATURE "T" +#define CommandBME280_REPORT_HUMIDITY "H" + +// Uncomment the next line to run the library in debug mode (verbose messages) +// #define CommandBME280_DEBUG + +class CommandBME280 { + public: + + CommandBME280(); + + BME280 bme280; + CommandHandler cmdHdl; + + + void registerToCommandManager(CommandManager &cmdMng, const char *command); + + static void wrapper_init(void *pt2Object); + void init(); + + static void wrapper_handleCommand(const char *command, void *pt2Object); + void handleCommand(const char *command); + + static void wrapper_setHeader(const char *command, void *pt2Object); + void setHeader(const char *command); + + static void wrapper_update(void *pt2Object); + void update(); + + private: + static void wrapper_bonjour(); + void bonjour(); + + static void wrapper_unrecognized(const char *command); + void unrecognized(const char *command); + + static void wrapper_pressure(); + void pressure(); + + static void wrapper_temperature(); + void temperature(); + + static void wrapper_humidity(); + void humidity(); +}; + +#endif diff --git a/CommandBME280/example/Demo.ino b/CommandBME280/example/Demo.ino new file mode 100644 index 0000000..96fca93 --- /dev/null +++ b/CommandBME280/example/Demo.ino @@ -0,0 +1,28 @@ + +// Command Handler and Manager for communication +#include +#include + +// Command Handler and Manager for communication +#include "CommandBME280.h" + +// CommandManager object for device registration +CommandManager cmdMgr; + +CommandBME280 cmdbme280; + +void setup() +{ + // Fire up the serial connection + Serial.begin(115200); + + // Register device to the Manager + cmdbme280.registerToCommandManager(cmdMgr, "BME280"); + + cmdMgr.init(); +} + +void loop() +{ + cmdMgr.update(); +} diff --git a/CommandDallasTemperature/CommandDallasTemperature.cpp b/CommandDallasTemperature/CommandDallasTemperature.cpp index 2b93b91..d5930cf 100644 --- a/CommandDallasTemperature/CommandDallasTemperature.cpp +++ b/CommandDallasTemperature/CommandDallasTemperature.cpp @@ -2,11 +2,11 @@ void* globalCommandDallasPtr; -CommandDallas::CommandDallas(int dataPin) +CommandDallas::CommandDallas(OneWire* onewire, int myDeviceIndex) { - OneWire onewire(dataPin); - DallasTemperature myDallas(&onewire); + DallasTemperature myDallas(onewire); dallasTemp = myDallas; + deviceIndex = myDeviceIndex; } // Register to CommandManager @@ -37,9 +37,11 @@ void CommandDallas::init() // Default command cmdHdl.setDefaultHandler(wrapper_unrecognized); + + dallasTemp.begin(); } -// Messages are redirected ehre +// Messages are redirected here void CommandDallas::wrapper_handleCommand(const char *command, void* obj) { globalCommandDallasPtr = obj; @@ -136,12 +138,12 @@ void CommandDallas::celsius() Serial.println("Dallas received celsius command"); #endif + dallasTemp.requestTemperaturesByIndex(deviceIndex); + cmdHdl.initCmd(); cmdHdl.addCmdString(COMMANDDALLAS_REPORT_CELSIUS); cmdHdl.addCmdDelim(); - cmdHdl.addCmdFloat(dallasTemp.getTempC(device)); + cmdHdl.addCmdFloat(dallasTemp.getTempCByIndex(deviceIndex)); cmdHdl.addCmdTerm(); cmdHdl.sendCmdSerial(); } - -// DS18B20 \ No newline at end of file diff --git a/CommandDallasTemperature/CommandDallasTemperature.h b/CommandDallasTemperature/CommandDallasTemperature.h index 4879813..52cd527 100644 --- a/CommandDallasTemperature/CommandDallasTemperature.h +++ b/CommandDallasTemperature/CommandDallasTemperature.h @@ -31,10 +31,11 @@ class CommandDallas { public: - CommandDallas(int); + CommandDallas(OneWire*, int); DallasTemperature dallasTemp; CommandHandler cmdHdl; + int deviceIndex; void registerToCommandManager(CommandManager &cmdMgr, const char *command); @@ -51,8 +52,6 @@ class CommandDallas void update(); private: - typedef uint8_t DeviceAddress[8]; - DeviceAddress device; static void wrapper_bonjour(); void bonjour(); @@ -64,4 +63,4 @@ class CommandDallas void celsius(); }; -#endif \ No newline at end of file +#endif diff --git a/CommandDallasTemperature/examples/Demo/Demo.ino b/CommandDallasTemperature/examples/Demo/Demo.ino new file mode 100644 index 0000000..d6bb2db --- /dev/null +++ b/CommandDallasTemperature/examples/Demo/Demo.ino @@ -0,0 +1,22 @@ +#include +#include +#include + +CommandManager cmdMng; + +OneWire onewire(2); +CommandDallas dallas(&onewire, 0); + +void setup() +{ + Serial.begin(115200); + + dallas.registerToCommandManager(cmdMng, "D1"); + + cmdMng.init(); +} + +void loop() +{ + cmdMng.update(); +} diff --git a/CommandLinearAccelStepperActuator/CommandLinearAccelStepperActuator.cpp b/CommandLinearAccelStepperActuator/CommandLinearAccelStepperActuator.cpp index a950848..cd8ecf7 100644 --- a/CommandLinearAccelStepperActuator/CommandLinearAccelStepperActuator.cpp +++ b/CommandLinearAccelStepperActuator/CommandLinearAccelStepperActuator.cpp @@ -32,7 +32,7 @@ void CommandLinearAccelStepperActuator::init() { Serial.println("Init CommandLinearAccelStepperActuator"); #endif - //do you device init fisrt + //do you device init first linearactuator.init(); // here register all the commands @@ -134,7 +134,7 @@ void CommandLinearAccelStepperActuator::update() { * a bonjour behavior enable to know who we are talking to * change the COMMANDLINEARACCELSTEPPER_BONJOUR_ID and ensure it is unique to your new device * keep COMMANDLINEARACCELSTEPPER_BONJOUR_ID short -* do not forget to change the name ofthis variable apropriately +* do not forget to change the name of this variable appropriately */ void CommandLinearAccelStepperActuator::wrapper_bonjour() { @@ -158,7 +158,7 @@ void CommandLinearAccelStepperActuator::bonjour() { /** * default unrecognized command and wrapper -* respond a message with heade "?" and the command received as argument +* respond a message with header "?" and the command received as argument */ void CommandLinearAccelStepperActuator::wrapper_unrecognized(const char *command) { // explicitly cast to a pointer to Classname diff --git a/CommandMAX31865/CommandMAX31865.cpp b/CommandMAX31865/CommandMAX31865.cpp new file mode 100644 index 0000000..c2d6711 --- /dev/null +++ b/CommandMAX31865/CommandMAX31865.cpp @@ -0,0 +1,239 @@ + +#include "CommandMAX31865.h" + +void* globalCommandMAX31865Pt2Object; + +CommandMAX31865::CommandMAX31865(int RNOMINAL, int RREF, Adafruit_MAX31865* ada) { + this->max31865 = ada; + this->RNOMINAL = RNOMINAL; + this->RREF = RREF; +} + + +/** +* register to a CommandManager +*/ +void CommandMAX31865::registerToCommandManager(CommandManager &cmdMng, const char *command) { + cmdMng.addDevice(command, this, wrapper_init, wrapper_handleCommand, wrapper_setHeader, wrapper_update); +} + +/** +* init function to be run one in setup +* we initialize all the callback here +* the wrapper is used by CommandManager +*/ +void CommandMAX31865::wrapper_init(void* pt2Object) { + // explicitly cast to a pointer to Classname + CommandMAX31865* self = (CommandMAX31865*) pt2Object; + self->init(); +} + +void CommandMAX31865::init() { + #ifdef COMMANDMAX31865_DEBUG + Serial.println("Init CommandMAX31865"); + #endif + + // device init first + Wire.begin(); + + // here register all the commands + // the following is mandatory for the bonjour behavior + cmdHdl.addCommand(BONJOUR_CMD, wrapper_bonjour); + + cmdHdl.addCommand(COMMANDMAX31865_INITIALIZE_SENSOR, wrapper_initialize_sensor); + cmdHdl.addCommand(COMMANDMAX31865_READ_TEMP, wrapper_read_temp); + + // the default unrecognized, keep it + cmdHdl.setDefaultHandler(wrapper_unrecognized); +} + +/** +* handling messages +* the wrapper is used by CommandManager +*/ +void CommandMAX31865::wrapper_handleCommand(const char *command, void* pt2Object) { + // each time the handleCommand is called, it is given the command and the pointer to the instance that should handle it + globalCommandMAX31865Pt2Object = pt2Object; + // explicitly cast to a pointer to Classname + CommandMAX31865* self = (CommandMAX31865*) globalCommandMAX31865Pt2Object; + + self->handleCommand(command); +} + +void CommandMAX31865::handleCommand(const char *command) { + #ifdef COMMANDMAX31865_DEBUG + Serial.print("Device received: "); + Serial.println(command); + #endif + + cmdHdl.processString(command); +} + + +/** +* set Header for the message that come out of this device +* the wrapper is used by CommandManager +*/ +void CommandMAX31865::wrapper_setHeader(const char *cmdHeader, void* pt2Object) { + // explicitly cast to a pointer to Classname + CommandMAX31865* self = (CommandMAX31865*) pt2Object; + self->setHeader(cmdHeader); +} + +void CommandMAX31865::setHeader(const char *cmdHeader) { + #ifdef COMMANDMAX31865_DEBUG + Serial.print("Set Header CommandMAX31865 to "); + Serial.println(cmdHeader); + #endif + + cmdHdl.setCmdHeader(cmdHeader); +} + +/** +* update function to be run each loop +* the wrapper is used by CommandManager +*/ +void CommandMAX31865::wrapper_update(void* pt2Object) { + // explicitly cast to a pointer to Classname + CommandMAX31865* self = (CommandMAX31865*) pt2Object; + self->update(); +} + +void CommandMAX31865::update() { + // do whatever you need to do here, non-blocking things!! + // update should be fast +} + +/* +* a bonjour behavior enable to know who we are talking to +* change the COMMANDMAX31865_BONJOUR_ID and ensure it is unique to your new device +* keep COMMANDMAX31865_BONJOUR_ID short +* do not forget to change the name ofthis variable apropriately +*/ +void CommandMAX31865::wrapper_bonjour() +{ + // explicitly cast to a pointer to Classname + CommandMAX31865* self = (CommandMAX31865*) globalCommandMAX31865Pt2Object; + self->bonjour(); +} + +void CommandMAX31865::bonjour() { + #ifdef COMMANDMAX31865_DEBUG + Serial.println("Device received bonjour command"); + #endif + + cmdHdl.initCmd(); + cmdHdl.addCmdString(BONJOUR_CMD); + cmdHdl.addCmdDelim(); + cmdHdl.addCmdString(MAX31865_BONJOUR_ID); + cmdHdl.addCmdTerm(); + cmdHdl.sendCmdSerial(); +} + +/** +* default unrecognized command and wrapper +* respond a message with heade "?" and the command received as argument +*/ +void CommandMAX31865::wrapper_unrecognized(const char *command) { + // explicitly cast to a pointer to Classname + CommandMAX31865* self = (CommandMAX31865*) globalCommandMAX31865Pt2Object; + self->unrecognized(command); +} + +void CommandMAX31865::unrecognized(const char *command) { + cmdHdl.initCmd(); + cmdHdl.addCmdString(UNRECOGNIZED_CMD); + cmdHdl.addCmdDelim(); + cmdHdl.addCmdString(command); + cmdHdl.addCmdTerm(); + cmdHdl.sendCmdSerial(); +} + +/** +* below you can add the command specific to your device +* such function should be quick to execute, non-blocking +* most of the work should be done iteratively in update, always non-blocking functionality +* Also as it is a class, do not forget to use wrappers for callbacks +*/ + +/* + Initilize the sensor. +*/ +void CommandMAX31865::wrapper_initialize_sensor() { + // explicitly cast to a pointer to Classname + CommandMAX31865* self = (CommandMAX31865*) globalCommandMAX31865Pt2Object; + self->initialize_sensor(); +} + +/* + Actually initialize the sensor. Begins communication and print 1 on success and 0 on failure. +*/ + +void CommandMAX31865::initialize_sensor() { + #ifdef COMMANDMAX31865_DEBUG + Serial.println("MAX31865 initializing sensor"); + #endif + + // (Un)comment lines depending on physical setup + // max31865->begin(MAX31865_2WIRE) + max31865->begin(MAX31865_3WIRE); + // max31865->begin(MAX31865_4WIRE) + + // check if initialization successfull + if (max31865->begin()) { + // constructing command on success + cmdHdl.initCmd(); + cmdHdl.addCmdString(COMMANDMAX31865_INITIALIZE_SENSOR_HEADER); + cmdHdl.addCmdDelim(); + cmdHdl.addCmdInt(1); + cmdHdl.addCmdTerm(); + cmdHdl.sendCmdSerial(); + } else { + // constructing command on failure + cmdHdl.initCmd(); + cmdHdl.addCmdString(COMMANDMAX31865_INITIALIZE_SENSOR_HEADER); + cmdHdl.addCmdDelim(); + cmdHdl.addCmdInt(0); + cmdHdl.addCmdTerm(); + cmdHdl.sendCmdSerial(); + } +} + +/* + Read the temperature +*/ +void CommandMAX31865::wrapper_read_temp() { + // explicitly cast to a pointer to Classname + CommandMAX31865* self = (CommandMAX31865*) globalCommandMAX31865Pt2Object; + self->read_temp(); +} + +/* + Actually read the temperature +*/ +void CommandMAX31865::read_temp() { + #ifdef COMMANDMAX31865_DEBUG + Serial.println("MAX31865 reading temperature"); + #endif + + float temp = max31865->temperature(this->RNOMINAL, this->RREF); + + uint16_t fault = max31865->readFault(); + // add code for no fault + if (!fault) { + uint16_t fault = 0x02; + }; + + // construct command + cmdHdl.initCmd(); + cmdHdl.addCmdString(COMMANDMAX31865_READ_HEADER); + cmdHdl.addCmdDelim(); + cmdHdl.addCmdInt((int) fault); + cmdHdl.addCmdDelim(); + cmdHdl.addCmdFloat(temp); + cmdHdl.addCmdTerm(); + cmdHdl.sendCmdSerial(); + + // clear fault + max31865->clearFault(); +} diff --git a/CommandMAX31865/CommandMAX31865.h b/CommandMAX31865/CommandMAX31865.h new file mode 100644 index 0000000..c1c8bc0 --- /dev/null +++ b/CommandMAX31865/CommandMAX31865.h @@ -0,0 +1,80 @@ +#ifndef CommandMAX31865_h +#define CommandMAX31865_h + +#if defined(WIRING) && WIRING >= 100 + #include +#elif defined(ARDUINO) && ARDUINO >= 100 + #include +#else + #include +#endif + +#include +#include + +#include + +#include + +#define UNRECOGNIZED_CMD "?" +#define BONJOUR_CMD "BONJOUR" + +// the bonjour id of this device +#define MAX31865_BONJOUR_ID "MAX31865" + +// incoming command + + +// outgoing command +#define COMMANDMAX31865_READ_TEMP "R" +#define COMMANDMAX31865_INITIALIZE_SENSOR "Z" + +// outgoing headers +#define COMMANDMAX31865_READ_HEADER "C" +#define COMMANDMAX31865_INITIALIZE_SENSOR_HEADER "E" + +// Uncomment the next line to run the library in debug mode (verbose messages) +// #define COMMANDMAX31865_DEBUG + +class CommandMAX31865 { + public: + CommandMAX31865(int, int, Adafruit_MAX31865*); + CommandHandler cmdHdl; + + void registerToCommandManager(CommandManager &cmdMng, const char *command); + + static void wrapper_init(void* pt2Object); + void init(); + + static void wrapper_handleCommand(const char *command, void* pt2Object); + void handleCommand(const char *command); + + static void wrapper_setHeader(const char *command, void* pt2Object); + void setHeader(const char *command); + + static void wrapper_update(void* pt2Object); + void update(); + + static void wrapper_initialize_sensor(); + void initialize_sensor(); + + static void wrapper_read_temp(); + void read_temp(); + + private: + + static void wrapper_bonjour(); + void bonjour(); + + static void wrapper_unrecognized(const char *command); + void unrecognized(const char *command); + + bool _initialized; + + Adafruit_MAX31865* max31865; + + int RNOMINAL; + int RREF; +}; + +#endif diff --git a/CommandMAX31865/examples/Demo/Demo.ino b/CommandMAX31865/examples/Demo/Demo.ino new file mode 100644 index 0000000..8611029 --- /dev/null +++ b/CommandMAX31865/examples/Demo/Demo.ino @@ -0,0 +1,29 @@ +#include +#include +CommandManager cmdMgr; + + +#include +#include + + +Adafruit_MAX31865 ada(10, 11, 12, 13); +CommandMAX31865 max31865(100, 430, &ada); + +void setup() { + Serial.begin(115200); + + max31865.registerToCommandManager(cmdMgr, "MAX"); + + cmdMgr.init(); +} + +void loop() { + cmdMgr.update(); +} + +/* + To test try the following commands: + MAX,Z; - to initialize sensor + MAX,R; - will print the current readings for fault code and temperature +*/ diff --git a/CommandMCP9600Temperature/CommandMCP9600Temperature.cpp b/CommandMCP9600Temperature/CommandMCP9600Temperature.cpp new file mode 100644 index 0000000..41cf276 --- /dev/null +++ b/CommandMCP9600Temperature/CommandMCP9600Temperature.cpp @@ -0,0 +1,161 @@ +#include "CommandMCP9600Temperature.h" + +void* globalCommandMCP9600Ptr; + +CommandMCP9600::CommandMCP9600( + int i2c_address, + MCP9600_ADCResolution adc_resolution, + MCP9600_ThemocoupleType thermocouple_type, + uint8_t filter_coefficient +) +{ + this->i2c_address=i2c_address; + this->adc_resolution=adc_resolution; + this->thermocouple_type=thermocouple_type; + this->filter_coefficient=filter_coefficient; +} +// Register to CommandManager +void CommandMCP9600::registerToCommandManager(CommandManager &cmdMgr, const char *command) +{ + cmdMgr.addDevice(command, this, wrapper_init, wrapper_handleCommand, wrapper_setHeader, wrapper_update); +} + +/** +Init function to be run once in setup +All callback initialised here +*/ +void CommandMCP9600::wrapper_init(void* obj) +{ + #ifdef CommandMCP9600_DEBUG + Serial.println("Init CommandMCP9600"); + #endif + CommandMCP9600* self = (CommandMCP9600*) obj; + self->init(); +} + +void CommandMCP9600::init() +{ + #ifdef CommandMCP9600_DEBUG + Serial.println("Init CommandMCP9600"); + #endif + + this->mcp9600.begin(this->i2c_address); + this->mcp9600.setADCresolution(this->adc_resolution); + this->mcp9600.setThermocoupleType(this->thermocouple_type); + this->mcp9600.setFilterCoefficient(this->filter_coefficient); + + // Register all commands + cmdHdl.addCommand(BONJOUR_CMD, wrapper_bonjour); + cmdHdl.addCommand(CommandMCP9600_REQUEST_CELSIUS, wrapper_celsius); + + // Default command + cmdHdl.setDefaultHandler(wrapper_unrecognized); + + this->mcp9600.enable(true); +} + +// Messages are redirected here +void CommandMCP9600::wrapper_handleCommand(const char *command, void* obj) +{ + globalCommandMCP9600Ptr = obj; + CommandMCP9600* self = (CommandMCP9600*) globalCommandMCP9600Ptr; + self->handleCommand(command); +} + +void CommandMCP9600::handleCommand(const char *command) +{ + #ifdef CommandMCP9600_DEBUG + Serial.println("Temp Received"); + Serial.println(command); + #endif + + cmdHdl.processString(command); +} + +// Set the header for the message coming out of the device +void CommandMCP9600::wrapper_setHeader(const char *cmdHeader, void* obj) +{ + CommandMCP9600* self = (CommandMCP9600*) obj; + self->setHeader(cmdHeader); +} + +void CommandMCP9600::setHeader(const char *cmdHeader) +{ + #ifdef CommandMCP9600_DEBUG + Serial.println("Set Header CommandMCP9600 to "); + Serial.println(cmdHeader); + #endif + + cmdHdl.setCmdHeader(cmdHeader); +} + +// Update to be run each loop +void CommandMCP9600::wrapper_update(void* obj) +{ + CommandMCP9600* self = (CommandMCP9600*) obj; + self->update(); +} + +void CommandMCP9600::update(){} + +/** +Bonjour behaviour to know who we're talking to +*/ +void CommandMCP9600::wrapper_bonjour() +{ + CommandMCP9600* self = (CommandMCP9600*) globalCommandMCP9600Ptr; + self->bonjour(); +} + +void CommandMCP9600::bonjour() +{ + #ifdef CommandMCP9600_DEBUG + Serial.println("Device received bonjour command"); + #endif + + cmdHdl.initCmd(); + cmdHdl.addCmdString(BONJOUR_CMD); + cmdHdl.addCmdDelim(); + cmdHdl.addCmdString(CommandMCP9600_BONJOUR_ID); + cmdHdl.addCmdTerm(); + cmdHdl.sendCmdSerial(); +} + +// Default unrecognized command (?) +void CommandMCP9600::wrapper_unrecognized(const char *command) +{ + CommandMCP9600* self = (CommandMCP9600*) globalCommandMCP9600Ptr; + self->unrecognized(command); +} + +void CommandMCP9600::unrecognized(const char *command) +{ + cmdHdl.initCmd(); + cmdHdl.addCmdString(UNRECOGNIZED_CMD); + cmdHdl.addCmdDelim(); + cmdHdl.addCmdString(command); + cmdHdl.addCmdTerm(); + cmdHdl.sendCmdSerial(); +} + +// Celsius +void CommandMCP9600::wrapper_celsius() +{ + CommandMCP9600* self = (CommandMCP9600*) globalCommandMCP9600Ptr; + self->celsius(); +} + +void CommandMCP9600::celsius() +{ + #ifdef CommandMCP9600_DEBUG + Serial.println("MCP9600 received celsius command"); + #endif + + + cmdHdl.initCmd(); + cmdHdl.addCmdString(CommandMCP9600_REPORT_CELSIUS); + cmdHdl.addCmdDelim(); + cmdHdl.addCmdFloat(this->mcp9600.readThermocouple()); + cmdHdl.addCmdTerm(); + cmdHdl.sendCmdSerial(); +} diff --git a/CommandMCP9600Temperature/CommandMCP9600Temperature.h b/CommandMCP9600Temperature/CommandMCP9600Temperature.h new file mode 100644 index 0000000..ec03cdb --- /dev/null +++ b/CommandMCP9600Temperature/CommandMCP9600Temperature.h @@ -0,0 +1,76 @@ +#ifndef CommandMCP9600Temperature_h +#define CommandMCP9600Temperature_h + +#if defined(WIRING) && WIRING >= 100 + #include +#elif defined(ARDUINO) && ARDUINO >= 100 + #include +#else + #include +#endif + +#include +#include + +#include "Adafruit_MCP9600.h" + +#define UNRECOGNIZED_CMD "?" +#define BONJOUR_CMD "BONJOUR" + +// Bonjour ID of the device +#define CommandMCP9600_BONJOUR_ID "MCP9600" + +// Incoming command +#define CommandMCP9600_REQUEST_CELSIUS "RC" + +// Outgoing command +#define CommandMCP9600_REPORT_CELSIUS "C" +// activate serial +// #define CommandMCP9600_DEBUG 0 + +class CommandMCP9600 +{ +public: + CommandMCP9600( + int i2c_address, + MCP9600_ADCResolution adc_resolution, + MCP9600_ThemocoupleType thermocouple_type, + uint8_t filter_coefficient + ); + + Adafruit_MCP9600 mcp9600; + CommandHandler cmdHdl; + int deviceIndex; + + void registerToCommandManager(CommandManager &cmdMgr, const char *command); + + static void wrapper_init(void* obj); + void init(); + + static void wrapper_handleCommand(const char *command, void* obj); + void handleCommand(const char *command); + + static void wrapper_setHeader(const char *command, void* obj); + void setHeader(const char *command); + + static void wrapper_update(void* obj); + void update(); + +private: + + int i2c_address; + MCP9600_ADCResolution adc_resolution; + MCP9600_ThemocoupleType thermocouple_type; + uint8_t filter_coefficient; + + static void wrapper_bonjour(); + void bonjour(); + + static void wrapper_unrecognized(const char *command); + void unrecognized(const char *command); + + static void wrapper_celsius(); + void celsius(); +}; + +#endif diff --git a/CommandMCP9600Temperature/examples/Demo/Demo.ino b/CommandMCP9600Temperature/examples/Demo/Demo.ino new file mode 100644 index 0000000..52af304 --- /dev/null +++ b/CommandMCP9600Temperature/examples/Demo/Demo.ino @@ -0,0 +1,25 @@ +#include +#include +#include +#include +CommandManager cmdMng; + +CommandMCP9600 mcp9600(0x67, MCP9600_ADCRESOLUTION_18, MCP9600_TYPE_K, 3); +CommandAnalogWrite AW_1(8); + +void setup() +{ + Serial.begin(115200); + + mcp9600.registerToCommandManager(cmdMng, "MCP1"); + AW_1.registerToCommandManager(cmdMng, "AW_1"); + + cmdMng.init(); +} + +void loop() +{ + cmdMng.update(); +} +// MCP1,BONJOUR; +// MCP1,MCP9600_RC; \ No newline at end of file diff --git a/CommandPCA9548A/CommandPCA9548A.cpp b/CommandPCA9548A/CommandPCA9548A.cpp new file mode 100644 index 0000000..f79aced --- /dev/null +++ b/CommandPCA9548A/CommandPCA9548A.cpp @@ -0,0 +1,219 @@ + +#include "CommandPCA9548A.h" + +void* globalCommandPCA9548APt2Object; + +CommandPCA9548A::CommandPCA9548A() { + // constructor here +} + +CommandPCA9548A::CommandPCA9548A(int address) { + PCA9548A_I2C_ADDRESS = address; +} + +/** +* register to a CommandManager +*/ +void CommandPCA9548A::registerToCommandManager(CommandManager &cmdMng, const char *command) { + cmdMng.addDevice(command, this, wrapper_init, wrapper_handleCommand, wrapper_setHeader, wrapper_update); +} + +/** +* init function to be run one in setup +* we initialize all the callback here +* the wrapper is used by CommandManager +*/ +void CommandPCA9548A::wrapper_init(void* pt2Object) { + // explicitly cast to a pointer to Classname + CommandPCA9548A* self = (CommandPCA9548A*) pt2Object; + self->init(); +} + +void CommandPCA9548A::init() { + #ifdef PCA9548A_DEBUG + Serial.println("Init CommandPCA9548A"); + #endif + + Wire.begin(); + + // here register all the commands + // the following is mandatory for the bonjour behavior + cmdHdl.addCommand(BONJOUR_CMD, wrapper_bonjour); + cmdHdl.addCommand(COMMANDPCA9548A_WRITE, wrapper_switch_channel); + cmdHdl.addCommand(COMMANDPCA9548A_READ, wrapper_get_channels); + + // the default unrecognized, keep it + cmdHdl.setDefaultHandler(wrapper_unrecognized); +} + +/** +* handling messages +* the wrapper is used by CommandManager +*/ +void CommandPCA9548A::wrapper_handleCommand(const char *command, void* pt2Object) { + // each time the handleCommand is called, it is given the command and the pointer to the instance that should handle it + globalCommandPCA9548APt2Object = pt2Object; + // explicitly cast to a pointer to Classname + CommandPCA9548A* self = (CommandPCA9548A*) globalCommandPCA9548APt2Object; + + self->handleCommand(command); +} + +void CommandPCA9548A::handleCommand(const char *command) { + #ifdef PCA9548A_DEBUG + Serial.print("Device received: "); + Serial.println(command); + #endif + + cmdHdl.processString(command); +} + +/** +* set Header for the message that come out of this device +* the wrapper is used by CommandManager +*/ +void CommandPCA9548A::wrapper_setHeader(const char *cmdHeader, void* pt2Object) { + // explicitly cast to a pointer to Classname + CommandPCA9548A* self = (CommandPCA9548A*) pt2Object; + self->setHeader(cmdHeader); +} + +void CommandPCA9548A::setHeader(const char *cmdHeader) { + #ifdef PCA9548A_DEBUG + Serial.print("Set Header CommandPCA9548A to "); + Serial.println(cmdHeader); + #endif + + cmdHdl.setCmdHeader(cmdHeader); +} + +/** +* update function to be run each loop +* the wrapper is used by CommandManager +*/ +void CommandPCA9548A::wrapper_update(void* pt2Object) { + // explicitly cast to a pointer to Classname + CommandPCA9548A* self = (CommandPCA9548A*) pt2Object; + self->update(); +} + +void CommandPCA9548A::update() { + // do whatever you need to do here, non-blocking things!! + // update should be fast +} + +/* +* a bonjour behavior enable to know who we are talking to +* change the PCA9548A_BONJOUR_ID and ensure it is unique to your new device +* keep PCA9548A_BONJOUR_ID short +* do not forget to change the name ofthis variable apropriately +*/ +void CommandPCA9548A::wrapper_bonjour() +{ + // explicitly cast to a pointer to Classname + CommandPCA9548A* self = (CommandPCA9548A*) globalCommandPCA9548APt2Object; + self->bonjour(); +} + +void CommandPCA9548A::bonjour() { + #ifdef PCA9548A_DEBUG + Serial.println("Device received bonjour command"); + #endif + + cmdHdl.initCmd(); + cmdHdl.addCmdString(BONJOUR_CMD); + cmdHdl.addCmdDelim(); + cmdHdl.addCmdString(PCA9548A_BONJOUR_ID); + cmdHdl.addCmdTerm(); + cmdHdl.sendCmdSerial(); +} + +/** +* default unrecognized command and wrapper +* respond a message with header "?" and the command received as argument +*/ +void CommandPCA9548A::wrapper_unrecognized(const char *command) { + // explicitly cast to a pointer to Classname + CommandPCA9548A* self = (CommandPCA9548A*) globalCommandPCA9548APt2Object; + self->unrecognized(command); +} + +void CommandPCA9548A::unrecognized(const char *command) { + cmdHdl.initCmd(); + cmdHdl.addCmdString(UNRECOGNIZED_CMD); + cmdHdl.addCmdDelim(); + cmdHdl.addCmdString(command); + cmdHdl.addCmdTerm(); + cmdHdl.sendCmdSerial(); +} + +/** +* below you can add the command specific to your device +* such function should be quick to execute, non-blocking +* most of the work should be done iteratively in update, always non-blocking functionality +* Also as it is a class, do not forget to use wrappers for callbacks +*/ + + +/** + Switch MUX channel wrapper +*/ +void CommandPCA9548A::wrapper_switch_channel() { + // explicitly cast to a pointer to Classname + CommandPCA9548A* self = (CommandPCA9548A*) globalCommandPCA9548APt2Object; + self->switch_channel(); +} + +/** Actual switch MUX channel function + * Gets channels mask as a first argument and sends it to the device + */ +void CommandPCA9548A::switch_channel() { + #ifdef PCA9548A_DEBUG + Serial.println("PCA9548A switch_channel()"); + #endif + + char mask = 0; + + // Get mask from argument + mask = cmdHdl.readIntArg(); + //Send mask to the device + Wire.beginTransmission(PCA9548A_I2C_ADDRESS); + Wire.write(mask); + Wire.endTransmission(); + //Release the bus and detach interrupts so that other devices can use it + +} + +/** + Read MUX channels wrapper +*/ +void CommandPCA9548A::wrapper_get_channels() { + // explicitly cast to a pointer to Classname + CommandPCA9548A* self = (CommandPCA9548A*) globalCommandPCA9548APt2Object; + self->get_channels(); +} + +/** Actual read MUX channels function + * Reads channels status byte from MUX and sends it over serial. + */ +void CommandPCA9548A::get_channels() { + #ifdef PCA9548A_DEBUG + Serial.println("PCA9548A get_channels()"); + #endif + + int channels_state; + + Wire.requestFrom(PCA9548A_I2C_ADDRESS, 1); + //while (! Wire.available()){}; + channels_state = Wire.read(); + //Release the bus and detach interrupts so that other devices can use it + + // Construct command + cmdHdl.initCmd(); + cmdHdl.addCmdString(COMMANDPCA9548A_READ_HEADER); + cmdHdl.addCmdDelim(); + cmdHdl.addCmdInt(channels_state); + cmdHdl.addCmdTerm(); + cmdHdl.sendCmdSerial(); + +} \ No newline at end of file diff --git a/CommandPCA9548A/CommandPCA9548A.h b/CommandPCA9548A/CommandPCA9548A.h new file mode 100644 index 0000000..a0b6d8e --- /dev/null +++ b/CommandPCA9548A/CommandPCA9548A.h @@ -0,0 +1,72 @@ +#ifndef CommandPCA9548A_h +#define CommandPCA9548A_h + +#if defined(WIRING) && WIRING >= 100 + #include +#elif defined(ARDUINO) && ARDUINO >= 100 + #include +#else + #include +#endif + +#include +#include +#include + +#define UNRECOGNIZED_CMD "?" +#define BONJOUR_CMD "BONJOUR" + +// Incoming command +#define COMMANDPCA9548A_WRITE "W" +// Outgoing command +#define COMMANDPCA9548A_READ "R" +// Outgoing command header +#define COMMANDPCA9548A_READ_HEADER "C" + +// the bonjour id of this device +#define PCA9548A_BONJOUR_ID "PCA9548A" + +// I2C address with all pull-ups low +static int PCA9548A_I2C_ADDRESS = 0x70; + +// Uncomment the next line to run the library in debug mode (verbose messages) +// #define PCA9548A_DEBUG + +class CommandPCA9548A { + public: + CommandPCA9548A(); + + CommandPCA9548A(int address); + + CommandHandler cmdHdl; + + void registerToCommandManager(CommandManager &cmdMng, const char *command); + + static void wrapper_init(void* pt2Object); + void init(); + + static void wrapper_handleCommand(const char *command, void* pt2Object); + void handleCommand(const char *command); + + static void wrapper_setHeader(const char *command, void* pt2Object); + void setHeader(const char *command); + + static void wrapper_update(void* pt2Object); + void update(); + + static void wrapper_switch_channel(); + void switch_channel(); + + static void wrapper_get_channels(); + void get_channels(); + + private: + + static void wrapper_bonjour(); + void bonjour(); + + static void wrapper_unrecognized(const char *command); + void unrecognized(const char *command); +}; + +#endif diff --git a/CommandPCA9548A/README.md b/CommandPCA9548A/README.md new file mode 100644 index 0000000..0d0a873 --- /dev/null +++ b/CommandPCA9548A/README.md @@ -0,0 +1,17 @@ +# CommandPCA9548A + +Device bonjour id is ```PCA9548A``` + +## Incoming + +| Command ID | operand(s) | Action | +|:-:|---|---| +|```W```| ```int,...``` list of integers [1,8]| Set enabled channels| +|```R```| | Request list of enabled channels
Sends back ```C``` command| + + +## Outgoing + +| Command ID | operand(s) | Action | +|:-:|---|---| +|```C```| ```int,...``` list of integers [1,8]| List of channels currently enabled| diff --git a/CommandPCA9548A/examples/Demo/Demo.ino b/CommandPCA9548A/examples/Demo/Demo.ino new file mode 100644 index 0000000..48cbab8 --- /dev/null +++ b/CommandPCA9548A/examples/Demo/Demo.ino @@ -0,0 +1,30 @@ + +#include +#include +CommandManager cmdMgr; + +#include +CommandPCA9548A mux; + +void setup() +{ + Serial.begin(115200); + + mux.registerToCommandManager(cmdMgr, "MUX"); + + cmdMgr.init(); +} + +void loop() +{ + cmdMgr.update(); +} + + +/** To test try switching the channels on the mux on or off: + * MUX,W,1; // Would switch channel 1 on + * MUX,W,0 // Would switch all channels off + * MUX,W,2; //Would switch channel2 on (bin(2) == 00000010) + * MUX,W,21; //Would switch channels 1,3 and 5 on (bin(21) == 00010101) + **/ + diff --git a/CommandSHT31/CommandSHT31.cpp b/CommandSHT31/CommandSHT31.cpp new file mode 100644 index 0000000..589e06e --- /dev/null +++ b/CommandSHT31/CommandSHT31.cpp @@ -0,0 +1,189 @@ + +#include "CommandSHT31.h" + +void* globalCommandSHT31Pt2Object; + +CommandSHT31::CommandSHT31() { + Adafruit_SHT31 sht31 = Adafruit_SHT31(); +} + +/** +* register to a CommandManager +*/ +void CommandSHT31::registerToCommandManager(CommandManager &cmdMng, const char *command) { + cmdMng.addDevice(command, this, wrapper_init, wrapper_handleCommand, wrapper_setHeader, wrapper_update); +} + + +/** +* init function to be run once in setup +* we initialize all the callback here +*/ +void CommandSHT31::wrapper_init(void* pt2Object) { + // explicitly cast to a pointer to Classname + CommandSHT31* self = (CommandSHT31*) pt2Object; + self->init(); +} + +void CommandSHT31::init() { + #ifdef COMMANDSHT31_DEBUG + Serial.println("Init CommandSHT31"); + #endif + + // here register all the commands + // the following is mandatory for the bonjour behavior + cmdHdl.addCommand(BONJOUR_CMD, wrapper_bonjour); + cmdHdl.addCommand(COMMANDSHT31_REQUEST_CELSIUS, wrapper_celsius); + cmdHdl.addCommand(COMMANDSHT31_REQUEST_HUMIDITY, wrapper_humidity); + + // the default unrecognized, keep it + cmdHdl.setDefaultHandler(wrapper_unrecognized); + + // Initialize Adafruit library + sht31.begin(0x44); +} + +/** +* message are redirected here +*/ +void CommandSHT31::wrapper_handleCommand(const char *command, void* pt2Object) { + // each time the handleCommand is called, it is given the command and the pointer to the instance that should handle it + globalCommandSHT31Pt2Object = pt2Object; + // explicitly cast to a pointer to Classname + CommandSHT31* self = (CommandSHT31*) globalCommandSHT31Pt2Object; + + self->handleCommand(command); +} + +void CommandSHT31::handleCommand(const char *command) { + #ifdef COMMANDSHT31_DEBUG + Serial.print("SHT31 received: "); + Serial.println(command); + #endif + + cmdHdl.processString(command); +} + +/** +* set Header for the message that come out of this device +* the wrapper is used by CommandManager +*/ +void CommandSHT31::wrapper_setHeader(const char *cmdHeader, void* pt2Object) { + // explicitly cast to a pointer to Classname + CommandSHT31* self = (CommandSHT31*) pt2Object; + self->setHeader(cmdHeader); +} + +void CommandSHT31::setHeader(const char *cmdHeader) { + #ifdef COMMANDSHT31_DEBUG + Serial.print("Set Header CommandSHT31 to "); + Serial.println(cmdHeader); + #endif + + cmdHdl.setCmdHeader(cmdHeader); +} + + +/** +* update function to be run each loop +*/ +void CommandSHT31::wrapper_update(void* pt2Object) { + // explicitly cast to a pointer to Classname + CommandSHT31* self = (CommandSHT31*) pt2Object; + self->update(); +} + +// update is empty for temperature sensors +void CommandSHT31::update() { +} + +/* +* a bonjour behavior enable to know who we are talking to +* change the CommandSHT31_BONJOUR_ID and ensure it is unique to your new device +*/ +void CommandSHT31::wrapper_bonjour() +{ + // explicitly cast to a pointer to Classname + CommandSHT31* self = (CommandSHT31*) globalCommandSHT31Pt2Object; + self->bonjour(); +} + +void CommandSHT31::bonjour() { + #ifdef CommandSHT31_DEBUG + Serial.println("Device received bonjour command"); + #endif + + cmdHdl.initCmd(); + cmdHdl.addCmdString(BONJOUR_CMD); + cmdHdl.addCmdDelim(); + cmdHdl.addCmdString(COMMANDSHT31_BONJOUR_ID); + cmdHdl.addCmdTerm(); + cmdHdl.sendCmdSerial(); +} + + +/** +* default unrecognized command and wrapper +* respond a message with header "?" and the command received as argument +*/ +void CommandSHT31::wrapper_unrecognized(const char *command) { + // explicitly cast to a pointer to Classname + CommandSHT31* self = (CommandSHT31*) globalCommandSHT31Pt2Object; + self->unrecognized(command); +} + +void CommandSHT31::unrecognized(const char *command) { + cmdHdl.initCmd(); + cmdHdl.addCmdString(UNRECOGNIZED_CMD); + cmdHdl.addCmdDelim(); + cmdHdl.addCmdString(command); + cmdHdl.addCmdTerm(); + cmdHdl.sendCmdSerial(); +} + + +/** +* celsius command and wrapper +*/ +void CommandSHT31::wrapper_celsius() +{ + // explicitly cast to a pointer to Classname + CommandSHT31* self = (CommandSHT31*) globalCommandSHT31Pt2Object; + self->celsius(); +} + +void CommandSHT31::celsius() { + #ifdef COMMANDSHT31_DEBUG + Serial.println("SHT31 received celsius command"); + #endif + + cmdHdl.initCmd(); + cmdHdl.addCmdString(COMMANDSHT31_REPORT_CELSIUS); + cmdHdl.addCmdDelim(); + cmdHdl.addCmdFloat(sht31.readTemperature()); + cmdHdl.addCmdTerm(); + cmdHdl.sendCmdSerial(); +} + +/** +* humidity command and wrapper +*/ +void CommandSHT31::wrapper_humidity() +{ + // explicitly cast to a pointer to Classname + CommandSHT31* self = (CommandSHT31*) globalCommandSHT31Pt2Object; + self->humidity(); +} + +void CommandSHT31::humidity() { + #ifdef COMMANDSHT31_DEBUG + Serial.println("SHT31 received humidity command"); + #endif + + cmdHdl.initCmd(); + cmdHdl.addCmdString(COMMANDSHT31_REPORT_HUMIDITY); + cmdHdl.addCmdDelim(); + cmdHdl.addCmdFloat(sht31.readHumidity()); + cmdHdl.addCmdTerm(); + cmdHdl.sendCmdSerial(); +} diff --git a/CommandSHT31/CommandSHT31.h b/CommandSHT31/CommandSHT31.h new file mode 100644 index 0000000..b291aca --- /dev/null +++ b/CommandSHT31/CommandSHT31.h @@ -0,0 +1,70 @@ +#ifndef CommandSHT31_h +#define CommandSHT31_h + +#if defined(WIRING) && WIRING >= 100 + #include +#elif defined(ARDUINO) && ARDUINO >= 100 + #include +#else + #include +#endif + +#include +#include + +#include + +#define UNRECOGNIZED_CMD "?" +#define BONJOUR_CMD "BONJOUR" + +// the bonjour id of this device +#define COMMANDSHT31_BONJOUR_ID "SHT31" + +// incoming command +#define COMMANDSHT31_REQUEST_CELSIUS "RC" +#define COMMANDSHT31_REQUEST_HUMIDITY "RH" + +//outgoing command +#define COMMANDSHT31_REPORT_CELSIUS "C" +#define COMMANDSHT31_REPORT_HUMIDITY "H" + +// Uncomment the next line to run the library in debug mode (verbose messages) +// #define COMMANDSHT31_DEBUG + +class CommandSHT31 { + public: + CommandSHT31(); + + Adafruit_SHT31 sht31; + CommandHandler cmdHdl; + + void registerToCommandManager(CommandManager &cmdMng, const char *command); + + static void wrapper_init(void* pt2Object); + void init(); + + static void wrapper_handleCommand(const char *command, void* pt2Object); + void handleCommand(const char *command); + + static void wrapper_setHeader(const char *command, void* pt2Object); + void setHeader(const char *command); + + static void wrapper_update(void* pt2Object); + void update(); + + private: + + static void wrapper_bonjour(); + void bonjour(); + + static void wrapper_unrecognized(const char *command); + void unrecognized(const char *command); + + static void wrapper_celsius(); + void celsius(); + + static void wrapper_humidity(); + void humidity(); +}; + +#endif diff --git a/CommandSHT31/README.md b/CommandSHT31/README.md new file mode 100644 index 0000000..1591010 --- /dev/null +++ b/CommandSHT31/README.md @@ -0,0 +1,18 @@ +# CommandServo + +Device bonjour id is ```SHT31``` + +## Incoming + +| Command ID | operand(s) | Action | +|:-:|---|---| +|```RC```| | Request temperature in Celsius
Send back ```C``` command| +|```RH```| | Request humidity in percent
Send back ```H``` command| + + +## Outgoing + +| Command ID | operand(s) | Action | +|:-:|---|---| +|```C```| ```float``` temperature in Celsius| Actual temperature in Celsius| +|```H```| ```float``` humidity [0,100]| Actual humidity in percentage| diff --git a/CommandSHT31/examples/Demo/Demo.ino b/CommandSHT31/examples/Demo/Demo.ino new file mode 100644 index 0000000..daa0b1b --- /dev/null +++ b/CommandSHT31/examples/Demo/Demo.ino @@ -0,0 +1,24 @@ +#include +#include +CommandManager cmdMng; + +#include +#include +#include +#include + +CommandSHT31 cmdSHT31; + +void setup() +{ + Serial.begin(115200); + + cmdSHT31.registerToCommandManager(cmdMng, "SHT31"); + + cmdMng.init(); +} + +void loop() +{ + cmdMng.update(); +} diff --git a/CommandTCS34725/CommandTCS34725.cpp b/CommandTCS34725/CommandTCS34725.cpp new file mode 100644 index 0000000..2675c4e --- /dev/null +++ b/CommandTCS34725/CommandTCS34725.cpp @@ -0,0 +1,317 @@ + +#include "CommandTCS34725.h" + +void* globalCommandTCS34725Pt2Object; + +CommandTCS34725::CommandTCS34725() { + // constructor here + Adafruit_TCS34725 tcs34725 = Adafruit_TCS34725(TCS34725_INTEGRATIONTIME_50MS, TCS34725_GAIN_4X); +} + +/** +* register to a CommandManager +*/ +void CommandTCS34725::registerToCommandManager(CommandManager &cmdMng, const char *command) { + cmdMng.addDevice(command, this, wrapper_init, wrapper_handleCommand, wrapper_setHeader, wrapper_update); +} + +/** +* init function to be run one in setup +* we initialize all the callback here +* the wrapper is used by CommandManager +*/ +void CommandTCS34725::wrapper_init(void* pt2Object) { + // explicitly cast to a pointer to Classname + CommandTCS34725* self = (CommandTCS34725*) pt2Object; + self->init(); +} + +void CommandTCS34725::init() { + #ifdef COMMANDTCS34725_DEBUG + Serial.println("Init CommandTCS34725"); + #endif + + // device init first + Wire.begin(); + + // here register all the commands + // the following is mandatory for the bonjour behavior + cmdHdl.addCommand(BONJOUR_CMD, wrapper_bonjour); + + cmdHdl.addCommand(COMMANDTCS34725_INITILIZE_SENSOR, wrapper_initailize_sensor); + cmdHdl.addCommand(COMMANDTCS34725_WRITE_INTEGRATION_TIME, wrapper_set_integration_time); + cmdHdl.addCommand(COMMANDTCS34725_WRITE_GAIN, wrapper_set_gain); + cmdHdl.addCommand(COMMANDTCS34725_READ_RGBC, wrapper_read_rgbc); + + // the default unrecognized, keep it + cmdHdl.setDefaultHandler(wrapper_unrecognized); +} + +/** +* handling messages +* the wrapper is used by CommandManager +*/ +void CommandTCS34725::wrapper_handleCommand(const char *command, void* pt2Object) { + // each time the handleCommand is called, it is given the command and the pointer to the instance that should handle it + globalCommandTCS34725Pt2Object = pt2Object; + // explicitly cast to a pointer to Classname + CommandTCS34725* self = (CommandTCS34725*) globalCommandTCS34725Pt2Object; + + self->handleCommand(command); +} + +void CommandTCS34725::handleCommand(const char *command) { + #ifdef COMMANDTCS34725_DEBUG + Serial.print("Device received: "); + Serial.println(command); + #endif + + cmdHdl.processString(command); +} + + +/** +* set Header for the message that come out of this device +* the wrapper is used by CommandManager +*/ +void CommandTCS34725::wrapper_setHeader(const char *cmdHeader, void* pt2Object) { + // explicitly cast to a pointer to Classname + CommandTCS34725* self = (CommandTCS34725*) pt2Object; + self->setHeader(cmdHeader); +} + +void CommandTCS34725::setHeader(const char *cmdHeader) { + #ifdef COMMANDTCS34725_DEBUG + Serial.print("Set Header CommandTCS34725 to "); + Serial.println(cmdHeader); + #endif + + cmdHdl.setCmdHeader(cmdHeader); +} + +/** +* update function to be run each loop +* the wrapper is used by CommandManager +*/ +void CommandTCS34725::wrapper_update(void* pt2Object) { + // explicitly cast to a pointer to Classname + CommandTCS34725* self = (CommandTCS34725*) pt2Object; + self->update(); +} + +void CommandTCS34725::update() { + // do whatever you need to do here, non-blocking things!! + // update should be fast +} + +/* +* a bonjour behavior enable to know who we are talking to +* change the COMMANDTCS34725_BONJOUR_ID and ensure it is unique to your new device +* keep COMMANDTCS34725_BONJOUR_ID short +* do not forget to change the name ofthis variable apropriately +*/ +void CommandTCS34725::wrapper_bonjour() +{ + // explicitly cast to a pointer to Classname + CommandTCS34725* self = (CommandTCS34725*) globalCommandTCS34725Pt2Object; + self->bonjour(); +} + +void CommandTCS34725::bonjour() { + #ifdef COMMANDTCS34725_DEBUG + Serial.println("Device received bonjour command"); + #endif + + cmdHdl.initCmd(); + cmdHdl.addCmdString(BONJOUR_CMD); + cmdHdl.addCmdDelim(); + cmdHdl.addCmdString(TCS34725_BONJOUR_ID); + cmdHdl.addCmdTerm(); + cmdHdl.sendCmdSerial(); +} + +/** +* default unrecognized command and wrapper +* respond a message with heade "?" and the command received as argument +*/ +void CommandTCS34725::wrapper_unrecognized(const char *command) { + // explicitly cast to a pointer to Classname + CommandTCS34725* self = (CommandTCS34725*) globalCommandTCS34725Pt2Object; + self->unrecognized(command); +} + +void CommandTCS34725::unrecognized(const char *command) { + cmdHdl.initCmd(); + cmdHdl.addCmdString(UNRECOGNIZED_CMD); + cmdHdl.addCmdDelim(); + cmdHdl.addCmdString(command); + cmdHdl.addCmdTerm(); + cmdHdl.sendCmdSerial(); +} + +/** +* below you can add the command specific to your device +* such function should be quick to execute, non-blocking +* most of the work should be done iteratively in update, always non-blocking functionality +* Also as it is a class, do not forget to use wrappers for callbacks +*/ + +/* + Initilize the sensor. +*/ +void CommandTCS34725::wrapper_initailize_sensor() { + // explicitly cast to a pointer to Classname + CommandTCS34725* self = (CommandTCS34725*) globalCommandTCS34725Pt2Object; + self->initialize_sensor(); +} + +/* + Actually initialize the sensor. Begins communication and print 1 on success and 0 on failure. +*/ + +void CommandTCS34725::initialize_sensor() { + #ifdef COMMANDTCS34725_DEBUG + Serial.println("TCS34725 initializing sensor"); + #endif + + // check if initialization successfull + if (tcs34725.begin()) { + // constructing command on success + cmdHdl.initCmd(); + cmdHdl.addCmdString(COMMANDTCS34725_INITILIZE_SENSOR_HEADER); + cmdHdl.addCmdDelim(); + cmdHdl.addCmdInt(1); + cmdHdl.addCmdTerm(); + cmdHdl.sendCmdSerial(); + } else { + // constructing command on failure + cmdHdl.initCmd(); + cmdHdl.addCmdString(COMMANDTCS34725_INITILIZE_SENSOR_HEADER); + cmdHdl.addCmdDelim(); + cmdHdl.addCmdInt(0); + cmdHdl.addCmdTerm(); + cmdHdl.sendCmdSerial(); + } +} + +/* + Set the integration time. +*/ +void CommandTCS34725::wrapper_set_integration_time() { + // explicitly cast to a pointer to Classname + CommandTCS34725* self = (CommandTCS34725*) globalCommandTCS34725Pt2Object; + self->set_integration_time(); +} + +/* + Actually set the integration time. Defines both the sensitivity and resolution of the sensor. +*/ +void CommandTCS34725::set_integration_time() { + #ifdef COMMANDTCS34725_DEBUG + Serial.println("TCS34725 setting integration time"); + #endif + + int integration_time; + + // obtaining the argument + integration_time = cmdHdl.readIntArg(); + // only listed values are possible + // NOTE: every value is mutplied by 10 to avoid floating point reading/calculation + switch (integration_time) { + case 24: // 2.4 ms - 1 cycle - Max count 1024 + tcs34725.setIntegrationTime(TCS34725_INTEGRATIONTIME_2_4MS); + break; + case 240: // 24 ms - 10 cycles - Max count 10240 + tcs34725.setIntegrationTime(TCS34725_INTEGRATIONTIME_24MS); + break; + case 500: // 50 ms - 20 cycles - Max count 20480 + tcs34725.setIntegrationTime(TCS34725_INTEGRATIONTIME_50MS); + break; + case 1010: // 101 ms - 42 cycles - Max count 43008 + tcs34725.setIntegrationTime(TCS34725_INTEGRATIONTIME_101MS); + break; + case 1540: // 154 ms - 64 cycles - Max count 65535 + tcs34725.setIntegrationTime(TCS34725_INTEGRATIONTIME_154MS); + break; + case 7000: // 700 ms - 256 cycles - Max count 65535 + tcs34725.setIntegrationTime(TCS34725_INTEGRATIONTIME_700MS); + break; + default: // 50 ms is a good default + tcs34725.setIntegrationTime(TCS34725_INTEGRATIONTIME_50MS); + } +} + +/* + Set the sensor gain. +*/ +void CommandTCS34725::wrapper_set_gain() { + // explicitly cast to a pointer to Classname + CommandTCS34725* self = (CommandTCS34725*) globalCommandTCS34725Pt2Object; + self->set_gain(); +} + +/* + Actually set the sensor gain. +*/ +void CommandTCS34725::set_gain() { + #ifdef COMMANDTCS34725_DEBUG + Serial.println("TCS34725 setting gain"); + #endif + + int gain; + + // obtaining the argument + gain = cmdHdl.readIntArg(); + // only listed values are possible + switch (gain) { + case 1: + tcs34725.setGain(TCS34725_GAIN_1X); + break; + case 4: + tcs34725.setGain(TCS34725_GAIN_4X); + break; + case 16: + tcs34725.setGain(TCS34725_GAIN_16X); + break; + case 60: + tcs34725.setGain(TCS34725_GAIN_60X); + break; + default: // 4 is a good default + tcs34725.setGain(TCS34725_GAIN_4X); + } +} + +/* + Read the RGBC channels +*/ +void CommandTCS34725::wrapper_read_rgbc() { + // explicitly cast to a pointer to Classname + CommandTCS34725* self = (CommandTCS34725*) globalCommandTCS34725Pt2Object; + self->read_rgbc(); +} + +/* + Read the RGBC channels +*/ +void CommandTCS34725::read_rgbc() { + #ifdef COMMANDTCS34725_DEBUG + Serial.println("TCS34725 reading rgbc"); + #endif + + uint16_t _red, _green, _blue, _clear; + tcs34725.getRawData(&_red, &_green, &_blue, &_clear); + + // construct command + cmdHdl.initCmd(); + cmdHdl.addCmdString(COMMANDTCS34725_READ_HEADER); + cmdHdl.addCmdDelim(); + cmdHdl.addCmdInt(_red); + cmdHdl.addCmdDelim(); + cmdHdl.addCmdInt(_green); + cmdHdl.addCmdDelim(); + cmdHdl.addCmdInt(_blue); + cmdHdl.addCmdDelim(); + cmdHdl.addCmdInt(_clear); + cmdHdl.addCmdTerm(); + cmdHdl.sendCmdSerial(); +} diff --git a/CommandTCS34725/CommandTCS34725.h b/CommandTCS34725/CommandTCS34725.h new file mode 100644 index 0000000..8b68b2f --- /dev/null +++ b/CommandTCS34725/CommandTCS34725.h @@ -0,0 +1,85 @@ +#ifndef CommandTCS34725_h +#define CommandTCS34725_h + +#if defined(WIRING) && WIRING >= 100 + #include +#elif defined(ARDUINO) && ARDUINO >= 100 + #include +#else + #include +#endif + +#include +#include + +#include + +#include + +#define UNRECOGNIZED_CMD "?" +#define BONJOUR_CMD "BONJOUR" + +// the bonjour id of this device +#define TCS34725_BONJOUR_ID "TCS34725" + +// incoming command +#define COMMANDTCS34725_WRITE_INTEGRATION_TIME "I" +#define COMMANDTCS34725_WRITE_GAIN "G" + +// outgoing command +#define COMMANDTCS34725_READ_RGBC "R" +#define COMMANDTCS34725_INITILIZE_SENSOR "Z" + +// outgoing headers +#define COMMANDTCS34725_READ_HEADER "C" +#define COMMANDTCS34725_INITILIZE_SENSOR_HEADER "E" + +// Uncomment the next line to run the library in debug mode (verbose messages) +// #define COMMANDTCS34725_DEBUG + +class CommandTCS34725 { + public: + CommandTCS34725(); + + Adafruit_TCS34725 tcs34725; + + CommandHandler cmdHdl; + + void registerToCommandManager(CommandManager &cmdMng, const char *command); + + static void wrapper_init(void* pt2Object); + void init(); + + static void wrapper_handleCommand(const char *command, void* pt2Object); + void handleCommand(const char *command); + + static void wrapper_setHeader(const char *command, void* pt2Object); + void setHeader(const char *command); + + static void wrapper_update(void* pt2Object); + void update(); + + static void wrapper_initailize_sensor(); + void initialize_sensor(); + + static void wrapper_read_rgbc(); + void read_rgbc(); + + static void wrapper_set_integration_time(); + void set_integration_time(); + + static void wrapper_set_gain(); + void set_gain(); + + private: + + static void wrapper_bonjour(); + void bonjour(); + + static void wrapper_unrecognized(const char *command); + void unrecognized(const char *command); + + bool _initailized; +}; + +#endif diff --git a/CommandTCS34725/examples/Demo/Demo.ino b/CommandTCS34725/examples/Demo/Demo.ino new file mode 100644 index 0000000..2d81d1e --- /dev/null +++ b/CommandTCS34725/examples/Demo/Demo.ino @@ -0,0 +1,25 @@ +#include +#include +CommandManager cmdMgr; + +#include +CommandTCS34725 tcs; + +void setup() { + Serial.begin(115200); + + tcs.registerToCommandManager(cmdMgr, "TCS"); + + cmdMgr.init(); +} + +void loop() { + cmdMgr.update(); +} + +/* + To test try the following commands: + TCS,I,500 - set the integration time to 50 ms + TCS,G,4 - set the channel gain to 4 + TCS,R - will print the current readings for red, green, blue and clear channels +*/ diff --git a/DallasTemperature b/DallasTemperature deleted file mode 160000 index 1fcabde..0000000 --- a/DallasTemperature +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 1fcabde4b12cd29688cdd464edb63c169802555f diff --git a/DallasTemperatureSensor/DallasTemperature.cpp b/DallasTemperatureSensor/DallasTemperature.cpp new file mode 100644 index 0000000..73c9b42 --- /dev/null +++ b/DallasTemperatureSensor/DallasTemperature.cpp @@ -0,0 +1,848 @@ +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. + +#include "DallasTemperature.h" + + +#if ARDUINO >= 100 +#include "Arduino.h" +#else +extern "C" { +#include "WConstants.h" +} +#endif + +// OneWire commands +#define STARTCONVO 0x44 // Tells device to take a temperature reading and put it on the scratchpad +#define COPYSCRATCH 0x48 // Copy EEPROM +#define READSCRATCH 0xBE // Read EEPROM +#define WRITESCRATCH 0x4E // Write to EEPROM +#define RECALLSCRATCH 0xB8 // Reload from last known +#define READPOWERSUPPLY 0xB4 // Determine if device needs parasite power +#define ALARMSEARCH 0xEC // Query bus for devices with an alarm condition + +// Scratchpad locations +#define TEMP_LSB 0 +#define TEMP_MSB 1 +#define HIGH_ALARM_TEMP 2 +#define LOW_ALARM_TEMP 3 +#define CONFIGURATION 4 +#define INTERNAL_BYTE 5 +#define COUNT_REMAIN 6 +#define COUNT_PER_C 7 +#define SCRATCHPAD_CRC 8 + +// Device resolution +#define TEMP_9_BIT 0x1F // 9 bit +#define TEMP_10_BIT 0x3F // 10 bit +#define TEMP_11_BIT 0x5F // 11 bit +#define TEMP_12_BIT 0x7F // 12 bit + +DallasTemperature::DallasTemperature() {} +DallasTemperature::DallasTemperature(OneWire* _oneWire) + +#if REQUIRESALARMS +: _AlarmHandler(&defaultAlarmHandler) +#endif +{ + setOneWire(_oneWire); +} + +bool DallasTemperature::validFamily(const uint8_t* deviceAddress){ + switch (deviceAddress[0]){ + case DS18S20MODEL: + case DS18B20MODEL: + case DS1822MODEL: + case DS1825MODEL: + case DS28EA00MODEL: + return true; + default: + return false; + } +} + +void DallasTemperature::setOneWire(OneWire* _oneWire){ + + _wire = _oneWire; + devices = 0; + parasite = false; + bitResolution = 9; + waitForConversion = true; + checkForConversion = true; + +} + +// initialise the bus +void DallasTemperature::begin(void){ + + DeviceAddress deviceAddress; + + _wire->reset_search(); + devices = 0; // Reset the number of devices when we enumerate wire devices + + while (_wire->search(deviceAddress)){ + + if (validAddress(deviceAddress)){ + + if (!parasite && readPowerSupply(deviceAddress)) parasite = true; + + bitResolution = max(bitResolution, getResolution(deviceAddress)); + + devices++; + } + } + +} + +// returns the number of devices found on the bus +uint8_t DallasTemperature::getDeviceCount(void){ + return devices; +} + +// returns true if address is valid +bool DallasTemperature::validAddress(const uint8_t* deviceAddress){ + return (_wire->crc8(deviceAddress, 7) == deviceAddress[7]); +} + +// finds an address at a given index on the bus +// returns true if the device was found +bool DallasTemperature::getAddress(uint8_t* deviceAddress, uint8_t index){ + + uint8_t depth = 0; + + _wire->reset_search(); + + while (depth <= index && _wire->search(deviceAddress)) { + if (depth == index && validAddress(deviceAddress)) return true; + depth++; + } + + return false; + +} + +// attempt to determine if the device at the given address is connected to the bus +bool DallasTemperature::isConnected(const uint8_t* deviceAddress){ + + ScratchPad scratchPad; + return isConnected(deviceAddress, scratchPad); + +} + +// attempt to determine if the device at the given address is connected to the bus +// also allows for updating the read scratchpad +bool DallasTemperature::isConnected(const uint8_t* deviceAddress, uint8_t* scratchPad) +{ + bool b = readScratchPad(deviceAddress, scratchPad); + return b && (_wire->crc8(scratchPad, 8) == scratchPad[SCRATCHPAD_CRC]); +} + +bool DallasTemperature::readScratchPad(const uint8_t* deviceAddress, uint8_t* scratchPad){ + + // send the reset command and fail fast + int b = _wire->reset(); + if (b == 0) return false; + + _wire->select(deviceAddress); + _wire->write(READSCRATCH); + + // Read all registers in a simple loop + // byte 0: temperature LSB + // byte 1: temperature MSB + // byte 2: high alarm temp + // byte 3: low alarm temp + // byte 4: DS18S20: store for crc + // DS18B20 & DS1822: configuration register + // byte 5: internal use & crc + // byte 6: DS18S20: COUNT_REMAIN + // DS18B20 & DS1822: store for crc + // byte 7: DS18S20: COUNT_PER_C + // DS18B20 & DS1822: store for crc + // byte 8: SCRATCHPAD_CRC + for(uint8_t i = 0; i < 9; i++){ + scratchPad[i] = _wire->read(); + } + + b = _wire->reset(); + return (b == 1); +} + + +void DallasTemperature::writeScratchPad(const uint8_t* deviceAddress, const uint8_t* scratchPad){ + + _wire->reset(); + _wire->select(deviceAddress); + _wire->write(WRITESCRATCH); + _wire->write(scratchPad[HIGH_ALARM_TEMP]); // high alarm temp + _wire->write(scratchPad[LOW_ALARM_TEMP]); // low alarm temp + + // DS1820 and DS18S20 have no configuration register + if (deviceAddress[0] != DS18S20MODEL) _wire->write(scratchPad[CONFIGURATION]); + + _wire->reset(); + + // save the newly written values to eeprom + _wire->select(deviceAddress); + _wire->write(COPYSCRATCH, parasite); + delay(20); // <--- added 20ms delay to allow 10ms long EEPROM write operation (as specified by datasheet) + + if (parasite) delay(10); // 10ms delay + _wire->reset(); + +} + +bool DallasTemperature::readPowerSupply(const uint8_t* deviceAddress){ + + bool ret = false; + _wire->reset(); + _wire->select(deviceAddress); + _wire->write(READPOWERSUPPLY); + if (_wire->read_bit() == 0) ret = true; + _wire->reset(); + return ret; + +} + + +// set resolution of all devices to 9, 10, 11, or 12 bits +// if new resolution is out of range, it is constrained. +void DallasTemperature::setResolution(uint8_t newResolution){ + + bitResolution = constrain(newResolution, 9, 12); + DeviceAddress deviceAddress; + for (int i=0; i newResolution)){ + bitResolution = newResolution; + DeviceAddress deviceAddr; + for (int i=0; iread_bit(); + return (b == 1); +} + +// sends command for all devices on the bus to perform a temperature conversion +void DallasTemperature::requestTemperatures(){ + + _wire->reset(); + _wire->skip(); + _wire->write(STARTCONVO, parasite); + + // ASYNC mode? + if (!waitForConversion) return; + blockTillConversionComplete(bitResolution); + +} + +// sends command for one device to perform a temperature by address +// returns FALSE if device is disconnected +// returns TRUE otherwise +bool DallasTemperature::requestTemperaturesByAddress(const uint8_t* deviceAddress){ + + uint8_t bitResolution = getResolution(deviceAddress); + if (bitResolution == 0){ + return false; //Device disconnected + } + + _wire->reset(); + _wire->select(deviceAddress); + _wire->write(STARTCONVO, parasite); + + // ASYNC mode? + if (!waitForConversion) return true; + + blockTillConversionComplete(bitResolution); + + return true; + +} + + +// Continue to check if the IC has responded with a temperature +void DallasTemperature::blockTillConversionComplete(uint8_t bitResolution){ + + int delms = millisToWaitForConversion(bitResolution); + if (checkForConversion && !parasite){ + unsigned long now = millis(); + while(!isConversionComplete() && (millis() - delms < now)); + } else { + delay(delms); + } + +} + +// returns number of milliseconds to wait till conversion is complete (based on IC datasheet) +int16_t DallasTemperature::millisToWaitForConversion(uint8_t bitResolution){ + + switch (bitResolution){ + case 9: + return 94; + case 10: + return 188; + case 11: + return 375; + default: + return 750; + } + +} + + +// sends command for one device to perform a temp conversion by index +bool DallasTemperature::requestTemperaturesByIndex(uint8_t deviceIndex){ + + DeviceAddress deviceAddress; + getAddress(deviceAddress, deviceIndex); + + return requestTemperaturesByAddress(deviceAddress); + +} + +// Fetch temperature for device index +float DallasTemperature::getTempCByIndex(uint8_t deviceIndex){ + + DeviceAddress deviceAddress; + if (!getAddress(deviceAddress, deviceIndex)){ + return DEVICE_DISCONNECTED_C; + } + + return getTempC((uint8_t*)deviceAddress); + +} + +// Fetch temperature for device index +float DallasTemperature::getTempFByIndex(uint8_t deviceIndex){ + + DeviceAddress deviceAddress; + + if (!getAddress(deviceAddress, deviceIndex)){ + return DEVICE_DISCONNECTED_F; + } + + return getTempF((uint8_t*)deviceAddress); + +} + +// reads scratchpad and returns fixed-point temperature, scaling factor 2^-7 +int16_t DallasTemperature::calculateTemperature(const uint8_t* deviceAddress, uint8_t* scratchPad){ + + int16_t fpTemperature = + (((int16_t) scratchPad[TEMP_MSB]) << 11) | + (((int16_t) scratchPad[TEMP_LSB]) << 3); + + /* + DS1820 and DS18S20 have a 9-bit temperature register. + + Resolutions greater than 9-bit can be calculated using the data from + the temperature, and COUNT REMAIN and COUNT PER °C registers in the + scratchpad. The resolution of the calculation depends on the model. + + While the COUNT PER °C register is hard-wired to 16 (10h) in a + DS18S20, it changes with temperature in DS1820. + + After reading the scratchpad, the TEMP_READ value is obtained by + truncating the 0.5°C bit (bit 0) from the temperature data. The + extended resolution temperature can then be calculated using the + following equation: + + COUNT_PER_C - COUNT_REMAIN + TEMPERATURE = TEMP_READ - 0.25 + -------------------------- + COUNT_PER_C + + Hagai Shatz simplified this to integer arithmetic for a 12 bits + value for a DS18S20, and James Cameron added legacy DS1820 support. + + See - http://myarduinotoy.blogspot.co.uk/2013/02/12bit-result-from-ds18s20.html + */ + + if (deviceAddress[0] == DS18S20MODEL){ + fpTemperature = ((fpTemperature & 0xfff0) << 3) - 16 + + ( + ((scratchPad[COUNT_PER_C] - scratchPad[COUNT_REMAIN]) << 7) / + scratchPad[COUNT_PER_C] + ); + } + + return fpTemperature; +} + + +// returns temperature in 1/128 degrees C or DEVICE_DISCONNECTED_RAW if the +// device's scratch pad cannot be read successfully. +// the numeric value of DEVICE_DISCONNECTED_RAW is defined in +// DallasTemperature.h. It is a large negative number outside the +// operating range of the device +int16_t DallasTemperature::getTemp(const uint8_t* deviceAddress){ + + ScratchPad scratchPad; + if (isConnected(deviceAddress, scratchPad)) return calculateTemperature(deviceAddress, scratchPad); + return DEVICE_DISCONNECTED_RAW; + +} + +// returns temperature in degrees C or DEVICE_DISCONNECTED_C if the +// device's scratch pad cannot be read successfully. +// the numeric value of DEVICE_DISCONNECTED_C is defined in +// DallasTemperature.h. It is a large negative number outside the +// operating range of the device +float DallasTemperature::getTempC(const uint8_t* deviceAddress){ + return rawToCelsius(getTemp(deviceAddress)); +} + +// returns temperature in degrees F or DEVICE_DISCONNECTED_F if the +// device's scratch pad cannot be read successfully. +// the numeric value of DEVICE_DISCONNECTED_F is defined in +// DallasTemperature.h. It is a large negative number outside the +// operating range of the device +float DallasTemperature::getTempF(const uint8_t* deviceAddress){ + return rawToFahrenheit(getTemp(deviceAddress)); +} + +// returns true if the bus requires parasite power +bool DallasTemperature::isParasitePowerMode(void){ + return parasite; +} + + +// IF alarm is not used one can store a 16 bit int of userdata in the alarm +// registers. E.g. an ID of the sensor. +// See github issue #29 + +// note if device is not connected it will fail writing the data. +void DallasTemperature::setUserData(const uint8_t* deviceAddress, int16_t data) +{ + // return when stored value == new value + if(getUserData(deviceAddress) == data) return; + + ScratchPad scratchPad; + if (isConnected(deviceAddress, scratchPad)) + { + scratchPad[HIGH_ALARM_TEMP] = data >> 8; + scratchPad[LOW_ALARM_TEMP] = data & 255; + writeScratchPad(deviceAddress, scratchPad); + } +} + +int16_t DallasTemperature::getUserData(const uint8_t* deviceAddress) +{ + int16_t data = 0; + ScratchPad scratchPad; + if (isConnected(deviceAddress, scratchPad)) + { + data = scratchPad[HIGH_ALARM_TEMP] << 8; + data += scratchPad[LOW_ALARM_TEMP]; + } + return data; +} + +// note If address cannot be found no error will be reported. +int16_t DallasTemperature::getUserDataByIndex(uint8_t deviceIndex) +{ + DeviceAddress deviceAddress; + getAddress(deviceAddress, deviceIndex); + return getUserData((uint8_t*) deviceAddress); +} + +void DallasTemperature::setUserDataByIndex(uint8_t deviceIndex, int16_t data) +{ + DeviceAddress deviceAddress; + getAddress(deviceAddress, deviceIndex); + setUserData((uint8_t*) deviceAddress, data); +} + + +// Convert float Celsius to Fahrenheit +float DallasTemperature::toFahrenheit(float celsius){ + return (celsius * 1.8) + 32; +} + +// Convert float Fahrenheit to Celsius +float DallasTemperature::toCelsius(float fahrenheit){ + return (fahrenheit - 32) * 0.555555556; +} + +// convert from raw to Celsius +float DallasTemperature::rawToCelsius(int16_t raw){ + + if (raw <= DEVICE_DISCONNECTED_RAW) + return DEVICE_DISCONNECTED_C; + // C = RAW/128 + return (float)raw * 0.0078125; + +} + +// convert from raw to Fahrenheit +float DallasTemperature::rawToFahrenheit(int16_t raw){ + + if (raw <= DEVICE_DISCONNECTED_RAW) + return DEVICE_DISCONNECTED_F; + // C = RAW/128 + // F = (C*1.8)+32 = (RAW/128*1.8)+32 = (RAW*0.0140625)+32 + return ((float)raw * 0.0140625) + 32; + +} + +#if REQUIRESALARMS + +/* + +ALARMS: + +TH and TL Register Format + +BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 +S 2^6 2^5 2^4 2^3 2^2 2^1 2^0 + +Only bits 11 through 4 of the temperature register are used +in the TH and TL comparison since TH and TL are 8-bit +registers. If the measured temperature is lower than or equal +to TL or higher than or equal to TH, an alarm condition exists +and an alarm flag is set inside the DS18B20. This flag is +updated after every temperature measurement; therefore, if the +alarm condition goes away, the flag will be turned off after +the next temperature conversion. + +*/ + +// sets the high alarm temperature for a device in degrees Celsius +// accepts a float, but the alarm resolution will ignore anything +// after a decimal point. valid range is -55C - 125C +void DallasTemperature::setHighAlarmTemp(const uint8_t* deviceAddress, char celsius){ + + // return when stored value == new value + if(getHighAlarmTemp(deviceAddress) == celsius) return; + + // make sure the alarm temperature is within the device's range + if (celsius > 125) celsius = 125; + else if (celsius < -55) celsius = -55; + + ScratchPad scratchPad; + if (isConnected(deviceAddress, scratchPad)){ + scratchPad[HIGH_ALARM_TEMP] = (uint8_t)celsius; + writeScratchPad(deviceAddress, scratchPad); + } + +} + +// sets the low alarm temperature for a device in degrees Celsius +// accepts a float, but the alarm resolution will ignore anything +// after a decimal point. valid range is -55C - 125C +void DallasTemperature::setLowAlarmTemp(const uint8_t* deviceAddress, char celsius){ + + // return when stored value == new value + if(getLowAlarmTemp(deviceAddress) == celsius) return; + + // make sure the alarm temperature is within the device's range + if (celsius > 125) celsius = 125; + else if (celsius < -55) celsius = -55; + + ScratchPad scratchPad; + if (isConnected(deviceAddress, scratchPad)){ + scratchPad[LOW_ALARM_TEMP] = (uint8_t)celsius; + writeScratchPad(deviceAddress, scratchPad); + } + +} + +// returns a char with the current high alarm temperature or +// DEVICE_DISCONNECTED for an address +char DallasTemperature::getHighAlarmTemp(const uint8_t* deviceAddress){ + + ScratchPad scratchPad; + if (isConnected(deviceAddress, scratchPad)) return (char)scratchPad[HIGH_ALARM_TEMP]; + return DEVICE_DISCONNECTED_C; + +} + +// returns a char with the current low alarm temperature or +// DEVICE_DISCONNECTED for an address +char DallasTemperature::getLowAlarmTemp(const uint8_t* deviceAddress){ + + ScratchPad scratchPad; + if (isConnected(deviceAddress, scratchPad)) return (char)scratchPad[LOW_ALARM_TEMP]; + return DEVICE_DISCONNECTED_C; + +} + +// resets internal variables used for the alarm search +void DallasTemperature::resetAlarmSearch(){ + + alarmSearchJunction = -1; + alarmSearchExhausted = 0; + for(uint8_t i = 0; i < 7; i++){ + alarmSearchAddress[i] = 0; + } + +} + +// This is a modified version of the OneWire::search method. +// +// Also added the OneWire search fix documented here: +// http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1238032295 +// +// Perform an alarm search. If this function returns a '1' then it has +// enumerated the next device and you may retrieve the ROM from the +// OneWire::address variable. If there are no devices, no further +// devices, or something horrible happens in the middle of the +// enumeration then a 0 is returned. If a new device is found then +// its address is copied to newAddr. Use +// DallasTemperature::resetAlarmSearch() to start over. +bool DallasTemperature::alarmSearch(uint8_t* newAddr){ + + uint8_t i; + char lastJunction = -1; + uint8_t done = 1; + + if (alarmSearchExhausted) return false; + if (!_wire->reset()) return false; + + // send the alarm search command + _wire->write(0xEC, 0); + + for(i = 0; i < 64; i++){ + + uint8_t a = _wire->read_bit( ); + uint8_t nota = _wire->read_bit( ); + uint8_t ibyte = i / 8; + uint8_t ibit = 1 << (i & 7); + + // I don't think this should happen, this means nothing responded, but maybe if + // something vanishes during the search it will come up. + if (a && nota) return false; + + if (!a && !nota){ + if (i == alarmSearchJunction){ + // this is our time to decide differently, we went zero last time, go one. + a = 1; + alarmSearchJunction = lastJunction; + }else if (i < alarmSearchJunction){ + + // take whatever we took last time, look in address + if (alarmSearchAddress[ibyte] & ibit){ + a = 1; + }else{ + // Only 0s count as pending junctions, we've already exhausted the 0 side of 1s + a = 0; + done = 0; + lastJunction = i; + } + }else{ + // we are blazing new tree, take the 0 + a = 0; + alarmSearchJunction = i; + done = 0; + } + // OneWire search fix + // See: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1238032295 + } + + if (a) alarmSearchAddress[ibyte] |= ibit; + else alarmSearchAddress[ibyte] &= ~ibit; + + _wire->write_bit(a); + } + + if (done) alarmSearchExhausted = 1; + for (i = 0; i < 8; i++) newAddr[i] = alarmSearchAddress[i]; + return true; + +} + +// returns true if device address might have an alarm condition +// (only an alarm search can verify this) +bool DallasTemperature::hasAlarm(const uint8_t* deviceAddress){ + + ScratchPad scratchPad; + if (isConnected(deviceAddress, scratchPad)){ + + char temp = calculateTemperature(deviceAddress, scratchPad) >> 7; + + // check low alarm + if (temp <= (char)scratchPad[LOW_ALARM_TEMP]) return true; + + // check high alarm + if (temp >= (char)scratchPad[HIGH_ALARM_TEMP]) return true; + } + + // no alarm + return false; + +} + +// returns true if any device is reporting an alarm condition on the bus +bool DallasTemperature::hasAlarm(void){ + + DeviceAddress deviceAddress; + resetAlarmSearch(); + return alarmSearch(deviceAddress); + +} + +// runs the alarm handler for all devices returned by alarmSearch() +void DallasTemperature::processAlarms(void){ + + resetAlarmSearch(); + DeviceAddress alarmAddr; + + while (alarmSearch(alarmAddr)){ + + if (validAddress(alarmAddr)){ + _AlarmHandler(alarmAddr); + } + + } +} + +// sets the alarm handler +void DallasTemperature::setAlarmHandler(AlarmHandler *handler){ + _AlarmHandler = handler; +} + +// The default alarm handler +void DallasTemperature::defaultAlarmHandler(const uint8_t* deviceAddress){} + +#endif + +#if REQUIRESNEW + +// MnetCS - Allocates memory for DallasTemperature. Allows us to instance a new object +void* DallasTemperature::operator new(unsigned int size){ // Implicit NSS obj size + + void * p; // void pointer + p = malloc(size); // Allocate memory + memset((DallasTemperature*)p,0,size); // Initialise memory + + //!!! CANT EXPLICITLY CALL CONSTRUCTOR - workaround by using an init() methodR - workaround by using an init() method + return (DallasTemperature*) p; // Cast blank region to NSS pointer +} + +// MnetCS 2009 - Free the memory used by this instance +void DallasTemperature::operator delete(void* p){ + + DallasTemperature* pNss = (DallasTemperature*) p; // Cast to NSS pointer + pNss->~DallasTemperature(); // Destruct the object + + free(p); // Free the memory +} + +#endif diff --git a/DallasTemperatureSensor/DallasTemperature.h b/DallasTemperatureSensor/DallasTemperature.h new file mode 100644 index 0000000..fca68bd --- /dev/null +++ b/DallasTemperatureSensor/DallasTemperature.h @@ -0,0 +1,245 @@ +#ifndef DallasTemperature_h +#define DallasTemperature_h + +#define DALLASTEMPLIBVERSION "3.7.7" // To be deprecated + +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. + +// set to true to include code for new and delete operators +#ifndef REQUIRESNEW +#define REQUIRESNEW false +#endif + +// set to true to include code implementing alarm search functions +#ifndef REQUIRESALARMS +#define REQUIRESALARMS true +#endif + +#include +#include + +// Model IDs +#define DS18S20MODEL 0x10 // also DS1820 +#define DS18B20MODEL 0x28 +#define DS1822MODEL 0x22 +#define DS1825MODEL 0x3B +#define DS28EA00MODEL 0x42 + +// Error Codes +#define DEVICE_DISCONNECTED_C -127 +#define DEVICE_DISCONNECTED_F -196.6 +#define DEVICE_DISCONNECTED_RAW -7040 + +typedef uint8_t DeviceAddress[8]; + +class DallasTemperature +{ +public: + + DallasTemperature(); + DallasTemperature(OneWire*); + + void setOneWire(OneWire*); + + // initialise bus + void begin(void); + + // returns the number of devices found on the bus + uint8_t getDeviceCount(void); + + // returns true if address is valid + bool validAddress(const uint8_t*); + + // returns true if address is of the family of sensors the lib supports. + bool validFamily(const uint8_t* deviceAddress); + + // finds an address at a given index on the bus + bool getAddress(uint8_t*, uint8_t); + + // attempt to determine if the device at the given address is connected to the bus + bool isConnected(const uint8_t*); + + // attempt to determine if the device at the given address is connected to the bus + // also allows for updating the read scratchpad + bool isConnected(const uint8_t*, uint8_t*); + + // read device's scratchpad + bool readScratchPad(const uint8_t*, uint8_t*); + + // write device's scratchpad + void writeScratchPad(const uint8_t*, const uint8_t*); + + // read device's power requirements + bool readPowerSupply(const uint8_t*); + + // get global resolution + uint8_t getResolution(); + + // set global resolution to 9, 10, 11, or 12 bits + void setResolution(uint8_t); + + // returns the device resolution: 9, 10, 11, or 12 bits + uint8_t getResolution(const uint8_t*); + + // set resolution of a device to 9, 10, 11, or 12 bits + bool setResolution(const uint8_t*, uint8_t, bool skipGlobalBitResolutionCalculation = false); + + // sets/gets the waitForConversion flag + void setWaitForConversion(bool); + bool getWaitForConversion(void); + + // sets/gets the checkForConversion flag + void setCheckForConversion(bool); + bool getCheckForConversion(void); + + // sends command for all devices on the bus to perform a temperature conversion + void requestTemperatures(void); + + // sends command for one device to perform a temperature conversion by address + bool requestTemperaturesByAddress(const uint8_t*); + + // sends command for one device to perform a temperature conversion by index + bool requestTemperaturesByIndex(uint8_t); + + // returns temperature raw value (12 bit integer of 1/128 degrees C) + int16_t getTemp(const uint8_t*); + + // returns temperature in degrees C + float getTempC(const uint8_t*); + + // returns temperature in degrees F + float getTempF(const uint8_t*); + + // Get temperature for device index (slow) + float getTempCByIndex(uint8_t); + + // Get temperature for device index (slow) + float getTempFByIndex(uint8_t); + + // returns true if the bus requires parasite power + bool isParasitePowerMode(void); + + // Is a conversion complete on the wire? + bool isConversionComplete(void); + + int16_t millisToWaitForConversion(uint8_t); + +#if REQUIRESALARMS + + typedef void AlarmHandler(const uint8_t*); + + // sets the high alarm temperature for a device + // accepts a char. valid range is -55C - 125C + void setHighAlarmTemp(const uint8_t*, char); + + // sets the low alarm temperature for a device + // accepts a char. valid range is -55C - 125C + void setLowAlarmTemp(const uint8_t*, char); + + // returns a signed char with the current high alarm temperature for a device + // in the range -55C - 125C + char getHighAlarmTemp(const uint8_t*); + + // returns a signed char with the current low alarm temperature for a device + // in the range -55C - 125C + char getLowAlarmTemp(const uint8_t*); + + // resets internal variables used for the alarm search + void resetAlarmSearch(void); + + // search the wire for devices with active alarms + bool alarmSearch(uint8_t*); + + // returns true if ia specific device has an alarm + bool hasAlarm(const uint8_t*); + + // returns true if any device is reporting an alarm on the bus + bool hasAlarm(void); + + // runs the alarm handler for all devices returned by alarmSearch() + void processAlarms(void); + + // sets the alarm handler + void setAlarmHandler(const AlarmHandler *); + + // The default alarm handler + static void defaultAlarmHandler(const uint8_t*); + +#endif + + // if no alarm handler is used the two bytes can be used as user data + // example of such usage is an ID. + // note if device is not connected it will fail writing the data. + // note if address cannot be found no error will be reported. + // in short use carefully + void setUserData(const uint8_t*, int16_t ); + void setUserDataByIndex(uint8_t, int16_t ); + int16_t getUserData(const uint8_t* ); + int16_t getUserDataByIndex(uint8_t ); + + // convert from Celsius to Fahrenheit + static float toFahrenheit(float); + + // convert from Fahrenheit to Celsius + static float toCelsius(float); + + // convert from raw to Celsius + static float rawToCelsius(int16_t); + + // convert from raw to Fahrenheit + static float rawToFahrenheit(int16_t); + +#if REQUIRESNEW + + // initialize memory area + void* operator new (unsigned int); + + // delete memory reference + void operator delete(void*); + +#endif + +private: + typedef uint8_t ScratchPad[9]; + + // parasite power on or off + bool parasite; + + // used to determine the delay amount needed to allow for the + // temperature conversion to take place + uint8_t bitResolution; + + // used to requestTemperature with or without delay + bool waitForConversion; + + // used to requestTemperature to dynamically check if a conversion is complete + bool checkForConversion; + + // count of devices on the bus + uint8_t devices; + + // Take a pointer to one wire instance + OneWire* _wire; + + // reads scratchpad and returns the raw temperature + int16_t calculateTemperature(const uint8_t*, uint8_t*); + + void blockTillConversionComplete(uint8_t); + +#if REQUIRESALARMS + + // required for alarmSearch + uint8_t alarmSearchAddress[8]; + char alarmSearchJunction; + uint8_t alarmSearchExhausted; + + // the alarm handler function pointer + AlarmHandler *_AlarmHandler; + +#endif + +}; +#endif diff --git a/DallasTemperatureSensor/examples/Alarm/Alarm.pde b/DallasTemperatureSensor/examples/Alarm/Alarm.pde new file mode 100644 index 0000000..d9c6e6c --- /dev/null +++ b/DallasTemperatureSensor/examples/Alarm/Alarm.pde @@ -0,0 +1,162 @@ +#include +#include + +// Data wire is plugged into port 2 on the Arduino +#define ONE_WIRE_BUS 2 + +// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs) +OneWire oneWire(ONE_WIRE_BUS); + +// Pass our oneWire reference to Dallas Temperature. +DallasTemperature sensors(&oneWire); + +// arrays to hold device addresses +DeviceAddress insideThermometer, outsideThermometer; + +void setup(void) +{ + // start serial port + Serial.begin(9600); + Serial.println("Dallas Temperature IC Control Library Demo"); + + // Start up the library + sensors.begin(); + + // locate devices on the bus + Serial.print("Found "); + Serial.print(sensors.getDeviceCount(), DEC); + Serial.println(" devices."); + + // search for devices on the bus and assign based on an index. + if (!sensors.getAddress(insideThermometer, 0)) Serial.println("Unable to find address for Device 0"); + if (!sensors.getAddress(outsideThermometer, 1)) Serial.println("Unable to find address for Device 1"); + + // show the addresses we found on the bus + Serial.print("Device 0 Address: "); + printAddress(insideThermometer); + Serial.println(); + + Serial.print("Device 0 Alarms: "); + printAlarms(insideThermometer); + Serial.println(); + + Serial.print("Device 1 Address: "); + printAddress(outsideThermometer); + Serial.println(); + + Serial.print("Device 1 Alarms: "); + printAlarms(outsideThermometer); + Serial.println(); + + Serial.println("Setting alarm temps..."); + + // alarm when temp is higher than 30C + sensors.setHighAlarmTemp(insideThermometer, 30); + + // alarm when temp is lower than -10C + sensors.setLowAlarmTemp(insideThermometer, -10); + + // alarm when temp is higher than 31C + sensors.setHighAlarmTemp(outsideThermometer, 31); + + // alarn when temp is lower than 27C + sensors.setLowAlarmTemp(outsideThermometer, 27); + + Serial.print("New Device 0 Alarms: "); + printAlarms(insideThermometer); + Serial.println(); + + Serial.print("New Device 1 Alarms: "); + printAlarms(outsideThermometer); + Serial.println(); +} + +// function to print a device address +void printAddress(DeviceAddress deviceAddress) +{ + for (uint8_t i = 0; i < 8; i++) + { + if (deviceAddress[i] < 16) Serial.print("0"); + Serial.print(deviceAddress[i], HEX); + } +} + +// function to print the temperature for a device +void printTemperature(DeviceAddress deviceAddress) +{ + float tempC = sensors.getTempC(deviceAddress); + Serial.print("Temp C: "); + Serial.print(tempC); + Serial.print(" Temp F: "); + Serial.print(DallasTemperature::toFahrenheit(tempC)); +} + +void printAlarms(uint8_t deviceAddress[]) +{ + char temp; + temp = sensors.getHighAlarmTemp(deviceAddress); + Serial.print("High Alarm: "); + Serial.print(temp, DEC); + Serial.print("C/"); + Serial.print(DallasTemperature::toFahrenheit(temp)); + Serial.print("F | Low Alarm: "); + temp = sensors.getLowAlarmTemp(deviceAddress); + Serial.print(temp, DEC); + Serial.print("C/"); + Serial.print(DallasTemperature::toFahrenheit(temp)); + Serial.print("F"); +} + +// main function to print information about a device +void printData(DeviceAddress deviceAddress) +{ + Serial.print("Device Address: "); + printAddress(deviceAddress); + Serial.print(" "); + printTemperature(deviceAddress); + Serial.println(); +} + +void checkAlarm(DeviceAddress deviceAddress) +{ + if (sensors.hasAlarm(deviceAddress)) + { + Serial.print("ALARM: "); + printData(deviceAddress); + } +} + +void loop(void) +{ + // call sensors.requestTemperatures() to issue a global temperature + // request to all devices on the bus + Serial.print("Requesting temperatures..."); + sensors.requestTemperatures(); + Serial.println("DONE"); + + // Method 1: + // check each address individually for an alarm condition + checkAlarm(insideThermometer); + checkAlarm(outsideThermometer); +/* + // Alternate method: + // Search the bus and iterate through addresses of devices with alarms + + // space for the alarm device's address + DeviceAddress alarmAddr; + + Serial.println("Searching for alarms..."); + + // resetAlarmSearch() must be called before calling alarmSearch() + sensors.resetAlarmSearch(); + + // alarmSearch() returns 0 when there are no devices with alarms + while (sensors.alarmSearch(alarmAddr)) + { + Serial.print("ALARM: "); + printData(alarmAddr); + } +*/ + +} + diff --git a/DallasTemperatureSensor/examples/AlarmHandler/AlarmHandler.pde b/DallasTemperatureSensor/examples/AlarmHandler/AlarmHandler.pde new file mode 100644 index 0000000..e0750d5 --- /dev/null +++ b/DallasTemperatureSensor/examples/AlarmHandler/AlarmHandler.pde @@ -0,0 +1,144 @@ +#include +#include + +// Data wire is plugged into port 2 on the Arduino +#define ONE_WIRE_BUS 2 + +// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs) +OneWire oneWire(ONE_WIRE_BUS); + +// Pass our oneWire reference to Dallas Temperature. +DallasTemperature sensors(&oneWire); + +// arrays to hold device addresses +DeviceAddress insideThermometer, outsideThermometer; + +// function that will be called when an alarm condition exists during DallasTemperatures::processAlarms(); +void newAlarmHandler(uint8_t* deviceAddress) +{ + Serial.println("Alarm Handler Start"); + printAlarmInfo(deviceAddress); + printTemp(deviceAddress); + Serial.println(); + Serial.println("Alarm Handler Finish"); +} + +void printCurrentTemp(DeviceAddress deviceAddress) +{ + printAddress(deviceAddress); + printTemp(deviceAddress); + Serial.println(); +} + +void printAddress(DeviceAddress deviceAddress) +{ + Serial.print("Address: "); + for (uint8_t i = 0; i < 8; i++) + { + if (deviceAddress[i] < 16) Serial.print("0"); + Serial.print(deviceAddress[i], HEX); + } + Serial.print(" "); +} + +void printTemp(DeviceAddress deviceAddress) +{ + float tempC = sensors.getTempC(deviceAddress); + if (tempC != DEVICE_DISCONNECTED_C) + { + Serial.print("Current Temp C: "); + Serial.print(tempC); + } + else Serial.print("DEVICE DISCONNECTED"); + Serial.print(" "); +} + +void printAlarmInfo(DeviceAddress deviceAddress) +{ + char temp; + printAddress(deviceAddress); + temp = sensors.getHighAlarmTemp(deviceAddress); + Serial.print("High Alarm: "); + Serial.print(temp, DEC); + Serial.print("C"); + Serial.print(" Low Alarm: "); + temp = sensors.getLowAlarmTemp(deviceAddress); + Serial.print(temp, DEC); + Serial.print("C"); + Serial.print(" "); +} + +void setup(void) +{ + // start serial port + Serial.begin(9600); + Serial.println("Dallas Temperature IC Control Library Demo"); + + // Start up the library + sensors.begin(); + + // locate devices on the bus + Serial.print("Found "); + Serial.print(sensors.getDeviceCount(), DEC); + Serial.println(" devices."); + + // search for devices on the bus and assign based on an index + if (!sensors.getAddress(insideThermometer, 0)) Serial.println("Unable to find address for Device 0"); + if (!sensors.getAddress(outsideThermometer, 1)) Serial.println("Unable to find address for Device 1"); + + Serial.print("Device insideThermometer "); + printAlarmInfo(insideThermometer); + Serial.println(); + + Serial.print("Device outsideThermometer "); + printAlarmInfo(outsideThermometer); + Serial.println(); + + // set alarm ranges + Serial.println("Setting alarm temps..."); + sensors.setHighAlarmTemp(insideThermometer, 26); + sensors.setLowAlarmTemp(insideThermometer, 22); + sensors.setHighAlarmTemp(outsideThermometer, 25); + sensors.setLowAlarmTemp(outsideThermometer, 21); + + Serial.print("New insideThermometer "); + printAlarmInfo(insideThermometer); + Serial.println(); + + Serial.print("New outsideThermometer "); + printAlarmInfo(outsideThermometer); + Serial.println(); + + // attach alarm handler + sensors.setAlarmHandler(&newAlarmHandler); + +} + +void loop(void) +{ + // ask the devices to measure the temperature + sensors.requestTemperatures(); + + // if an alarm condition exists as a result of the most recent + // requestTemperatures() request, it exists until the next time + // requestTemperatures() is called AND there isn't an alarm condition + // on the device + if (sensors.hasAlarm()) + { + Serial.println("Oh noes! There is at least one alarm on the bus."); + } + + // call alarm handler function defined by sensors.setAlarmHandler + // for each device reporting an alarm + sensors.processAlarms(); + + if (!sensors.hasAlarm()) + { + // just print out the current temperature + printCurrentTemp(insideThermometer); + printCurrentTemp(outsideThermometer); + } + + delay(1000); +} + diff --git a/DallasTemperatureSensor/examples/Multibus_simple/Multibus_simple.ino b/DallasTemperatureSensor/examples/Multibus_simple/Multibus_simple.ino new file mode 100644 index 0000000..a818e07 --- /dev/null +++ b/DallasTemperatureSensor/examples/Multibus_simple/Multibus_simple.ino @@ -0,0 +1,48 @@ +#include +#include + +int oneWirePins[]={3,7};//OneWire DS18x20 temperature sensors on these wires +const int oneWirePinsCount=sizeof(oneWirePins)/sizeof(int); + +OneWire ds18x20[oneWirePinsCount]; +DallasTemperature sensor[oneWirePinsCount]; + + +void setup(void) { + // start serial port + Serial.begin(9600); + Serial.println("Dallas Temperature Multiple Bus Control Library Simple Demo"); + Serial.print("============Ready with "); + Serial.print(oneWirePinsCount); + Serial.println(" Sensors================"); + + // Start up the library on all defined bus-wires + DeviceAddress deviceAddress; + for (int i=0; i +#include + +// Data wire is plugged into port 2 on the Arduino +#define ONE_WIRE_BUS 2 +#define TEMPERATURE_PRECISION 9 + +// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs) +OneWire oneWire(ONE_WIRE_BUS); + +// Pass our oneWire reference to Dallas Temperature. +DallasTemperature sensors(&oneWire); + +// arrays to hold device addresses +DeviceAddress insideThermometer, outsideThermometer; + +void setup(void) +{ + // start serial port + Serial.begin(9600); + Serial.println("Dallas Temperature IC Control Library Demo"); + + // Start up the library + sensors.begin(); + + // locate devices on the bus + Serial.print("Locating devices..."); + Serial.print("Found "); + Serial.print(sensors.getDeviceCount(), DEC); + Serial.println(" devices."); + + // report parasite power requirements + Serial.print("Parasite power is: "); + if (sensors.isParasitePowerMode()) Serial.println("ON"); + else Serial.println("OFF"); + + // Assign address manually. The addresses below will beed to be changed + // to valid device addresses on your bus. Device address can be retrieved + // by using either oneWire.search(deviceAddress) or individually via + // sensors.getAddress(deviceAddress, index) + //insideThermometer = { 0x28, 0x1D, 0x39, 0x31, 0x2, 0x0, 0x0, 0xF0 }; + //outsideThermometer = { 0x28, 0x3F, 0x1C, 0x31, 0x2, 0x0, 0x0, 0x2 }; + + // Search for devices on the bus and assign based on an index. Ideally, + // you would do this to initially discover addresses on the bus and then + // use those addresses and manually assign them (see above) once you know + // the devices on your bus (and assuming they don't change). + // + // method 1: by index + if (!sensors.getAddress(insideThermometer, 0)) Serial.println("Unable to find address for Device 0"); + if (!sensors.getAddress(outsideThermometer, 1)) Serial.println("Unable to find address for Device 1"); + + // method 2: search() + // search() looks for the next device. Returns 1 if a new address has been + // returned. A zero might mean that the bus is shorted, there are no devices, + // or you have already retrieved all of them. It might be a good idea to + // check the CRC to make sure you didn't get garbage. The order is + // deterministic. You will always get the same devices in the same order + // + // Must be called before search() + //oneWire.reset_search(); + // assigns the first address found to insideThermometer + //if (!oneWire.search(insideThermometer)) Serial.println("Unable to find address for insideThermometer"); + // assigns the seconds address found to outsideThermometer + //if (!oneWire.search(outsideThermometer)) Serial.println("Unable to find address for outsideThermometer"); + + // show the addresses we found on the bus + Serial.print("Device 0 Address: "); + printAddress(insideThermometer); + Serial.println(); + + Serial.print("Device 1 Address: "); + printAddress(outsideThermometer); + Serial.println(); + + // set the resolution to 9 bit per device + sensors.setResolution(insideThermometer, TEMPERATURE_PRECISION); + sensors.setResolution(outsideThermometer, TEMPERATURE_PRECISION); + + Serial.print("Device 0 Resolution: "); + Serial.print(sensors.getResolution(insideThermometer), DEC); + Serial.println(); + + Serial.print("Device 1 Resolution: "); + Serial.print(sensors.getResolution(outsideThermometer), DEC); + Serial.println(); +} + +// function to print a device address +void printAddress(DeviceAddress deviceAddress) +{ + for (uint8_t i = 0; i < 8; i++) + { + // zero pad the address if necessary + if (deviceAddress[i] < 16) Serial.print("0"); + Serial.print(deviceAddress[i], HEX); + } +} + +// function to print the temperature for a device +void printTemperature(DeviceAddress deviceAddress) +{ + float tempC = sensors.getTempC(deviceAddress); + Serial.print("Temp C: "); + Serial.print(tempC); + Serial.print(" Temp F: "); + Serial.print(DallasTemperature::toFahrenheit(tempC)); +} + +// function to print a device's resolution +void printResolution(DeviceAddress deviceAddress) +{ + Serial.print("Resolution: "); + Serial.print(sensors.getResolution(deviceAddress)); + Serial.println(); +} + +// main function to print information about a device +void printData(DeviceAddress deviceAddress) +{ + Serial.print("Device Address: "); + printAddress(deviceAddress); + Serial.print(" "); + printTemperature(deviceAddress); + Serial.println(); +} + +/* + * Main function, calls the temperatures in a loop. + */ +void loop(void) +{ + // call sensors.requestTemperatures() to issue a global temperature + // request to all devices on the bus + Serial.print("Requesting temperatures..."); + sensors.requestTemperatures(); + Serial.println("DONE"); + + // print the device information + printData(insideThermometer); + printData(outsideThermometer); +} + diff --git a/DallasTemperatureSensor/examples/Simple/Simple.pde b/DallasTemperatureSensor/examples/Simple/Simple.pde new file mode 100644 index 0000000..68f7276 --- /dev/null +++ b/DallasTemperatureSensor/examples/Simple/Simple.pde @@ -0,0 +1,41 @@ +// Include the libraries we need +#include +#include + +// Data wire is plugged into port 2 on the Arduino +#define ONE_WIRE_BUS 2 + +// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs) +OneWire oneWire(ONE_WIRE_BUS); + +// Pass our oneWire reference to Dallas Temperature. +DallasTemperature sensors(&oneWire); + +/* + * The setup function. We only start the sensors here + */ +void setup(void) +{ + // start serial port + Serial.begin(9600); + Serial.println("Dallas Temperature IC Control Library Demo"); + + // Start up the library + sensors.begin(); +} + +/* + * Main function, get and show the temperature + */ +void loop(void) +{ + // call sensors.requestTemperatures() to issue a global temperature + // request to all devices on the bus + Serial.print("Requesting temperatures..."); + sensors.requestTemperatures(); // Send the command to get temperatures + Serial.println("DONE"); + // After we got the temperatures, we can print them here. + // We use the function ByIndex, and as an example get the temperature from the first sensor only. + Serial.print("Temperature for the device 1 (index 0) is: "); + Serial.println(sensors.getTempCByIndex(0)); +} diff --git a/DallasTemperatureSensor/examples/Single/Single.pde b/DallasTemperatureSensor/examples/Single/Single.pde new file mode 100644 index 0000000..3c4e4b4 --- /dev/null +++ b/DallasTemperatureSensor/examples/Single/Single.pde @@ -0,0 +1,116 @@ +// Include the libraries we need +#include +#include + +// Data wire is plugged into port 2 on the Arduino +#define ONE_WIRE_BUS 2 + +// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs) +OneWire oneWire(ONE_WIRE_BUS); + +// Pass our oneWire reference to Dallas Temperature. +DallasTemperature sensors(&oneWire); + +// arrays to hold device address +DeviceAddress insideThermometer; + +/* + * Setup function. Here we do the basics + */ +void setup(void) +{ + // start serial port + Serial.begin(9600); + Serial.println("Dallas Temperature IC Control Library Demo"); + + // locate devices on the bus + Serial.print("Locating devices..."); + sensors.begin(); + Serial.print("Found "); + Serial.print(sensors.getDeviceCount(), DEC); + Serial.println(" devices."); + + // report parasite power requirements + Serial.print("Parasite power is: "); + if (sensors.isParasitePowerMode()) Serial.println("ON"); + else Serial.println("OFF"); + + // Assign address manually. The addresses below will beed to be changed + // to valid device addresses on your bus. Device address can be retrieved + // by using either oneWire.search(deviceAddress) or individually via + // sensors.getAddress(deviceAddress, index) + // Note that you will need to use your specific address here + //insideThermometer = { 0x28, 0x1D, 0x39, 0x31, 0x2, 0x0, 0x0, 0xF0 }; + + // Method 1: + // Search for devices on the bus and assign based on an index. Ideally, + // you would do this to initially discover addresses on the bus and then + // use those addresses and manually assign them (see above) once you know + // the devices on your bus (and assuming they don't change). + if (!sensors.getAddress(insideThermometer, 0)) Serial.println("Unable to find address for Device 0"); + + // method 2: search() + // search() looks for the next device. Returns 1 if a new address has been + // returned. A zero might mean that the bus is shorted, there are no devices, + // or you have already retrieved all of them. It might be a good idea to + // check the CRC to make sure you didn't get garbage. The order is + // deterministic. You will always get the same devices in the same order + // + // Must be called before search() + //oneWire.reset_search(); + // assigns the first address found to insideThermometer + //if (!oneWire.search(insideThermometer)) Serial.println("Unable to find address for insideThermometer"); + + // show the addresses we found on the bus + Serial.print("Device 0 Address: "); + printAddress(insideThermometer); + Serial.println(); + + // set the resolution to 9 bit (Each Dallas/Maxim device is capable of several different resolutions) + sensors.setResolution(insideThermometer, 9); + + Serial.print("Device 0 Resolution: "); + Serial.print(sensors.getResolution(insideThermometer), DEC); + Serial.println(); +} + +// function to print the temperature for a device +void printTemperature(DeviceAddress deviceAddress) +{ + // method 1 - slower + //Serial.print("Temp C: "); + //Serial.print(sensors.getTempC(deviceAddress)); + //Serial.print(" Temp F: "); + //Serial.print(sensors.getTempF(deviceAddress)); // Makes a second call to getTempC and then converts to Fahrenheit + + // method 2 - faster + float tempC = sensors.getTempC(deviceAddress); + Serial.print("Temp C: "); + Serial.print(tempC); + Serial.print(" Temp F: "); + Serial.println(DallasTemperature::toFahrenheit(tempC)); // Converts tempC to Fahrenheit +} +/* + * Main function. It will request the tempC from the sensors and display on Serial. + */ +void loop(void) +{ + // call sensors.requestTemperatures() to issue a global temperature + // request to all devices on the bus + Serial.print("Requesting temperatures..."); + sensors.requestTemperatures(); // Send the command to get temperatures + Serial.println("DONE"); + + // It responds almost immediately. Let's print out the data + printTemperature(insideThermometer); // Use a simple function to print out the data +} + +// function to print a device address +void printAddress(DeviceAddress deviceAddress) +{ + for (uint8_t i = 0; i < 8; i++) + { + if (deviceAddress[i] < 16) Serial.print("0"); + Serial.print(deviceAddress[i], HEX); + } +} diff --git a/DallasTemperatureSensor/examples/Tester/Tester.pde b/DallasTemperatureSensor/examples/Tester/Tester.pde new file mode 100644 index 0000000..1b7db36 --- /dev/null +++ b/DallasTemperatureSensor/examples/Tester/Tester.pde @@ -0,0 +1,124 @@ +#include +#include + +// Data wire is plugged into port 2 on the Arduino +#define ONE_WIRE_BUS 2 +#define TEMPERATURE_PRECISION 9 // Lower resolution + +// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs) +OneWire oneWire(ONE_WIRE_BUS); + +// Pass our oneWire reference to Dallas Temperature. +DallasTemperature sensors(&oneWire); + +int numberOfDevices; // Number of temperature devices found + +DeviceAddress tempDeviceAddress; // We'll use this variable to store a found device address + +void setup(void) +{ + // start serial port + Serial.begin(9600); + Serial.println("Dallas Temperature IC Control Library Demo"); + + // Start up the library + sensors.begin(); + + // Grab a count of devices on the wire + numberOfDevices = sensors.getDeviceCount(); + + // locate devices on the bus + Serial.print("Locating devices..."); + + Serial.print("Found "); + Serial.print(numberOfDevices, DEC); + Serial.println(" devices."); + + // report parasite power requirements + Serial.print("Parasite power is: "); + if (sensors.isParasitePowerMode()) Serial.println("ON"); + else Serial.println("OFF"); + + // Loop through each device, print out address + for(int i=0;i +#include + +#define ONE_WIRE_BUS_1 2 +#define ONE_WIRE_BUS_2 4 + +OneWire oneWire_in(ONE_WIRE_BUS_1); +OneWire oneWire_out(ONE_WIRE_BUS_2); + +DallasTemperature sensor_inhouse(&oneWire_in); +DallasTemperature sensor_outhouse(&oneWire_out); + +void setup(void) +{ + Serial.begin(9600); + Serial.println("Dallas Temperature Control Library Demo - TwoPin_DS18B20"); + + sensor_inhouse.begin(); + sensor_outhouse.begin(); +} + +void loop(void) +{ + Serial.print("Requesting temperatures..."); + sensor_inhouse.requestTemperatures(); + sensor_outhouse.requestTemperatures(); + Serial.println(" done"); + + Serial.print("Inhouse: "); + Serial.println(sensor_inhouse.getTempCByIndex(0)); + + Serial.print("Outhouse: "); + Serial.println(sensor_outhouse.getTempCByIndex(0)); +} \ No newline at end of file diff --git a/DallasTemperatureSensor/examples/WaitForConversion/WaitForConversion.pde b/DallasTemperatureSensor/examples/WaitForConversion/WaitForConversion.pde new file mode 100644 index 0000000..3adda17 --- /dev/null +++ b/DallasTemperatureSensor/examples/WaitForConversion/WaitForConversion.pde @@ -0,0 +1,66 @@ +#include +#include + +// Data wire is plugged into port 2 on the Arduino +#define ONE_WIRE_BUS 2 + +// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs) +OneWire oneWire(ONE_WIRE_BUS); + +// Pass our oneWire reference to Dallas Temperature. +DallasTemperature sensors(&oneWire); + +void setup(void) +{ + // start serial port + Serial.begin(115200); + Serial.println("Dallas Temperature Control Library - Async Demo"); + Serial.println("\nDemo shows the difference in length of the call\n\n"); + + // Start up the library + sensors.begin(); +} + +void loop(void) +{ + // Request temperature conversion (traditional) + Serial.println("Before blocking requestForConversion"); + unsigned long start = millis(); + + sensors.requestTemperatures(); + + unsigned long stop = millis(); + Serial.println("After blocking requestForConversion"); + Serial.print("Time used: "); + Serial.println(stop - start); + + // get temperature + Serial.print("Temperature: "); + Serial.println(sensors.getTempCByIndex(0)); + Serial.println("\n"); + + // Request temperature conversion - non-blocking / async + Serial.println("Before NON-blocking/async requestForConversion"); + start = millis(); + sensors.setWaitForConversion(false); // makes it async + sensors.requestTemperatures(); + sensors.setWaitForConversion(true); + stop = millis(); + Serial.println("After NON-blocking/async requestForConversion"); + Serial.print("Time used: "); + Serial.println(stop - start); + + + // 9 bit resolution by default + // Note the programmer is responsible for the right delay + // we could do something usefull here instead of the delay + int resolution = 9; + delay(750/ (1 << (12-resolution))); + + // get temperature + Serial.print("Temperature: "); + Serial.println(sensors.getTempCByIndex(0)); + Serial.println("\n\n\n\n"); + + delay(5000); +} diff --git a/DallasTemperatureSensor/examples/WaitForConversion2/WaitForConversion2.pde b/DallasTemperatureSensor/examples/WaitForConversion2/WaitForConversion2.pde new file mode 100644 index 0000000..4322330 --- /dev/null +++ b/DallasTemperatureSensor/examples/WaitForConversion2/WaitForConversion2.pde @@ -0,0 +1,80 @@ +// +// Sample of using Async reading of Dallas Temperature Sensors +// +#include +#include + +// Data wire is plugged into port 2 on the Arduino +#define ONE_WIRE_BUS 2 + +// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs) +OneWire oneWire(ONE_WIRE_BUS); + +// Pass our oneWire reference to Dallas Temperature. +DallasTemperature sensors(&oneWire); + +DeviceAddress tempDeviceAddress; + +int resolution = 12; +unsigned long lastTempRequest = 0; +int delayInMillis = 0; +float temperature = 0.0; +int idle = 0; +// +// SETUP +// +void setup(void) +{ + Serial.begin(115200); + Serial.println("Dallas Temperature Control Library - Async Demo"); + Serial.print("Library Version: "); + Serial.println(DALLASTEMPLIBVERSION); + Serial.println("\n"); + + sensors.begin(); + sensors.getAddress(tempDeviceAddress, 0); + sensors.setResolution(tempDeviceAddress, resolution); + + sensors.setWaitForConversion(false); + sensors.requestTemperatures(); + delayInMillis = 750 / (1 << (12 - resolution)); + lastTempRequest = millis(); + + pinMode(13, OUTPUT); +} + +void loop(void) +{ + + if (millis() - lastTempRequest >= delayInMillis) // waited long enough?? + { + digitalWrite(13, LOW); + Serial.print(" Temperature: "); + temperature = sensors.getTempCByIndex(0); + Serial.println(temperature, resolution - 8); + Serial.print(" Resolution: "); + Serial.println(resolution); + Serial.print("Idle counter: "); + Serial.println(idle); + Serial.println(); + + idle = 0; + + // immediately after fetching the temperature we request a new sample + // in the async modus + // for the demo we let the resolution change to show differences + resolution++; + if (resolution > 12) resolution = 9; + + sensors.setResolution(tempDeviceAddress, resolution); + sensors.requestTemperatures(); + delayInMillis = 750 / (1 << (12 - resolution)); + lastTempRequest = millis(); + } + + digitalWrite(13, HIGH); + // we can do usefull things here + // for the demo we just count the idle time in millis + delay(1); + idle++; +} diff --git a/DallasTemperatureSensor/examples/oneWireSearch/oneWireSearch.ino b/DallasTemperatureSensor/examples/oneWireSearch/oneWireSearch.ino new file mode 100644 index 0000000..44da619 --- /dev/null +++ b/DallasTemperatureSensor/examples/oneWireSearch/oneWireSearch.ino @@ -0,0 +1,67 @@ +// +// FILE: oneWireSearch.ino +// AUTHOR: Rob Tillaart +// VERSION: 0.1.02 +// PURPOSE: scan for 1-Wire devices + code snippet generator +// DATE: 2015-june-30 +// URL: http://forum.arduino.cc/index.php?topic=333923 +// +// inspired by http://www.hacktronics.com/Tutorials/arduino-1-wire-address-finder.html +// +// Released to the public domain +// +// 0.1.00 initial version +// 0.1.01 first published version +// 0.1.02 small output changes + +#include + +void setup() +{ + Serial.begin(115200); + Serial.println("//\n// Start oneWireSearch.ino \n//"); + + for (uint8_t pin = 2; pin < 13; pin++) + { + findDevices(pin); + } + Serial.println("\n//\n// End oneWireSearch.ino \n//"); +} + +void loop() +{ +} + +uint8_t findDevices(int pin) +{ + OneWire ow(pin); + + uint8_t address[8]; + uint8_t count = 0; + + + if (ow.search(address)) + { + Serial.print("\nuint8_t pin"); + Serial.print(pin, DEC); + Serial.println("[][8] = {"); + do { + count++; + Serial.println(" {"); + for (uint8_t i = 0; i < 8; i++) + { + Serial.print("0x"); + if (address[i] < 0x10) Serial.print("0"); + Serial.print(address[i], HEX); + if (i < 7) Serial.print(", "); + } + Serial.println(" },"); + } while (ow.search(address)); + + Serial.println("};"); + Serial.print("// nr devices found: "); + Serial.println(count); + } + + return count; +} diff --git a/DallasTemperatureSensor/examples/setUserData/SetUserData.ino b/DallasTemperatureSensor/examples/setUserData/SetUserData.ino new file mode 100644 index 0000000..44bd797 --- /dev/null +++ b/DallasTemperatureSensor/examples/setUserData/SetUserData.ino @@ -0,0 +1,47 @@ +// +// This sketch does not use the ALARM registers and uses those 2 bytes as a counter +// these 2 bytes can be used for other purposes as well e.g. last temperature or +// a specific ID. +// + +#include +#include + +// Data wire is plugged into port 2 on the Arduino +#define ONE_WIRE_BUS 2 + +// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs) +OneWire oneWire(ONE_WIRE_BUS); + +// Pass our oneWire reference to Dallas Temperature. +DallasTemperature sensors(&oneWire); + +int count = 0; + +void setup(void) +{ + // start serial port + Serial.begin(9600); + Serial.println("Dallas Temperature IC Control Library Demo"); + + // Start up the library + sensors.begin(); + +} + +void loop(void) +{ + // call sensors.requestTemperatures() to issue a global temperature + // request to all devices on the bus + Serial.print("Requesting temperatures..."); + sensors.requestTemperatures(); // Send the command to get temperatures + Serial.println("DONE"); + + Serial.print("Temperature for the device 1 (index 0) is: "); + Serial.println(sensors.getTempCByIndex(0)); + + count++; + sensors.setUserDataByIndex(0, count); + int x = sensors.getUserDataByIndex(0); + Serial.println(count); +} diff --git a/OneWire b/OneWire deleted file mode 160000 index b1ef6b9..0000000 --- a/OneWire +++ /dev/null @@ -1 +0,0 @@ -Subproject commit b1ef6b994fe005aec9e6b23e05010ce88a93fac3 diff --git a/Onewire/OneWire.cpp b/Onewire/OneWire.cpp new file mode 100644 index 0000000..3b6fa82 --- /dev/null +++ b/Onewire/OneWire.cpp @@ -0,0 +1,597 @@ +/* +Copyright (c) 2007, Jim Studt (original old version - many contributors since) + +The latest version of this library may be found at: + http://www.pjrc.com/teensy/td_libs_OneWire.html + +OneWire has been maintained by Paul Stoffregen (paul@pjrc.com) since +January 2010. + +DO NOT EMAIL for technical support, especially not for ESP chips! +All project support questions must be posted on public forums +relevant to the board or chips used. If using Arduino, post on +Arduino's forum. If using ESP, post on the ESP community forums. +There is ABSOLUTELY NO TECH SUPPORT BY PRIVATE EMAIL! + +Github's issue tracker for OneWire should be used only to report +specific bugs. DO NOT request project support via Github. All +project and tech support questions must be posted on forums, not +github issues. If you experience a problem and you are not +absolutely sure it's an issue with the library, ask on a forum +first. Only use github to report issues after experts have +confirmed the issue is with OneWire rather than your project. + +Back in 2010, OneWire was in need of many bug fixes, but had +been abandoned the original author (Jim Studt). None of the known +contributors were interested in maintaining OneWire. Paul typically +works on OneWire every 6 to 12 months. Patches usually wait that +long. If anyone is interested in more actively maintaining OneWire, +please contact Paul (this is pretty much the only reason to use +private email about OneWire). + +OneWire is now very mature code. No changes other than adding +definitions for newer hardware support are anticipated. + +Version 2.3: + Unknown chip fallback mode, Roger Clark + Teensy-LC compatibility, Paul Stoffregen + Search bug fix, Love Nystrom + +Version 2.2: + Teensy 3.0 compatibility, Paul Stoffregen, paul@pjrc.com + Arduino Due compatibility, http://arduino.cc/forum/index.php?topic=141030 + Fix DS18B20 example negative temperature + Fix DS18B20 example's low res modes, Ken Butcher + Improve reset timing, Mark Tillotson + Add const qualifiers, Bertrik Sikken + Add initial value input to crc16, Bertrik Sikken + Add target_search() function, Scott Roberts + +Version 2.1: + Arduino 1.0 compatibility, Paul Stoffregen + Improve temperature example, Paul Stoffregen + DS250x_PROM example, Guillermo Lovato + PIC32 (chipKit) compatibility, Jason Dangel, dangel.jason AT gmail.com + Improvements from Glenn Trewitt: + - crc16() now works + - check_crc16() does all of calculation/checking work. + - Added read_bytes() and write_bytes(), to reduce tedious loops. + - Added ds2408 example. + Delete very old, out-of-date readme file (info is here) + +Version 2.0: Modifications by Paul Stoffregen, January 2010: +http://www.pjrc.com/teensy/td_libs_OneWire.html + Search fix from Robin James + http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1238032295/27#27 + Use direct optimized I/O in all cases + Disable interrupts during timing critical sections + (this solves many random communication errors) + Disable interrupts during read-modify-write I/O + Reduce RAM consumption by eliminating unnecessary + variables and trimming many to 8 bits + Optimize both crc8 - table version moved to flash + +Modified to work with larger numbers of devices - avoids loop. +Tested in Arduino 11 alpha with 12 sensors. +26 Sept 2008 -- Robin James +http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1238032295/27#27 + +Updated to work with arduino-0008 and to include skip() as of +2007/07/06. --RJL20 + +Modified to calculate the 8-bit CRC directly, avoiding the need for +the 256-byte lookup table to be loaded in RAM. Tested in arduino-0010 +-- Tom Pollard, Jan 23, 2008 + +Jim Studt's original library was modified by Josh Larios. + +Tom Pollard, pollard@alum.mit.edu, contributed around May 20, 2008 + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Much of the code was inspired by Derek Yerger's code, though I don't +think much of that remains. In any event that was.. + (copyleft) 2006 by Derek Yerger - Free to distribute freely. + +The CRC code was excerpted and inspired by the Dallas Semiconductor +sample code bearing this copyright. +//--------------------------------------------------------------------------- +// Copyright (C) 2000 Dallas Semiconductor Corporation, All Rights Reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL DALLAS SEMICONDUCTOR BE LIABLE FOR ANY CLAIM, DAMAGES +// OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// +// Except as contained in this notice, the name of Dallas Semiconductor +// shall not be used except as stated in the Dallas Semiconductor +// Branding Policy. +//-------------------------------------------------------------------------- +*/ + +#include "OneWire.h" + + +OneWire::OneWire(uint8_t pin) +{ + pinMode(pin, INPUT); + bitmask = PIN_TO_BITMASK(pin); + baseReg = PIN_TO_BASEREG(pin); +#if ONEWIRE_SEARCH + reset_search(); +#endif +} + + +// Perform the onewire reset function. We will wait up to 250uS for +// the bus to come high, if it doesn't then it is broken or shorted +// and we return a 0; +// +// Returns 1 if a device asserted a presence pulse, 0 otherwise. +// +uint8_t OneWire::reset(void) +{ + IO_REG_TYPE mask = bitmask; + volatile IO_REG_TYPE *reg IO_REG_ASM = baseReg; + uint8_t r; + uint8_t retries = 125; + + noInterrupts(); + DIRECT_MODE_INPUT(reg, mask); + interrupts(); + // wait until the wire is high... just in case + do { + if (--retries == 0) return 0; + delayMicroseconds(2); + } while ( !DIRECT_READ(reg, mask)); + + noInterrupts(); + DIRECT_WRITE_LOW(reg, mask); + DIRECT_MODE_OUTPUT(reg, mask); // drive output low + interrupts(); + delayMicroseconds(480); + noInterrupts(); + DIRECT_MODE_INPUT(reg, mask); // allow it to float + delayMicroseconds(70); + r = !DIRECT_READ(reg, mask); + interrupts(); + delayMicroseconds(410); + return r; +} + +// +// Write a bit. Port and bit is used to cut lookup time and provide +// more certain timing. +// +void OneWire::write_bit(uint8_t v) +{ + IO_REG_TYPE mask=bitmask; + volatile IO_REG_TYPE *reg IO_REG_ASM = baseReg; + + if (v & 1) { + noInterrupts(); + DIRECT_WRITE_LOW(reg, mask); + DIRECT_MODE_OUTPUT(reg, mask); // drive output low + delayMicroseconds(10); + DIRECT_WRITE_HIGH(reg, mask); // drive output high + interrupts(); + delayMicroseconds(55); + } else { + noInterrupts(); + DIRECT_WRITE_LOW(reg, mask); + DIRECT_MODE_OUTPUT(reg, mask); // drive output low + delayMicroseconds(65); + DIRECT_WRITE_HIGH(reg, mask); // drive output high + interrupts(); + delayMicroseconds(5); + } +} + +// +// Read a bit. Port and bit is used to cut lookup time and provide +// more certain timing. +// +uint8_t OneWire::read_bit(void) +{ + IO_REG_TYPE mask=bitmask; + volatile IO_REG_TYPE *reg IO_REG_ASM = baseReg; + uint8_t r; + + noInterrupts(); + DIRECT_MODE_OUTPUT(reg, mask); + DIRECT_WRITE_LOW(reg, mask); + delayMicroseconds(3); + DIRECT_MODE_INPUT(reg, mask); // let pin float, pull up will raise + delayMicroseconds(10); + r = DIRECT_READ(reg, mask); + interrupts(); + delayMicroseconds(53); + return r; +} + +// +// Write a byte. The writing code uses the active drivers to raise the +// pin high, if you need power after the write (e.g. DS18S20 in +// parasite power mode) then set 'power' to 1, otherwise the pin will +// go tri-state at the end of the write to avoid heating in a short or +// other mishap. +// +void OneWire::write(uint8_t v, uint8_t power /* = 0 */) { + uint8_t bitMask; + + for (bitMask = 0x01; bitMask; bitMask <<= 1) { + OneWire::write_bit( (bitMask & v)?1:0); + } + if ( !power) { + noInterrupts(); + DIRECT_MODE_INPUT(baseReg, bitmask); + DIRECT_WRITE_LOW(baseReg, bitmask); + interrupts(); + } +} + +void OneWire::write_bytes(const uint8_t *buf, uint16_t count, bool power /* = 0 */) { + for (uint16_t i = 0 ; i < count ; i++) + write(buf[i]); + if (!power) { + noInterrupts(); + DIRECT_MODE_INPUT(baseReg, bitmask); + DIRECT_WRITE_LOW(baseReg, bitmask); + interrupts(); + } +} + +// +// Read a byte +// +uint8_t OneWire::read() { + uint8_t bitMask; + uint8_t r = 0; + + for (bitMask = 0x01; bitMask; bitMask <<= 1) { + if ( OneWire::read_bit()) r |= bitMask; + } + return r; +} + +void OneWire::read_bytes(uint8_t *buf, uint16_t count) { + for (uint16_t i = 0 ; i < count ; i++) + buf[i] = read(); +} + +// +// Do a ROM select +// +void OneWire::select(const uint8_t rom[8]) +{ + uint8_t i; + + write(0x55); // Choose ROM + + for (i = 0; i < 8; i++) write(rom[i]); +} + +// +// Do a ROM skip +// +void OneWire::skip() +{ + write(0xCC); // Skip ROM +} + +void OneWire::depower() +{ + noInterrupts(); + DIRECT_MODE_INPUT(baseReg, bitmask); + interrupts(); +} + +#if ONEWIRE_SEARCH + +// +// You need to use this function to start a search again from the beginning. +// You do not need to do it for the first search, though you could. +// +void OneWire::reset_search() +{ + // reset the search state + LastDiscrepancy = 0; + LastDeviceFlag = FALSE; + LastFamilyDiscrepancy = 0; + for(int i = 7; ; i--) { + ROM_NO[i] = 0; + if ( i == 0) break; + } +} + +// Setup the search to find the device type 'family_code' on the next call +// to search(*newAddr) if it is present. +// +void OneWire::target_search(uint8_t family_code) +{ + // set the search state to find SearchFamily type devices + ROM_NO[0] = family_code; + for (uint8_t i = 1; i < 8; i++) + ROM_NO[i] = 0; + LastDiscrepancy = 64; + LastFamilyDiscrepancy = 0; + LastDeviceFlag = FALSE; +} + +// +// Perform a search. If this function returns a '1' then it has +// enumerated the next device and you may retrieve the ROM from the +// OneWire::address variable. If there are no devices, no further +// devices, or something horrible happens in the middle of the +// enumeration then a 0 is returned. If a new device is found then +// its address is copied to newAddr. Use OneWire::reset_search() to +// start over. +// +// --- Replaced by the one from the Dallas Semiconductor web site --- +//-------------------------------------------------------------------------- +// Perform the 1-Wire Search Algorithm on the 1-Wire bus using the existing +// search state. +// Return TRUE : device found, ROM number in ROM_NO buffer +// FALSE : device not found, end of search +// +uint8_t OneWire::search(uint8_t *newAddr, bool search_mode /* = true */) +{ + uint8_t id_bit_number; + uint8_t last_zero, rom_byte_number, search_result; + uint8_t id_bit, cmp_id_bit; + + unsigned char rom_byte_mask, search_direction; + + // initialize for search + id_bit_number = 1; + last_zero = 0; + rom_byte_number = 0; + rom_byte_mask = 1; + search_result = 0; + + // if the last call was not the last one + if (!LastDeviceFlag) + { + // 1-Wire reset + if (!reset()) + { + // reset the search + LastDiscrepancy = 0; + LastDeviceFlag = FALSE; + LastFamilyDiscrepancy = 0; + return FALSE; + } + + // issue the search command + if (search_mode == true) { + write(0xF0); // NORMAL SEARCH + } else { + write(0xEC); // CONDITIONAL SEARCH + } + + // loop to do the search + do + { + // read a bit and its complement + id_bit = read_bit(); + cmp_id_bit = read_bit(); + + // check for no devices on 1-wire + if ((id_bit == 1) && (cmp_id_bit == 1)) + break; + else + { + // all devices coupled have 0 or 1 + if (id_bit != cmp_id_bit) + search_direction = id_bit; // bit write value for search + else + { + // if this discrepancy if before the Last Discrepancy + // on a previous next then pick the same as last time + if (id_bit_number < LastDiscrepancy) + search_direction = ((ROM_NO[rom_byte_number] & rom_byte_mask) > 0); + else + // if equal to last pick 1, if not then pick 0 + search_direction = (id_bit_number == LastDiscrepancy); + + // if 0 was picked then record its position in LastZero + if (search_direction == 0) + { + last_zero = id_bit_number; + + // check for Last discrepancy in family + if (last_zero < 9) + LastFamilyDiscrepancy = last_zero; + } + } + + // set or clear the bit in the ROM byte rom_byte_number + // with mask rom_byte_mask + if (search_direction == 1) + ROM_NO[rom_byte_number] |= rom_byte_mask; + else + ROM_NO[rom_byte_number] &= ~rom_byte_mask; + + // serial number search direction write bit + write_bit(search_direction); + + // increment the byte counter id_bit_number + // and shift the mask rom_byte_mask + id_bit_number++; + rom_byte_mask <<= 1; + + // if the mask is 0 then go to new SerialNum byte rom_byte_number and reset mask + if (rom_byte_mask == 0) + { + rom_byte_number++; + rom_byte_mask = 1; + } + } + } + while(rom_byte_number < 8); // loop until through all ROM bytes 0-7 + + // if the search was successful then + if (!(id_bit_number < 65)) + { + // search successful so set LastDiscrepancy,LastDeviceFlag,search_result + LastDiscrepancy = last_zero; + + // check for last device + if (LastDiscrepancy == 0) + LastDeviceFlag = TRUE; + + search_result = TRUE; + } + } + + // if no device found then reset counters so next 'search' will be like a first + if (!search_result || !ROM_NO[0]) + { + LastDiscrepancy = 0; + LastDeviceFlag = FALSE; + LastFamilyDiscrepancy = 0; + search_result = FALSE; + } else { + for (int i = 0; i < 8; i++) newAddr[i] = ROM_NO[i]; + } + return search_result; + } + +#endif + +#if ONEWIRE_CRC +// The 1-Wire CRC scheme is described in Maxim Application Note 27: +// "Understanding and Using Cyclic Redundancy Checks with Maxim iButton Products" +// + +#if ONEWIRE_CRC8_TABLE +// This table comes from Dallas sample code where it is freely reusable, +// though Copyright (C) 2000 Dallas Semiconductor Corporation +static const uint8_t PROGMEM dscrc_table[] = { + 0, 94,188,226, 97, 63,221,131,194,156,126, 32,163,253, 31, 65, + 157,195, 33,127,252,162, 64, 30, 95, 1,227,189, 62, 96,130,220, + 35,125,159,193, 66, 28,254,160,225,191, 93, 3,128,222, 60, 98, + 190,224, 2, 92,223,129, 99, 61,124, 34,192,158, 29, 67,161,255, + 70, 24,250,164, 39,121,155,197,132,218, 56,102,229,187, 89, 7, + 219,133,103, 57,186,228, 6, 88, 25, 71,165,251,120, 38,196,154, + 101, 59,217,135, 4, 90,184,230,167,249, 27, 69,198,152,122, 36, + 248,166, 68, 26,153,199, 37,123, 58,100,134,216, 91, 5,231,185, + 140,210, 48,110,237,179, 81, 15, 78, 16,242,172, 47,113,147,205, + 17, 79,173,243,112, 46,204,146,211,141,111, 49,178,236, 14, 80, + 175,241, 19, 77,206,144,114, 44,109, 51,209,143, 12, 82,176,238, + 50,108,142,208, 83, 13,239,177,240,174, 76, 18,145,207, 45,115, + 202,148,118, 40,171,245, 23, 73, 8, 86,180,234,105, 55,213,139, + 87, 9,235,181, 54,104,138,212,149,203, 41,119,244,170, 72, 22, + 233,183, 85, 11,136,214, 52,106, 43,117,151,201, 74, 20,246,168, + 116, 42,200,150, 21, 75,169,247,182,232, 10, 84,215,137,107, 53}; + +// +// Compute a Dallas Semiconductor 8 bit CRC. These show up in the ROM +// and the registers. (note: this might better be done without to +// table, it would probably be smaller and certainly fast enough +// compared to all those delayMicrosecond() calls. But I got +// confused, so I use this table from the examples.) +// +uint8_t OneWire::crc8(const uint8_t *addr, uint8_t len) +{ + uint8_t crc = 0; + + while (len--) { + crc = pgm_read_byte(dscrc_table + (crc ^ *addr++)); + } + return crc; +} +#else +// +// Compute a Dallas Semiconductor 8 bit CRC directly. +// this is much slower, but much smaller, than the lookup table. +// +uint8_t OneWire::crc8(const uint8_t *addr, uint8_t len) +{ + uint8_t crc = 0; + + while (len--) { +#if defined(__AVR__) + crc = _crc_ibutton_update(crc, *addr++); +#else + uint8_t inbyte = *addr++; + for (uint8_t i = 8; i; i--) { + uint8_t mix = (crc ^ inbyte) & 0x01; + crc >>= 1; + if (mix) crc ^= 0x8C; + inbyte >>= 1; + } +#endif + } + return crc; +} +#endif + +#if ONEWIRE_CRC16 +bool OneWire::check_crc16(const uint8_t* input, uint16_t len, const uint8_t* inverted_crc, uint16_t crc) +{ + crc = ~crc16(input, len, crc); + return (crc & 0xFF) == inverted_crc[0] && (crc >> 8) == inverted_crc[1]; +} + +uint16_t OneWire::crc16(const uint8_t* input, uint16_t len, uint16_t crc) +{ +#if defined(__AVR__) + for (uint16_t i = 0 ; i < len ; i++) { + crc = _crc16_update(crc, input[i]); + } +#else + static const uint8_t oddparity[16] = + { 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 }; + + for (uint16_t i = 0 ; i < len ; i++) { + // Even though we're just copying a byte from the input, + // we'll be doing 16-bit computation with it. + uint16_t cdata = input[i]; + cdata = (cdata ^ crc) & 0xff; + crc >>= 8; + + if (oddparity[cdata & 0x0F] ^ oddparity[cdata >> 4]) + crc ^= 0xC001; + + cdata <<= 6; + crc ^= cdata; + cdata <<= 1; + crc ^= cdata; + } +#endif + return crc; +} +#endif + +#endif diff --git a/Onewire/OneWire.h b/Onewire/OneWire.h new file mode 100644 index 0000000..189855c --- /dev/null +++ b/Onewire/OneWire.h @@ -0,0 +1,376 @@ +#ifndef OneWire_h +#define OneWire_h + +#include + +#if defined(__AVR__) +#include +#endif + +#if ARDUINO >= 100 +#include "Arduino.h" // for delayMicroseconds, digitalPinToBitMask, etc +#else +#include "WProgram.h" // for delayMicroseconds +#include "pins_arduino.h" // for digitalPinToBitMask, etc +#endif + +// You can exclude certain features from OneWire. In theory, this +// might save some space. In practice, the compiler automatically +// removes unused code (technically, the linker, using -fdata-sections +// and -ffunction-sections when compiling, and Wl,--gc-sections +// when linking), so most of these will not result in any code size +// reduction. Well, unless you try to use the missing features +// and redesign your program to not need them! ONEWIRE_CRC8_TABLE +// is the exception, because it selects a fast but large algorithm +// or a small but slow algorithm. + +// you can exclude onewire_search by defining that to 0 +#ifndef ONEWIRE_SEARCH +#define ONEWIRE_SEARCH 1 +#endif + +// You can exclude CRC checks altogether by defining this to 0 +#ifndef ONEWIRE_CRC +#define ONEWIRE_CRC 1 +#endif + +// Select the table-lookup method of computing the 8-bit CRC +// by setting this to 1. The lookup table enlarges code size by +// about 250 bytes. It does NOT consume RAM (but did in very +// old versions of OneWire). If you disable this, a slower +// but very compact algorithm is used. +#ifndef ONEWIRE_CRC8_TABLE +#define ONEWIRE_CRC8_TABLE 1 +#endif + +// You can allow 16-bit CRC checks by defining this to 1 +// (Note that ONEWIRE_CRC must also be 1.) +#ifndef ONEWIRE_CRC16 +#define ONEWIRE_CRC16 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif +#ifndef TRUE +#define TRUE 1 +#endif + +// Platform specific I/O definitions + +#if defined(__AVR__) +#define PIN_TO_BASEREG(pin) (portInputRegister(digitalPinToPort(pin))) +#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin)) +#define IO_REG_TYPE uint8_t +#define IO_REG_ASM asm("r30") +#define DIRECT_READ(base, mask) (((*(base)) & (mask)) ? 1 : 0) +#define DIRECT_MODE_INPUT(base, mask) ((*((base)+1)) &= ~(mask)) +#define DIRECT_MODE_OUTPUT(base, mask) ((*((base)+1)) |= (mask)) +#define DIRECT_WRITE_LOW(base, mask) ((*((base)+2)) &= ~(mask)) +#define DIRECT_WRITE_HIGH(base, mask) ((*((base)+2)) |= (mask)) + +#elif defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK66FX1M0__) || defined(__MK64FX512__) +#define PIN_TO_BASEREG(pin) (portOutputRegister(pin)) +#define PIN_TO_BITMASK(pin) (1) +#define IO_REG_TYPE uint8_t +#define IO_REG_ASM +#define DIRECT_READ(base, mask) (*((base)+512)) +#define DIRECT_MODE_INPUT(base, mask) (*((base)+640) = 0) +#define DIRECT_MODE_OUTPUT(base, mask) (*((base)+640) = 1) +#define DIRECT_WRITE_LOW(base, mask) (*((base)+256) = 1) +#define DIRECT_WRITE_HIGH(base, mask) (*((base)+128) = 1) + +#elif defined(__MKL26Z64__) +#define PIN_TO_BASEREG(pin) (portOutputRegister(pin)) +#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin)) +#define IO_REG_TYPE uint8_t +#define IO_REG_ASM +#define DIRECT_READ(base, mask) ((*((base)+16) & (mask)) ? 1 : 0) +#define DIRECT_MODE_INPUT(base, mask) (*((base)+20) &= ~(mask)) +#define DIRECT_MODE_OUTPUT(base, mask) (*((base)+20) |= (mask)) +#define DIRECT_WRITE_LOW(base, mask) (*((base)+8) = (mask)) +#define DIRECT_WRITE_HIGH(base, mask) (*((base)+4) = (mask)) + +#elif defined(__SAM3X8E__) || defined(__SAM3A8C__) || defined(__SAM3A4C__) +// Arduino 1.5.1 may have a bug in delayMicroseconds() on Arduino Due. +// http://arduino.cc/forum/index.php/topic,141030.msg1076268.html#msg1076268 +// If you have trouble with OneWire on Arduino Due, please check the +// status of delayMicroseconds() before reporting a bug in OneWire! +#define PIN_TO_BASEREG(pin) (&(digitalPinToPort(pin)->PIO_PER)) +#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin)) +#define IO_REG_TYPE uint32_t +#define IO_REG_ASM +#define DIRECT_READ(base, mask) (((*((base)+15)) & (mask)) ? 1 : 0) +#define DIRECT_MODE_INPUT(base, mask) ((*((base)+5)) = (mask)) +#define DIRECT_MODE_OUTPUT(base, mask) ((*((base)+4)) = (mask)) +#define DIRECT_WRITE_LOW(base, mask) ((*((base)+13)) = (mask)) +#define DIRECT_WRITE_HIGH(base, mask) ((*((base)+12)) = (mask)) +#ifndef PROGMEM +#define PROGMEM +#endif +#ifndef pgm_read_byte +#define pgm_read_byte(addr) (*(const uint8_t *)(addr)) +#endif + +#elif defined(__PIC32MX__) +#define PIN_TO_BASEREG(pin) (portModeRegister(digitalPinToPort(pin))) +#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin)) +#define IO_REG_TYPE uint32_t +#define IO_REG_ASM +#define DIRECT_READ(base, mask) (((*(base+4)) & (mask)) ? 1 : 0) //PORTX + 0x10 +#define DIRECT_MODE_INPUT(base, mask) ((*(base+2)) = (mask)) //TRISXSET + 0x08 +#define DIRECT_MODE_OUTPUT(base, mask) ((*(base+1)) = (mask)) //TRISXCLR + 0x04 +#define DIRECT_WRITE_LOW(base, mask) ((*(base+8+1)) = (mask)) //LATXCLR + 0x24 +#define DIRECT_WRITE_HIGH(base, mask) ((*(base+8+2)) = (mask)) //LATXSET + 0x28 + +#elif defined(ARDUINO_ARCH_ESP8266) +// Special note: I depend on the ESP community to maintain these definitions and +// submit good pull requests. I can not answer any ESP questions or help you +// resolve any problems related to ESP chips. Please do not contact me and please +// DO NOT CREATE GITHUB ISSUES for ESP support. All ESP questions must be asked +// on ESP community forums. +#define PIN_TO_BASEREG(pin) ((volatile uint32_t*) GPO) +#define PIN_TO_BITMASK(pin) (1 << pin) +#define IO_REG_TYPE uint32_t +#define IO_REG_ASM +#define DIRECT_READ(base, mask) ((GPI & (mask)) ? 1 : 0) //GPIO_IN_ADDRESS +#define DIRECT_MODE_INPUT(base, mask) (GPE &= ~(mask)) //GPIO_ENABLE_W1TC_ADDRESS +#define DIRECT_MODE_OUTPUT(base, mask) (GPE |= (mask)) //GPIO_ENABLE_W1TS_ADDRESS +#define DIRECT_WRITE_LOW(base, mask) (GPOC = (mask)) //GPIO_OUT_W1TC_ADDRESS +#define DIRECT_WRITE_HIGH(base, mask) (GPOS = (mask)) //GPIO_OUT_W1TS_ADDRESS + +#elif defined(__SAMD21G18A__) +#define PIN_TO_BASEREG(pin) portModeRegister(digitalPinToPort(pin)) +#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin)) +#define IO_REG_TYPE uint32_t +#define IO_REG_ASM +#define DIRECT_READ(base, mask) (((*((base)+8)) & (mask)) ? 1 : 0) +#define DIRECT_MODE_INPUT(base, mask) ((*((base)+1)) = (mask)) +#define DIRECT_MODE_OUTPUT(base, mask) ((*((base)+2)) = (mask)) +#define DIRECT_WRITE_LOW(base, mask) ((*((base)+5)) = (mask)) +#define DIRECT_WRITE_HIGH(base, mask) ((*((base)+6)) = (mask)) + +#elif defined(RBL_NRF51822) +#define PIN_TO_BASEREG(pin) (0) +#define PIN_TO_BITMASK(pin) (pin) +#define IO_REG_TYPE uint32_t +#define IO_REG_ASM +#define DIRECT_READ(base, pin) nrf_gpio_pin_read(pin) +#define DIRECT_WRITE_LOW(base, pin) nrf_gpio_pin_clear(pin) +#define DIRECT_WRITE_HIGH(base, pin) nrf_gpio_pin_set(pin) +#define DIRECT_MODE_INPUT(base, pin) nrf_gpio_cfg_input(pin, NRF_GPIO_PIN_NOPULL) +#define DIRECT_MODE_OUTPUT(base, pin) nrf_gpio_cfg_output(pin) + +#elif defined(__arc__) /* Arduino101/Genuino101 specifics */ + +#include "scss_registers.h" +#include "portable.h" +#include "avr/pgmspace.h" + +#define GPIO_ID(pin) (g_APinDescription[pin].ulGPIOId) +#define GPIO_TYPE(pin) (g_APinDescription[pin].ulGPIOType) +#define GPIO_BASE(pin) (g_APinDescription[pin].ulGPIOBase) +#define DIR_OFFSET_SS 0x01 +#define DIR_OFFSET_SOC 0x04 +#define EXT_PORT_OFFSET_SS 0x0A +#define EXT_PORT_OFFSET_SOC 0x50 + +/* GPIO registers base address */ +#define PIN_TO_BASEREG(pin) ((volatile uint32_t *)g_APinDescription[pin].ulGPIOBase) +#define PIN_TO_BITMASK(pin) pin +#define IO_REG_TYPE uint32_t +#define IO_REG_ASM + +static inline __attribute__((always_inline)) +IO_REG_TYPE directRead(volatile IO_REG_TYPE *base, IO_REG_TYPE pin) +{ + IO_REG_TYPE ret; + if (SS_GPIO == GPIO_TYPE(pin)) { + ret = READ_ARC_REG(((IO_REG_TYPE)base + EXT_PORT_OFFSET_SS)); + } else { + ret = MMIO_REG_VAL_FROM_BASE((IO_REG_TYPE)base, EXT_PORT_OFFSET_SOC); + } + return ((ret >> GPIO_ID(pin)) & 0x01); +} + +static inline __attribute__((always_inline)) +void directModeInput(volatile IO_REG_TYPE *base, IO_REG_TYPE pin) +{ + if (SS_GPIO == GPIO_TYPE(pin)) { + WRITE_ARC_REG(READ_ARC_REG((((IO_REG_TYPE)base) + DIR_OFFSET_SS)) & ~(0x01 << GPIO_ID(pin)), + ((IO_REG_TYPE)(base) + DIR_OFFSET_SS)); + } else { + MMIO_REG_VAL_FROM_BASE((IO_REG_TYPE)base, DIR_OFFSET_SOC) &= ~(0x01 << GPIO_ID(pin)); + } +} + +static inline __attribute__((always_inline)) +void directModeOutput(volatile IO_REG_TYPE *base, IO_REG_TYPE pin) +{ + if (SS_GPIO == GPIO_TYPE(pin)) { + WRITE_ARC_REG(READ_ARC_REG(((IO_REG_TYPE)(base) + DIR_OFFSET_SS)) | (0x01 << GPIO_ID(pin)), + ((IO_REG_TYPE)(base) + DIR_OFFSET_SS)); + } else { + MMIO_REG_VAL_FROM_BASE((IO_REG_TYPE)base, DIR_OFFSET_SOC) |= (0x01 << GPIO_ID(pin)); + } +} + +static inline __attribute__((always_inline)) +void directWriteLow(volatile IO_REG_TYPE *base, IO_REG_TYPE pin) +{ + if (SS_GPIO == GPIO_TYPE(pin)) { + WRITE_ARC_REG(READ_ARC_REG(base) & ~(0x01 << GPIO_ID(pin)), base); + } else { + MMIO_REG_VAL(base) &= ~(0x01 << GPIO_ID(pin)); + } +} + +static inline __attribute__((always_inline)) +void directWriteHigh(volatile IO_REG_TYPE *base, IO_REG_TYPE pin) +{ + if (SS_GPIO == GPIO_TYPE(pin)) { + WRITE_ARC_REG(READ_ARC_REG(base) | (0x01 << GPIO_ID(pin)), base); + } else { + MMIO_REG_VAL(base) |= (0x01 << GPIO_ID(pin)); + } +} + +#define DIRECT_READ(base, pin) directRead(base, pin) +#define DIRECT_MODE_INPUT(base, pin) directModeInput(base, pin) +#define DIRECT_MODE_OUTPUT(base, pin) directModeOutput(base, pin) +#define DIRECT_WRITE_LOW(base, pin) directWriteLow(base, pin) +#define DIRECT_WRITE_HIGH(base, pin) directWriteHigh(base, pin) + +#else +#define PIN_TO_BASEREG(pin) (0) +#define PIN_TO_BITMASK(pin) (pin) +#define IO_REG_TYPE unsigned int +#define IO_REG_ASM +#define DIRECT_READ(base, pin) digitalRead(pin) +#define DIRECT_WRITE_LOW(base, pin) digitalWrite(pin, LOW) +#define DIRECT_WRITE_HIGH(base, pin) digitalWrite(pin, HIGH) +#define DIRECT_MODE_INPUT(base, pin) pinMode(pin,INPUT) +#define DIRECT_MODE_OUTPUT(base, pin) pinMode(pin,OUTPUT) +#warning "OneWire. Fallback mode. Using API calls for pinMode,digitalRead and digitalWrite. Operation of this library is not guaranteed on this architecture." + +#endif + + +class OneWire +{ + private: + IO_REG_TYPE bitmask; + volatile IO_REG_TYPE *baseReg; + +#if ONEWIRE_SEARCH + // global search state + unsigned char ROM_NO[8]; + uint8_t LastDiscrepancy; + uint8_t LastFamilyDiscrepancy; + uint8_t LastDeviceFlag; +#endif + + public: + OneWire( uint8_t pin); + + // Perform a 1-Wire reset cycle. Returns 1 if a device responds + // with a presence pulse. Returns 0 if there is no device or the + // bus is shorted or otherwise held low for more than 250uS + uint8_t reset(void); + + // Issue a 1-Wire rom select command, you do the reset first. + void select(const uint8_t rom[8]); + + // Issue a 1-Wire rom skip command, to address all on bus. + void skip(void); + + // Write a byte. If 'power' is one then the wire is held high at + // the end for parasitically powered devices. You are responsible + // for eventually depowering it by calling depower() or doing + // another read or write. + void write(uint8_t v, uint8_t power = 0); + + void write_bytes(const uint8_t *buf, uint16_t count, bool power = 0); + + // Read a byte. + uint8_t read(void); + + void read_bytes(uint8_t *buf, uint16_t count); + + // Write a bit. The bus is always left powered at the end, see + // note in write() about that. + void write_bit(uint8_t v); + + // Read a bit. + uint8_t read_bit(void); + + // Stop forcing power onto the bus. You only need to do this if + // you used the 'power' flag to write() or used a write_bit() call + // and aren't about to do another read or write. You would rather + // not leave this powered if you don't have to, just in case + // someone shorts your bus. + void depower(void); + +#if ONEWIRE_SEARCH + // Clear the search state so that if will start from the beginning again. + void reset_search(); + + // Setup the search to find the device type 'family_code' on the next call + // to search(*newAddr) if it is present. + void target_search(uint8_t family_code); + + // Look for the next device. Returns 1 if a new address has been + // returned. A zero might mean that the bus is shorted, there are + // no devices, or you have already retrieved all of them. It + // might be a good idea to check the CRC to make sure you didn't + // get garbage. The order is deterministic. You will always get + // the same devices in the same order. + uint8_t search(uint8_t *newAddr, bool search_mode = true); +#endif + +#if ONEWIRE_CRC + // Compute a Dallas Semiconductor 8 bit CRC, these are used in the + // ROM and scratchpad registers. + static uint8_t crc8(const uint8_t *addr, uint8_t len); + +#if ONEWIRE_CRC16 + // Compute the 1-Wire CRC16 and compare it against the received CRC. + // Example usage (reading a DS2408): + // // Put everything in a buffer so we can compute the CRC easily. + // uint8_t buf[13]; + // buf[0] = 0xF0; // Read PIO Registers + // buf[1] = 0x88; // LSB address + // buf[2] = 0x00; // MSB address + // WriteBytes(net, buf, 3); // Write 3 cmd bytes + // ReadBytes(net, buf+3, 10); // Read 6 data bytes, 2 0xFF, 2 CRC16 + // if (!CheckCRC16(buf, 11, &buf[11])) { + // // Handle error. + // } + // + // @param input - Array of bytes to checksum. + // @param len - How many bytes to use. + // @param inverted_crc - The two CRC16 bytes in the received data. + // This should just point into the received data, + // *not* at a 16-bit integer. + // @param crc - The crc starting value (optional) + // @return True, iff the CRC matches. + static bool check_crc16(const uint8_t* input, uint16_t len, const uint8_t* inverted_crc, uint16_t crc = 0); + + // Compute a Dallas Semiconductor 16 bit CRC. This is required to check + // the integrity of data received from many 1-Wire devices. Note that the + // CRC computed here is *not* what you'll get from the 1-Wire network, + // for two reasons: + // 1) The CRC is transmitted bitwise inverted. + // 2) Depending on the endian-ness of your processor, the binary + // representation of the two-byte return value may have a different + // byte order than the two bytes you get from 1-Wire. + // @param input - Array of bytes to checksum. + // @param len - How many bytes to use. + // @param crc - The crc starting value (optional) + // @return The CRC16, as defined by Dallas Semiconductor. + static uint16_t crc16(const uint8_t* input, uint16_t len, uint16_t crc = 0); +#endif +#endif +}; + +#endif diff --git a/Onewire/examples/DS18x20_Temperature/DS18x20_Temperature.pde b/Onewire/examples/DS18x20_Temperature/DS18x20_Temperature.pde new file mode 100644 index 0000000..68ca194 --- /dev/null +++ b/Onewire/examples/DS18x20_Temperature/DS18x20_Temperature.pde @@ -0,0 +1,112 @@ +#include + +// OneWire DS18S20, DS18B20, DS1822 Temperature Example +// +// http://www.pjrc.com/teensy/td_libs_OneWire.html +// +// The DallasTemperature library can do all this work for you! +// http://milesburton.com/Dallas_Temperature_Control_Library + +OneWire ds(10); // on pin 10 (a 4.7K resistor is necessary) + +void setup(void) { + Serial.begin(9600); +} + +void loop(void) { + byte i; + byte present = 0; + byte type_s; + byte data[12]; + byte addr[8]; + float celsius, fahrenheit; + + if ( !ds.search(addr)) { + Serial.println("No more addresses."); + Serial.println(); + ds.reset_search(); + delay(250); + return; + } + + Serial.print("ROM ="); + for( i = 0; i < 8; i++) { + Serial.write(' '); + Serial.print(addr[i], HEX); + } + + if (OneWire::crc8(addr, 7) != addr[7]) { + Serial.println("CRC is not valid!"); + return; + } + Serial.println(); + + // the first ROM byte indicates which chip + switch (addr[0]) { + case 0x10: + Serial.println(" Chip = DS18S20"); // or old DS1820 + type_s = 1; + break; + case 0x28: + Serial.println(" Chip = DS18B20"); + type_s = 0; + break; + case 0x22: + Serial.println(" Chip = DS1822"); + type_s = 0; + break; + default: + Serial.println("Device is not a DS18x20 family device."); + return; + } + + ds.reset(); + ds.select(addr); + ds.write(0x44, 1); // start conversion, with parasite power on at the end + + delay(1000); // maybe 750ms is enough, maybe not + // we might do a ds.depower() here, but the reset will take care of it. + + present = ds.reset(); + ds.select(addr); + ds.write(0xBE); // Read Scratchpad + + Serial.print(" Data = "); + Serial.print(present, HEX); + Serial.print(" "); + for ( i = 0; i < 9; i++) { // we need 9 bytes + data[i] = ds.read(); + Serial.print(data[i], HEX); + Serial.print(" "); + } + Serial.print(" CRC="); + Serial.print(OneWire::crc8(data, 8), HEX); + Serial.println(); + + // Convert the data to actual temperature + // because the result is a 16 bit signed integer, it should + // be stored to an "int16_t" type, which is always 16 bits + // even when compiled on a 32 bit processor. + int16_t raw = (data[1] << 8) | data[0]; + if (type_s) { + raw = raw << 3; // 9 bit resolution default + if (data[7] == 0x10) { + // "count remain" gives full 12 bit resolution + raw = (raw & 0xFFF0) + 12 - data[6]; + } + } else { + byte cfg = (data[4] & 0x60); + // at lower res, the low bits are undefined, so let's zero them + if (cfg == 0x00) raw = raw & ~7; // 9 bit resolution, 93.75 ms + else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms + else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms + //// default is 12 bit resolution, 750 ms conversion time + } + celsius = (float)raw / 16.0; + fahrenheit = celsius * 1.8 + 32.0; + Serial.print(" Temperature = "); + Serial.print(celsius); + Serial.print(" Celsius, "); + Serial.print(fahrenheit); + Serial.println(" Fahrenheit"); +} diff --git a/Onewire/examples/DS2408_Switch/DS2408_Switch.pde b/Onewire/examples/DS2408_Switch/DS2408_Switch.pde new file mode 100644 index 0000000..d171f9b --- /dev/null +++ b/Onewire/examples/DS2408_Switch/DS2408_Switch.pde @@ -0,0 +1,77 @@ +#include + +/* + * DS2408 8-Channel Addressable Switch + * + * Writte by Glenn Trewitt, glenn at trewitt dot org + * + * Some notes about the DS2408: + * - Unlike most input/output ports, the DS2408 doesn't have mode bits to + * set whether the pins are input or output. If you issue a read command, + * they're inputs. If you write to them, they're outputs. + * - For reading from a switch, you should use 10K pull-up resisters. + */ + +void PrintBytes(uint8_t* addr, uint8_t count, bool newline=0) { + for (uint8_t i = 0; i < count; i++) { + Serial.print(addr[i]>>4, HEX); + Serial.print(addr[i]&0x0f, HEX); + } + if (newline) + Serial.println(); +} + +void ReadAndReport(OneWire* net, uint8_t* addr) { + Serial.print(" Reading DS2408 "); + PrintBytes(addr, 8); + Serial.println(); + + uint8_t buf[13]; // Put everything in the buffer so we can compute CRC easily. + buf[0] = 0xF0; // Read PIO Registers + buf[1] = 0x88; // LSB address + buf[2] = 0x00; // MSB address + net->write_bytes(buf, 3); + net->read_bytes(buf+3, 10); // 3 cmd bytes, 6 data bytes, 2 0xFF, 2 CRC16 + net->reset(); + + if (!OneWire::check_crc16(buf, 11, &buf[11])) { + Serial.print("CRC failure in DS2408 at "); + PrintBytes(addr, 8, true); + return; + } + Serial.print(" DS2408 data = "); + // First 3 bytes contain command, register address. + Serial.println(buf[3], BIN); +} + +OneWire net(10); // on pin 10 + +void setup(void) { + Serial.begin(9600); +} + +void loop(void) { + byte i; + byte present = 0; + byte addr[8]; + + if (!net.search(addr)) { + Serial.print("No more addresses.\n"); + net.reset_search(); + delay(1000); + return; + } + + if (OneWire::crc8(addr, 7) != addr[7]) { + Serial.print("CRC is not valid!\n"); + return; + } + + if (addr[0] != 0x29) { + PrintBytes(addr, 8); + Serial.print(" is not a DS2408.\n"); + return; + } + + ReadAndReport(&net, addr); +} diff --git a/Onewire/examples/DS250x_PROM/DS250x_PROM.pde b/Onewire/examples/DS250x_PROM/DS250x_PROM.pde new file mode 100644 index 0000000..baa51c8 --- /dev/null +++ b/Onewire/examples/DS250x_PROM/DS250x_PROM.pde @@ -0,0 +1,90 @@ +/* +DS250x add-only programmable memory reader w/SKIP ROM. + + The DS250x is a 512/1024bit add-only PROM(you can add data but cannot change the old one) that's used mainly for device identification purposes + like serial number, mfgr data, unique identifiers, etc. It uses the Maxim 1-wire bus. + + This sketch will use the SKIP ROM function that skips the 1-Wire search phase since we only have one device connected in the bus on digital pin 6. + If more than one device is connected to the bus, it will fail. + Sketch will not verify if device connected is from the DS250x family since the skip rom function effectively skips the family-id byte readout. + thus it is possible to run this sketch with any Maxim OneWire device in which case the command CRC will most likely fail. + Sketch will only read the first page of memory(32bits) starting from the lower address(0000h), if more than 1 device is present, then use the sketch with search functions. + Remember to put a 4.7K pullup resistor between pin 6 and +Vcc + + To change the range or ammount of data to read, simply change the data array size, LSB/MSB addresses and for loop iterations + + This example code is in the public domain and is provided AS-IS. + + Built with Arduino 0022 and PJRC OneWire 2.0 library http://www.pjrc.com/teensy/td_libs_OneWire.html + + created by Guillermo Lovato + march/2011 + + */ + +#include +OneWire ds(6); // OneWire bus on digital pin 6 +void setup() { + Serial.begin (9600); +} + +void loop() { + byte i; // This is for the for loops + boolean present; // device present var + byte data[32]; // container for the data from device + byte leemem[3] = { // array with the commands to initiate a read, DS250x devices expect 3 bytes to start a read: command,LSB&MSB adresses + 0xF0 , 0x00 , 0x00 }; // 0xF0 is the Read Data command, followed by 00h 00h as starting address(the beginning, 0000h) + byte ccrc; // Variable to store the command CRC + byte ccrc_calc; + + present = ds.reset(); // OneWire bus reset, always needed to start operation on the bus, returns a 1/TRUE if there's a device present. + ds.skip(); // Skip ROM search + + if (present == TRUE){ // We only try to read the data if there's a device present + Serial.println("DS250x device present"); + ds.write(leemem[0],1); // Read data command, leave ghost power on + ds.write(leemem[1],1); // LSB starting address, leave ghost power on + ds.write(leemem[2],1); // MSB starting address, leave ghost power on + + ccrc = ds.read(); // DS250x generates a CRC for the command we sent, we assign a read slot and store it's value + ccrc_calc = OneWire::crc8(leemem, 3); // We calculate the CRC of the commands we sent using the library function and store it + + if ( ccrc_calc != ccrc) { // Then we compare it to the value the ds250x calculated, if it fails, we print debug messages and abort + Serial.println("Invalid command CRC!"); + Serial.print("Calculated CRC:"); + Serial.println(ccrc_calc,HEX); // HEX makes it easier to observe and compare + Serial.print("DS250x readback CRC:"); + Serial.println(ccrc,HEX); + return; // Since CRC failed, we abort the rest of the loop and start over + } + Serial.println("Data is: "); // For the printout of the data + for ( i = 0; i < 32; i++) { // Now it's time to read the PROM data itself, each page is 32 bytes so we need 32 read commands + data[i] = ds.read(); // we store each read byte to a different position in the data array + Serial.print(data[i]); // printout in ASCII + Serial.print(" "); // blank space + } + Serial.println(); + delay(5000); // Delay so we don't saturate the serial output + } + else { // Nothing is connected in the bus + Serial.println("Nothing connected"); + delay(3000); + } +} + + + + + + + + + + + + + + + + + diff --git a/README.md b/README.md index a7b819e..bdd26b7 100644 --- a/README.md +++ b/README.md @@ -38,8 +38,12 @@ Any symbolic link implementation for Windows is welcomed. The ```symlinks.py``` script comes from https://github.com/janelia-arduino/arduino-libraries -## License +## Authors + +[Jonathan Grizou](http://jgrizou.com/) while working in the [Cronin Group](http://www.chem.gla.ac.uk/cronin/). -This code has been written by Jonathan Grizou while working in the CroninGroup. +Contributions by [Graham Keenan](https://github.com/ShinRa26) and [Jean-Patrick Francoia](https://github.com/JPFrancoia). + +## License -[![LGPL V3](http://www.gnu.org/graphics/lgplv3-147x51.png)](http://www.gnu.org/licenses/lgpl-3.0.en.html) +[![GPL V3](https://www.gnu.org/graphics/gplv3-127x51.png)](https://www.gnu.org/licenses/gpl.html) diff --git a/symlinks.py b/symlinks.py index a77042c..464ccba 100644 --- a/symlinks.py +++ b/symlinks.py @@ -24,7 +24,9 @@ import platform USERDIR = os.path.expanduser('~') -if platform.system() in ['Linux', 'Darwin']: +if platform.system() == 'Darwin': + LIBDIR = os.path.join(USERDIR, 'Documents','Arduino','libraries') +elif platform.system() == 'Linux': LIBDIR = os.path.join(USERDIR, 'Arduino', 'libraries') elif platform.system() == 'Windows': sys.exit(0) diff --git a/symlinks_windows_ext.py b/symlinks_windows_ext.py index 36f0f90..d2ea022 100644 --- a/symlinks_windows_ext.py +++ b/symlinks_windows_ext.py @@ -22,41 +22,44 @@ if platform.system() in ['Linux', 'Darwin']: LIBDIR = os.path.join(USERDIR, 'sketchbook', 'libraries') elif platform.system() == 'Windows': - LIBDIR = os.path.join(USERDIR, 'Documents', 'Arduino', 'libraries') - #Symlinks for windows - def symlink_ms(source, link_name): - import ctypes - csl = ctypes.windll.kernel32.CreateSymbolicLinkW - csl.argtypes = (ctypes.c_wchar_p, ctypes.c_wchar_p, ctypes.c_uint32) - csl.restype = ctypes.c_ubyte - flags = 1 if os.path.isdir(source) else 0 - try: - if csl(link_name, source.replace('/', '\\'), flags) == 0: - raise ctypes.WinError() - except: - pass + LIBDIR = os.path.join(USERDIR, 'Documents', 'Arduino', 'libraries') + + def symlink_ms(source, link_name): + """ Symlinks for windows """ + import ctypes + csl = ctypes.windll.kernel32.CreateSymbolicLinkW + csl.argtypes = (ctypes.c_wchar_p, ctypes.c_wchar_p, ctypes.c_uint32) + csl.restype = ctypes.c_ubyte + flags = 1 if os.path.isdir(source) else 0 + try: + if csl(link_name, source.replace('/', '\\'), flags) == 0: + raise ctypes.WinError() + except WindowsError as e: + print(f"Symbolic link creation failed. The error is: {e}") + except: + pass def create_symlinks_windows(): - if not os.path.isdir(LIBDIR): - print ('Libraries directory does not exist - creating...') - os.makedirs(LIBDIR) - - src_paths, dst_paths = get_paths() - for src, dst in zip(src_paths, dst_paths): - if os.path.exists(dst): - if not isLink(dst): - print ('{0} exists and in not a symbolic link - not overwriting'.format(dst)) - continue - else: - print ('Unlinking {0}'.format(dst)) - os.unlink(dst) - - print('Creating new symbolic link {0}'.format(dst)) - symlink_ms(src, dst) + if not os.path.isdir(LIBDIR): + print('Libraries directory does not exist - creating...') + os.makedirs(LIBDIR) + + src_paths, dst_paths = get_paths() + for src, dst in zip(src_paths, dst_paths): + if os.path.exists(dst): + if not isLink(dst): + print('{0} exists and in not a symbolic link - not overwriting'.format(dst)) + continue + else: + print('Unlinking {0}'.format(dst)) + os.unlink(dst) + + print('Creating new symbolic link {0}'.format(dst)) + symlink_ms(src, dst) -def create_symlinks_unix(): +def create_symlinks_unix(): # Create library directory if it doesn't exist if not os.path.isdir(LIBDIR): print('libraries directory does not exist - creating') @@ -78,7 +81,6 @@ def create_symlinks_unix(): def remove_symlinks(): - if not os.path.isdir(LIBDIR): return @@ -108,28 +110,32 @@ def get_paths(): dst_paths.append(dst) return src_paths, dst_paths -#For Windows only + +# For Windows only def isLink(path): - if os.path.exists(path): - if os.path.isdir(path): - FILE_ATTRIBUTE_REPARSE_POINT = 0x4000 - attributes = ctypes.windll.kernel32.GetFileAttributesW(unicode(path)) - return (attributes & FILE_ATTRIBUTE_REPARSE_POINT) > 0 - else: - command = ['dir', path] - try: - with open(os.devnull, 'w') as NULL_FILE: - o0 = check_output(command, stderr=NULL_FILE, shell=True) - except CalledProcessError as e: - print e.check_output - return False - o1 = [s.strip() for s in o0.split('\n')] - if len(o1) < 6: - return False - else: - return 'SYMLINK' in o1[5] - else: - return False + if os.path.exists(path): + if os.path.isdir(path): + FILE_ATTRIBUTE_REPARSE_POINT = 0x4000 + if sys.version_info[0] < 3: + attributes = ctypes.windll.kernel32.GetFileAttributesW(unicode(path)) + else: + attributes = ctypes.windll.kernel32.GetFileAttributesW(path) + return (attributes & FILE_ATTRIBUTE_REPARSE_POINT) > 0 + else: + command = ['dir', path] + try: + with open(os.devnull, 'w') as NULL_FILE: + o0 = check_output(command, stderr=NULL_FILE, shell=True) + except CalledProcessError as e: + print(e.check_output) + return False + o1 = [s.strip() for s in o0.split('\n')] + if len(o1) < 6: + return False + else: + return 'SYMLINK' in o1[5] + else: + return False # ----------------------------------------------------------------------------- @@ -147,9 +153,14 @@ def isLink(path): sys.exit(1) args = parser.parse_args() if args.install: - if platform.system() in ['Linux', 'Darwin']: - create_symlinks_unix() + if platform.system() in ['Linux', 'Darwin']: + create_symlinks_unix() elif platform.system() == 'Windows': - create_symlinks_windows() + import ctypes + if not ctypes.windll.shell32.IsUserAnAdmin(): + # Re-run with admin privileges + ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, __file__+" -i", None, 1) + else: + create_symlinks_windows() elif args.remove: remove_symlinks()