├── images ├── .gitkeep ├── CO2_SenseAir_S8.png ├── 2020-09-25_14-17-18.png ├── CO2_SenseAir_S8_1.png ├── CO2_SenseAir_S8_10.png ├── CO2_SenseAir_S8_11.png ├── CO2_SenseAir_S8_12.png ├── CO2_SenseAir_S8_15.png ├── CO2_SenseAir_S8_2.png ├── CO2_SenseAir_S8_5.png ├── CO2_SenseAir_S8_6.png ├── CO2_SenseAir_S8_8.png └── Schematic_CO2_SenseAir_S8.png ├── firmwares └── .gitkeep ├── .github └── FUNDING.yml ├── hardware ├── BOM.xlsx └── Gerber_CO2_BME280_DS.zip ├── CC2530DB ├── settings │ └── GenericApp.reggroups └── GenericApp.eww ├── Source ├── version.h ├── OSAL_App.c ├── preinclude.h ├── zcl_app.h ├── zcl_app_data.c ├── zcl_app.c └── hal_board_cfg.h ├── .clang-format ├── CM1106_driver ├── cm1106.h └── cm1106.c ├── .release-it.yml ├── .gitmodules ├── ver.py ├── .gitignore ├── .vscode └── c_cpp_properties.json ├── README.md ├── 0001-Fixes.patch ├── converters └── DIYRuZ_AirSense.js └── LICENSE /images/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /firmwares/.gitkeep: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | custom: https://www.buymeacoffee.com/nurikk 2 | -------------------------------------------------------------------------------- /hardware/BOM.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyzroe/AirSense/master/hardware/BOM.xlsx -------------------------------------------------------------------------------- /CC2530DB/settings/GenericApp.reggroups: -------------------------------------------------------------------------------- 1 | group = "io", "P0" 2 | group = "Unnamed2", "P1" 3 | -------------------------------------------------------------------------------- /Source/version.h: -------------------------------------------------------------------------------- 1 | extern const uint8 zclApp_DateCode[]; 2 | extern const char zclApp_DateCodeNT[]; -------------------------------------------------------------------------------- /images/CO2_SenseAir_S8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyzroe/AirSense/master/images/CO2_SenseAir_S8.png -------------------------------------------------------------------------------- /images/2020-09-25_14-17-18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyzroe/AirSense/master/images/2020-09-25_14-17-18.png -------------------------------------------------------------------------------- /images/CO2_SenseAir_S8_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyzroe/AirSense/master/images/CO2_SenseAir_S8_1.png -------------------------------------------------------------------------------- /images/CO2_SenseAir_S8_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyzroe/AirSense/master/images/CO2_SenseAir_S8_10.png -------------------------------------------------------------------------------- /images/CO2_SenseAir_S8_11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyzroe/AirSense/master/images/CO2_SenseAir_S8_11.png -------------------------------------------------------------------------------- /images/CO2_SenseAir_S8_12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyzroe/AirSense/master/images/CO2_SenseAir_S8_12.png -------------------------------------------------------------------------------- /images/CO2_SenseAir_S8_15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyzroe/AirSense/master/images/CO2_SenseAir_S8_15.png -------------------------------------------------------------------------------- /images/CO2_SenseAir_S8_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyzroe/AirSense/master/images/CO2_SenseAir_S8_2.png -------------------------------------------------------------------------------- /images/CO2_SenseAir_S8_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyzroe/AirSense/master/images/CO2_SenseAir_S8_5.png -------------------------------------------------------------------------------- /images/CO2_SenseAir_S8_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyzroe/AirSense/master/images/CO2_SenseAir_S8_6.png -------------------------------------------------------------------------------- /images/CO2_SenseAir_S8_8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyzroe/AirSense/master/images/CO2_SenseAir_S8_8.png -------------------------------------------------------------------------------- /hardware/Gerber_CO2_BME280_DS.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyzroe/AirSense/master/hardware/Gerber_CO2_BME280_DS.zip -------------------------------------------------------------------------------- /images/Schematic_CO2_SenseAir_S8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyzroe/AirSense/master/images/Schematic_CO2_SenseAir_S8.png -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | # We'll use defaults from the LLVM style, but with 4 columns indentation. 3 | BasedOnStyle: LLVM 4 | IndentWidth: 4 5 | ColumnLimit: 180 -------------------------------------------------------------------------------- /CM1106_driver/cm1106.h: -------------------------------------------------------------------------------- 1 | #ifndef cm1106_h 2 | #define cm1106_h 3 | #include "air_quality.h" 4 | 5 | extern zclAirSensor_t CM1106_dev; 6 | 7 | #endif //cm1106_h -------------------------------------------------------------------------------- /.release-it.yml: -------------------------------------------------------------------------------- 1 | git: 2 | requireCleanWorkingDir: false 3 | github: 4 | release: true 5 | assets: ["firmwares/DIYRuZ_*.hex", "converters/DIYRuZ_*.js"] 6 | draft: false -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "zstack-lib"] 2 | path = zstack-lib 3 | url = git@github.com:diyruz/zstack-lib.git 4 | [submodule "BME280_driver"] 5 | path = BME280_driver 6 | url = git@github.com:BoschSensortec/BME280_driver.git 7 | -------------------------------------------------------------------------------- /ver.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from os.path import dirname, join 3 | cwd = dirname(__file__) 4 | now = datetime.now() 5 | dt_string = now.strftime("%d/%m/%Y %H:%M") 6 | print("date and time =", dt_string) 7 | with open(join(cwd, './Source/version.c'), 'w') as f: 8 | chars = ["'{0}'".format(char) for char in dt_string] 9 | f.write(""" 10 | #ifndef ZCL_APP_VERSION_H 11 | #define ZCL_APP_VERSION_H 12 | 13 | #ifdef __cplusplus 14 | extern "C" { 15 | #endif 16 | 17 | """ 18 | ) 19 | f.write('#include "version.h"\n') 20 | code = """const uint8 zclApp_DateCode[] = {{ {0}, {1} }};\n""".format(len(chars), ', '.join(chars)) 21 | f.write(code) 22 | code = """const char zclApp_DateCodeNT[] = \"{0}\";\n""".format(dt_string) 23 | f.write(code) 24 | f.write(""" 25 | #ifdef __cplusplus 26 | } 27 | #endif 28 | 29 | #endif /* ZCL_APP_VERSION_H */ 30 | """) -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # IAR C-STAT and C-RUN 2 | # Comment this out if you use C-Stat or C-Run to compile/analyze your project 3 | *.ewt 4 | 5 | # IAR Debugger files 6 | *.ewd 7 | 8 | 9 | # IAR Settings 10 | **/settings/*.crun 11 | **/settings/*.dbgdt 12 | **/settings/*.cspy 13 | **/settings/*.cspy.* 14 | **/settings/*.xcl 15 | **/settings/*.dni 16 | **/settings/*.wsdt 17 | **/settings/*.wspos 18 | 19 | # IAR Debug Exe 20 | **/CoordinatorEB/Exe/ 21 | 22 | # IAR Debug List 23 | **/CoordinatorEB/List 24 | 25 | # IAR Debug Obj 26 | **/CoordinatorEB/Obj/*.pbd 27 | **/CoordinatorEB/Obj/*.pbd.* 28 | **/CoordinatorEB/Obj/*.pbi 29 | **/CoordinatorEB/Obj/*.pbi.* 30 | **/CoordinatorEB/Obj/*.r51 31 | 32 | # Log files 33 | **.log 34 | 35 | # IAR backup files 36 | Backup* 37 | 38 | # IAR .dep files 39 | *.dep 40 | 41 | # Compiled Binaries 42 | *.bin 43 | *.elf 44 | *.map 45 | 46 | # Trash files 47 | *.bak 48 | 49 | # CC2530DB 50 | 51 | CC2530DB/CHDTECH_DEV 52 | CC2530DB/FREEPAD* 53 | CC2530DB/flower 54 | CC2530DB/HAL_BOARD_TARGET 55 | CC2530DB/DIYRuZ* 56 | Source/version.c 57 | !.vscode/ 58 | .vscode/settings.json 59 | firmwares/* 60 | -------------------------------------------------------------------------------- /CC2530DB/GenericApp.eww: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $WS_DIR$\GenericApp.ewp 5 | 6 | 7 | 8 | ALL 9 | 10 | GenericApp 11 | DIYRuZ_AirSense_EndDevice 12 | 13 | 14 | GenericApp 15 | DIYRuZ_AirSense_Router 16 | 17 | 18 | GenericApp 19 | DIYRuZ_AirSense_Router_CC2592 20 | 21 | 22 | GenericApp 23 | DIYRuZ_AirSense_EndDevice_CC2592 24 | 25 | 26 | GenericApp 27 | DIYRuZ_AirSense_EndDevice_CC2591 28 | 29 | 30 | GenericApp 31 | DIYRuZ_AirSense_Router_CC2591 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [{ 3 | "name": "Mac", 4 | "forcedInclude": ["${workspaceRoot}/source/preinclude.h"], 5 | "defines": ["HAL_BOARD_TARGET", "HAL_I2C=TRUE", "HAL_I2C_MASTER"], 6 | "includePath": [ 7 | "${workspaceRoot}", 8 | "${workspaceRoot}/BME280_driver", 9 | "${workspaceRoot}/Source", 10 | "${workspaceRoot}/zstack-lib", 11 | "${env:ZSTACK_PATH}/Components/mac/include/", 12 | "${env:ZSTACK_PATH}/Components/mt", 13 | "${env:ZSTACK_PATH}/Components/zmac", 14 | "${env:ZSTACK_PATH}/Components/zmac/f8w", 15 | "${env:ZSTACK_PATH}/Components/osal/include", 16 | "${env:ZSTACK_PATH}/Components/stack/af", 17 | "${env:ZSTACK_PATH}/Components/stack/bdb", 18 | "${env:ZSTACK_PATH}/Components/stack/sec", 19 | "${env:ZSTACK_PATH}/Components/stack/sys", 20 | "${env:ZSTACK_PATH}/Components/stack/zdo", 21 | "${env:ZSTACK_PATH}/Components/stack/GP", 22 | "${env:ZSTACK_PATH}/Components/stack/nwk", 23 | "${env:ZSTACK_PATH}/Components/stack/zcl", 24 | "${env:ZSTACK_PATH}/Components/hal/target/CC2530EB/", 25 | "${env:ZSTACK_PATH}/Components/hal/include/", 26 | "${env:ZSTACK_PATH}/Components/services/saddr/", 27 | "${env:ZSTACK_PATH}/Components/services/sdata/", 28 | "${env:ZSTACK_PATH}/Projects/zstack/ZMain/TI2530DB", 29 | "${env:ZSTACK_PATH}/Projects/zstack/HomeAutomation/Source" 30 | ], 31 | "intelliSenseMode": "clang-x64", 32 | "compilerPath": "/usr/bin/clang", 33 | "cStandard": "c99", 34 | "cppStandard": "c++17" 35 | }], 36 | "version": 4 37 | } -------------------------------------------------------------------------------- /CM1106_driver/cm1106.c: -------------------------------------------------------------------------------- 1 | #include "cm1106.h" 2 | #include "Debug.h" 3 | #include "OSAL.h" 4 | #include "OnBoard.h" 5 | #include "hal_led.h" 6 | #include "hal_uart.h" 7 | 8 | #ifndef CO2_UART_PORT 9 | #define CO2_UART_PORT HAL_UART_PORT_1 10 | #endif 11 | 12 | #define CM1106_RESPONSE_LENGTH 13 13 | 14 | static void CM1106_SetABC(bool isEnabled); 15 | static void CM1106_RequestMeasure(void); 16 | static uint16 CM1106_Read(void); 17 | 18 | zclAirSensor_t CM1106_dev = {&CM1106_RequestMeasure, &CM1106_Read, &CM1106_SetABC}; 19 | 20 | //uint8 CM1106_RESPONSE_LENGTH = 9; 21 | uint8 CM1106_COMMAND_GET_PPM[] = {0x11, 0x01, 0x01, 0xED}; 22 | uint8 CM1106_COMMAND_ABC_ENABLE[] = {0x11, 0x07, 0x10, 0x64, 0x00, 0x07, 0x01, 0x90, 0x64, 0x78}; 23 | uint8 CM1106_COMMAND_ABC_DISABLE[] = {0x11, 0x07, 0x10, 0x64, 0x02, 0x07, 0x01, 0x90, 0x64, 0x76}; 24 | 25 | void CM1106_SetABC(bool isEnabled) { 26 | if (isEnabled) { 27 | HalUARTWrite(CO2_UART_PORT, CM1106_COMMAND_ABC_ENABLE, sizeof(CM1106_COMMAND_ABC_ENABLE) / sizeof(CM1106_COMMAND_ABC_ENABLE[0])); 28 | } else { 29 | HalUARTWrite(CO2_UART_PORT, CM1106_COMMAND_ABC_DISABLE, sizeof(CM1106_COMMAND_ABC_DISABLE) / sizeof(CM1106_COMMAND_ABC_DISABLE[0])); 30 | } 31 | } 32 | 33 | void CM1106_RequestMeasure(void) { 34 | HalUARTWrite(CO2_UART_PORT, CM1106_COMMAND_GET_PPM, sizeof(CM1106_COMMAND_GET_PPM) / sizeof(CM1106_COMMAND_GET_PPM[0])); 35 | } 36 | 37 | uint16 CM1106_Read(void) { 38 | uint8 response[CM1106_RESPONSE_LENGTH]; 39 | HalUARTRead(CO2_UART_PORT, (uint8 *)&response, sizeof(response) / sizeof(response[0])); 40 | 41 | if (response[0] != 0x16 || response[1] != 0x05) { 42 | LREPMaster("CM1106 Invalid response\r\n"); 43 | HalLedSet(HAL_LED_ALL, HAL_LED_MODE_FLASH); 44 | return AIR_QUALITY_INVALID_RESPONSE; 45 | } 46 | 47 | const uint16 ppm = (((uint16)response[3]) << 8) | response[4]; 48 | LREP("CM1106 Received CO₂=%d ppm\r\n", ppm); 49 | return ppm; 50 | } -------------------------------------------------------------------------------- /Source/OSAL_App.c: -------------------------------------------------------------------------------- 1 | #include "OSAL.h" 2 | #include "OSAL_Tasks.h" 3 | #include "ZComDef.h" 4 | #include "hal_drivers.h" 5 | 6 | #include "APS.h" 7 | #include "ZDApp.h" 8 | #include "nwk.h" 9 | 10 | #if defined ( MT_TASK ) 11 | #include "MT.h" 12 | #include "MT_TASK.h" 13 | #endif 14 | 15 | #include "commissioning.h" 16 | #include "factory_reset.h" 17 | #include "Debug.h" 18 | 19 | #include "bdb_interface.h" 20 | #include "zcl_app.h" 21 | 22 | const pTaskEventHandlerFn tasksArr[] = {macEventLoop, 23 | nwk_event_loop, 24 | Hal_ProcessEvent, 25 | #if defined( MT_TASK ) 26 | MT_ProcessEvent, 27 | #endif 28 | APS_event_loop, 29 | ZDApp_event_loop, 30 | zcl_event_loop, 31 | bdb_event_loop, 32 | zclApp_event_loop, 33 | zclCommissioning_event_loop, 34 | zclFactoryResetter_loop}; 35 | 36 | const uint8 tasksCnt = sizeof(tasksArr) / sizeof(tasksArr[0]); 37 | uint16 *tasksEvents; 38 | 39 | void osalInitTasks(void) { 40 | uint8 taskID = 0; 41 | DebugInit(); 42 | 43 | tasksEvents = (uint16 *)osal_mem_alloc(sizeof(uint16) * tasksCnt); 44 | osal_memset(tasksEvents, 0, (sizeof(uint16) * tasksCnt)); 45 | macTaskInit(taskID++); 46 | nwk_init(taskID++); 47 | Hal_Init(taskID++); 48 | #if defined( MT_TASK ) 49 | MT_TaskInit( taskID++ ); 50 | #endif 51 | APS_Init(taskID++); 52 | ZDApp_Init(taskID++); 53 | zcl_Init(taskID++); 54 | bdb_Init(taskID++); 55 | zclApp_Init(taskID++); 56 | zclCommissioning_Init(taskID++); 57 | zclFactoryResetter_Init(taskID++); 58 | } 59 | 60 | /********************************************************************* 61 | *********************************************************************/ 62 | -------------------------------------------------------------------------------- /Source/preinclude.h: -------------------------------------------------------------------------------- 1 | #define TC_LINKKEY_JOIN 2 | #define NV_INIT 3 | #define NV_RESTORE 4 | 5 | #define TP2_LEGACY_ZC 6 | // patch sdk 7 | // #define ZDSECMGR_TC_ATTEMPT_DEFAULT_KEY TRUE 8 | 9 | #define NWK_AUTO_POLL 10 | #define MULTICAST_ENABLED FALSE 11 | 12 | #define ZCL_READ 13 | #define ZCL_WRITE 14 | #define ZCL_BASIC 15 | #define ZCL_IDENTIFY 16 | #define ZCL_REPORTING_DEVICE 17 | 18 | #define DISABLE_GREENPOWER_BASIC_PROXY 19 | #define BDB_FINDING_BINDING_CAPABILITY_ENABLED 1 20 | #define BDB_REPORTING TRUE 21 | 22 | 23 | #define HAL_BUZZER FALSE 24 | #define HAL_KEY TRUE 25 | #define ISR_KEYINTERRUPT 26 | 27 | 28 | #define HAL_LED TRUE 29 | #define HAL_ADC FALSE 30 | #define HAL_LCD FALSE 31 | 32 | #define BLINK_LEDS TRUE 33 | 34 | // one of this boards 35 | // #define HAL_BOARD_TARGET 36 | // #define HAL_BOARD_CHDTECH_DEV 37 | 38 | #if !defined(HAL_BOARD_TARGET) && !defined(HAL_BOARD_CHDTECH_DEV) 39 | #error "Board type must be defined" 40 | #endif 41 | 42 | #if defined(HAL_BOARD_TARGET) 43 | #define HAL_KEY_P2_INPUT_PINS BV(0) 44 | #define CO2_UART_PORT 0x00 45 | #define HAL_UART_DMA 1 46 | #define HAL_UART_ISR 0 47 | #define INT_HEAP_LEN (2256 - 0xE - 0x1E) 48 | #elif defined(HAL_BOARD_CHDTECH_DEV) 49 | #define HAL_UART_DMA 1 50 | #define HAL_UART_ISR 2 51 | #define CO2_UART_PORT 0x01 52 | #define HAL_KEY_P0_INPUT_PINS BV(1) 53 | #define DO_DEBUG_UART 54 | #endif 55 | 56 | #define FACTORY_RESET_HOLD_TIME_LONG 5000 57 | 58 | 59 | #ifdef DO_DEBUG_UART 60 | #define HAL_UART TRUE 61 | #define HAL_UART_DMA 1 62 | #define INT_HEAP_LEN 2060 63 | #endif 64 | 65 | // #define INT_HEAP_LEN (2685 - 0x4B - 0xBB-0x50-0xae) 66 | // #define HAL_UART TRUE 67 | // #define HAL_UART_DMA 2 68 | #define HAL_UART TRUE 69 | 70 | #define BME280_32BIT_ENABLE 71 | //i2c bme280 72 | #define OCM_CLK_PORT 1 73 | #define OCM_CLK_PIN 6 74 | 75 | #define OCM_DATA_PORT 1 76 | #define OCM_DATA_PIN 7 77 | 78 | 79 | #define DS18B20_PORT 0 80 | #define TSENS_SBIT P0_0 81 | #define TSENS_BV BV(0) 82 | #define TSENS_DIR P0DIR 83 | 84 | 85 | 86 | 87 | #include "hal_board_cfg.h" 88 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![](/images/CO2_SenseAir_S8.png) 2 | Carbon dioxide has a very negative effect on the human body and is a carcinogen. Being in a room with a high concentration of CO2 can cause weakness, drowsiness, headaches, and problems concentrating. In this regard, it is necessary to monitor the level of CO2 and take measures to reduce it. 3 | 4 | Today there are several options available for CO2 measurement, the most interesting being the SenseAir S8. His readings will be displayed on the Zigbee network. 5 | ### How to compile 6 | Follow this article https://zigdevwiki.github.io/Begin/IAR_install/ 7 | 8 | ### Diagram 9 | ![](/images/Schematic_CO2_SenseAir_S8.png) 10 | 11 | The Zigbee part is implemented on the E18-MS1PA1-PCB module, besides it, the board contains the SenseAir S8 CO2 sensor itself 12 | ![](/images/CO2_SenseAir_S8_2.png) 13 | ![](/images/CO2_SenseAir_S8_1.png) 14 | and two variants of temperature sensors is the DS18B20 and the more universal BME280 sensor, which allows you to measure temperature, humidity and atmospheric pressure. 15 | 16 | ### PCB 17 | The board is designed in the popular "USB stick" form factor, you can unsolder both micro USB and USB-A connectors 18 | ![](/images/CO2_SenseAir_S8_6.png) 19 | ![](/images/CO2_SenseAir_S8_5.png) 20 | 21 | 22 | The assembly of the device should not cause difficulties even for people with initial soldering skills, all elements are large enough, except for the BME280. 23 | 24 | When assembled, the device looks like this, please note that a gap must be left between the SenseAir S8 and the board. 25 | ![](/images/2020-09-25_14-17-18.png) 26 | 27 | Anonymass wrote the firmware for this device, it is open source. 28 | 29 | ### Support 30 | The sensor is supported in the zigbee2mqtt via interval and external converter. It looks like this 31 | ![](/images/CO2_SenseAir_S8_10.png) 32 | ![](/images/CO2_SenseAir_S8_11.png) 33 | 34 | also implemented support in SLS Gateway 35 | ![](/images/CO2_SenseAir_S8_15.png) 36 | 37 | According to the test results, the high sensitivity of SenseAir S8 was found, the sensor quickly responds to changes in the CO2 level. 38 | 39 | Jager's daily schedule. 40 | ![](/images/CO2_SenseAir_S8_8.png) 41 | 42 | Anonymass' daily schedule. 43 | ![](/images/CO2_SenseAir_S8_12.png) 44 | 45 | ### Other info 46 | * The MHZ19B sensor (and clones) also can be installed on the board. 47 | * End devices use sleep mode, so E18 board stays cold and BME280 shows more truthful values. 48 | 49 | ### How to join 50 | * Reset to FN rebooting device 5 times with interval less than 10 seconds, led will start flashing during reset 51 | * Reset to FN by pressing and holding the button (SW1) for 5 seconds 52 | 53 | ### User interface 54 | #### LEDs 55 | * LED1 blinks when accessing the CO2 sensor. 56 | * LED2 blinks if the CO2 value is higher than the first set point (1000), while LED3 is off. 57 | * LED3 blinks if the CO2 value is higher than the second set point (2000), while LED2 is on. 58 | 59 | #### Buttons 60 | * SW2 E18 Manual report / FN reset 61 | * SW1 CO2 Calibration 62 | 63 | ### Files to reproduce 64 | * [Gerbers and BOM](https://github.com/diyruz/AirSense/tree/master/hardware) by [Jager](https://t.me/Jager_f) 65 | * [Firmware](https://github.com/diyruz/AirSense/releases) by [@anonymass](https://t.me/anonymass) 66 | * [Housing](https://www.thingiverse.com/thing:4739711) by [ArtBrayko](https://www.thingiverse.com/ArtBrayko) 67 | 68 | [Original post by Jager](https://modkam.ru/?p=1715) 69 | -------------------------------------------------------------------------------- /Source/zcl_app.h: -------------------------------------------------------------------------------- 1 | #ifndef ZCL_APP_H 2 | #define ZCL_APP_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | /********************************************************************* 9 | * INCLUDES 10 | */ 11 | #include "version.h" 12 | #include "zcl.h" 13 | 14 | /********************************************************************* 15 | * CONSTANTS 16 | */ 17 | #define APP_REPORT_DELAY ((uint32)60 * (uint32)1000) // 1 minute 18 | 19 | // Application Events 20 | #define APP_REPORT_EVT 0x0001 21 | #define APP_SAVE_ATTRS_EVT 0x0002 22 | #define APP_READ_SENSORS_EVT 0x0004 23 | /********************************************************************* 24 | * MACROS 25 | */ 26 | #define NW_APP_CONFIG 0x0402 27 | 28 | #define R ACCESS_CONTROL_READ 29 | // ACCESS_CONTROL_AUTH_WRITE 30 | #define RW (R | ACCESS_CONTROL_WRITE | ACCESS_CONTROL_AUTH_WRITE) 31 | #define RR (R | ACCESS_REPORTABLE) 32 | 33 | #define BASIC ZCL_CLUSTER_ID_GEN_BASIC 34 | #define GEN_ON_OFF ZCL_CLUSTER_ID_GEN_ON_OFF 35 | #define POWER_CFG ZCL_CLUSTER_ID_GEN_ON 36 | #define TEMP ZCL_CLUSTER_ID_MS_TEMPERATURE_MEASUREMENT 37 | #define HUMIDITY ZCL_CLUSTER_ID_MS_RELATIVE_HUMIDITY 38 | #define PRESSURE ZCL_CLUSTER_ID_MS_PRESSURE_MEASUREMENT 39 | 40 | //Carbon Dioxide (CO2) 41 | #define ZCL_CO2 0x040d 42 | 43 | enum { 44 | EBME280 = 0, 45 | EDS18B20 = 1, 46 | ENOTFOUND = 2 47 | }; 48 | 49 | enum { 50 | ABC_DISABLED = 0, 51 | ABC_ENABLED = 1, 52 | ABC_NOT_AVALIABLE = 0xFF, 53 | }; 54 | 55 | // Carbon Dioxide (CO2) 56 | #define ATTRID_CO2_MEASURED_VALUE 0x0000 57 | #define ATTRID_CO2_TOLERANCE 0x0003 58 | #define ATTRID_ENABLE_ABC 0x0202 59 | #define ATTRID_LED_FEEDBACK 0x0203 60 | #define ATTRID_THRESHOLD1_PPM 0x0204 61 | #define ATTRID_THRESHOLD2_PPM 0x0205 62 | 63 | #define ATTRID_TemperatureOffset 0x0210 64 | #define ATTRID_PressureOffset 0x0210 65 | #define ATTRID_HumidityOffset 0x0210 66 | 67 | #define ZCL_UINT8 ZCL_DATATYPE_UINT8 68 | #define ZCL_UINT16 ZCL_DATATYPE_UINT16 69 | #define ZCL_INT16 ZCL_DATATYPE_INT16 70 | #define ZCL_INT8 ZCL_DATATYPE_INT8 71 | #define ZCL_INT32 ZCL_DATATYPE_INT32 72 | #define ZCL_UINT32 ZCL_DATATYPE_UINT32 73 | #define ZCL_SINGLE ZCL_DATATYPE_SINGLE_PREC 74 | /********************************************************************* 75 | * TYPEDEFS 76 | */ 77 | 78 | typedef struct { 79 | uint8 LedFeedback; 80 | uint8 EnableABC; 81 | uint16 Threshold1_PPM; 82 | uint16 Threshold2_PPM; 83 | int16 TemperatureOffset; 84 | int32 PressureOffset; 85 | int16 HumidityOffset; 86 | } application_config_t; 87 | 88 | typedef struct { 89 | float CO2; 90 | int16 CO2_PPM; 91 | int16 Temperature; 92 | int16 BME280_Temperature_Sensor_MeasuredValue; 93 | uint16 BME280_HumiditySensor_MeasuredValue; 94 | int16 BME280_PressureSensor_MeasuredValue; 95 | int16 BME280_PressureSensor_ScaledValue; 96 | int8 BME280_PressureSensor_Scale; 97 | } sensors_state_t; 98 | 99 | /********************************************************************* 100 | * VARIABLES 101 | */ 102 | 103 | extern SimpleDescriptionFormat_t zclApp_FirstEP; 104 | extern CONST zclAttrRec_t zclApp_AttrsFirstEP[]; 105 | extern CONST uint8 zclApp_AttrsCount; 106 | 107 | 108 | extern const uint8 zclApp_ManufacturerName[]; 109 | extern const uint8 zclApp_ModelId[]; 110 | extern const uint8 zclApp_PowerSource; 111 | 112 | extern application_config_t zclApp_Config; 113 | extern sensors_state_t zclApp_Sensors; 114 | // APP_TODO: Declare application specific attributes here 115 | 116 | /********************************************************************* 117 | * FUNCTIONS 118 | */ 119 | 120 | /* 121 | * Initialization for the task 122 | */ 123 | extern void zclApp_Init(byte task_id); 124 | 125 | /* 126 | * Event Process for the task 127 | */ 128 | extern UINT16 zclApp_event_loop(byte task_id, UINT16 events); 129 | 130 | extern void zclApp_ResetAttributesToDefaultValues(void); 131 | 132 | /********************************************************************* 133 | *********************************************************************/ 134 | 135 | #ifdef __cplusplus 136 | } 137 | #endif 138 | 139 | #endif /* ZCL_APP_H */ 140 | -------------------------------------------------------------------------------- /0001-Fixes.patch: -------------------------------------------------------------------------------- 1 | From de8dde18843842ea317baac0c9a09471b596d9c6 Mon Sep 17 00:00:00 2001 2 | From: nur 3 | Date: Thu, 28 May 2020 07:54:34 +0800 4 | Subject: [PATCH] Fixes 5 | 6 | --- 7 | Components/stack/bdb/bdb_Reporting.c | 28 ++++++++++++++++++++++------ 8 | Components/stack/bdb/bdb_interface.h | 4 ++-- 9 | 2 files changed, 24 insertions(+), 8 deletions(-) 10 | 11 | diff --git a/Components/stack/bdb/bdb_Reporting.c b/Components/stack/bdb/bdb_Reporting.c 12 | index 7a601f2..42c610d 100644 13 | --- a/Components/stack/bdb/bdb_Reporting.c 14 | +++ b/Components/stack/bdb/bdb_Reporting.c 15 | @@ -1662,7 +1662,7 @@ static uint8 bdb_RepLoadCfgRecords( void ) 16 | static void bdb_RepReport( uint8 specificCLusterEndpointIndex ) 17 | { 18 | afAddrType_t dstAddr; 19 | - zclReportCmd_t *pReportCmd; 20 | + zclReportCmd_t *pReportCmd = NULL; 21 | uint8 i; 22 | 23 | bdbReportAttrClusterEndpoint_t* clusterEndpointItem = NULL; 24 | @@ -1681,14 +1681,21 @@ static void bdb_RepReport( uint8 specificCLusterEndpointIndex ) 25 | // actually send the report 26 | if( clusterEndpointItem->consolidatedMaxReportInt != ZCL_REPORTING_OFF && clusterEndpointItem->attrLinkedList.numItems ) 27 | { 28 | + uint8 *pAttrData = NULL; 29 | + uint8 *pAttrDataTemp = NULL; 30 | + 31 | dstAddr.addrMode = (afAddrMode_t)AddrNotPresent; 32 | dstAddr.addr.shortAddr = 0; 33 | dstAddr.endPoint = clusterEndpointItem->endpoint; 34 | dstAddr.panId = _NIB.nwkPanId; 35 | 36 | + // List of attributes to report 37 | pReportCmd = osal_mem_alloc( sizeof( zclReportCmd_t ) + (clusterEndpointItem->attrLinkedList.numItems * sizeof( zclReport_t )) ); 38 | - if ( pReportCmd != NULL ) 39 | + // List of attribute data 40 | + pAttrData = osal_mem_alloc(clusterEndpointItem->attrLinkedList.numItems * BDBREPORTING_MAX_ANALOG_ATTR_SIZE); 41 | + if ( (pReportCmd != NULL) && (pAttrData != NULL) ) 42 | { 43 | + pAttrDataTemp = pAttrData; 44 | pReportCmd->numAttr = clusterEndpointItem->attrLinkedList.numItems; 45 | for ( i = 0; i < clusterEndpointItem->attrLinkedList.numItems; ++ i ) 46 | { 47 | @@ -1699,13 +1706,16 @@ static void bdb_RepReport( uint8 specificCLusterEndpointIndex ) 48 | bdbLinkedListAttrItem_t* attrListItem = bdb_linkedListAttrGetAtIndex( &clusterEndpointItem->attrLinkedList, i ); 49 | if(attrListItem!=NULL) 50 | { 51 | - pReportCmd->attrList[i].attrID = attrListItem->data->attrID; 52 | zclAttribute_t attrRec; 53 | + pReportCmd->attrList[i].attrID = attrListItem->data->attrID; 54 | uint8 attrRes = bdb_RepFindAttrEntry( clusterEndpointItem->endpoint, clusterEndpointItem->cluster, attrListItem->data->attrID, &attrRec ); 55 | if( attrRes == BDBREPORTING_TRUE ) 56 | { 57 | - pReportCmd->attrList[i].dataType = attrRec.dataType; 58 | - pReportCmd->attrList[i].attrData = attrRec.dataPtr; 59 | + pReportCmd->attrList[i].dataType = attrRec.dataType; 60 | + pReportCmd->attrList[i].attrData = pAttrDataTemp; 61 | + // Copy data to current attribute data pointer 62 | + pAttrDataTemp = osal_memcpy(pAttrDataTemp, attrRec.dataPtr, BDBREPORTING_MAX_ANALOG_ATTR_SIZE); 63 | + 64 | //Update last value reported 65 | if( zclAnalogDataType( attrRec.dataType ) ) 66 | { 67 | @@ -1720,9 +1730,15 @@ static void bdb_RepReport( uint8 specificCLusterEndpointIndex ) 68 | zcl_SendReportCmd( clusterEndpointItem->endpoint, &dstAddr, 69 | clusterEndpointItem->cluster, pReportCmd, 70 | ZCL_FRAME_SERVER_CLIENT_DIR, BDB_REPORTING_DISABLE_DEFAULT_RSP, bdb_getZCLFrameCounter( ) ); 71 | - 72 | + } 73 | + if( (pReportCmd != NULL ) ) 74 | + { 75 | osal_mem_free( pReportCmd ); 76 | } 77 | + if ( (pAttrData != NULL) ) 78 | + { 79 | + osal_mem_free( pAttrData ); 80 | + } 81 | } 82 | } 83 | 84 | diff --git a/Components/stack/bdb/bdb_interface.h b/Components/stack/bdb/bdb_interface.h 85 | index 2cb5d99..be0baba 100644 86 | --- a/Components/stack/bdb/bdb_interface.h 87 | +++ b/Components/stack/bdb/bdb_interface.h 88 | @@ -182,10 +182,10 @@ extern "C" 89 | // For certification only: 90 | #define TOUCHLINK_ENC_KEY TOUCHLINK_CERTIFICATION_ENC_KEY 91 | #define TOUCHLINK_LINK_KEY TOUCHLINK_CERTIFICATION_LINK_KEY 92 | -#define TOUCHLINK_KEY_INDEX TOUCHLINK_KEY_INDEX_CERT 93 | +#define TOUCHLINK_KEY_INDEX TOUCHLINK_KEY_INDEX_MASTER 94 | 95 | // For internal EP's simple descriptor 96 | -#define TOUCHLINK_INTERNAL_ENDPOINT 13 97 | +#define TOUCHLINK_INTERNAL_ENDPOINT 42 98 | #define TOUCHLINK_INTERNAL_DEVICE_ID 0xE15E 99 | #define TOUCHLINK_INTERNAL_FLAGS 0 100 | #define TOUCHLINK_DEFAULT_IDENTIFY_TIME 3 101 | -- 102 | 2.24.3 (Apple Git-128) 103 | 104 | -------------------------------------------------------------------------------- /converters/DIYRuZ_AirSense.js: -------------------------------------------------------------------------------- 1 | const { 2 | fromZigbeeConverters, 3 | toZigbeeConverters, 4 | exposes 5 | } = require('zigbee-herdsman-converters'); 6 | const ZCL_DATATYPE_INT16 = 0x29; 7 | const ZCL_DATATYPE_UINT16 = 0x21; 8 | const ZCL_DATATYPE_BOOLEAN = 0x10; 9 | const ZCL_DATATYPE_INT32 = 0x2b; 10 | const bind = async (endpoint, target, clusters) => { 11 | for (const cluster of clusters) { 12 | await endpoint.bind(cluster, target); 13 | } 14 | }; 15 | 16 | const ACCESS_STATE = 0b001, ACCESS_WRITE = 0b010, ACCESS_READ = 0b100; 17 | 18 | 19 | const deviceOptions = [{ 20 | cluster: 'msCO2', 21 | attrId: 0x0203, 22 | type: ZCL_DATATYPE_BOOLEAN, 23 | key: 'led_feedback', 24 | }, 25 | { 26 | cluster: 'msCO2', 27 | attrId: 0x0202, 28 | type: ZCL_DATATYPE_BOOLEAN, 29 | key: 'enable_abc', 30 | }, 31 | { 32 | cluster: 'msCO2', 33 | attrId: 0x0204, 34 | type: ZCL_DATATYPE_UINT16, 35 | key: 'threshold1', 36 | }, 37 | { 38 | cluster: 'msCO2', 39 | attrId: 0x0205, 40 | type: ZCL_DATATYPE_UINT16, 41 | key: 'threshold2', 42 | }, 43 | { 44 | cluster: 'msTemperatureMeasurement', 45 | attrId: 0x0210, 46 | type: ZCL_DATATYPE_INT16, 47 | key: 'temperature_offset', 48 | }, 49 | { 50 | cluster: 'msPressureMeasurement', 51 | attrId: 0x0210, 52 | type: ZCL_DATATYPE_INT32, 53 | key: 'pressure_offset', 54 | }, 55 | { 56 | cluster: 'msRelativeHumidity', 57 | attrId: 0x0210, 58 | type: ZCL_DATATYPE_INT16, 59 | key: 'humidity_offset', 60 | }, 61 | 62 | ]; 63 | const BOOL_MAP = ['OFF', 'ON']; 64 | const generateConfigConverter = (cluster) => ({ 65 | cluster, 66 | type: 'readResponse', 67 | convert: (model, msg, publish, options, meta) => { 68 | console.log(msg.data); 69 | const result = {}; 70 | deviceOptions.forEach(({ 71 | key, 72 | attrId, 73 | type 74 | }) => { 75 | if (attrId.toString() in msg.data) { 76 | if (type === ZCL_DATATYPE_BOOLEAN) { 77 | result[key] = BOOL_MAP[msg.data[attrId.toString()]]; 78 | } else { 79 | result[key] = msg.data[attrId.toString()]; 80 | } 81 | } 82 | }); 83 | return result; 84 | } 85 | }); 86 | const convertValue = (rawValue) => { 87 | const lookup = { 88 | 'OFF': 0x00, 89 | 'ON': 0x01, 90 | }; 91 | return lookup.hasOwnProperty(rawValue) ? lookup[rawValue] : parseInt(rawValue, 10); 92 | } 93 | const tz = { 94 | config: { 95 | key: deviceOptions.map(({ 96 | key 97 | }) => key), 98 | convertSet: async (entity, key, rawValue, meta) => { 99 | const { 100 | cluster, 101 | attrId, 102 | type 103 | } = deviceOptions.find(({ 104 | key: _optionKey 105 | }) => key === _optionKey); 106 | 107 | await entity.write(cluster, { 108 | [attrId]: { 109 | value: convertValue(rawValue), 110 | type 111 | } 112 | }); 113 | return { 114 | state: { 115 | [key]: rawValue 116 | } 117 | }; 118 | }, 119 | convertGet: async (entity, key, meta) => { 120 | const { 121 | cluster, 122 | attrId 123 | } = deviceOptions.find(({ 124 | key: _optionKey 125 | }) => key === _optionKey); 126 | await entity.read(cluster, [attrId]); 127 | }, 128 | } 129 | } 130 | 131 | const device = { 132 | zigbeeModel: ['DIYRuZ_AirSense'], 133 | model: 'DIYRuZ_AirSense', 134 | vendor: 'DIYRuZ', 135 | description: '[Air quality sensor, external converter](http://modkam.ru/?p=xxxx)', 136 | supports: '', 137 | fromZigbee: [ 138 | fromZigbeeConverters.temperature, 139 | fromZigbeeConverters.humidity, 140 | fromZigbeeConverters.co2, 141 | fromZigbeeConverters.pressure, 142 | ...[...new Set(deviceOptions)].map(({ 143 | cluster 144 | }) => generateConfigConverter(cluster)) 145 | ], 146 | toZigbee: [ 147 | toZigbeeConverters.factory_reset, 148 | tz.config 149 | ], 150 | meta: { 151 | configureKey: 1, 152 | }, 153 | configure: async (device, coordinatorEndpoint) => { 154 | const firstEndpoint = device.getEndpoint(1); 155 | 156 | await bind(firstEndpoint, coordinatorEndpoint, [ 157 | 'msTemperatureMeasurement', 158 | 'msRelativeHumidity', 159 | 'msPressureMeasurement', 160 | 'msCO2' 161 | ]); 162 | 163 | const msBindPayload = [{ 164 | attribute: 'measuredValue', 165 | minimumReportInterval: 0, 166 | maximumReportInterval: 3600, 167 | reportableChange: 0, 168 | }]; 169 | 170 | await firstEndpoint.configureReporting('msCO2', msBindPayload); 171 | await firstEndpoint.configureReporting('msTemperatureMeasurement', msBindPayload); 172 | await firstEndpoint.configureReporting('msRelativeHumidity', msBindPayload); 173 | await firstEndpoint.configureReporting('msPressureMeasurement', msBindPayload); 174 | }, 175 | exposes: [ 176 | exposes.numeric('co2', ACCESS_STATE).withUnit('ppm'), 177 | exposes.numeric('temperature', ACCESS_STATE).withUnit('°C'), 178 | exposes.numeric('humidity', ACCESS_STATE).withUnit('%'), 179 | exposes.numeric('pressure', ACCESS_STATE).withUnit('hPa'), 180 | 181 | 182 | //device options 183 | exposes.binary('led_feedback', ACCESS_STATE | ACCESS_WRITE | ACCESS_READ, 'ON', 'OFF'), 184 | exposes.binary('enable_abc', ACCESS_STATE | ACCESS_WRITE | ACCESS_READ, 'ON', 'OFF'), 185 | // led lights thresholds 186 | exposes.numeric('threshold1', ACCESS_STATE | ACCESS_WRITE | ACCESS_READ).withUnit('ppm'), 187 | exposes.numeric('threshold2', ACCESS_STATE | ACCESS_WRITE | ACCESS_READ).withUnit('ppm'), 188 | //fake BME280 workarounds 189 | exposes.numeric('temperature_offset', ACCESS_STATE | ACCESS_WRITE | ACCESS_READ).withUnit('°C'), 190 | exposes.numeric('pressure_offset', ACCESS_STATE | ACCESS_WRITE | ACCESS_READ).withUnit('hPa'), 191 | exposes.numeric('humidity_offset', ACCESS_STATE | ACCESS_WRITE | ACCESS_READ).withUnit('%') 192 | ], 193 | }; 194 | 195 | module.exports = device; 196 | -------------------------------------------------------------------------------- /Source/zcl_app_data.c: -------------------------------------------------------------------------------- 1 | #include "AF.h" 2 | #include "OSAL.h" 3 | #include "ZComDef.h" 4 | #include "ZDConfig.h" 5 | 6 | #include "zcl.h" 7 | #include "zcl_general.h" 8 | #include "zcl_ha.h" 9 | #include "zcl_ms.h" 10 | 11 | #include "zcl_app.h" 12 | 13 | #include "version.h" 14 | 15 | #include "bdb_touchlink.h" 16 | #include "bdb_touchlink_target.h" 17 | #include "stub_aps.h" 18 | 19 | /********************************************************************* 20 | * CONSTANTS 21 | */ 22 | 23 | #define APP_DEVICE_VERSION 2 24 | #define APP_FLAGS 0 25 | 26 | #define APP_HWVERSION 1 27 | #define APP_ZCLVERSION 1 28 | 29 | /********************************************************************* 30 | * TYPEDEFS 31 | */ 32 | 33 | /********************************************************************* 34 | * MACROS 35 | */ 36 | 37 | /********************************************************************* 38 | * GLOBAL VARIABLES 39 | */ 40 | 41 | // Global attributes 42 | const uint16 zclApp_clusterRevision_all = 0x0002; 43 | 44 | // Basic Cluster 45 | const uint8 zclApp_HWRevision = APP_HWVERSION; 46 | const uint8 zclApp_ZCLVersion = APP_ZCLVERSION; 47 | const uint8 zclApp_ApplicationVersion = 3; 48 | const uint8 zclApp_StackVersion = 4; 49 | 50 | //{lenght, 'd', 'a', 't', 'a'} 51 | const uint8 zclApp_ManufacturerName[] = {9, 'x', 'y', 'z', 'r', 'o', 'e', '.', 'c', 'c'}; 52 | const uint8 zclApp_ModelId[] = {15, 'D', 'I', 'Y', 'R', 'u', 'Z', '_', 'A', 'i', 'r', 'S', 'e', 'n', 's', 'e'}; 53 | const uint8 zclApp_PowerSource = POWER_SOURCE_MAINS_1_PHASE; 54 | 55 | #define DEFAULT_LedFeedback TRUE 56 | #define DEFAULT_EnableABC TRUE 57 | // FYI: https://www.kane.co.uk/knowledge-centre/what-are-safe-levels-of-co-and-co2-in-rooms 58 | #define DEFAULT_Threshold1_PPM 1000 59 | #define DEFAULT_Threshold2_PPM 2000 60 | #define DEFAULT_TemperatureOffset 0 61 | #define DEFAULT_PressureOffset 0 62 | #define DEFAULT_HumidityOffset 0 63 | 64 | 65 | 66 | application_config_t zclApp_Config = { 67 | .LedFeedback = DEFAULT_LedFeedback, 68 | .EnableABC = DEFAULT_EnableABC, 69 | .Threshold1_PPM = DEFAULT_Threshold1_PPM, 70 | .Threshold2_PPM = DEFAULT_Threshold2_PPM, 71 | .TemperatureOffset = DEFAULT_TemperatureOffset, 72 | .PressureOffset = DEFAULT_PressureOffset, 73 | .HumidityOffset = DEFAULT_HumidityOffset 74 | }; 75 | 76 | sensors_state_t zclApp_Sensors = { 77 | .CO2 = 0.0, 78 | .CO2_PPM = 0, 79 | .Temperature = 0, 80 | .BME280_PressureSensor_MeasuredValue = 0, 81 | .BME280_HumiditySensor_MeasuredValue = 0, 82 | .BME280_PressureSensor_ScaledValue = 0, 83 | .BME280_PressureSensor_Scale = -1 84 | }; 85 | 86 | /********************************************************************* 87 | * ATTRIBUTE DEFINITIONS - Uses REAL cluster IDs 88 | */ 89 | 90 | CONST zclAttrRec_t zclApp_AttrsFirstEP[] = { 91 | {BASIC, {ATTRID_BASIC_ZCL_VERSION, ZCL_UINT8, R, (void *)&zclApp_ZCLVersion}}, 92 | {BASIC, {ATTRID_BASIC_APPL_VERSION, ZCL_UINT8, R, (void *)&zclApp_ApplicationVersion}}, 93 | {BASIC, {ATTRID_BASIC_STACK_VERSION, ZCL_UINT8, R, (void *)&zclApp_StackVersion}}, 94 | {BASIC, {ATTRID_BASIC_HW_VERSION, ZCL_UINT8, R, (void *)&zclApp_HWRevision}}, 95 | {BASIC, {ATTRID_BASIC_MANUFACTURER_NAME, ZCL_DATATYPE_CHAR_STR, R, (void *)zclApp_ManufacturerName}}, 96 | {BASIC, {ATTRID_BASIC_MODEL_ID, ZCL_DATATYPE_CHAR_STR, R, (void *)zclApp_ModelId}}, 97 | {BASIC, {ATTRID_BASIC_DATE_CODE, ZCL_DATATYPE_CHAR_STR, R, (void *)zclApp_DateCode}}, 98 | {BASIC, {ATTRID_BASIC_POWER_SOURCE, ZCL_DATATYPE_ENUM8, R, (void *)&zclApp_PowerSource}}, 99 | {BASIC, {ATTRID_BASIC_SW_BUILD_ID, ZCL_DATATYPE_CHAR_STR, R, (void *)zclApp_DateCode}}, 100 | {BASIC, {ATTRID_CLUSTER_REVISION, ZCL_UINT16, R, (void *)&zclApp_clusterRevision_all}}, 101 | 102 | {TEMP, {ATTRID_MS_TEMPERATURE_MEASURED_VALUE, ZCL_INT16, RR, (void *)&zclApp_Sensors.Temperature}}, 103 | {TEMP, {ATTRID_TemperatureOffset, ZCL_INT16, RW, (void *)&zclApp_Config.TemperatureOffset}}, 104 | 105 | {PRESSURE, {ATTRID_MS_PRESSURE_MEASUREMENT_MEASURED_VALUE, ZCL_INT16, RR, (void *)&zclApp_Sensors.BME280_PressureSensor_MeasuredValue}}, 106 | {PRESSURE, {ATTRID_MS_PRESSURE_MEASUREMENT_SCALED_VALUE, ZCL_INT16, RR, (void *)&zclApp_Sensors.BME280_PressureSensor_ScaledValue}}, 107 | {PRESSURE, {ATTRID_MS_PRESSURE_MEASUREMENT_SCALE, ZCL_INT8, R, (void *)&zclApp_Sensors.BME280_PressureSensor_Scale}}, 108 | {PRESSURE, {ATTRID_PressureOffset, ZCL_INT32, RW, (void *)&zclApp_Config.PressureOffset}}, 109 | 110 | 111 | {HUMIDITY, {ATTRID_MS_RELATIVE_HUMIDITY_MEASURED_VALUE, ZCL_UINT16, RR, (void *)&zclApp_Sensors.BME280_HumiditySensor_MeasuredValue}}, 112 | {HUMIDITY, {ATTRID_HumidityOffset, ZCL_INT16, RW, (void *)&zclApp_Config.HumidityOffset}}, 113 | 114 | {ZCL_CO2, {ATTRID_CO2_MEASURED_VALUE, ZCL_SINGLE, RR, (void *)&zclApp_Sensors.CO2}}, 115 | {ZCL_CO2, {ATTRID_ENABLE_ABC, ZCL_DATATYPE_BOOLEAN, RW, (void *)&zclApp_Config.EnableABC}}, 116 | {ZCL_CO2, {ATTRID_LED_FEEDBACK, ZCL_DATATYPE_BOOLEAN, RW, (void *)&zclApp_Config.LedFeedback}}, 117 | {ZCL_CO2, {ATTRID_THRESHOLD1_PPM, ZCL_UINT16, RW, (void *)&zclApp_Config.Threshold1_PPM}}, 118 | {ZCL_CO2, {ATTRID_THRESHOLD2_PPM, ZCL_UINT16, RW, (void *)&zclApp_Config.Threshold2_PPM}} 119 | }; 120 | 121 | 122 | uint8 CONST zclApp_AttrsCount = (sizeof(zclApp_AttrsFirstEP) / sizeof(zclApp_AttrsFirstEP[0])); 123 | 124 | const cId_t zclApp_InClusterList[] = {ZCL_CLUSTER_ID_GEN_BASIC}; 125 | 126 | #define APP_MAX_INCLUSTERS (sizeof(zclApp_InClusterList) / sizeof(zclApp_InClusterList[0])) 127 | 128 | const cId_t zclApp_OutClusterList[] = {TEMP, HUMIDITY, PRESSURE, ZCL_CO2}; 129 | 130 | 131 | #define APP_MAX_OUT_CLUSTERS (sizeof(zclApp_OutClusterList) / sizeof(zclApp_OutClusterList[0])) 132 | 133 | 134 | SimpleDescriptionFormat_t zclApp_FirstEP = { 135 | 1, // int Endpoint; 136 | ZCL_HA_PROFILE_ID, // uint16 AppProfId[2]; 137 | ZCL_HA_DEVICEID_SIMPLE_SENSOR, // uint16 AppDeviceId[2]; 138 | APP_DEVICE_VERSION, // int AppDevVer:4; 139 | APP_FLAGS, // int AppFlags:4; 140 | APP_MAX_INCLUSTERS, // byte AppNumInClusters; 141 | (cId_t *)zclApp_InClusterList, // byte *pAppInClusterList; 142 | APP_MAX_OUT_CLUSTERS, // byte AppNumInClusters; 143 | (cId_t *)zclApp_OutClusterList // byte *pAppInClusterList; 144 | }; 145 | 146 | 147 | void zclApp_ResetAttributesToDefaultValues(void) { 148 | zclApp_Config.LedFeedback = DEFAULT_LedFeedback; 149 | zclApp_Config.EnableABC = DEFAULT_EnableABC; 150 | zclApp_Config.Threshold1_PPM = DEFAULT_Threshold1_PPM; 151 | zclApp_Config.Threshold2_PPM = DEFAULT_Threshold2_PPM; 152 | zclApp_Config.TemperatureOffset = DEFAULT_TemperatureOffset; 153 | zclApp_Config.HumidityOffset = DEFAULT_HumidityOffset; 154 | zclApp_Config.PressureOffset = DEFAULT_PressureOffset; 155 | } -------------------------------------------------------------------------------- /Source/zcl_app.c: -------------------------------------------------------------------------------- 1 | 2 | #include "AF.h" 3 | #include "OSAL.h" 4 | #include "OSAL_Clock.h" 5 | #include "OSAL_PwrMgr.h" 6 | #include "ZComDef.h" 7 | #include "ZDApp.h" 8 | #include "ZDObject.h" 9 | #include "math.h" 10 | 11 | #include "nwk_util.h" 12 | #include "zcl.h" 13 | #include "zcl_app.h" 14 | #include "zcl_diagnostic.h" 15 | #include "zcl_general.h" 16 | #include "zcl_ms.h" 17 | 18 | #include "bdb.h" 19 | #include "bdb_interface.h" 20 | #include "bdb_touchlink.h" 21 | #include "bdb_touchlink_target.h" 22 | 23 | #include "gp_interface.h" 24 | 25 | #include "Debug.h" 26 | 27 | #include "OnBoard.h" 28 | 29 | #include "commissioning.h" 30 | #include "factory_reset.h" 31 | /* HAL */ 32 | #include "bme280.h" 33 | #include "ds18b20.h" 34 | #include "hal_drivers.h" 35 | #include "hal_i2c.h" 36 | #include "hal_key.h" 37 | #include "hal_led.h" 38 | #include "mhz19.h" 39 | #include "senseair.h" 40 | #include "cm1106.h" 41 | #include "utils.h" 42 | #include "version.h" 43 | 44 | /********************************************************************* 45 | * MACROS 46 | */ 47 | 48 | /********************************************************************* 49 | * CONSTANTS 50 | */ 51 | 52 | /********************************************************************* 53 | * TYPEDEFS 54 | */ 55 | 56 | /********************************************************************* 57 | * GLOBAL VARIABLES 58 | */ 59 | byte zclApp_TaskID; 60 | 61 | /********************************************************************* 62 | * GLOBAL FUNCTIONS 63 | */ 64 | void user_delay_ms(uint32_t period); 65 | void user_delay_ms(uint32_t period) { MicroWait(period * 1000); } 66 | /********************************************************************* 67 | * LOCAL VARIABLES 68 | */ 69 | struct bme280_dev bme_dev = {.dev_id = BME280_I2C_ADDR_PRIM, .intf = BME280_I2C_INTF, .read = I2C_ReadMultByte, .write = I2C_WriteMultByte, .delay_ms = user_delay_ms}; 70 | 71 | static zclAirSensor_t const *air_dev = &sense_air_dev; 72 | 73 | /********************************************************************* 74 | * LOCAL FUNCTIONS 75 | */ 76 | static void zclApp_Report(void); 77 | static void zclApp_BasicResetCB(void); 78 | static void zclApp_RestoreAttributesFromNV(void); 79 | static void zclApp_SaveAttributesToNV(void); 80 | static void zclApp_ReadSensors(void); 81 | static void zclApp_HandleKeys(byte portAndAction, byte keyCode); 82 | static uint8 zclApp_RequestBME280(struct bme280_dev *dev); 83 | static uint8 zclApp_ReadBME280(struct bme280_dev *dev); 84 | static void zclApp_InitCO2Uart(void); 85 | static ZStatus_t zclApp_ReadWriteAuthCB(afAddrType_t *srcAddr, zclAttrRec_t *pAttr, uint8 oper); 86 | static void zclApp_SetupABC(bool force); 87 | 88 | /********************************************************************* 89 | * ZCL General Profile Callback table 90 | */ 91 | static zclGeneral_AppCallbacks_t zclApp_CmdCallbacks = { 92 | zclApp_BasicResetCB, // Basic Cluster Reset command 93 | NULL, // Identify Trigger Effect command 94 | NULL, // On/Off cluster commands 95 | NULL, // On/Off cluster enhanced command Off with Effect 96 | NULL, // On/Off cluster enhanced command On with Recall Global Scene 97 | NULL, // On/Off cluster enhanced command On with Timed Off 98 | NULL, // RSSI Location command 99 | NULL // RSSI Location Response command 100 | }; 101 | 102 | void zclApp_Init(byte task_id) { 103 | HalLedSet(HAL_LED_ALL, HAL_LED_MODE_BLINK); 104 | 105 | zclApp_RestoreAttributesFromNV(); 106 | zclApp_InitCO2Uart(); 107 | zclApp_TaskID = task_id; 108 | 109 | bdb_RegisterSimpleDescriptor(&zclApp_FirstEP); 110 | 111 | zclGeneral_RegisterCmdCallbacks(zclApp_FirstEP.EndPoint, &zclApp_CmdCallbacks); 112 | 113 | zcl_registerAttrList(zclApp_FirstEP.EndPoint, zclApp_AttrsCount, zclApp_AttrsFirstEP); 114 | 115 | zcl_registerReadWriteCB(zclApp_FirstEP.EndPoint, NULL, zclApp_ReadWriteAuthCB); 116 | zcl_registerForMsg(zclApp_TaskID); 117 | RegisterForKeys(zclApp_TaskID); 118 | 119 | LREP("Build %s \r\n", zclApp_DateCodeNT); 120 | 121 | HalI2CInit(); 122 | osal_start_reload_timer(zclApp_TaskID, APP_REPORT_EVT, APP_REPORT_DELAY); 123 | } 124 | 125 | static void zclApp_HandleKeys(byte portAndAction, byte keyCode) { 126 | LREP("zclApp_HandleKeys portAndAction=0x%X keyCode=0x%X\r\n", portAndAction, keyCode); 127 | zclFactoryResetter_HandleKeys(portAndAction, keyCode); 128 | zclCommissioning_HandleKeys(portAndAction, keyCode); 129 | if (portAndAction & HAL_KEY_PRESS) { 130 | LREPMaster("Key press\r\n"); 131 | zclApp_Report(); 132 | } 133 | } 134 | 135 | static void zclApp_InitCO2Uart(void) { 136 | halUARTCfg_t halUARTConfig; 137 | halUARTConfig.configured = TRUE; 138 | halUARTConfig.baudRate = HAL_UART_BR_9600; 139 | halUARTConfig.flowControl = FALSE; 140 | halUARTConfig.flowControlThreshold = 48; // this parameter indicates number of bytes left before Rx Buffer 141 | // reaches maxRxBufSize 142 | halUARTConfig.idleTimeout = 10; // this parameter indicates rx timeout period in millisecond 143 | halUARTConfig.rx.maxBufSize = 15; 144 | halUARTConfig.tx.maxBufSize = 15; 145 | halUARTConfig.intEnable = TRUE; 146 | halUARTConfig.callBackFunc = NULL; 147 | HalUARTInit(); 148 | if (HalUARTOpen(CO2_UART_PORT, &halUARTConfig) == HAL_UART_SUCCESS) { 149 | LREPMaster("Initialized CO2 UART \r\n"); 150 | } 151 | } 152 | 153 | uint16 zclApp_event_loop(uint8 task_id, uint16 events) { 154 | LREP("events 0x%x \r\n", events); 155 | if (events & SYS_EVENT_MSG) { 156 | afIncomingMSGPacket_t *MSGpkt; 157 | while ((MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive(zclApp_TaskID))) { 158 | LREP("MSGpkt->hdr.event 0x%X clusterId=0x%X\r\n", MSGpkt->hdr.event, MSGpkt->clusterId); 159 | switch (MSGpkt->hdr.event) { 160 | case KEY_CHANGE: 161 | zclApp_HandleKeys(((keyChange_t *)MSGpkt)->state, ((keyChange_t *)MSGpkt)->keys); 162 | break; 163 | 164 | case ZCL_INCOMING_MSG: 165 | if (((zclIncomingMsg_t *)MSGpkt)->attrCmd) { 166 | osal_mem_free(((zclIncomingMsg_t *)MSGpkt)->attrCmd); 167 | } 168 | break; 169 | 170 | default: 171 | break; 172 | } 173 | 174 | // Release the memory 175 | osal_msg_deallocate((uint8 *)MSGpkt); 176 | } 177 | // return unprocessed events 178 | return (events ^ SYS_EVENT_MSG); 179 | } 180 | if (events & APP_REPORT_EVT) { 181 | LREPMaster("APP_REPORT_EVT\r\n"); 182 | zclApp_Report(); 183 | return (events ^ APP_REPORT_EVT); 184 | } 185 | 186 | if (events & APP_SAVE_ATTRS_EVT) { 187 | LREPMaster("APP_SAVE_ATTRS_EVT\r\n"); 188 | zclApp_SaveAttributesToNV(); 189 | return (events ^ APP_SAVE_ATTRS_EVT); 190 | } 191 | if (events & APP_READ_SENSORS_EVT) { 192 | LREPMaster("APP_READ_SENSORS_EVT\r\n"); 193 | zclApp_ReadSensors(); 194 | return (events ^ APP_READ_SENSORS_EVT); 195 | } 196 | return 0; 197 | } 198 | 199 | static void zclApp_LedFeedback(void) { 200 | if (zclApp_Config.LedFeedback) { 201 | if (zclApp_Sensors.CO2_PPM > zclApp_Config.Threshold2_PPM) { 202 | HalLedSet(HAL_LED_3, HAL_LED_MODE_FLASH); 203 | HalLedSet(HAL_LED_2, HAL_LED_MODE_ON); 204 | } else if (zclApp_Sensors.CO2_PPM > zclApp_Config.Threshold1_PPM) { 205 | HalLedSet(HAL_LED_2, HAL_LED_MODE_FLASH); 206 | HalLedSet(HAL_LED_3, HAL_LED_MODE_OFF); 207 | } 208 | } else { 209 | HalLedSet(HAL_LED_2 | HAL_LED_3, HAL_LED_MODE_OFF); 210 | } 211 | } 212 | 213 | static uint8 current_co2_sensor_state = ABC_NOT_AVALIABLE; 214 | static void zclApp_SetupABC(bool force) { 215 | if ((current_co2_sensor_state != ABC_NOT_AVALIABLE) != zclApp_Config.EnableABC || force) { 216 | (*air_dev->SetABC)(zclApp_Config.EnableABC); 217 | current_co2_sensor_state = zclApp_Config.EnableABC ? ABC_ENABLED : ABC_DISABLED; // write 218 | } 219 | } 220 | 221 | static void zclApp_ReadSensors(void) { 222 | if (zclApp_Config.LedFeedback) { 223 | HalLedSet(HAL_LED_1, HAL_LED_MODE_BLINK); 224 | } 225 | static uint8 currentSensorsReadingPhase = 0; 226 | static uint8 temp_sensor_type = EBME280; 227 | bool sensor_state_not_avaliable = false; 228 | 229 | LREP("currentSensorsReadingPhase %d\r\n", currentSensorsReadingPhase); 230 | // FYI: split reading sensors into phases, so single call wouldn't block processor 231 | // for extensive ammount of time 232 | uint16 ppm = 0; 233 | int16 temp; 234 | switch (currentSensorsReadingPhase++) { 235 | case 0: 236 | osal_pwrmgr_task_state(zclApp_TaskID, PWRMGR_HOLD); 237 | (*air_dev->RequestMeasure)(); 238 | break; 239 | case 1: 240 | ppm = (*air_dev->Read)(); 241 | if (ppm == AIR_QUALITY_INVALID_RESPONSE) { 242 | 243 | 244 | if (air_dev == &sense_air_dev) { 245 | air_dev = &MHZ19_dev; 246 | } 247 | else if (air_dev == &MHZ19_dev) { 248 | air_dev = &CM1106_dev; 249 | } 250 | else if (air_dev == &CM1106_dev){ 251 | air_dev = &sense_air_dev; 252 | } 253 | 254 | 255 | LREPMaster("Sensor type UNKNOWN continue detect\r\n"); 256 | current_co2_sensor_state = ABC_NOT_AVALIABLE; // a part of algorithm avoiding exceptional io 257 | osal_pwrmgr_task_state(zclApp_TaskID, PWRMGR_CONSERVE); 258 | break; 259 | } 260 | sensor_state_not_avaliable = current_co2_sensor_state == ABC_NOT_AVALIABLE; 261 | current_co2_sensor_state = sensor_state_not_avaliable ? ABC_DISABLED : current_co2_sensor_state; 262 | zclApp_Sensors.CO2_PPM = ppm; 263 | zclApp_Sensors.CO2 = (double)ppm / 1000000.0; 264 | bdb_RepChangedAttrValue(zclApp_FirstEP.EndPoint, ZCL_CO2, ATTRID_CO2_MEASURED_VALUE); 265 | zclApp_SetupABC(sensor_state_not_avaliable); 266 | osal_pwrmgr_task_state(zclApp_TaskID, PWRMGR_CONSERVE); 267 | break; 268 | case 2: 269 | if (temp_sensor_type == EBME280) { 270 | temp_sensor_type = (zclApp_RequestBME280(&bme_dev) == 0) ? EBME280 : EDS18B20; 271 | break; 272 | } 273 | currentSensorsReadingPhase++; 274 | // missed break means: do not initiate new read iteration in case of missing ds18b20 sensor 275 | case 3: 276 | if (temp_sensor_type == EBME280) { 277 | zclApp_ReadBME280(&bme_dev); 278 | break; 279 | } 280 | currentSensorsReadingPhase++; 281 | // missed break means: do not initiate new read iteration in case of missing ds18b20 sensor 282 | case 4: 283 | if (temp_sensor_type == EDS18B20) { 284 | temp = readTemperature(); 285 | if (temp == 1) { 286 | temp_sensor_type = ENOTFOUND; 287 | LREPMaster("ReadDS18B20 error\r\n"); 288 | } else { 289 | zclApp_Sensors.Temperature = temp + zclApp_Config.TemperatureOffset; 290 | LREP("ReadDS18B20 t=%d offset=\r\n", zclApp_Sensors.Temperature, zclApp_Config.TemperatureOffset); 291 | } 292 | break; 293 | } // missed break means: do not initiate new read iteration in case of missing ds18b20 sensor 294 | default: 295 | osal_stop_timerEx(zclApp_TaskID, APP_READ_SENSORS_EVT); 296 | osal_clear_event(zclApp_TaskID, APP_READ_SENSORS_EVT); 297 | if (temp_sensor_type == EBME280) { 298 | bdb_RepChangedAttrValue(zclApp_FirstEP.EndPoint, TEMP, ATTRID_MS_TEMPERATURE_MEASURED_VALUE); 299 | bdb_RepChangedAttrValue(zclApp_FirstEP.EndPoint, PRESSURE, ATTRID_MS_PRESSURE_MEASUREMENT_MEASURED_VALUE); 300 | bdb_RepChangedAttrValue(zclApp_FirstEP.EndPoint, HUMIDITY, ATTRID_MS_RELATIVE_HUMIDITY_MEASURED_VALUE); 301 | } 302 | 303 | if (temp_sensor_type == EDS18B20) { 304 | bdb_RepChangedAttrValue(zclApp_FirstEP.EndPoint, TEMP, ATTRID_MS_TEMPERATURE_MEASURED_VALUE); 305 | } 306 | currentSensorsReadingPhase = 0; 307 | zclApp_LedFeedback(); 308 | break; 309 | } 310 | } 311 | 312 | static void zclApp_Report(void) { osal_start_reload_timer(zclApp_TaskID, APP_READ_SENSORS_EVT, 500); } 313 | 314 | static void zclApp_BasicResetCB(void) { 315 | LREPMaster("BasicResetCB\r\n"); 316 | zclApp_ResetAttributesToDefaultValues(); 317 | zclApp_SaveAttributesToNV(); 318 | } 319 | 320 | static ZStatus_t zclApp_ReadWriteAuthCB(afAddrType_t *srcAddr, zclAttrRec_t *pAttr, uint8 oper) { 321 | LREPMaster("AUTH CB called\r\n"); 322 | osal_pwrmgr_task_state(zclApp_TaskID, PWRMGR_HOLD); 323 | zclApp_SetupABC(true); 324 | osal_pwrmgr_task_state(zclApp_TaskID, PWRMGR_CONSERVE); 325 | osal_start_timerEx(zclApp_TaskID, APP_SAVE_ATTRS_EVT, 2000); 326 | return ZSuccess; 327 | } 328 | 329 | static void zclApp_SaveAttributesToNV(void) { 330 | uint8 writeStatus = osal_nv_write(NW_APP_CONFIG, 0, sizeof(application_config_t), &zclApp_Config); 331 | LREP("Saving attributes to NV write=%d\r\n", writeStatus); 332 | } 333 | 334 | static void zclApp_RestoreAttributesFromNV(void) { 335 | uint8 status = osal_nv_item_init(NW_APP_CONFIG, sizeof(application_config_t), NULL); 336 | LREP("Restoring attributes from NV status=%d \r\n", status); 337 | if (status == NV_ITEM_UNINIT) { 338 | uint8 writeStatus = osal_nv_write(NW_APP_CONFIG, 0, sizeof(application_config_t), &zclApp_Config); 339 | LREP("NV was empty, writing %d\r\n", writeStatus); 340 | } 341 | if (status == ZSUCCESS) { 342 | LREPMaster("Reading from NV\r\n"); 343 | osal_nv_read(NW_APP_CONFIG, 0, sizeof(application_config_t), &zclApp_Config); 344 | } 345 | } 346 | 347 | static uint8 zclApp_RequestBME280(struct bme280_dev *dev) { 348 | int8_t rslt = bme280_init(dev); 349 | if (rslt == BME280_OK) { 350 | uint8_t settings_sel; 351 | dev->settings.osr_h = BME280_OVERSAMPLING_16X; 352 | dev->settings.osr_p = BME280_OVERSAMPLING_16X; 353 | dev->settings.osr_t = BME280_OVERSAMPLING_16X; 354 | dev->settings.filter = BME280_FILTER_COEFF_16; 355 | dev->settings.standby_time = BME280_STANDBY_TIME_62_5_MS; 356 | 357 | settings_sel = BME280_OSR_PRESS_SEL; 358 | settings_sel |= BME280_OSR_TEMP_SEL; 359 | settings_sel |= BME280_OSR_HUM_SEL; 360 | settings_sel |= BME280_STANDBY_SEL; 361 | settings_sel |= BME280_FILTER_SEL; 362 | rslt = bme280_set_sensor_settings(settings_sel, dev); 363 | rslt = bme280_set_sensor_mode(BME280_FORCED_MODE, dev); 364 | } else { 365 | LREP("ReadBME280 init error %d\r\n", rslt); 366 | return 1; 367 | } 368 | return 0; 369 | } 370 | static uint8 zclApp_ReadBME280(struct bme280_dev *dev) { 371 | struct bme280_data bme_results; 372 | int8_t rslt = bme280_get_sensor_data(BME280_ALL, &bme_results, dev); 373 | if (rslt == BME280_OK) { 374 | LREP("ReadBME280 t=%ld, p=%ld, h=%ld\r\n", bme_results.temperature, bme_results.pressure, bme_results.humidity); 375 | zclApp_Sensors.BME280_HumiditySensor_MeasuredValue = (uint16)(bme_results.humidity * 100 / 1024.0) + zclApp_Config.HumidityOffset; 376 | zclApp_Sensors.BME280_PressureSensor_ScaledValue = (int16) (pow(10.0, (double) zclApp_Sensors.BME280_PressureSensor_Scale) * (double) bme_results.pressure); 377 | zclApp_Sensors.BME280_PressureSensor_MeasuredValue = zclApp_Sensors.BME280_PressureSensor_ScaledValue / 10.0; 378 | zclApp_Sensors.Temperature = (int16)bme_results.temperature + zclApp_Config.TemperatureOffset; 379 | } else { 380 | LREP("ReadBME280 bme280_get_sensor_data error %d\r\n", rslt); 381 | return 1; 382 | } 383 | return 0; 384 | } 385 | 386 | /**************************************************************************** 387 | ****************************************************************************/ 388 | -------------------------------------------------------------------------------- /Source/hal_board_cfg.h: -------------------------------------------------------------------------------- 1 | #ifndef HAL_BOARD_CFG_H 2 | #define HAL_BOARD_CFG_H 3 | 4 | 5 | /* ------------------------------------------------------------------------------------------------ 6 | * Includes 7 | * ------------------------------------------------------------------------------------------------ 8 | */ 9 | 10 | #include "hal_mcu.h" 11 | #include "hal_defs.h" 12 | #include "hal_types.h" 13 | 14 | /* ------------------------------------------------------------------------------------------------ 15 | * CC2590/CC2591 support 16 | * 17 | * Define HAL_PA_LNA_CC2590 if CC2530+CC2590EM is used 18 | * Define HAL_PA_LNA if CC2530+CC2591EM is used 19 | * Note that only one of them can be defined 20 | * ------------------------------------------------------------------------------------------------ 21 | */ 22 | #define xHAL_PA_LNA 23 | #define xHAL_PA_LNA_CC2590 24 | #define xHAL_PA_LNA_SE2431L 25 | #define xHAL_PA_LNA_CC2592 26 | 27 | /* ------------------------------------------------------------------------------------------------ 28 | * Clock Speed 29 | * ------------------------------------------------------------------------------------------------ 30 | */ 31 | 32 | #define HAL_CPU_CLOCK_MHZ 32 33 | 34 | /* This flag should be defined if the SoC uses the 32MHz crystal 35 | * as the main clock source (instead of DCO). 36 | */ 37 | #define HAL_CLOCK_CRYSTAL 38 | 39 | /* 32 kHz clock source select in CLKCONCMD */ 40 | #if !defined (OSC32K_CRYSTAL_INSTALLED) || (defined (OSC32K_CRYSTAL_INSTALLED) && (OSC32K_CRYSTAL_INSTALLED == TRUE)) 41 | #define OSC_32KHZ 0x00 /* external 32 KHz xosc */ 42 | #else 43 | #define OSC_32KHZ 0x80 /* internal 32 KHz rcosc */ 44 | #endif 45 | 46 | #define HAL_CLOCK_STABLE() st( while (CLKCONSTA != (CLKCONCMD_32MHZ | OSC_32KHZ)); ) 47 | 48 | /* ------------------------------------------------------------------------------------------------ 49 | * LED Configuration 50 | * ------------------------------------------------------------------------------------------------ 51 | */ 52 | 53 | #if defined (HAL_BOARD_CHDTECH_DEV) 54 | #define HAL_NUM_LEDS 3 55 | #elif defined(HAL_BOARD_TARGET) 56 | #define HAL_NUM_LEDS 1 57 | #else 58 | #error Unknown Board Indentifier 59 | #endif 60 | 61 | #define HAL_LED_BLINK_DELAY() st( { volatile uint32 i; for (i=0; i<0x5800; i++) { }; } ) 62 | 63 | #if defined(HAL_BOARD_TARGET) 64 | #define LED1_BV BV(1) 65 | #define LED1_SBIT P0_1 66 | #define LED1_DDR P0DIR 67 | #define LED1_POLARITY ACTIVE_HIGH 68 | 69 | #define LED2_BV BV(4) 70 | #define LED2_SBIT P0_4 71 | #define LED2_DDR P0DIR 72 | #define LED2_POLARITY ACTIVE_HIGH 73 | 74 | #define LED3_BV BV(5) 75 | #define LED3_SBIT P0_5 76 | #define LED3_DDR P0DIR 77 | #define LED3_POLARITY ACTIVE_HIGH 78 | 79 | 80 | #define LED4_BV BV(4) 81 | #define LED4_SBIT P1_4 82 | #define LED4_DDR P1DIR 83 | #define LED4_POLARITY ACTIVE_HIGH 84 | 85 | #elif defined(HAL_BOARD_CHDTECH_DEV) 86 | #define LED1_BV BV(0) 87 | #define LED1_SBIT P1_0 88 | #define LED1_DDR P1DIR 89 | #define LED1_POLARITY ACTIVE_LOW 90 | 91 | #define LED2_BV BV(1) 92 | #define LED2_SBIT P1_1 93 | #define LED2_DDR P1DIR 94 | #define LED2_POLARITY ACTIVE_LOW 95 | 96 | #define LED3_BV BV(4) 97 | #define LED3_SBIT P1_4 98 | #define LED3_DDR P1DIR 99 | #define LED3_POLARITY ACTIVE_LOW 100 | 101 | 102 | #define LED4_BV BV(4) 103 | #define LED4_SBIT P1_4 104 | #define LED4_DDR P1DIR 105 | #define LED4_POLARITY ACTIVE_LOW 106 | #endif 107 | 108 | 109 | 110 | /* ------------------------------------------------------------------------------------------------ 111 | * Push Button Configuration 112 | * ------------------------------------------------------------------------------------------------ 113 | */ 114 | 115 | #define ACTIVE_LOW ! 116 | #define ACTIVE_HIGH !! /* double negation forces result to be '1' */ 117 | 118 | /* S1 */ 119 | #define PUSH1_BV BV(1) 120 | #define PUSH1_SBIT P0_1 121 | 122 | 123 | 124 | 125 | /* ------------------------------------------------------------------------------------------------ 126 | * OSAL NV implemented by internal flash pages. 127 | * ------------------------------------------------------------------------------------------------ 128 | */ 129 | 130 | // Flash is partitioned into 8 banks of 32 KB or 16 pages. 131 | #define HAL_FLASH_PAGE_PER_BANK 16 132 | // Flash is constructed of 128 pages of 2 KB. 133 | #define HAL_FLASH_PAGE_SIZE 2048 134 | #define HAL_FLASH_WORD_SIZE 4 135 | 136 | // CODE banks get mapped into the XDATA range 8000-FFFF. 137 | #define HAL_FLASH_PAGE_MAP 0x8000 138 | 139 | // The last 16 bytes of the last available page are reserved for flash lock bits. 140 | // NV page definitions must coincide with segment declaration in project *.xcl file. 141 | #if defined NON_BANKED 142 | #define HAL_FLASH_LOCK_BITS 16 143 | #define HAL_NV_PAGE_END 30 144 | #define HAL_NV_PAGE_CNT 2 145 | #else 146 | #define HAL_FLASH_LOCK_BITS 16 147 | #define HAL_NV_PAGE_END 126 148 | #define HAL_NV_PAGE_CNT 6 149 | #endif 150 | 151 | // Re-defining Z_EXTADDR_LEN here so as not to include a Z-Stack .h file. 152 | #define HAL_FLASH_IEEE_SIZE 8 153 | #define HAL_FLASH_IEEE_PAGE (HAL_NV_PAGE_END+1) 154 | #define HAL_FLASH_IEEE_OSET (HAL_FLASH_PAGE_SIZE - HAL_FLASH_LOCK_BITS - HAL_FLASH_IEEE_SIZE) 155 | #define HAL_INFOP_IEEE_OSET 0xC 156 | 157 | #define HAL_FLASH_DEV_PRIVATE_KEY_OSET 0x7D2 158 | #define HAL_FLASH_CA_PUBLIC_KEY_OSET 0x7BC 159 | #define HAL_FLASH_IMPLICIT_CERT_OSET 0x78C 160 | 161 | #define HAL_NV_PAGE_BEG (HAL_NV_PAGE_END-HAL_NV_PAGE_CNT+1) 162 | // Used by DMA macros to shift 1 to create a mask for DMA registers. 163 | #define HAL_NV_DMA_CH 0 164 | #define HAL_DMA_CH_RX 3 165 | #define HAL_DMA_CH_TX 4 166 | 167 | #define HAL_NV_DMA_GET_DESC() HAL_DMA_GET_DESC0() 168 | #define HAL_NV_DMA_SET_ADDR(a) HAL_DMA_SET_ADDR_DESC0((a)) 169 | 170 | /* ------------------------------------------------------------------------------------------------ 171 | * Serial Boot Loader: reserving the first 4 pages of flash and other memory in cc2530-sb.xcl. 172 | * ------------------------------------------------------------------------------------------------ 173 | */ 174 | 175 | #define HAL_SB_IMG_ADDR 0x2000 176 | #define HAL_SB_CRC_ADDR 0x2090 177 | // Size of internal flash less 4 pages for boot loader, 6 pages for NV, & 1 page for lock bits. 178 | #define HAL_SB_IMG_SIZE (0x40000 - 0x2000 - 0x3000 - 0x0800) 179 | 180 | /* ------------------------------------------------------------------------------------------------ 181 | * Macros 182 | * ------------------------------------------------------------------------------------------------ 183 | */ 184 | 185 | /* ----------- RF-frontend Connection Initialization ---------- */ 186 | #if defined HAL_PA_LNA || defined HAL_PA_LNA_CC2590 || \ 187 | defined HAL_PA_LNA_SE2431L || defined HAL_PA_LNA_CC2592 188 | extern void MAC_RfFrontendSetup(void); 189 | #define HAL_BOARD_RF_FRONTEND_SETUP() MAC_RfFrontendSetup() 190 | #else 191 | #define HAL_BOARD_RF_FRONTEND_SETUP() 192 | #endif 193 | 194 | /* ----------- Cache Prefetch control ---------- */ 195 | #define PREFETCH_ENABLE() st( FCTL = 0x08; ) 196 | #define PREFETCH_DISABLE() st( FCTL = 0x04; ) 197 | 198 | /* ----------- Board Initialization ---------- */ 199 | #if defined (HAL_BOARD_CHDTECH_DEV) || (!defined(HAL_PA_LNA) && !defined(HAL_PA_LNA_CC2592)) 200 | #define HAL_BOARD_INIT() \ 201 | { \ 202 | uint16 i; \ 203 | \ 204 | SLEEPCMD &= ~OSC_PD; /* turn on 16MHz RC and 32MHz XOSC */ \ 205 | while (!(SLEEPSTA & XOSC_STB)); /* wait for 32MHz XOSC stable */ \ 206 | asm("NOP"); /* chip bug workaround */ \ 207 | for (i=0; i<504; i++) asm("NOP"); /* Require 63us delay for all revs */ \ 208 | CLKCONCMD = (CLKCONCMD_32MHZ | OSC_32KHZ); /* Select 32MHz XOSC and the source for 32K clock */ \ 209 | while (CLKCONSTA != (CLKCONCMD_32MHZ | OSC_32KHZ)); /* Wait for the change to be effective */ \ 210 | SLEEPCMD |= OSC_PD; /* turn off 16MHz RC */ \ 211 | \ 212 | /* Turn on cache prefetch mode */ \ 213 | PREFETCH_ENABLE(); \ 214 | \ 215 | LED1_DDR |= LED1_BV; \ 216 | LED2_DDR |= LED2_BV; \ 217 | LED3_DDR |= LED3_BV; \ 218 | } 219 | 220 | #elif defined (HAL_PA_LNA) 221 | #define HAL_BOARD_INIT() \ 222 | { \ 223 | uint16 i; \ 224 | \ 225 | SLEEPCMD &= ~OSC_PD; /* turn on 16MHz RC and 32MHz XOSC */ \ 226 | while (!(SLEEPSTA & XOSC_STB)); /* wait for 32MHz XOSC stable */ \ 227 | asm("NOP"); /* chip bug workaround */ \ 228 | for (i=0; i<504; i++) asm("NOP"); /* Require 63us delay for all revs */ \ 229 | CLKCONCMD = (CLKCONCMD_32MHZ | OSC_32KHZ); /* Select 32MHz XOSC and the source for 32K clock */ \ 230 | while (CLKCONSTA != (CLKCONCMD_32MHZ | OSC_32KHZ)); /* Wait for the change to be effective */ \ 231 | SLEEPCMD |= OSC_PD; /* turn off 16MHz RC */ \ 232 | \ 233 | /* Turn on cache prefetch mode */ \ 234 | PREFETCH_ENABLE(); \ 235 | \ 236 | /* set direction for GPIO outputs */ \ 237 | /* For SE2431L PA LNA this sets ANT_SEL to output */ \ 238 | /* For CC2592 this enables LNA */ \ 239 | P1DIR |= BV(0) | BV(1); \ 240 | \ 241 | /* Set PA/LNA HGM control P0_7 */ \ 242 | P0DIR |= BV(7); \ 243 | \ 244 | \ 245 | /* setup RF frontend if necessary */ \ 246 | HAL_BOARD_RF_FRONTEND_SETUP(); \ 247 | LED1_DDR |= LED1_BV; \ 248 | LED2_DDR |= LED2_BV; \ 249 | LED3_DDR |= LED3_BV; \ 250 | } 251 | 252 | #elif defined (HAL_PA_LNA_CC2592) || defined (HAL_PA_LNA_SE2431L) 253 | #define HAL_BOARD_INIT() \ 254 | { \ 255 | uint16 i; \ 256 | \ 257 | SLEEPCMD &= ~OSC_PD; /* turn on 16MHz RC and 32MHz XOSC */ \ 258 | while (!(SLEEPSTA & XOSC_STB)); /* wait for 32MHz XOSC stable */ \ 259 | asm("NOP"); /* chip bug workaround */ \ 260 | for (i=0; i<504; i++) asm("NOP"); /* Require 63us delay for all revs */ \ 261 | CLKCONCMD = (CLKCONCMD_32MHZ | OSC_32KHZ); /* Select 32MHz XOSC and the source for 32K clock */ \ 262 | while (CLKCONSTA != (CLKCONCMD_32MHZ | OSC_32KHZ)); /* Wait for the change to be effective */ \ 263 | SLEEPCMD |= OSC_PD; /* turn off 16MHz RC */ \ 264 | \ 265 | /* Turn on cache prefetch mode */ \ 266 | PREFETCH_ENABLE(); \ 267 | \ 268 | /* set direction for GPIO outputs */ \ 269 | /* For SE2431L PA LNA this sets ANT_SEL to output */ \ 270 | /* For CC2592 this enables LNA */ \ 271 | P1DIR |= BV(0) | BV(1); \ 272 | \ 273 | /* Set PA/LNA HGM control P0_7 */ \ 274 | P0DIR |= BV(7); \ 275 | \ 276 | \ 277 | /* setup RF frontend if necessary */ \ 278 | HAL_BOARD_RF_FRONTEND_SETUP(); \ 279 | LED1_DDR |= LED1_BV; \ 280 | LED2_DDR |= LED2_BV; \ 281 | LED3_DDR |= LED3_BV; \ 282 | } 283 | #endif 284 | 285 | /* ----------- Debounce ---------- */ 286 | #define HAL_DEBOUNCE(expr) { int i; for (i=0; i<500; i++) { if (!(expr)) i = 0; } } 287 | 288 | /* ----------- Push Buttons ---------- */ 289 | #define HAL_PUSH_BUTTON1() (0) 290 | #define HAL_PUSH_BUTTON2() (0) 291 | #define HAL_PUSH_BUTTON3() (0) 292 | #define HAL_PUSH_BUTTON4() (0) 293 | #define HAL_PUSH_BUTTON5() (0) 294 | #define HAL_PUSH_BUTTON6() (0) 295 | 296 | /* ----------- LED's ---------- */ 297 | #define HAL_TURN_OFF_LED1() st( LED1_SBIT = LED1_POLARITY (0); ) 298 | #define HAL_TURN_OFF_LED2() st( LED2_SBIT = LED2_POLARITY (0); ) 299 | #define HAL_TURN_OFF_LED3() st( LED3_SBIT = LED3_POLARITY (0); ) 300 | #define HAL_TURN_OFF_LED4() st( LED4_SBIT = LED4_POLARITY (0); ) 301 | 302 | #define HAL_TURN_ON_LED1() st( LED1_SBIT = LED1_POLARITY (1); ) 303 | #define HAL_TURN_ON_LED2() st( LED2_SBIT = LED2_POLARITY (1); ) 304 | #define HAL_TURN_ON_LED3() st( LED3_SBIT = LED3_POLARITY (1); ) 305 | #define HAL_TURN_ON_LED4() st( LED4_SBIT = LED4_POLARITY (1); ) 306 | 307 | #define HAL_TOGGLE_LED1() st( if (LED1_SBIT) { LED1_SBIT = 0; } else { LED1_SBIT = 1;} ) 308 | #define HAL_TOGGLE_LED2() st( if (LED2_SBIT) { LED2_SBIT = 0; } else { LED2_SBIT = 1;} ) 309 | #define HAL_TOGGLE_LED3() st( if (LED3_SBIT) { LED3_SBIT = 0; } else { LED3_SBIT = 1;} ) 310 | #define HAL_TOGGLE_LED4() st( if (LED4_SBIT) { LED4_SBIT = 0; } else { LED4_SBIT = 1;} ) 311 | 312 | #define HAL_STATE_LED1() (LED1_POLARITY (LED1_SBIT)) 313 | #define HAL_STATE_LED2() (LED2_POLARITY (LED2_SBIT)) 314 | #define HAL_STATE_LED3() (LED3_POLARITY (LED3_SBIT)) 315 | #define HAL_STATE_LED4() (LED4_POLARITY (LED4_SBIT)) 316 | 317 | /* ----------- XNV ---------- */ 318 | #define XNV_SPI_BEGIN() st(P1_3 = 0;) 319 | #define XNV_SPI_TX(x) st(U1CSR &= ~0x02; U1DBUF = (x);) 320 | #define XNV_SPI_RX() U1DBUF 321 | #define XNV_SPI_WAIT_RXRDY() st(while (!(U1CSR & 0x02));) 322 | #define XNV_SPI_END() st(P1_3 = 1;) 323 | 324 | // The TI reference design uses UART1 Alt. 2 in SPI mode. 325 | #define XNV_SPI_INIT() \ 326 | st( \ 327 | /* Mode select UART1 SPI Mode as master. */\ 328 | U1CSR = 0; \ 329 | \ 330 | /* Setup for 115200 baud. */\ 331 | U1GCR = 11; \ 332 | U1BAUD = 216; \ 333 | \ 334 | /* Set bit order to MSB */\ 335 | U1GCR |= BV(5); \ 336 | \ 337 | /* Set UART1 I/O to alternate 2 location on P1 pins. */\ 338 | PERCFG |= 0x02; /* U1CFG */\ 339 | \ 340 | /* Select peripheral function on I/O pins but SS is left as GPIO for separate control. */\ 341 | P1SEL |= 0xE0; /* SELP1_[7:4] */\ 342 | /* P1.1,2,3: reset, LCD CS, XNV CS. */\ 343 | P1SEL &= ~0x0E; \ 344 | P1 |= 0x0E; \ 345 | P1_1 = 0; \ 346 | P1DIR |= 0x0E; \ 347 | \ 348 | /* Give UART1 priority over Timer3. */\ 349 | P2SEL &= ~0x20; /* PRI2P1 */\ 350 | \ 351 | /* When SPI config is complete, enable it. */\ 352 | U1CSR |= 0x40; \ 353 | /* Release XNV reset. */\ 354 | P1_1 = 1; \ 355 | ) 356 | 357 | /* ----------- Minimum safe bus voltage ---------- */ 358 | 359 | // Vdd/3 / Internal Reference X ENOB --> (Vdd / 3) / 1.15 X 127 360 | #define VDD_2_0 74 // 2.0 V required to safely read/write internal flash. 361 | #define VDD_2_7 100 // 2.7 V required for the Numonyx device. 362 | #define VDD_MIN_RUN (VDD_2_0+4) // VDD_MIN_RUN = VDD_MIN_NV 363 | #define VDD_MIN_NV (VDD_2_0+4) // 5% margin over minimum to survive a page erase and compaction. 364 | #define VDD_MIN_GOOD (VDD_2_0+8) // 10% margin over minimum to survive a page erase and compaction. 365 | #define VDD_MIN_XNV (VDD_2_7+5) // 5% margin over minimum to survive a page erase and compaction. 366 | 367 | /* ------------------------------------------------------------------------------------------------ 368 | * Driver Configuration 369 | * ------------------------------------------------------------------------------------------------ 370 | */ 371 | 372 | /* Set to TRUE enable H/W TIMER usage, FALSE disable it */ 373 | #ifndef HAL_TIMER 374 | #define HAL_TIMER FALSE 375 | #endif 376 | 377 | /* Set to TRUE enable ADC usage, FALSE disable it */ 378 | #ifndef HAL_ADC 379 | #define HAL_ADC TRUE 380 | #endif 381 | 382 | /* Set to TRUE enable DMA usage, FALSE disable it */ 383 | #ifndef HAL_DMA 384 | #define HAL_DMA TRUE 385 | #endif 386 | 387 | /* Set to TRUE enable Flash access, FALSE disable it */ 388 | #ifndef HAL_FLASH 389 | #define HAL_FLASH TRUE 390 | #endif 391 | 392 | /* Set to TRUE enable AES usage, FALSE disable it */ 393 | #ifndef HAL_AES 394 | #define HAL_AES TRUE 395 | #endif 396 | 397 | #ifndef HAL_AES_DMA 398 | #define HAL_AES_DMA TRUE 399 | #endif 400 | 401 | /* Set to TRUE enable LCD usage, FALSE disable it */ 402 | #ifndef HAL_LCD 403 | #define HAL_LCD TRUE 404 | #endif 405 | 406 | /* Set to TRUE enable LED usage, FALSE disable it */ 407 | #ifndef HAL_LED 408 | #define HAL_LED TRUE 409 | #endif 410 | #if (!defined BLINK_LEDS) && (HAL_LED == TRUE) 411 | #define BLINK_LEDS 412 | #endif 413 | 414 | /* Set to TRUE enable KEY usage, FALSE disable it */ 415 | #ifndef HAL_KEY 416 | #define HAL_KEY TRUE 417 | #endif 418 | 419 | /* Set to TRUE enable UART usage, FALSE disable it */ 420 | #ifndef HAL_UART 421 | #if (defined ZAPP_P1) || (defined ZAPP_P2) || (defined ZTOOL_P1) || (defined ZTOOL_P2) 422 | #define HAL_UART TRUE 423 | #else 424 | #define HAL_UART FALSE 425 | #endif 426 | #endif 427 | 428 | #if HAL_UART 429 | #ifndef HAL_UART_DMA 430 | #if HAL_DMA 431 | #if (defined ZAPP_P2) || (defined ZTOOL_P2) 432 | #define HAL_UART_DMA 2 433 | #else 434 | #define HAL_UART_DMA 1 435 | #endif 436 | #else 437 | #define HAL_UART_DMA 0 438 | #endif 439 | #endif 440 | 441 | #ifndef HAL_UART_ISR 442 | #if HAL_UART_DMA // Default preference for DMA over ISR. 443 | #define HAL_UART_ISR 0 444 | #elif (defined ZAPP_P2) || (defined ZTOOL_P2) 445 | #define HAL_UART_ISR 2 446 | #else 447 | #define HAL_UART_ISR 1 448 | #endif 449 | #endif 450 | 451 | #if (HAL_UART_DMA && (HAL_UART_DMA == HAL_UART_ISR)) 452 | #error HAL_UART_DMA & HAL_UART_ISR must be different. 453 | #endif 454 | 455 | // Used to set P2 priority - USART0 over USART1 if both are defined. 456 | #if ((HAL_UART_DMA == 1) || (HAL_UART_ISR == 1)) 457 | #define HAL_UART_PRIPO 0x00 458 | #else 459 | #define HAL_UART_PRIPO 0x40 460 | #endif 461 | 462 | #else 463 | #define HAL_UART_DMA 0 464 | #define HAL_UART_ISR 0 465 | #endif 466 | 467 | /* USB is not used for CC2530 configuration */ 468 | #define HAL_UART_USB 0 469 | #endif 470 | /******************************************************************************************************* 471 | */ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | --------------------------------------------------------------------------------