diff --git a/openBeken_win32_mvsc2017.vcxproj b/openBeken_win32_mvsc2017.vcxproj index cdfcb65f6..6d41a8347 100644 --- a/openBeken_win32_mvsc2017.vcxproj +++ b/openBeken_win32_mvsc2017.vcxproj @@ -217,6 +217,8 @@ + + @@ -1294,4 +1296,4 @@ - \ No newline at end of file + diff --git a/platforms/obk_main.cmake b/platforms/obk_main.cmake index 870e2fde6..cfb1d80eb 100644 --- a/platforms/obk_main.cmake +++ b/platforms/obk_main.cmake @@ -81,7 +81,9 @@ set(OBKM_SRC ${OBK_SRCS}driver/drv_dht.c ${OBK_SRCS}driver/drv_drawers.c ${OBK_SRCS}driver/drv_doorSensorWithDeepSleep.c + ${OBK_SRCS}driver/drv_ds1820_common.c ${OBK_SRCS}driver/drv_ds1820_simple.c + ${OBK_SRCS}driver/drv_ds1820_full.c ${OBK_SRCS}driver/drv_freeze.c ${OBK_SRCS}driver/drv_gn6932.c ${OBK_SRCS}driver/drv_hd2015.c diff --git a/platforms/obk_main.mk b/platforms/obk_main.mk index 432b31220..727ed0a33 100644 --- a/platforms/obk_main.mk +++ b/platforms/obk_main.mk @@ -96,7 +96,9 @@ OBKM_SRC += $(OBK_SRCS)driver/drv_dht_internal.c OBKM_SRC += $(OBK_SRCS)driver/drv_dht.c OBKM_SRC += $(OBK_SRCS)driver/drv_drawers.c OBKM_SRC += $(OBK_SRCS)driver/drv_doorSensorWithDeepSleep.c +OBKM_SRC += $(OBK_SRCS)driver/drv_ds1820_common.c OBKM_SRC += $(OBK_SRCS)driver/drv_ds1820_simple.c +OBKM_SRC += $(OBK_SRCS)driver/drv_ds1820_full.c OBKM_SRC += $(OBK_SRCS)driver/drv_freeze.c OBKM_SRC += $(OBK_SRCS)driver/drv_gn6932.c OBKM_SRC += $(OBK_SRCS)driver/drv_hd2015.c @@ -159,4 +161,4 @@ OBKM_SRC += $(OBK_SRCS)i2c/drv_i2c_mcp23017.c OBKM_SRC += $(OBK_SRCS)i2c/drv_i2c_tc74.c OBKM_SRC_CXX += $(OBK_SRCS)driver/drv_ir.cpp -OBKM_SRC_CXX += $(OBK_SRCS)driver/drv_ir_new.cpp \ No newline at end of file +OBKM_SRC_CXX += $(OBK_SRCS)driver/drv_ir_new.cpp diff --git a/src/driver/drv_ds1820_common.c b/src/driver/drv_ds1820_common.c new file mode 100644 index 000000000..1b2bd57b8 --- /dev/null +++ b/src/driver/drv_ds1820_common.c @@ -0,0 +1,259 @@ +#include "../obk_config.h" + +#if (ENABLE_DRIVER_DS1820_FULL) || (ENABLE_DRIVER_DS1820) + + +#include "drv_ds1820_common.h" +#include "../hal/hal_generic.h" +#include "../hal/hal_pins.h" +#if PLATFORM_ESPIDF +#include "freertos/task.h" +#define noInterrupts() portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;taskENTER_CRITICAL(&mux) +#define interrupts() taskEXIT_CRITICAL(&mux) +#elif LINUX || WINDOWS +#define noInterrupts() +#define interrupts() +#else +#include +#define noInterrupts() taskENTER_CRITICAL() +#define interrupts() taskEXIT_CRITICAL() +#endif + + +#define DEVSTR "0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X" +#define DEV2STR(T) T[0],T[1],T[2],T[3],T[4],T[5],T[6],T[7] +#define SPSTR DEVSTR " 0x%02X " +#define SP2STR(T) DEV2STR(T),T[8] + + + + +int OWReset(int Pin) +{ + int result; + +// ESP32 will crash if interrupts are disabled for > 480us +#ifndef CONFIG_IDF_TARGET_ESP32 + noInterrupts(); +#endif + + //HAL_Delay_us(OWtimeG); + HAL_PIN_Setup_Output(Pin); + HAL_PIN_SetOutputValue(Pin, 0); // Drives DQ low + HAL_Delay_us(OWtimeH); + HAL_PIN_Setup_Input_Pullup(Pin); // Releases the bus + HAL_Delay_us(OWtimeI); + result = HAL_PIN_ReadDigitalInput(Pin) ^ 0x01; // Sample for presence pulse from slave + +#ifndef CONFIG_IDF_TARGET_ESP32 + interrupts(); +#endif + + HAL_Delay_us(OWtimeJ); // Complete the reset sequence recovery + return result; // Return sample presence pulse result +} + +//----------------------------------------------------------------------------- +// Send a 1-Wire write bit. Provide 10us recovery time. +//----------------------------------------------------------------------------- +void OWWriteBit(int Pin, int bit) +{ + if(bit) + { + // Write '1' bit + HAL_PIN_Setup_Output(Pin); + noInterrupts(); + HAL_PIN_SetOutputValue(Pin, 0); // Drives DQ low + HAL_Delay_us(OWtimeA); + HAL_PIN_SetOutputValue(Pin, 1); // Releases the bus + interrupts(); // hope for the best for the following timer and keep CRITICAL as short as possible + HAL_Delay_us(OWtimeB); // Complete the time slot and 10us recovery + } + else + { + // Write '0' bit + HAL_PIN_Setup_Output(Pin); + noInterrupts(); + HAL_PIN_SetOutputValue(Pin, 0); // Drives DQ low + HAL_Delay_us(OWtimeC); + HAL_PIN_SetOutputValue(Pin, 1); // Releases the bus + interrupts(); // hope for the best for the following timer and keep CRITICAL as short as possible + HAL_Delay_us(OWtimeD); + } +} + +//----------------------------------------------------------------------------- +// Read a bit from the 1-Wire bus and return it. Provide 10us recovery time. +//----------------------------------------------------------------------------- +int OWReadBit(int Pin) +{ + int result; + + noInterrupts(); + HAL_PIN_Setup_Output(Pin); + HAL_PIN_SetOutputValue(Pin, 0); // Drives DQ low + HAL_Delay_us(1); // give sensor time to react on start pulse + HAL_PIN_Setup_Input_Pullup(Pin); // Release the bus + HAL_Delay_us(OWtimeE); // give time for bus rise, if not pulled + + result = HAL_PIN_ReadDigitalInput(Pin); // Sample for presence pulse from slave + interrupts(); // hope for the best for the following timer and keep CRITICAL as short as possible + HAL_Delay_us(OWtimeF); // Complete the time slot and 10us recovery + return result; +} + +//----------------------------------------------------------------------------- +// Poll if DS1820 temperature conversion is complete +//----------------------------------------------------------------------------- +int DS1820TConversionDone(int Pin) +{ + // Write '1' bit + OWWriteBit(Pin, 1); + // check for '1' - conversion complete (will be '0' else) + return OWReadBit(Pin); +} + + +//----------------------------------------------------------------------------- +// Write 1-Wire data byte +//----------------------------------------------------------------------------- +void OWWriteByte(int Pin, int data) +{ + int loop; + + // Loop to write each bit in the byte, LS-bit first + for(loop = 0; loop < 8; loop++) + { + OWWriteBit(Pin, data & 0x01); + + // shift the data byte for the next bit + data >>= 1; + } +} + +//----------------------------------------------------------------------------- +// Read 1-Wire data byte and return it +//----------------------------------------------------------------------------- +int OWReadByte(int Pin) +{ + int loop, result = 0; + + for(loop = 0; loop < 8; loop++) + { + // shift the result to get it ready for the next bit + result >>= 1; + + // if result is one, then set MS bit + if(OWReadBit(Pin)) + result |= 0x80; + } + return result; +} +/* +//----------------------------------------------------------------------------- +// Write a 1-Wire data byte and return the sampled result. +//----------------------------------------------------------------------------- +int OWTouchByte(int Pin, int data) +{ + int loop, result = 0; + + for(loop = 0; loop < 8; loop++) + { + // shift the result to get it ready for the next bit + result >>= 1; + + // If sending a '1' then read a bit else write a '0' + if(data & 0x01) + { + if(OWReadBit(Pin)) + result |= 0x80; + } + else + OWWriteBit(Pin, 0); + + // shift the data byte for the next bit + data >>= 1; + } + return result; +} +*/ + +// quicker CRC with lookup table +// based on code found here: https://community.st.com/t5/stm32-mcus-security/use-stm32-crc-to-compare-ds18b20-crc/m-p/333749/highlight/true#M4690 +// Dallas 1-Wire CRC Test App - +// x^8 + x^5 + x^4 + 1 0x8C (0x131) + +uint8_t Crc8CQuick(uint8_t* Buffer, uint8_t Size) +{ + // Nibble table for polynomial 0x8C + static const uint8_t CrcTable[] = + { + 0x00,0x9D,0x23,0xBE,0x46,0xDB,0x65,0xF8, + 0x8C,0x11,0xAF,0x32,0xCA,0x57,0xE9,0x74 + }; + uint8_t Crc = 0x00; + while(Size--) + { + Crc ^= *Buffer++; // Apply Data + Crc = (Crc >> 4) ^ CrcTable[Crc & 0x0F]; // Two rounds of 4-bits + Crc = (Crc >> 4) ^ CrcTable[Crc & 0x0F]; + } + return(Crc); +} + + +#if ENABLE_DS1820_TEST_US +// will allow testus .... +commandResult_t CMD_OW_testus(const void *context, const char *cmd, const char *args, int cmdFlags) { + Tokenizer_TokenizeString(args, TOKENIZER_ALLOW_QUOTES); + int tests= Tokenizer_GetArgsCount()-2; // first two are pin and pause-value + if(Tokenizer_GetArgsCount()<=3) { + return CMD_RES_NOT_ENOUGH_ARGUMENTS; + } +#define MAXUSTESTS 10 + int testvals[MAXUSTESTS]; + int pin = Tokenizer_GetArgInteger(0); + int pause = Tokenizer_GetArgInteger(1); + if (tests > MAXUSTESTS){ + tests = MAXUSTESTS; + DS1820_LOG(INFO, "testus - Warning, will only do the first %i tests!\r\n",tests); + } + for (int i=0; i [...]", + //cmddetail:"descr":"tests usleep on given pin ", + //cmddetail:"fn":"NULL);","file":"driver/drv_ds1820_simple.c","requires":"", + //cmddetail:"examples":"testus 11 5 2 4 6 10 20 50 100 200 500"} + CMD_RegisterCommand("testus", CMD_OW_testus, NULL); +#endif +} + +#endif // to #if (ENABLE_DRIVER_DS1820_FULL) || (ENABLE_DRIVER_DS1820) diff --git a/src/driver/drv_ds1820_common.h b/src/driver/drv_ds1820_common.h new file mode 100644 index 000000000..4cca59b4b --- /dev/null +++ b/src/driver/drv_ds1820_common.h @@ -0,0 +1,72 @@ +#pragma once + +#include "../new_common.h" +#include "../new_pins.h" +#include "../new_cfg.h" +// Commands register, execution API and cmd tokenizer +#include "../cmnds/cmd_public.h" +#include "../mqtt/new_mqtt.h" +#include "../logging/logging.h" +#include "../httpserver/new_http.h" + + +// some OneWire commands +#define SEARCH_ROM 0xF0 // to identify the ROM codes of all slave devices on the bus +#define ALARM_SEARCH 0xEC // all devices with an alarm condition (as SEARCH_ROM except only slaves with a set alarm flag will respond) +#define READ_ROM 0x33 // Only single device! Read 64-bit ROM code without using the Search ROM procedure +#define SKIP_ROM 0xCC // Ignore ROM adress / address all devices +#define CONVERT_T 0x44 // take temperature reading and copy it to scratchpad +#define READ_SCRATCHPAD 0xBE // Read scratchpad +#define WRITE_SCRATCHPAD 0x4E // Write scratchpad +#define SELECT_DEVICE 0x55 // (Match ROM) address a single devices on the bus +/* +//unused for now +#define COPY_SCRATCHPAD 0x48 // Copy scratchpad to EEPROM +#define RECALL_E2 0xB8 // Recall from EEPROM to scratchpad +#define READ_POWER_SUPPLY 0xB4 // Determine if device needs parasite power +*/ + +// 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 + +#define OWtimeA 6 +#define OWtimeB 64 +#define OWtimeC 60 +#define OWtimeD 10 +#define OWtimeE 9 +#define OWtimeF 55 +#define OWtimeG 0 +#define OWtimeH 480 +#define OWtimeI 70 +#define OWtimeJ 410 + + +#define DEVICE_DISCONNECTED_C -127 + + +void init_TEST_US(); + +int OWReset(int Pin); +void OWWriteBit(int Pin, int bit); +int OWReadBit(int Pin); +int DS1820TConversionDone(int Pin); +void OWWriteByte(int Pin, int data); +int OWReadByte(int Pin); +int OWTouchByte(int Pin, int data); +uint8_t Crc8CQuick(uint8_t* Buffer, uint8_t Size); + + + diff --git a/src/driver/drv_ds1820_full.c b/src/driver/drv_ds1820_full.c new file mode 100644 index 000000000..259db9bd5 --- /dev/null +++ b/src/driver/drv_ds1820_full.c @@ -0,0 +1,920 @@ +#include "../obk_config.h" + +#if (ENABLE_DRIVER_DS1820_FULL) + +#include "drv_ds1820_common.h" +#include "drv_ds1820_full.h" + +#include "../new_common.h" +#include "../new_pins.h" +#include "../new_cfg.h" +// Commands register, execution API and cmd tokenizer +#include "../cmnds/cmd_public.h" +#include "../mqtt/new_mqtt.h" +#include "../logging/logging.h" +#include "drv_local.h" +#include "../httpserver/new_http.h" +#include "../hal/hal_pins.h" + +#define DEVSTR "0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X" +#define DEV2STR(T) T[0],T[1],T[2],T[3],T[4],T[5],T[6],T[7] +#define SPSTR DEVSTR " 0x%02X " +#define SP2STR(T) DEV2STR(T),T[8] + + + +static uint8_t dsread = 0; +static int Pin = -1; +//static int t = -127; +static int errcount = 0; +static int lastconv; // secondsElapsed on last successfull reading +static uint8_t ds18_family = 0; +static int ds18_conversionPeriod = 0; + +typedef uint8_t ScratchPad[9]; +typedef uint8_t DeviceAddress[8]; // we need to distinguish sensors by their address + +typedef struct { + DeviceAddress array[DS18B20MAX]; + uint8_t index; + char name[DS18B20MAX][DS18B20namel]; + float lasttemp[DS18B20MAX]; + unsigned short last_read[DS18B20MAX]; + short channel[DS18B20MAX]; + short GPIO[DS18B20MAX]; + +} DS1820devices; + +static int ds18_count = 0; // detected number of devices + +uint8_t DS18B20_GPIO; // the actual GPIO used (changes in case we have multiple GPIOs defined ...) + +DeviceAddress ROM_NO; + +static DS1820devices ds18b20devices; +uint8_t DS18B20GPIOS[DS18B20MAX_GPIOS]; +uint8_t devices = 0; + + +uint8_t LastDiscrepancy; +uint8_t LastFamilyDiscrepancy; +bool LastDeviceFlag; + +#define DS1820_LOG(x, fmt, ...) addLogAdv(LOG_##x, LOG_FEATURE_SENSOR, "DS1820 - " fmt, ##__VA_ARGS__) + +// prototypes +int devstr2DeviceAddr(uint8_t *devaddr, const char *dev); +bool ds18b20_getGPIO(const uint8_t* devaddr,uint8_t *GPIO); +bool ds18b20_readScratchPad(const uint8_t* deviceAddress, uint8_t* scratchPad); + + + +bool ds18b20_writeScratchPad(const uint8_t *deviceAddress, const uint8_t *scratchPad) { + if ( ! ds18b20_getGPIO(deviceAddress, &DS18B20_GPIO ) ) { + DS1820_LOG(DEBUG, "No GPIO found for device - DS18B20_GPIO=%i", DS18B20_GPIO); + return false; + } + DS1820_LOG(DEBUG, "GPIO found for device - DS18B20_GPIO=%i", DS18B20_GPIO); + // send the reset command and fail fast + int b = OWReset(DS18B20_GPIO); + if (b == 0) { +// DS1820_LOG(DEBUG, "Resetting GPIO %i failed", DS18B20_GPIO); + return false; + } + ds18b20_select(deviceAddress); + OWWriteByte(DS18B20_GPIO,WRITE_SCRATCHPAD); + OWWriteByte(DS18B20_GPIO,scratchPad[HIGH_ALARM_TEMP]); // high alarm temp + OWWriteByte(DS18B20_GPIO,scratchPad[LOW_ALARM_TEMP]); // low alarm temp + OWWriteByte(DS18B20_GPIO,scratchPad[CONFIGURATION]); + DS1820_LOG(DEBUG, "Wrote scratchpad " SPSTR , SP2STR(scratchPad)); + return (bool)OWReset(DS18B20_GPIO); +} + + + +static commandResult_t Cmd_DS18B20_SetResolution(const void* context, const char* cmd, const char* args, int cmdFlags) { + Tokenizer_TokenizeString(args, TOKENIZER_ALLOW_QUOTES); + if (Tokenizer_CheckArgsCountAndPrintWarning(cmd, 1)) { + return CMD_RES_NOT_ENOUGH_ARGUMENTS; + } + int arg = Tokenizer_GetArgInteger(0); + if (arg > 12 || arg < 9) + return CMD_RES_BAD_ARGUMENT; + // arg can be 9 10 11 12 + // the newValue shall be 9:0x1F 10:0x3F 11:0x5F 12:0x7F + // ignoring the "0x0F" an lookig just at the first digit, + // we can easily see this is 1+(arg-9)*2 + // so this can be written as + uint8_t newValue = 0x1F | (arg-9)<<5 ; + DS1820_LOG(DEBUG, "DS1820_SetResolution: newValue=0x%02X ", newValue); + ScratchPad scratchPad; + if (Tokenizer_GetArgsCount() > 1){ + const char *dev = Tokenizer_GetArg(1); + DeviceAddress devaddr={0}; + if (! devstr2DeviceAddr(devaddr,(const char*)dev)){ + DS1820_LOG(ERROR, "DS1820_SetResolution: device not found"); + return CMD_RES_BAD_ARGUMENT; + } + if (devaddr[0] != 0x28) { + DS1820_LOG(ERROR, "DS1820_SetResolution not supported by sensor family 0x%02X",devaddr[0]); + return CMD_RES_UNKNOWN_COMMAND; + } + + if (ds18b20_isConnected((uint8_t*)devaddr, scratchPad)){ + // if it needs to be updated we write the new value + DS1820_LOG(DEBUG, "Read scratchpad " SPSTR , SP2STR(scratchPad)); + if (scratchPad[CONFIGURATION] != newValue) { + scratchPad[CONFIGURATION] = newValue; + DS1820_LOG(DEBUG, "Going to write scratchpad " SPSTR , SP2STR(scratchPad)); + if (! ds18b20_writeScratchPad((uint8_t*)devaddr, scratchPad)){ +// DS1820_LOG(ERROR, "DS1820_SetResolution: failed to write scratchpad for sensor " DEVSTR ,DEV2STR((uint8_t*)devaddr)); + DS1820_LOG(ERROR, "DS1820_SetResolution: failed to write scratchpad for sensor " DEVSTR ,DEV2STR(devaddr)); + } + } + } + else { + DS1820_LOG(ERROR, "DS1820_SetResolution: failed to read scratchpad!"); + } + } + else { + for (int i=0; i < ds18_count; i++) { +// DS1820_LOG(DEBUG, "DS1820_SetResolution: setting sensor " DEVSTR ,DEV2STR((uint8_t*)ds18b20devices.array[i])); + DS1820_LOG(DEBUG, "DS1820_SetResolution: setting sensor " DEVSTR ,DEV2STR(ds18b20devices.array[i])); + if (ds18b20devices.array[i][0] != 0x28) { + DS1820_LOG(ERROR, "DS1820_SetResolution not supported by sensor family 0x%02X",ds18b20devices.array[i][0]); + return CMD_RES_UNKNOWN_COMMAND; + } + if (ds18b20_isConnected((uint8_t*)ds18b20devices.array[i], scratchPad)) { + if (scratchPad[CONFIGURATION] != newValue) { + scratchPad[CONFIGURATION] = newValue; + if (! ds18b20_writeScratchPad((uint8_t*)ds18b20devices.array[i], scratchPad)){ +// DS1820_LOG(ERROR, "DS1820_SetResolution: failed to write scratchpad for sensor " DEVSTR ,DEV2STR((uint8_t*)ds18b20devices.array[i])); + DS1820_LOG(ERROR, "DS1820_SetResolution: failed to write scratchpad for sensor " DEVSTR ,DEV2STR(ds18b20devices.array[i])); + } + } + } + else { +// DS1820_LOG(ERROR, "DS1820_SetResolution: couldn't connect to sensor " DEVSTR ,DEV2STR((uint8_t*)ds18b20devices.array[i])); + DS1820_LOG(ERROR, "DS1820_SetResolution: couldn't connect to sensor " DEVSTR ,DEV2STR(ds18b20devices.array[i])); + } + } + } + + + //temperature conversion was interrupted + dsread = 0; + + return CMD_RES_OK; +} + +void ds18b20_requestConvertT(int GPIO) { + OWReset(GPIO); + OWWriteByte(GPIO,SKIP_ROM); + OWWriteByte(GPIO,CONVERT_T); +} + + + + +// use same code to read scatchpad and test CRC in one +// parameter beside scratchPad to fill is +// only GPIO pin for single DS1820 +// sensor address for multiple devices +bool ds18b20_readScratchPad(const uint8_t *deviceAddress, uint8_t* scratchPad) { + if ( ! ds18b20_getGPIO(deviceAddress, &DS18B20_GPIO ) ) { + DS1820_LOG(DEBUG, "No GPIO found for device - DS18B20_GPIO=%i", DS18B20_GPIO); + return false; + } + DS1820_LOG(DEBUG, "GPIO found for device - DS18B20_GPIO=%i", DS18B20_GPIO); + // send the reset command and fail fast + int b = OWReset(DS18B20_GPIO); + if (b == 0) { +// DS1820_LOG(DEBUG, "Resetting GPIO %i failed", DS18B20_GPIO); + return false; + } + ds18b20_select(deviceAddress); + OWWriteByte(DS18B20_GPIO, READ_SCRATCHPAD); + // 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: DS18B20 & DS1822: configuration register + // byte 5: internal use & crc + // byte 6: DS18B20 & DS1822: store for crc + // byte 7: DS18B20 & DS1822: store for crc + // byte 8: SCRATCHPAD_CRC + for (uint8_t i = 0; i < 9; i++) { + scratchPad[i] = OWReadByte(DS18B20_GPIO); + } + uint8_t crc = Crc8CQuick(scratchPad, 8); + if(crc != scratchPad[8]) + { + DS1820_LOG(ERROR, "Read CRC=%x != calculated:%x (errcount=%i)", scratchPad[8], crc, errcount); + DS1820_LOG(ERROR, "Scratchpad Data Read: " SPSTR, + SP2STR(scratchPad)); + + return false; + } + + return OWReset(DS18B20_GPIO); +} + + +float ds18b20_Scratchpat2TempC(const ScratchPad scratchPad, uint8_t family) { + int16_t raw = (int16_t)scratchPad[TEMP_MSB] << 8 | (int16_t)scratchPad[TEMP_LSB]; + if(family == 0x10) + { + // DS18S20 or old DS1820 + int16_t dT = 128 * (scratchPad[7] - scratchPad[6]); + dT /= scratchPad[7]; + raw = 64 * (raw & 0xFFFE) - 32 + dT; + DS1820_LOG(DEBUG, "family=%x, raw=%i, count_remain=%i, count_per_c=%i, dT=%i", family, raw, scratchPad[6], scratchPad[7], dT); + } + else + { // DS18B20 + + // Bits 6 and 5 of CFG byte will contain R1 R0 representing the resolution: + // 00 9 bits + // 01 10 bits + // 10 11 bits + // 11 12 bits + // + // might be read as "how many from the last three bits are valid? 0 for 9bits, all 3 for 12 bits + // we want the unused bits to be 0, so we need to mask out ~ R1R0 bits ( 0 for 12bit ... 3 for 9 bit) + // so here's what we do: + // get bits 6 and five ( & 0x60) and push them 5 bits right --> so we have 0 0 0 0 0 0 R1 R0 --> decimal 0 (for 9 bits) to 3 (for 12 bts) + // we want to mask the bits, so substract from 3 --> decimal 3 (=3-0 for 9 bits) to 0 (=3-3 for 12 bits) + // to mask out / delete x bits we use & ((1 << x ) -1) + // + uint8_t maskbits = 3 - ((scratchPad[4] & 0x60) >> 5) ; // maskbits will be number of bit to zero out + raw = raw & ~ ( (1 << maskbits) -1) ; +// DS1820_LOG(DEBUG, "maskbits=%x, raw=%i", maskbits, raw); + raw = raw << 3; // multiply by 8 + DS1820_LOG(DEBUG, "ds18b20_Scratchpat2TempC: family=%x, raw=%i (%i bit resolution)", family, raw, 12 - maskbits ); + } + + // Raw is t * 128 +/* + t = (raw / 128) * 100; // Whole degrees + int frac = (raw % 128) * 100 / 128; // Fractional degrees + t += t > 0 ? frac : -frac; +*/ +// t = (raw * 100) / 128; // no need to calc fractional, if we can simply get 100 * temp in one line + if (raw <= DEVICE_DISCONNECTED_C * 128) + return DEVICE_DISCONNECTED_C; + // C = RAW/128 + return (float)raw / 128.0f; +} + + +bool ds18b20_used_channel(int ch) { + for (int i=0; i < ds18_count; i++) { + if (ds18b20devices.channel[i] == ch) { + return true; + } + } + return false; +}; + +bool ds18b20_getGPIO(const uint8_t* devaddr,uint8_t *GPIO) +{ + int i=0; + for (i=0; i < ds18_count; i++) { + if (! memcmp(devaddr,ds18b20devices.array[i],8)){ // found device + DS1820_LOG(DEBUG, "Found device at index %i - GPIO=%i", i,ds18b20devices.GPIO[i]); + *GPIO=ds18b20devices.GPIO[i]; + return true; + } + } + return false; +}; + +bool ds18b20_select(const uint8_t *address) { + if ( ! ds18b20_getGPIO(address, &DS18B20_GPIO ) ) return false; + uint8_t i; + OWWriteByte(DS18B20_GPIO, SELECT_DEVICE); // Choose ROM + for (i = 0; i < 8; i++) OWWriteByte(DS18B20_GPIO, ((uint8_t *)address)[i]); + return true; +} + +bool ds18b20_isAllZeros(const uint8_t * const scratchPad) { + for (size_t i = 0; i < 9; i++) { + if (scratchPad[i] != 0) { + return false; + } + } + return true; +} + +bool ds18b20_isConnected(const uint8_t *deviceAddress, uint8_t *scratchPad) { + // no need to check for GPIO of device here, ds18b20_readScratchPad() will do so and return false, if not + bool b = ds18b20_readScratchPad((const uint8_t *)deviceAddress, scratchPad); + DS1820_LOG(DEBUG, "ds18b20_readScratchPad returned %i - Crc8CQuick=%i / scratchPad[SCRATCHPAD_CRC]=%i",b,Crc8CQuick(scratchPad, 8),scratchPad[SCRATCHPAD_CRC]); + return b && !ds18b20_isAllZeros(scratchPad) && (Crc8CQuick(scratchPad, 8) == scratchPad[SCRATCHPAD_CRC]); +} + + +float ds18b20_getTempC(const uint8_t *dev) { + ScratchPad scratchPad; + if (ds18b20_isConnected((const uint8_t *)dev, scratchPad)) { + return ds18b20_Scratchpat2TempC(scratchPad, (uint8_t)dev[0]); // deviceAddress[0] equals to "family" (0x28 for DS18B20) + } else DS1820_LOG(DEBUG, "Device not connected"); + return DEVICE_DISCONNECTED_C; +} + + +bool isConversionComplete() { + return DS1820TConversionDone(DS18B20_GPIO); +} + + +// +// 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 reset_search() { + devices = 0; + // reset the search state + LastDiscrepancy = 0; + LastDeviceFlag = false; + LastFamilyDiscrepancy = 0; + for (int i = 7; i >= 0; i--) { + ROM_NO[i] = 0; + } +} +// --- 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 + +bool search(uint8_t *newAddr, bool search_mode, int Pin) { + uint8_t id_bit_number; + uint8_t last_zero, rom_byte_number; + bool 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 = false; + + // if the last call was not the last one + if (!LastDeviceFlag) { + // 1-Wire reset + if (!OWReset(Pin)) { + // reset the search + LastDiscrepancy = 0; + LastDeviceFlag = false; + LastFamilyDiscrepancy = 0; + return false; + } + + // issue the search command + if (search_mode == true) { + OWWriteByte(Pin,SEARCH_ROM); // search all devices + } + else { + OWWriteByte(Pin,ALARM_SEARCH); // search for devices with alarm only + } + + // loop to do the search + do { + // read a bit and its complement + id_bit = OWReadBit(Pin); + cmp_id_bit = OWReadBit(Pin); + + // 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 + OWWriteBit(Pin,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]) { + devices = 0; + LastDiscrepancy = 0; + LastDeviceFlag = false; + LastFamilyDiscrepancy = 0; + search_result = false; + } + else { + for (int i = 0; i < 8; i++) { + newAddr[i] = ROM_NO[i]; + } + devices++; + } + return search_result; +} + + + + +// add a new device into DS1820devices +void insertArray(DS1820devices *a, DeviceAddress devaddr) { + if (ds18_count >= DS18B20MAX){ + bk_printf("insertArray ERROR:Arry is full, can't add device " DEVSTR " ", + DEV2STR(devaddr)); + return; + } + bk_printf("insertArray - ds18_count=%i -- adding device " DEVSTR " ",ds18_count, + DEV2STR(devaddr)); + + for (int i=0; i < ds18_count; i++) { + if (! memcmp(devaddr,ds18b20devices.array[i],8)){ // found device, no need to reenter + a->GPIO[i]=DS18B20_GPIO; // just to be sure - maybe device is on other GPIO now?!? + bk_printf("device " DEVSTR " was allready present - just (re-)setting GPIO to %i", + DEV2STR(devaddr),DS18B20_GPIO); + return; + } + } + + for (int i = 0; i < 8; i++) { + a->array[ds18_count][i] = devaddr[i]; + } + sprintf(a->name[ds18_count],"Sensor %i",ds18_count); + a->lasttemp[ds18_count] = -127; + a->last_read[ds18_count] = 0; + a->channel[ds18_count] = -1; + a->GPIO[ds18_count]=DS18B20_GPIO; + ds18_count++; +} + +// search DS18B20 devices on one GPIO pin +int DS18B20_fill_devicelist(int Pin) +{ + DeviceAddress devaddr={0}; + int ret=0; +#if WINDOWS + // For Windows add some "fake" sensors with increasing addresses + // 28 FF AA BB CC DD EE 01, 28 FF AA BB CC DD EE 02, ... + devaddr[0]=0x28; devaddr[1]=0xFF; devaddr[2]=0xAA; devaddr[3]=0xBB;devaddr[4]=0xCC;devaddr[5]=0xDD;devaddr[6]=0xEE; + while (ds18_count < 1+(DS18B20MAX/2) ){ + devaddr[7]=++ret; + bk_printf("found device " DEVSTR " ", + DEV2STR(devaddr)); + insertArray(&ds18b20devices,devaddr); + } +#else + reset_search(); + while (search(devaddr,1,Pin) && ds18_count < DS18B20MAX ){ + bk_printf("found device " DEVSTR" ", + DEV2STR(devaddr)); + insertArray(&ds18b20devices,devaddr); + ret++; + } +#endif + return ret; +}; + +// a sensor must have a GPIO assigned +int DS18B20_set_deviceGPIO(DeviceAddress devaddr,const int pin) +{ + int i=0; + for (i=0; i < ds18_count; i++) { + if (! memcmp(devaddr,ds18b20devices.array[i],8)){ // found device + ds18b20devices.GPIO[i]=pin; + return 1; + } + } + bk_printf("didn't find device " DEVSTR " - inserting", + DEV2STR(devaddr)); + insertArray(&ds18b20devices,devaddr); + // if device was inserted (array not full) now the new device is the last one at position ds18_count-1 + if (! memcmp(devaddr,ds18b20devices.array[ds18_count-1],8)){ // found device + ds18b20devices.GPIO[i]=pin; + return 1; + } + return 0; +}; + + +// a sensor should have a human readable name to distinguish sensors +int DS18B20_set_devicename(DeviceAddress devaddr,const char *name) +{ + int i=0; + for (i=0; i < ds18_count; i++) { + if (! memcmp(devaddr,ds18b20devices.array[i],8)){ // found device + if (strlen(name)= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); +} + +// convert a string with sensor address to "DeviceAddress" +// valid input is +// "0x28 0x01 0x02 0x03 0x04 0x05 0x06 0x07" or +// "2801020304050607" +// additional whitespace is ignored, also any input after 8 bytes (warning is printed) +int devstr2DeviceAddr(uint8_t *devaddr, const char *dev){ + // Clear the address array + memset(devaddr, 0, 8); + int count = 0; // Count of valid hex values read + char hex_pair[3] = {0}; // Buffer to hold two hex digits + + for (int i = 0; dev[i] != '\0'; i++) { + // Skip whitespace + if (isspace((unsigned char)dev[i])) { + continue; + } + if (count >= 8) { // we already found 8 address byte, but input is not empty ! + DS1820_LOG(WARN, "devstr2DeviceAddr: WARNING additional input after 8th address byte ('%s') is ignored. Using only %.*s",&dev[i],i,dev); + return count; + } + // Check for "0x" or "0X" + if (dev[i] == '0' && (dev[i + 1] == 'x' || dev[i + 1] == 'X')) { + i++; // Skip both '0' and 'x' + // Read the next two hex digits + if (is_valid_hex_char(dev[i + 1]) && is_valid_hex_char(dev[i + 2])) { + hex_pair[0] = dev[i + 1]; + hex_pair[1] = dev[i + 2]; + devaddr[count++] = (uint8_t)strtol(hex_pair, NULL, 16); // Convert to uint8_t + i += 2; // advance the two hex digits + } else { + return -1; // Error: Invalid hex sequence + } + } else if (is_valid_hex_char(dev[i])) { + // If a valid hex character is found, read the next character + if (is_valid_hex_char(dev[i + 1])) { + hex_pair[0] = dev[i]; + hex_pair[1] = dev[i + 1]; + devaddr[count++] = (uint8_t)strtol(hex_pair, NULL, 16); // Convert to uint8_t + i++; // Move to the next hex character + } else { + return -1; // Error: Incomplete hex pair + } + } else { + return -1; // Error: Invalid character found + } + } + // Return the number of valid hex values read + return count; // Success +} + +commandResult_t CMD_DS18B20_setsensor(const void *context, const char *cmd, const char *args, int cmdFlags) { + Tokenizer_TokenizeString(args, TOKENIZER_ALLOW_QUOTES); + + if(Tokenizer_GetArgsCount()<=1) { + return CMD_RES_NOT_ENOUGH_ARGUMENTS; + } + + const char *dev = Tokenizer_GetArg(0); + int gpio = Tokenizer_IsArgInteger(1) ? Tokenizer_GetArgInteger(1) : HAL_PIN_Find(Tokenizer_GetArg(1)); + if (gpio < 0) { + DS1820_LOG(ERROR, "DS18B20_setsensor: failed to find GPIO for '%s' (as int: %i)",Tokenizer_GetArg(1),gpio); + return CMD_RES_ERROR; + } + const char *name = Tokenizer_GetArg(2); + DeviceAddress devaddr={0}; + if (devstr2DeviceAddr(devaddr,(const char*)dev)){ + DS18B20_set_deviceGPIO(devaddr,gpio); + DS18B20_set_devicename(devaddr,name); + if (Tokenizer_GetArgsCount() >= 3 && Tokenizer_IsArgInteger(3)){ + DS18B20_set_channel(devaddr,Tokenizer_GetArgInteger(3)); + } + + return CMD_RES_OK; + } + else return CMD_RES_ERROR; +} + + +void scan_sensors(){ + ds18_count=0; + reset_search(); + int i,j=0; + for (i = 0; i < PLATFORM_GPIO_MAX; i++) { + if ((g_cfg.pins.roles[i] == IOR_DS1820_IO) && ( j < DS18B20MAX_GPIOS)){ + DS18B20GPIOS[j++]=i; + DS18B20_GPIO = i ; // set DS18B20_GPIO to i + DS18B20_fill_devicelist(i); + } + } + // fill unused "pins" with 99 as sign for unused + for (;jDS18B20 devices detected/configured: %i",ds18_count); + return; + } + + if (ds18_count > 0 ){ + hprintf255(request, "DS18B20 devices" + "",ds18_count); + for (int i=0; i < ds18_count; i++) { + const char * pinalias=NULL; + char gpioname[10]; + char tmp[50]; + pinalias = HAL_PIN_GetPinNameAlias(ds18b20devices.GPIO[i]); + if (! pinalias ) { + sprintf(gpioname,"GPIO %u",ds18b20devices.GPIO[i]); + pinalias = gpioname; + } + if (ds18b20devices.lasttemp[i] > -127){ + sprintf(tmp,"%0.2f" + "" + "",ds18b20devices.name[i], + DEV2STR(ds18b20devices.array[i]), + pinalias, chan, tmp); + } + hprintf255(request, "
Name   Address Pin CH Temp read %i s ago",(ds18b20devices.lasttemp[i]),ds18b20devices.last_read[i]); + } + else { + sprintf(tmp, " -- --"); + } + int ch=ds18b20devices.channel[i]; + char chan[5]=" - "; + if (ch >=0) sprintf(chan,"%i",(uint8_t)ch); + hprintf255(request, "
%s   %02X %02X %02X %02X %02X %02X %02X %02X%s%s%s
"); + } +} + +#include "../httpserver/http_fns.h" + +int http_fn_cfg_ds18b20(http_request_t* request) +{ + char tmp[64], tmp2[64]; + + for (int i=0; i < ds18_count; i++) { + sprintf(tmp2,"ds1820name%i",i); + if (http_getArg(request->url, tmp2, tmp, sizeof(tmp))) { + DS18B20_set_devicename(ds18b20devices.array[i],tmp); + } + sprintf(tmp2,"ds1820chan%i",i); + if (http_getArg(request->url, tmp2, tmp, sizeof(tmp))) { + int c=atoi(tmp); + DS18B20_set_channel(ds18b20devices.array[i],c); + } + + } + + http_setup(request, httpMimeTypeHTML); + http_html_start(request, "DS18B20"); + + +// poststr_h2(request, "Here you can configure DS18B20 sensors detected or configured"); + hprintf255(request, "

Configure DS18B20 Sensors

"); + hprintf255(request, ""); + for (int i=0; i < ds18_count; i++) { + int ch=ds18b20devices.channel[i]; + char chan[5]={0}; + if (ch >=0) sprintf(chan,"%i",(uint8_t)ch); + hprintf255(request, "" + "",i, + DEV2STR(ds18b20devices.array[i]), + i,ds18b20devices.GPIO[i], + i,i,ds18b20devices.name[i]); + hprintf255(request, "", + i,i,chan); + } + hprintf255(request, "
Sensor AddressPin   Name Channel
"DEVSTR" %i" + "   
"); + + + poststr(request, "
"); + poststr(request,"
Use multiline command

"); + hprintf255(request, ""); + poststr(request, htmlFooterReturnToCfgOrMainPage); + http_html_end(request); + poststr(request, NULL); + return 0; +} + +void DS1820_full_OnEverySecond() +{ + // for now just find the pin used + Pin = PIN_FindPinIndexForRole(IOR_DS1820_IO, -1); + + // only if (at least one) pin is set + if(Pin < 0) { + DS1820_LOG(INFO, "No Pin found\r\n"); + return; + } + //Temperature measurement is done in two repeatable steps. + // Step 1 - dsread = 0. Sensor requested to do temperature conversion. + // That requires some time - 15-100-750ms, depending on sensor family/vendor. + // However, time between steps is always one second. + // Step 2 - dsread = 1. Sensor finished conversion, requesting conversion result. + + // request temp if conversion was requested two seconds after request + // if (dsread == 1 && g_secondsElapsed % 5 == 2) { + // better if we don't use parasitic power, we can check if conversion is ready + DS1820_LOG(DEBUG, ".. Pin %i found! dsread=%i \r\n",Pin,dsread); + if(dsread == 1){ +#if WINDOWS + bk_printf("Reading temperature from fake DS18B20 sensor(s)\r\n"); + for (int i=0; i < ds18_count; i++) { + ds18b20devices.last_read[i] += 1 ; + errcount = 0; + float t_float = 20.0 + i/10.0 + (float)(g_secondsElapsed%100)/100.0; + ds18b20devices.lasttemp[i] = t_float; + ds18b20devices.last_read[i] = 0; + if (ds18b20devices.channel[i]>=0) CHANNEL_Set(ds18b20devices.channel[i], (int)(t_float*100), CHANNEL_SET_FLAG_SILENT); + lastconv = g_secondsElapsed; + } +#else // to #if WINDOWS + float t_float = -127; + const char * pinalias; + char gpioname[10]; + DS1820_LOG(INFO, "Reading temperature from %i DS18B20 sensor(s)\r\n",ds18_count); + for (int i=0; i < ds18_count; i++) { + pinalias = HAL_PIN_GetPinNameAlias(ds18b20devices.GPIO[i]); + if (! pinalias ) { + sprintf(gpioname,"GPIO %u",ds18b20devices.GPIO[i]); + pinalias = gpioname; + } + ds18b20devices.last_read[i] += 1 ; + errcount = 0; + t_float = -127; + while ( t_float == -127 && errcount++ < 5){ + t_float = ds18b20_getTempC((const uint8_t*)ds18b20devices.array[i]); + DS1820_LOG(DEBUG, "Device %i (" DEVSTR ") reported %0.2f\r\n",i, + DEV2STR(ds18b20devices.array[i]),t_float); + } + if (t_float != -127){ + ds18b20devices.lasttemp[i] = t_float; + ds18b20devices.last_read[i] = 0; + if (ds18b20devices.channel[i]>=0) CHANNEL_Set(ds18b20devices.channel[i], (int)(t_float*100), CHANNEL_SET_FLAG_SILENT); + lastconv = g_secondsElapsed; + DS1820_LOG(INFO, "Sensor " DEVSTR " on %s reported %0.2f\r\n",DEV2STR(ds18b20devices.array[i]),pinalias,t_float); + } else{ + if (ds18b20devices.last_read[i] > 60) { + DS1820_LOG(ERROR, "No temperature read for over 60 seconds for" + " device %i (" DEVSTR " on %s)! Setting to -127°C!\r\n",i, + DEV2STR(ds18b20devices.array[i]),pinalias); + ds18b20devices.lasttemp[i] = -127; + dsread=0; + } + } + } +#endif // to #if WINDOWS + dsread=0; + } + else{ +// bk_printf("No tepms read! dsread=%i -- isConversionComplete()=%i\r\n",dsread,isConversionComplete()); +// DS1820_LOG(INFO, "No tepms read! dsread=%i -- isConversionComplete()=%i\r\n",dsread,isConversionComplete()); + for (int i=0; i < ds18_count; i++) { + ds18b20devices.last_read[i] += 1 ; + } + if(dsread == 0 && (g_secondsElapsed % ds18_conversionPeriod == 0 || lastconv == 0)) + { + DS1820_LOG(INFO, "Starting conversion"); + for (int i=0; i -#define noInterrupts() taskENTER_CRITICAL() -#define interrupts() taskEXIT_CRITICAL() -#endif +#include "drv_ds1820_common.h" static uint8_t dsread = 0; static int Pin = -1; -static int t = -127; +static int t = -12700; //t is 100 * temperature (so we can represent 2 fractional digits) static int errcount = 0; static int lastconv; // secondsElapsed on last successfull reading static uint8_t ds18_family = 0; @@ -23,268 +15,10 @@ static int ds18_conversionPeriod = 0; static int DS1820_DiscoverFamily(); + #define DS1820_LOG(x, fmt, ...) addLogAdv(LOG_##x, LOG_FEATURE_SENSOR, "DS1820[%i] - " fmt, Pin, ##__VA_ARGS__) -// usleep adopted from DHT driver -static void usleepds(int r) -{ - HAL_Delay_us(r); -} -// add some "special timing" for Beken - works w/o and with powerSave 1 for me -static void usleepshort(int r) //delay function do 10*r nops, because rtos_delay_milliseconds is too much -{ -#if PLATFORM_BEKEN - int newr = r / (3 * g_powersave + 1); // devide by 4 if powerSave set to 1 - for(volatile int i = 0; i < newr; i++) - { - __asm__("nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop"); - //__asm__("nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop"); - __asm__("nop\nnop\nnop\nnop"); - } - -#else - usleepds(r); -#endif -} - -static void usleepmed(int r) //delay function do 10*r nops, because rtos_delay_milliseconds is too much -{ -#if PLATFORM_BEKEN - int newr = 10 * r / (10 + 5 * g_powersave); // devide by 1.5 powerSave set to 1 - for(volatile int i = 0; i < newr; i++) - { - __asm__("nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop"); - __asm__("nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop"); - __asm__("nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop"); - __asm__("nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop"); - __asm__("nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop"); // 5 - __asm__("nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop"); - } - -#else - usleepds(r); -#endif -} - -static void usleeplong(int r) //delay function do 10*r nops, because rtos_delay_milliseconds is too much -{ -#if PLATFORM_BEKEN - int newr = 10 * r / (10 + 5 * g_powersave); // devide by 1.5 powerSave set to 1 - for(volatile int i = 0; i < newr; i++) - { - __asm__("nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop"); - __asm__("nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop"); - __asm__("nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop"); - __asm__("nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop"); - // __asm__("nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop"); // 5 - __asm__("nop\nnop\nnop\nnop\nnop"); // 5 - } - -#else - usleepds(r); -#endif -} - -/* - -timing numbers and general code idea from - -https://www.analog.com/en/resources/technical-articles/1wire-communication-through-software.html - -Parameter Speed Recommended (µs) -A Standard 6 -B Standard 64 -C Standard 60 -D Standard 10 -E Standard 9 -F Standard 55 -G Standard 0 -H Standard 480 -I Standard 70 -J Standard 410 - -*/ - -#define OWtimeA 6 -#define OWtimeB 64 -#define OWtimeC 60 -#define OWtimeD 10 -#define OWtimeE 9 -#define OWtimeF 55 -#define OWtimeG 0 -#define OWtimeH 480 -#define OWtimeI 70 -#define OWtimeJ 410 - -#define READ_ROM 0x33 -#define SKIP_ROM 0xCC -#define CONVERT_T 0x44 -#define READ_SCRATCHPAD 0xBE -#define WRITE_SCRATCHPAD 0x4E - -static int OWReset(int Pin) -{ - int result; - - //usleep(OWtimeG); - HAL_PIN_Setup_Output(Pin); - HAL_PIN_SetOutputValue(Pin, 0); // Drives DQ low - usleeplong(OWtimeH); - HAL_PIN_SetOutputValue(Pin, 1); // Releases the bus - usleepmed(OWtimeI); - HAL_PIN_Setup_Input(Pin); - result = HAL_PIN_ReadDigitalInput(Pin) ^ 0x01; // Sample for presence pulse from slave - usleeplong(OWtimeJ); // Complete the reset sequence recovery - return result; // Return sample presence pulse result -} - -//----------------------------------------------------------------------------- -// Send a 1-Wire write bit. Provide 10us recovery time. -//----------------------------------------------------------------------------- -static void OWWriteBit(int Pin, int bit) -{ - if(bit) - { - // Write '1' bit - HAL_PIN_Setup_Output(Pin); - noInterrupts(); - HAL_PIN_SetOutputValue(Pin, 0); // Drives DQ low - usleepshort(OWtimeA); - HAL_PIN_SetOutputValue(Pin, 1); // Releases the bus - interrupts(); // hope for the best for the following timer and keep CRITICAL as short as possible - usleepmed(OWtimeB); // Complete the time slot and 10us recovery - } - else - { - // Write '0' bit - HAL_PIN_Setup_Output(Pin); - noInterrupts(); - HAL_PIN_SetOutputValue(Pin, 0); // Drives DQ low - usleepmed(OWtimeC); - HAL_PIN_SetOutputValue(Pin, 1); // Releases the bus - interrupts(); // hope for the best for the following timer and keep CRITICAL as short as possible - usleepshort(OWtimeD); - } -} - -//----------------------------------------------------------------------------- -// Read a bit from the 1-Wire bus and return it. Provide 10us recovery time. -//----------------------------------------------------------------------------- -static int OWReadBit(int Pin) -{ - int result; - - noInterrupts(); - HAL_PIN_Setup_Output(Pin); - HAL_PIN_SetOutputValue(Pin, 0); // Drives DQ low - usleepshort(OWtimeA); - HAL_PIN_SetOutputValue(Pin, 1); // Releases the bus - usleepshort(OWtimeE); - HAL_PIN_Setup_Input(Pin); - result = HAL_PIN_ReadDigitalInput(Pin); // Sample for presence pulse from slave - interrupts(); // hope for the best for the following timer and keep CRITICAL as short as possible - usleepmed(OWtimeF); // Complete the time slot and 10us recovery - return result; -} - -//----------------------------------------------------------------------------- -// Poll if DS1820 temperature conversion is complete -//----------------------------------------------------------------------------- -static int DS1820TConversionDone(int Pin) -{ - // Write '1' bit - OWWriteBit(Pin, 1); - // check for '1' - conversion complete (will be '0' else) - return OWReadBit(Pin); -} - - -//----------------------------------------------------------------------------- -// Write 1-Wire data byte -//----------------------------------------------------------------------------- -static void OWWriteByte(int Pin, int data) -{ - int loop; - - // Loop to write each bit in the byte, LS-bit first - for(loop = 0; loop < 8; loop++) - { - OWWriteBit(Pin, data & 0x01); - - // shift the data byte for the next bit - data >>= 1; - } -} - -//----------------------------------------------------------------------------- -// Read 1-Wire data byte and return it -//----------------------------------------------------------------------------- -static int OWReadByte(int Pin) -{ - int loop, result = 0; - - for(loop = 0; loop < 8; loop++) - { - // shift the result to get it ready for the next bit - result >>= 1; - - // if result is one, then set MS bit - if(OWReadBit(Pin)) - result |= 0x80; - } - return result; -} - -//----------------------------------------------------------------------------- -// Write a 1-Wire data byte and return the sampled result. -//----------------------------------------------------------------------------- -static int OWTouchByte(int Pin, int data) -{ - int loop, result = 0; - - for(loop = 0; loop < 8; loop++) - { - // shift the result to get it ready for the next bit - result >>= 1; - - // If sending a '1' then read a bit else write a '0' - if(data & 0x01) - { - if(OWReadBit(Pin)) - result |= 0x80; - } - else - OWWriteBit(Pin, 0); - - // shift the data byte for the next bit - data >>= 1; - } - return result; -} - -// quicker CRC with lookup table -// based on code found here: https://community.st.com/t5/stm32-mcus-security/use-stm32-crc-to-compare-ds18b20-crc/m-p/333749/highlight/true#M4690 -// Dallas 1-Wire CRC Test App - -// x^8 + x^5 + x^4 + 1 0x8C (0x131) - -static uint8_t Crc8CQuick(uint8_t* Buffer, uint8_t Size) -{ - // Nibble table for polynomial 0x8C - static const uint8_t CrcTable[] = - { - 0x00,0x9D,0x23,0xBE,0x46,0xDB,0x65,0xF8, - 0x8C,0x11,0xAF,0x32,0xCA,0x57,0xE9,0x74 - }; - uint8_t Crc = 0x00; - while(Size--) - { - Crc ^= *Buffer++; // Apply Data - Crc = (Crc >> 4) ^ CrcTable[Crc & 0x0F]; // Two rounds of 4-bits - Crc = (Crc >> 4) ^ CrcTable[Crc & 0x0F]; - } - return(Crc); -} int DS1820_getTemp() { @@ -304,12 +38,14 @@ static commandResult_t Cmd_SetResolution(const void* context, const char* cmd, c DS1820_LOG(ERROR, "DS1820_SetResolution not supported by sensor"); return CMD_RES_UNKNOWN_COMMAND; } + // arg can be 9 10 11 12 + // the cfg for resolution shall be 9:0x1F 10:0x3F 11:0x5F 12:0x7F + // ignoring the "0x0F" an lookig just at the first digit, + // we can easily see this is 1+(arg-9)*2 + // so this can be written as + uint8_t cfg = 0x1F | (arg-9)<<5 ; - uint8_t cfg = arg; - cfg = cfg - 9; - cfg = cfg * 32; - cfg |= 0x1F; - + // use simple temperature setting, always write, ignoring actual scratchpad if(OWReset(Pin) == 0) { DS1820_LOG(ERROR, "WriteScratchpad Reset failed"); @@ -341,15 +77,17 @@ void DS1820_driver_Init() //cmddetail:"fn":"Cmd_SetResolution","file":"drv/drv_ds1820_simple.c","requires":"", //cmddetail:"examples":""} CMD_RegisterCommand("DS1820_SetResolution", Cmd_SetResolution, NULL); - //Find PIN and check device so DS1820_SetResolution could be used in autoexec.bat Pin = PIN_FindPinIndexForRole(IOR_DS1820_IO, -1); if (Pin >= 0) DS1820_DiscoverFamily(); }; -void DS1820_AppendInformationToHTTPIndexPage(http_request_t* request) +void DS1820_AppendInformationToHTTPIndexPage(http_request_t* request, int bPreState) { + if (bPreState){ + return; + } hprintf255(request, "

DS1820 Temperature: %.2f C (read %i secs ago)
", (float)t / 100, g_secondsElapsed - lastconv); } @@ -357,7 +95,7 @@ static int DS1820_DiscoverFamily() { if(!OWReset(Pin)) { - DS1820_LOG(DEBUG, "Discover Reset failed"); +// DS1820_LOG(DEBUG, "Discover Reset failed"); return 0; } @@ -383,28 +121,32 @@ static int DS1820_DiscoverFamily() if(family == 0x10 || family == 0x28) { ds18_family = family; - DS1820_LOG(INFO, "Discover Family - discovered %x", family); + DS1820_LOG(INFO, "Discoverd Family: %x", family); return 1; } else { - DS1820_LOG(DEBUG, "Discover Family %x not supported", family); + DS1820_LOG(DEBUG, "Discovered Family %x not supported", family); return 0; } } + + void DS1820_OnEverySecond() { uint8_t scratchpad[9], crc; int16_t raw; + // for now just find the pin used Pin = PIN_FindPinIndexForRole(IOR_DS1820_IO, -1); // only if pin is set - if(Pin < 0) + if(Pin < 0) { + DS1820_LOG(INFO, "No Pin found\r\n"); return; - + } //Temperature measurement is done in two repeatable steps. // Step 1 - dsread = 0. Sensor requested to do temperature conversion. // That requires some time - 15-100-750ms, depending on sensor family/vendor. @@ -468,10 +210,12 @@ void DS1820_OnEverySecond() } // Raw is t * 128 +/* t = (raw / 128) * 100; // Whole degrees int frac = (raw % 128) * 100 / 128; // Fractional degrees t += t > 0 ? frac : -frac; - +*/ + t = (raw * 100) / 128; // no need to calc fractional, if we can simply get 100 * temp in one line dsread = 0; lastconv = g_secondsElapsed; CHANNEL_Set(g_cfg.pins.channels[Pin], t, CHANNEL_SET_FLAG_SILENT); @@ -492,7 +236,6 @@ void DS1820_OnEverySecond() return; } } - if(OWReset(Pin) == 0) { lastconv = -1; // reset lastconv to avoid immediate retry @@ -521,15 +264,16 @@ void DS1820_OnEverySecond() // calc a new factor for usleepds DS1820_LOG(ERROR, "usleepds duration divergates - proposed factor to adjust usleepds %f ", (float)100 / duration); } -#endif +#endif // #if DS1820_DEBUG return; } DS1820_LOG(INFO, "Starting conversion"); OWWriteByte(Pin, SKIP_ROM); OWWriteByte(Pin, CONVERT_T); - errcount = 0; dsread = 1; } } + +#endif // to #if (ENABLE_DRIVER_DS1820) diff --git a/src/driver/drv_ds1820_simple.h b/src/driver/drv_ds1820_simple.h index 21370652f..94d93a427 100644 --- a/src/driver/drv_ds1820_simple.h +++ b/src/driver/drv_ds1820_simple.h @@ -7,13 +7,11 @@ #include "../cmnds/cmd_public.h" #include "../mqtt/new_mqtt.h" #include "../logging/logging.h" -#include "drv_local.h" -#include "drv_uart.h" #include "../httpserver/new_http.h" -#include "../hal/hal_pins.h" + int DS1820_getTemp(); void DS1820_driver_Init(); void DS1820_OnEverySecond(); -void DS1820_AppendInformationToHTTPIndexPage(http_request_t *request); +void DS1820_AppendInformationToHTTPIndexPage(http_request_t *request, int bPreState); diff --git a/src/driver/drv_main.c b/src/driver/drv_main.c index 2344f50d8..b580a82ad 100644 --- a/src/driver/drv_main.c +++ b/src/driver/drv_main.c @@ -13,6 +13,8 @@ #include "drv_tuyaMCU.h" #include "drv_uart.h" #include "drv_ds1820_simple.h" +#include "drv_ds1820_full.h" +#include "drv_ds1820_common.h" typedef struct driver_s { @@ -453,6 +455,13 @@ static driver_t g_drivers[] = { //drvdetail:"requires":""} { "DS1820", DS1820_driver_Init, DS1820_OnEverySecond, DS1820_AppendInformationToHTTPIndexPage, NULL, NULL, NULL, false }, #endif +#if ENABLE_DRIVER_DS1820_FULL + //drvdetail:{"name":"DS1820_FULL", + //drvdetail:"title":"TODO", + //drvdetail:"descr":"Driver for oneWire temperature sensor DS18(B)20.", + //drvdetail:"requires":""} + { "DS1820_FULL", DS1820_full_driver_Init, DS1820_full_OnEverySecond, DS1820_full_AppendInformationToHTTPIndexPage, NULL, NULL, NULL, false }, +#endif #if ENABLE_DRIVER_HT16K33 //drvdetail:{"name":"HT16K33", //drvdetail:"title":"TODO", @@ -626,8 +635,24 @@ void DRV_StartDriver(const char* name) { return; } bStarted = 0; +#if (ENABLE_DRIVER_DS1820) && (ENABLE_DRIVER_DS1820_FULL) + bool twinrunning=false; +#endif for (i = 0; i < g_numDrivers; i++) { if (!stricmp(g_drivers[i].name, name)) { +#if (ENABLE_DRIVER_DS1820) && (ENABLE_DRIVER_DS1820_FULL) + twinrunning=false; + if (!stricmp("DS1820", name) && DRV_IsRunning("DS1820_FULL")){ + addLogAdv(LOG_ERROR, LOG_FEATURE_MAIN, "Drv DS1820_FULL is already loaded - can't start DS1820, too.\n", name); + twinrunning=true; + break; + } + if (!stricmp("DS1820_FULL", name) && DRV_IsRunning("DS1820")){ + addLogAdv(LOG_ERROR, LOG_FEATURE_MAIN, "Drv DS1820 is already loaded - can't start DS1820_FULL, too.\n", name); + twinrunning=true; + break; + } +#endif if (g_drivers[i].bLoaded) { addLogAdv(LOG_INFO, LOG_FEATURE_MAIN, "Drv %s is already loaded.\n", name); bStarted = 1; @@ -645,7 +670,11 @@ void DRV_StartDriver(const char* name) { } } } +#if (ENABLE_DRIVER_DS1820) && (ENABLE_DRIVER_DS1820_FULL) + if (!bStarted && !twinrunning) { +#else if (!bStarted) { +#endif addLogAdv(LOG_INFO, LOG_FEATURE_MAIN, "Driver %s is not known in this build.\n", name); addLogAdv(LOG_INFO, LOG_FEATURE_MAIN, "Available drivers: "); for (i = 0; i < g_numDrivers; i++) { diff --git a/src/driver/ds18b20.c b/src/driver/ds18b20.c deleted file mode 100644 index 65bd8fb8e..000000000 --- a/src/driver/ds18b20.c +++ /dev/null @@ -1,475 +0,0 @@ -/* - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "../new_common.h" -#include "../new_pins.h" -#include "../new_cfg.h" -// Commands register, execution API and cmd tokenizer -#include "../cmnds/cmd_public.h" -#include "../mqtt/new_mqtt.h" -#include "../logging/logging.h" -#include "drv_local.h" -#include "drv_uart.h" -#include "../httpserver/new_http.h" -#include "../hal/hal_pins.h" - -#include "ds18b20.h" - -// OneWire commands -#define GETTEMP 0x44 // Tells device to take a temperature reading and put it on the scratchpad -#define SKIPROM 0xCC // Command to address all devices on the bus -#define SELECTDEVICE 0x55 // Command to address all devices on the bus -#define COPYSCRATCH 0x48 // Copy scratchpad to EEPROM -#define READSCRATCH 0xBE // Read from scratchpad -#define WRITESCRATCH 0x4E // Write to scratchpad -#define RECALLSCRATCH 0xB8 // Recall from EEPROM to scratchpad -#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 -// DSROM FIELDS -#define DSROM_FAMILY 0 -#define DSROM_CRC 7 -// 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 - -uint8_t DS_GPIO; -uint8_t init = 0; -uint8_t bitResolution = 12; -uint8_t devices = 0; - -DeviceAddress ROM_NO; -uint8_t LastDiscrepancy; -uint8_t LastFamilyDiscrepancy; -bool LastDeviceFlag; - -/// Sends one bit to bus -void ds18b20_write(char bit) { - if (bit & 1) { - HAL_PIN_Setup_Output(DS_GPIO); - noInterrupts(); - HAL_PIN_SetOutputValue(DS_GPIO, 0); - usleep(6); - HAL_PIN_Setup_Input(DS_GPIO); // release bus - usleep(64); - interrupts(); - } - else { - HAL_PIN_Setup_Output(DS_GPIO); - noInterrupts(); - HAL_PIN_SetOutputValue(DS_GPIO, 0); - usleep(60); - HAL_PIN_Setup_Input(DS_GPIO); // release bus - usleep(10); - interrupts(); - } -} - -// Reads one bit from bus -unsigned char ds18b20_read(void) { - unsigned char value = 0; - HAL_PIN_Setup_Output(DS_GPIO); - noInterrupts(); - HAL_PIN_SetOutputValue(DS_GPIO, 0); - usleep(6); - HAL_PIN_Setup_Input(DS_GPIO); - usleep(9); - value = HAL_PIN_ReadDigitalInput(DS_GPIO); - usleep(55); - interrupts(); - return (value); -} -// Sends one byte to bus -void ds18b20_write_byte(char data) { - unsigned char i; - unsigned char x; - for (i = 0; i < 8; i++) { - x = data >> i; - x &= 0x01; - ds18b20_write(x); - } - usleep(100); -} -// Reads one byte from bus -unsigned char ds18b20_read_byte(void) { - unsigned char i; - unsigned char data = 0; - for (i = 0; i < 8; i++) - { - if (ds18b20_read()) data |= 0x01 << i; - usleep(15); - } - return(data); -} -// Sends reset pulse -unsigned char ds18b20_reset(void) { - unsigned char presence; - HAL_PIN_Setup_Output(DS_GPIO); - noInterrupts(); - HAL_PIN_SetOutputValue(DS_GPIO, 0); - usleep(480); - HAL_PIN_SetOutputValue(DS_GPIO, 1); - HAL_PIN_Setup_Input(DS_GPIO); - usleep(70); - presence = (HAL_PIN_ReadDigitalInput(DS_GPIO) == 0); - usleep(410); - interrupts(); - return presence; -} - -bool ds18b20_setResolution(const DeviceAddress tempSensorAddresses[], int numAddresses, uint8_t newResolution) { - bool success = false; - // handle the sensors with configuration register - newResolution = constrain(newResolution, 9, 12); - uint8_t newValue = 0; - ScratchPad scratchPad; - // loop through each address - for (int i = 0; i < numAddresses; i++) { - // we can only update the sensor if it is connected - if (ds18b20_isConnected((DeviceAddress*)tempSensorAddresses[i], scratchPad)) { - switch (newResolution) { - case 12: - newValue = TEMP_12_BIT; - break; - case 11: - newValue = TEMP_11_BIT; - break; - case 10: - newValue = TEMP_10_BIT; - break; - case 9: - default: - newValue = TEMP_9_BIT; - break; - } - // if it needs to be updated we write the new value - if (scratchPad[CONFIGURATION] != newValue) { - scratchPad[CONFIGURATION] = newValue; - ds18b20_writeScratchPad((DeviceAddress*)tempSensorAddresses[i], scratchPad); - } - // done - success = true; - } - } - return success; -} - -void ds18b20_writeScratchPad(const DeviceAddress *deviceAddress, const uint8_t *scratchPad) { - ds18b20_reset(); - ds18b20_select(deviceAddress); - ds18b20_write_byte(WRITESCRATCH); - ds18b20_write_byte(scratchPad[HIGH_ALARM_TEMP]); // high alarm temp - ds18b20_write_byte(scratchPad[LOW_ALARM_TEMP]); // low alarm temp - ds18b20_write_byte(scratchPad[CONFIGURATION]); - ds18b20_reset(); -} - -bool ds18b20_readScratchPad(const DeviceAddress *deviceAddress, uint8_t* scratchPad) { - // send the reset command and fail fast - int b = ds18b20_reset(); - if (b == 0) return false; - ds18b20_select(deviceAddress); - ds18b20_write_byte(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: DS18B20 & DS1822: configuration register - // byte 5: internal use & crc - // byte 6: DS18B20 & DS1822: store for crc - // byte 7: DS18B20 & DS1822: store for crc - // byte 8: SCRATCHPAD_CRC - for (uint8_t i = 0; i < 9; i++) { - scratchPad[i] = ds18b20_read_byte(); - } - b = ds18b20_reset(); - return (b == 1); -} - -void ds18b20_select(const DeviceAddress *address) { - uint8_t i; - ds18b20_write_byte(SELECTDEVICE); // Choose ROM - for (i = 0; i < 8; i++) ds18b20_write_byte(((uint8_t *)address)[i]); -} - -void ds18b20_requestTemperatures() { - ds18b20_reset(); - ds18b20_write_byte(SKIPROM); - ds18b20_write_byte(GETTEMP); - //unsigned long start = esp_timer_get_time() / 1000ULL; - //while (!isConversionComplete() && ((esp_timer_get_time() / 1000ULL) - start < millisToWaitForConversion())) vPortYield(); -} - -bool isConversionComplete() { - uint8_t b = ds18b20_read(); - return (b == 1); -} - -uint16_t millisToWaitForConversion() { - switch (bitResolution) { - case 9: - return 94; - case 10: - return 188; - case 11: - return 375; - default: - return 750; - } -} - -bool ds18b20_isConnected(const DeviceAddress *deviceAddress, uint8_t *scratchPad) { - bool b = ds18b20_readScratchPad(deviceAddress, scratchPad); - return b && !ds18b20_isAllZeros(scratchPad) && (ds18b20_crc8(scratchPad, 8) == scratchPad[SCRATCHPAD_CRC]); -} - -uint8_t ds18b20_crc8(const uint8_t *addr, uint8_t len) { - uint8_t crc = 0; - while (len--) { - crc = *addr++ ^ crc; // just re-using crc as intermediate - crc = pgm_read_byte(dscrc2x16_table + (crc & 0x0f)) ^ - pgm_read_byte(dscrc2x16_table + 16 + ((crc >> 4) & 0x0f)); - } - return crc; -} - -bool ds18b20_isAllZeros(const uint8_t * const scratchPad) { - for (size_t i = 0; i < 9; i++) { - if (scratchPad[i] != 0) { - return false; - } - } - return true; -} - -float ds18b20_getTempF(const DeviceAddress *deviceAddress) { - ScratchPad scratchPad; - if (ds18b20_isConnected(deviceAddress, scratchPad)) { - int16_t rawTemp = calculateTemperature(deviceAddress, scratchPad); - if (rawTemp <= 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)rawTemp * 0.0140625f) + 32.0f; - } - return DEVICE_DISCONNECTED_F; -} - -float ds18b20_getTempC(const DeviceAddress *deviceAddress) { - ScratchPad scratchPad; - if (ds18b20_isConnected(deviceAddress, scratchPad)) { - int16_t rawTemp = calculateTemperature(deviceAddress, scratchPad); - if (rawTemp <= 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)rawTemp / 128.0f; - } - return DEVICE_DISCONNECTED_F; -} - -// reads scratchpad and returns fixed-point temperature, scaling factor 2^-7 -int16_t calculateTemperature(const DeviceAddress *deviceAddress, uint8_t* scratchPad) { - int16_t fpTemperature = (((int16_t)scratchPad[TEMP_MSB]) << 11) | (((int16_t)scratchPad[TEMP_LSB]) << 3); - return fpTemperature; -} - -// Returns temperature from sensor -float ds18b20_get_temp(void) { - if (init == 1) { - unsigned char check; - char temp1 = 0, temp2 = 0; - check = ds18b20_RST_PULSE(); - if (check == 1) - { - ds18b20_send_byte(0xCC); - ds18b20_send_byte(0x44); - vTaskDelay(750 / portTICK_RATE_MS); - check = ds18b20_RST_PULSE(); - ds18b20_send_byte(0xCC); - ds18b20_send_byte(0xBE); - temp1 = ds18b20_read_byte(); - temp2 = ds18b20_read_byte(); - check = ds18b20_RST_PULSE(); - float temp = 0; - temp = (float)(temp1 + (temp2 * 256)) / 16; - return temp; - } - else { return 0; } - - } - else { return 0; } -} - -void ds18b20_init(int GPIO) { - DS_GPIO = GPIO; - //gpio_pad_select_gpio(DS_GPIO); - init = 1; -} - -// -// 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 reset_search() { - devices = 0; - // reset the search state - LastDiscrepancy = 0; - LastDeviceFlag = false; - LastFamilyDiscrepancy = 0; - for (int i = 7; i >= 0; i--) { - ROM_NO[i] = 0; - } -} -// --- 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 - -bool search(uint8_t *newAddr, bool search_mode) { - uint8_t id_bit_number; - uint8_t last_zero, rom_byte_number; - bool 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 = false; - - // if the last call was not the last one - if (!LastDeviceFlag) { - // 1-Wire reset - if (!ds18b20_reset()) { - // reset the search - LastDiscrepancy = 0; - LastDeviceFlag = false; - LastFamilyDiscrepancy = 0; - return false; - } - - // issue the search command - if (search_mode == true) { - ds18b20_write_byte(0xF0); // NORMAL SEARCH - } - else { - ds18b20_write_byte(0xEC); // CONDITIONAL SEARCH - } - - // loop to do the search - do { - // read a bit and its complement - id_bit = ds18b20_read(); - cmp_id_bit = ds18b20_read(); - - // 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 - ds18b20_write(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]) { - devices = 0; - LastDiscrepancy = 0; - LastDeviceFlag = false; - LastFamilyDiscrepancy = 0; - search_result = false; - } - else { - for (int i = 0; i < 8; i++) { - newAddr[i] = ROM_NO[i]; - } - devices++; - } - return search_result; -} \ No newline at end of file diff --git a/src/driver/ds18b20.h b/src/driver/ds18b20.h deleted file mode 100644 index 929005674..000000000 --- a/src/driver/ds18b20.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#ifndef DS18B20_H_ -#define DS18B20_H_ - -#define noInterrupts() -#define interrupts() - -#define DEVICE_DISCONNECTED_C -127 -#define DEVICE_DISCONNECTED_F -196.6 -#define DEVICE_DISCONNECTED_RAW -7040 -#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt))) -#define pgm_read_byte(addr) (*(const unsigned char *)(addr)) - -typedef uint8_t DeviceAddress[8]; -typedef uint8_t ScratchPad[9]; - -// Dow-CRC using polynomial X^8 + X^5 + X^4 + X^0 -// Tiny 2x16 entry CRC table created by Arjen Lentz -// See http://lentz.com.au/blog/calculating-crc-with-a-tiny-32-entry-lookup-table -static const uint8_t dscrc2x16_table[] = { - 0x00, 0x5E, 0xBC, 0xE2, 0x61, 0x3F, 0xDD, 0x83, - 0xC2, 0x9C, 0x7E, 0x20, 0xA3, 0xFD, 0x1F, 0x41, - 0x00, 0x9D, 0x23, 0xBE, 0x46, 0xDB, 0x65, 0xF8, - 0x8C, 0x11, 0xAF, 0x32, 0xCA, 0x57, 0xE9, 0x74 -}; - -/* *INDENT-OFF* */ -#ifdef __cplusplus -extern "C" { -#endif - /* *INDENT-ON* */ - - void ds18b20_init(int GPIO); - -#define ds18b20_send ds18b20_write -#define ds18b20_send_byte ds18b20_write_byte -#define ds18b20_RST_PULSE ds18b20_reset - - void ds18b20_write(char bit); - unsigned char ds18b20_read(void); - void ds18b20_write_byte(char data); - unsigned char ds18b20_read_byte(void); - unsigned char ds18b20_reset(void); - - bool ds18b20_setResolution(const DeviceAddress tempSensorAddresses[], int numAddresses, uint8_t newResolution); - bool ds18b20_isConnected(const DeviceAddress *deviceAddress, uint8_t *scratchPad); - void ds18b20_writeScratchPad(const DeviceAddress *deviceAddress, const uint8_t *scratchPad); - bool ds18b20_readScratchPad(const DeviceAddress *deviceAddress, uint8_t *scratchPad); - void ds18b20_select(const DeviceAddress *address); - uint8_t ds18b20_crc8(const uint8_t *addr, uint8_t len); - bool ds18b20_isAllZeros(const uint8_t * const scratchPad); - bool isConversionComplete(); - uint16_t millisToWaitForConversion(); - - void ds18b20_requestTemperatures(); - float ds18b20_getTempF(const DeviceAddress *deviceAddress); - float ds18b20_getTempC(const DeviceAddress *deviceAddress); - int16_t calculateTemperature(const DeviceAddress *deviceAddress, uint8_t* scratchPad); - float ds18b20_get_temp(void); - - void reset_search(); - bool search(uint8_t *newAddr, bool search_mode); - - /* *INDENT-OFF* */ -#ifdef __cplusplus -} -#endif -/* *INDENT-ON* */ - -#endif \ No newline at end of file diff --git a/src/httpserver/http_fns.c b/src/httpserver/http_fns.c index fb02b0714..290550688 100644 --- a/src/httpserver/http_fns.c +++ b/src/httpserver/http_fns.c @@ -2615,6 +2615,9 @@ int http_fn_cfg(http_request_t* request) { postFormAction(request, "cfg_wifi", "Configure WiFi & Web"); #if ENABLE_HTTP_IP postFormAction(request, "cfg_ip", "Configure IP"); +#endif +#if (ENABLE_DRIVER_DS1820_FULL) + postFormAction(request, "cfg_ds18b20", "Configure DS18B20 Sensors"); #endif postFormAction(request, "cfg_mqtt", "Configure MQTT"); #if ENABLE_HTTP_NAMES diff --git a/src/httpserver/new_http.c b/src/httpserver/new_http.c index 066ca89c1..a34cff546 100644 --- a/src/httpserver/new_http.c +++ b/src/httpserver/new_http.c @@ -855,6 +855,12 @@ int HTTP_ProcessPacket(http_request_t* request) { #if ENABLE_HTTP_IP if (http_checkUrlBase(urlStr, "cfg_ip")) return http_fn_cfg_ip(request); #endif +#if (ENABLE_DRIVER_DS1820_FULL) + // including "../driver/drv_ds1820_simple.h" will complain about typedefs not used here + // so lets declare it "extern" + extern int http_fn_cfg_ds18b20(http_request_t* request); + if (http_checkUrlBase(urlStr, "cfg_ds18b20")) return http_fn_cfg_ds18b20(request); +#endif #if ENABLE_HTTP_WEBAPP if (http_checkUrlBase(urlStr, "cfg_webapp")) return http_fn_cfg_webapp(request); diff --git a/src/new_pins.c b/src/new_pins.c index c18859d00..71c4c20eb 100644 --- a/src/new_pins.c +++ b/src/new_pins.c @@ -1735,6 +1735,10 @@ bool CHANNEL_IsInUse(int ch) { } } } +#if (ENABLE_DRIVER_DS1820_FULL) +#include "driver/drv_ds1820_full.h" + return ds18b20_used_channel(ch); +#endif return false; } diff --git a/src/obk_config.h b/src/obk_config.h index d42d16184..b3b4a1aab 100644 --- a/src/obk_config.h +++ b/src/obk_config.h @@ -174,6 +174,7 @@ #define ENABLE_DRIVER_SHIFTREGISTER 1 #define ENABLE_OBK_SCRIPTING 1 #define ENABLE_OBK_BERRY 1 +#define ENABLE_DRIVER_DS1820_FULL 1 #elif PLATFORM_BL602 @@ -319,7 +320,8 @@ #if (OBK_VARIANT == OBK_VARIANT_SENSORS) #define ENABLE_DRIVER_BMP280 1 #define ENABLE_DRIVER_BMPI2C 1 -#define ENABLE_DRIVER_SHT3X 1 +#define ENABLE_DRIVER_SHT3X 1 +#define ENABLE_DRIVER_DS1820_FULL 1 #endif