Hackster is hosting Hackster Holidays, Ep. 6: Livestream & Giveaway Drawing. Watch previous episodes or stream live on Monday!Stream Hackster Holidays, Ep. 6 on Monday!
Ravi Teja Chappa
Created January 5, 2019 © GPL3+

Blind-Mute Communicator

IoT device helping the physically challenged people!

IntermediateFull instructions providedOver 1 day59
Blind-Mute Communicator

Things used in this project

Hardware components

Rapid IoT Prototyping Kit
NXP Rapid IoT Prototyping Kit
×1

Software apps and online services

NXP Rapid IoT Studio

Story

Read more

Custom parts and enclosures

Project Build File

This is the complete project build file

Schematics

Blind-Mute Communicator model

This is just a pictorial representation of the working model

Code

Blind-Mute_Communicator

C/C++
I'm uploading the .atmo file of my project. This can be run on rapid IoT studio online IDE by simply importing the file. Please save the below code as .atmo file and import it on Rapid IoT Online Studio.
Steps to follow to complete the project:
1. Upload and run this code onto your Rapid IOT Device
2. Enable Bluetooth on your smartphone
3. Open the NXP Rapid IOT App and navigate to My Devices
4. Search for the Device called Blind Mute Communicator and provision it
5. Tap the screen for the required number of times
6. A message corresponding to the taps will be displayed on the app
{
  "name": "Blind_Mute_Communicator",
  "createVersion": "2017-08-12",
  "description": "New Project",
  "lastModified": "2018-11-19T15:47:16.587Z",
  "created": "2018-11-19T15:47:16.587Z",
  "meta": {
    "projectTypeName": "NXP Rapid IoT",
    "projectTypeId": "NxpRpk"
  },
  "planes": {
    "NXP Rapid IoT": {
      "type": "mcuxpresso",
      "compilerVersion": "latest",
      "variants": [
        "NxpRpk"
      ],
      "meta": {},
      "elements": [
        {
          "name": "Interval",
          "type": "EmbeddedInterval",
          "variants": [
            "embedded",
            "triggers",
            "abilities",
            "properties",
            "variables"
          ],
          "properties": {
            "errorData": {},
            "code": {
              "trigger": "\treturn ATMO_Status_Success;",
              "setup": "\n\tATMO_INTERVAL_Handle_t intervalHandle;\n    ATMO_INTERVAL_AddAbilityInterval(\n\t\tATMO_PROPERTY(Interval, instance), \n\t\tATMO_ABILITY(Interval, interval), \n\t\tATMO_PROPERTY(Interval, time), \n\t\t&intervalHandle\n\t);\n\t\n\treturn ATMO_Status_Success;\n\t",
              "interval": "\treturn ATMO_Status_Success;"
            },
            "variables": {},
            "embeddedPropertyConversions": {},
            "codeUserChanged": {
              "setup": false,
              "interval": false
            },
            "instance": 0,
            "time": 1000
          },
          "meta": {
            "editorX": 64,
            "editorY": 155,
            "lastTrigger": "interval"
          },
          "triggers": {
            "triggered": [],
            "interval": [
              {
                "mapping": {},
                "targetOrder": [],
                "targetElement": "FXOS8700AccelerometerMagnetometer",
                "targetAbility": "enableTapDetection"
              }
            ]
          },
          "interruptAbilities": {
            "trigger": false,
            "setup": false,
            "interval": true
          },
          "abilities": [
            {
              "name": "trigger",
              "triggers": [
                "triggered"
              ]
            },
            {
              "name": "setup",
              "triggers": []
            },
            {
              "name": "interval",
              "triggers": [
                "interval"
              ]
            }
          ]
        },
        {
          "name": "FXOS8700AccelerometerMagnetometer",
          "type": "EmbeddedFXOS8700",
          "variants": [
            "embedded",
            "triggers",
            "abilities",
            "properties",
            "variables"
          ],
          "properties": {
            "errorData": {},
            "code": {
              "trigger": "\treturn ATMO_Status_Success;",
              "setup": "\tATMO_FXOS8700_Config_t config;\n\tconfig.address = ATMO_PROPERTY(FXOS8700AccelerometerMagnetometer, i2cAddress);\n\tconfig.i2cDriverInstance = ATMO_PROPERTY(FXOS8700AccelerometerMagnetometer, i2cInstance);\n\tconfig.gpioDriverInstance = ATMO_PROPERTY(FXOS8700AccelerometerMagnetometer, gpioInstance);\n\tconfig.int1En = ATMO_PROPERTY(FXOS8700AccelerometerMagnetometer, interrupt1Enabled);\n    config.int2En = ATMO_PROPERTY(FXOS8700AccelerometerMagnetometer, interrupt2Enabled);\n    config.int1Pin = ATMO_PROPERTY(FXOS8700AccelerometerMagnetometer, interrupt1Gpio);\n    config.int2Pin = ATMO_PROPERTY(FXOS8700AccelerometerMagnetometer, interrupt2Gpio);\n\n    switch(ATMO_PROPERTY(FXOS8700AccelerometerMagnetometer, motionDetectType))\n    {\n        case FXOS8700_NoDetect:\n        {\n            config.freefallEnabled = false;\n            config.motionEnabled = false;\n            config.tapDetectionEnabled = false;\n            break;\n        }\n        case FXOS8700_FreefallDetect:\n        {\n            config.freefallEnabled = true;\n            config.motionEnabled = false;\n            config.tapDetectionEnabled = false;\n            break;\n        }\n        case FXOS8700_MotionDetect:\n        {\n            config.freefallEnabled = false;\n            config.motionEnabled = true;\n            config.tapDetectionEnabled = false;\n            break;\n        }\n        case FXOS8700_TapDetect:\n        {\n            config.freefallEnabled = false;\n            config.motionEnabled = false;\n            config.tapDetectionEnabled = true;\n            break; \n        }\n        default:\n        {\n            config.freefallEnabled = false;\n            config.motionEnabled = false;  \n            config.tapDetectionEnabled = false;\n            break;\n        }\n    }\n\n    ATMO_FXOS8700_SetMotionDetectedAbilityHandle(ATMO_ABILITY(FXOS8700AccelerometerMagnetometer, detectMotion));\n    ATMO_FXOS8700_SetFreefallDetectedAbilityHandle(ATMO_ABILITY(FXOS8700AccelerometerMagnetometer, detectFreefall));\n    ATMO_FXOS8700_SetTapDetectedAbilityHandle(ATMO_ABILITY(FXOS8700AccelerometerMagnetometer, detectTap));\n\tATMO_FXOS8700_Init(&config);\n\n    return ATMO_Status_Success;\n\t",
              "setEnabled": "ATMO_FXOS8700_SetEnabled(true);\nreturn ATMO_Status_Success;",
              "setDisabled": "ATMO_FXOS8700_SetEnabled(false);\nreturn ATMO_Status_Success;",
              "setEnabledDisabled": "bool enabled = false;\nATMO_GetBool(in, &enabled);\nATMO_FXOS8700_SetEnabled(enabled);\nreturn ATMO_Status_Success;",
              "getSensorData": "\tATMO_FXOS8700_SensorData_t data;\n\n\tif(ATMO_FXOS8700_GetSensorData(&data) != ATMO_FXOS8700_Status_Success)\n\t{\n\t\tATMO_CreateValueVoid(out);\n\t\treturn ATMO_Status_Fail;\n\t}\n\n\tATMO_CreateValueBinary(out, &data, sizeof(data));\n\treturn ATMO_Status_Success;\n",
              "getAccelX": "\tATMO_FXOS8700_SensorData_t data;\n\n\tif(ATMO_FXOS8700_GetSensorData(&data) != ATMO_FXOS8700_Status_Success)\n\t{\n\t\tATMO_CreateValueVoid(out);\n\t\treturn ATMO_Status_Fail;\n\t}\n\n\tATMO_CreateValueFloat(out, data.accelX);\n\treturn ATMO_Status_Success;\n",
              "getAccelY": "\tATMO_FXOS8700_SensorData_t data;\n\n\tif(ATMO_FXOS8700_GetSensorData(&data) != ATMO_FXOS8700_Status_Success)\n\t{\n\t\tATMO_CreateValueVoid(out);\n\t\treturn ATMO_Status_Fail;\n\t}\n\n\tATMO_CreateValueFloat(out, data.accelY);\n\treturn ATMO_Status_Success;\n",
              "getAccelZ": "\tATMO_FXOS8700_SensorData_t data;\n\n\tif(ATMO_FXOS8700_GetSensorData(&data) != ATMO_FXOS8700_Status_Success)\n\t{\n\t\tATMO_CreateValueVoid(out);\n\t\treturn ATMO_Status_Fail;\n\t}\n\n\tATMO_CreateValueFloat(out, data.accelZ);\n\treturn ATMO_Status_Success;\n",
              "getMagX": "\tATMO_FXOS8700_SensorData_t data;\n\n\tif(ATMO_FXOS8700_GetSensorData(&data) != ATMO_FXOS8700_Status_Success)\n\t{\n\t\tATMO_CreateValueVoid(out);\n\t\treturn ATMO_Status_Fail;\n\t}\n\n\tATMO_CreateValueFloat(out, data.magX);\n\treturn ATMO_Status_Success;\n",
              "getMagY": "\tATMO_FXOS8700_SensorData_t data;\n\n\tif(ATMO_FXOS8700_GetSensorData(&data) != ATMO_FXOS8700_Status_Success)\n\t{\n\t\tATMO_CreateValueVoid(out);\n\t\treturn ATMO_Status_Fail;\n\t}\n\n\tATMO_CreateValueFloat(out, data.magY);\n\treturn ATMO_Status_Success;\n",
              "getMagZ": "\tATMO_FXOS8700_SensorData_t data;\n\n\tif(ATMO_FXOS8700_GetSensorData(&data) != ATMO_FXOS8700_Status_Success)\n\t{\n\t\tATMO_CreateValueVoid(out);\n\t\treturn ATMO_Status_Fail;\n\t}\n\n\tATMO_CreateValueFloat(out, data.magZ);\n\treturn ATMO_Status_Success;\n",
              "detectTap": "\treturn ATMO_Status_Success;\n",
              "detectMotion": "\treturn ATMO_Status_Success;\n",
              "detectFreefall": "\treturn ATMO_Status_Success;\n",
              "enableFreefallDetection": "if(ATMO_FXOS8700_EnableFreefallDetection() == ATMO_FXOS8700_Status_Success)\n{\n    return ATMO_Status_Success;\n}\n\nreturn ATMO_Status_Fail;",
              "enableMotionDetection": "if(ATMO_FXOS8700_EnableMotionDetection() == ATMO_FXOS8700_Status_Success)\n{\n    return ATMO_Status_Success;\n}\n\nreturn ATMO_Status_Fail;",
              "enableTapDetection": "if(ATMO_FXOS8700_EnableTapDetection() == ATMO_FXOS8700_Status_Success)\n{\n    return ATMO_Status_Success;\n}\n\nreturn ATMO_Status_Fail;",
              "disableDetection": "if(ATMO_FXOS8700_DisableAllDetection() == ATMO_FXOS8700_Status_Success)\n{\n    return ATMO_Status_Success;\n}\n\nreturn ATMO_Status_Fail;"
            },
            "variables": {},
            "embeddedPropertyConversions": {},
            "codeUserChanged": {
              "setup": false,
              "setEnabled": false,
              "setDisabled": false,
              "setEnabledDisabled": false,
              "getSensorData": false,
              "getAccelX": false,
              "getAccelY": false,
              "getAccelZ": false,
              "getMagX": false,
              "getMagY": false,
              "getMagZ": false,
              "detectTap": false,
              "detectMotion": false,
              "detectFreefall": false,
              "enableFreefallDetection": false,
              "enableMotionDetection": false,
              "enableTapDetection": false,
              "disableDetection": false
            },
            "i2cInstance": 1,
            "gpioInstance": 0,
            "interrupt1Enabled": false,
            "interrupt2Enabled": true,
            "interrupt1Gpio": "ATMO_DEFAULT_GPIO",
            "interrupt2Gpio": "PTD13",
            "motionDetectType": "FXOS8700_TapDetect",
            "i2cAddress": "0x1E"
          },
          "meta": {
            "editorX": 222,
            "editorY": 155,
            "lastTrigger": "tapDetected"
          },
          "triggers": {
            "triggered": [],
            "sensorDataRead": [
              {
                "mapping": {},
                "targetOrder": [],
                "targetElement": "GetTapCount",
                "targetAbility": "trigger"
              },
              {
                "mapping": {},
                "targetOrder": [],
                "targetElement": "Tap_BT",
                "targetAbility": "trigger"
              }
            ],
            "accelXRead": [],
            "accelYRead": [],
            "accelZRead": [],
            "magXRead": [],
            "magYRead": [],
            "magZRead": [],
            "tapDetected": [
              {
                "mapping": {},
                "targetOrder": [],
                "targetElement": "GetTapCount",
                "targetAbility": "trigger"
              },
              {
                "mapping": {},
                "targetOrder": [],
                "targetElement": "Tap_BT",
                "targetAbility": "trigger"
              }
            ],
            "motionDetected": [],
            "freefallDetected": []
          },
          "interruptAbilities": {
            "trigger": false,
            "setup": false,
            "setEnabled": false,
            "setDisabled": false,
            "setEnabledDisabled": false,
            "getSensorData": false,
            "getAccelX": false,
            "getAccelY": false,
            "getAccelZ": false,
            "getMagX": false,
            "getMagY": false,
            "getMagZ": false,
            "detectTap": false,
            "detectMotion": false,
            "detectFreefall": false,
            "enableFreefallDetection": false,
            "enableMotionDetection": false,
            "enableTapDetection": false,
            "disableDetection": false
          },
          "abilities": [
            {
              "name": "trigger",
              "triggers": [
                "triggered"
              ]
            },
            {
              "name": "setup",
              "triggers": []
            },
            {
              "name": "setEnabled",
              "triggers": []
            },
            {
              "name": "setDisabled",
              "triggers": []
            },
            {
              "name": "setEnabledDisabled",
              "triggers": []
            },
            {
              "name": "getSensorData",
              "triggers": [
                "sensorDataRead"
              ]
            },
            {
              "name": "getAccelX",
              "triggers": [
                "accelXRead"
              ]
            },
            {
              "name": "getAccelY",
              "triggers": [
                "accelYRead"
              ]
            },
            {
              "name": "getAccelZ",
              "triggers": [
                "accelZRead"
              ]
            },
            {
              "name": "getMagX",
              "triggers": [
                "magXRead"
              ]
            },
            {
              "name": "getMagY",
              "triggers": [
                "magYRead"
              ]
            },
            {
              "name": "getMagZ",
              "triggers": [
                "magZRead"
              ]
            },
            {
              "name": "detectTap",
              "triggers": [
                "tapDetected"
              ]
            },
            {
              "name": "detectMotion",
              "triggers": [
                "motionDetected"
              ]
            },
            {
              "name": "detectFreefall",
              "triggers": [
                "freefallDetected"
              ]
            },
            {
              "name": "enableFreefallDetection",
              "triggers": []
            },
            {
              "name": "enableMotionDetection",
              "triggers": []
            },
            {
              "name": "enableTapDetection",
              "triggers": []
            },
            {
              "name": "disableDetection",
              "triggers": []
            }
          ]
        },
        {
          "name": "GetTapCount",
          "type": "EmbeddedFunction",
          "variants": [
            "embedded",
            "triggers",
            "abilities",
            "properties",
            "variables"
          ],
          "properties": {
            "errorData": {},
            "code": {
              "trigger": "\tstatic int x = 0;\n\t\n\tif(x==14)\n\t{\n\tATMO_CreateValueUnsignedInt(out, x);\n\tx=0;\n\t}\n\t\n\telse\n\t{\n\t ATMO_CreateValueUnsignedInt(out, x);\n\t x++;\n\t}\n\t\n\treturn ATMO_Status_Success;"
            },
            "variables": {},
            "embeddedPropertyConversions": {},
            "codeUserChanged": {
              "trigger": true
            }
          },
          "meta": {
            "editorX": 385,
            "editorY": 162,
            "lastTrigger": "triggered"
          },
          "triggers": {
            "triggered": [
              {
                "mapping": {},
                "targetOrder": [],
                "targetElement": "EmbeddedIconLabelDisplay",
                "targetAbility": "setLabel"
              }
            ]
          },
          "interruptAbilities": {
            "trigger": false
          },
          "abilities": [
            {
              "name": "trigger",
              "triggers": [
                "triggered"
              ]
            }
          ]
        },
        {
          "name": "EmbeddedIconLabelDisplay",
          "type": "EmbeddedIconLabelDisplay",
          "variants": [
            "embedded",
            "triggers",
            "abilities",
            "properties",
            "variables",
            "rpk"
          ],
          "properties": {
            "errorData": {},
            "code": {
              "trigger": "\treturn ATMO_Status_Success;",
              "displayPage": "\n\tATMO_UI_Page_DisplayPageByCoord(ATMO_PROPERTY(EmbeddedIconLabelDisplay, x), ATMO_PROPERTY(EmbeddedIconLabelDisplay, y), false);\n\treturn ATMO_Status_Success;\n\t",
              "onDisplayed": "\n\treturn ATMO_Status_Success;\n    ",
              "topRightButtonPressed": "\n\treturn ATMO_Status_Success;\n\t",
              "bottomRightButtonPressed": "\n\treturn ATMO_Status_Success;\n\t",
              "topLeftButtonPressed": "\n\treturn ATMO_Status_Success;\n\t",
              "bottomLeftButtonPressed": "\n\treturn ATMO_Status_Success;\n\t",
              "setup": "\n    ATMO_UI_PAGE_Config_t config;\n\tconfig.hidden = ATMO_PROPERTY(EmbeddedIconLabelDisplay, pageHidden);\n\tconfig.textColor = ATMO_PROPERTY(EmbeddedIconLabelDisplay, textColor);\n    config.activeButtons = ATMO_UI_Page_GetButtonMask(ATMO_PROPERTY(EmbeddedIconLabelDisplay, topRightButtonEnabled),\n    ATMO_PROPERTY(EmbeddedIconLabelDisplay,bottomRightButtonEnabled), ATMO_PROPERTY(EmbeddedIconLabelDisplay, topLeftButtonEnabled), ATMO_PROPERTY(EmbeddedIconLabelDisplay, bottomLeftButtonEnabled));\n\tconfig.x = ATMO_PROPERTY(EmbeddedIconLabelDisplay, x);\n    config.x = ATMO_PROPERTY(EmbeddedIconLabelDisplay, x);\n    config.y = ATMO_PROPERTY(EmbeddedIconLabelDisplay, y);\n\tstrncpy(config.topLeftButtonLabel, ATMO_PROPERTY(EmbeddedIconLabelDisplay, topLeftButtonLabel), ATMO_BUTTON_LABEL_MAXLEN);\n\tstrncpy(config.topRightButtonLabel, ATMO_PROPERTY(EmbeddedIconLabelDisplay, topRightButtonLabel), ATMO_BUTTON_LABEL_MAXLEN);\n\tstrncpy(config.bottomLeftButtonLabel, ATMO_PROPERTY(EmbeddedIconLabelDisplay, bottomLeftButtonLabel), ATMO_BUTTON_LABEL_MAXLEN);\n\tstrncpy(config.bottomRightButtonLabel, ATMO_PROPERTY(EmbeddedIconLabelDisplay, bottomRightButtonLabel), ATMO_BUTTON_LABEL_MAXLEN);\n    config.spanX = ATMO_PROPERTY(EmbeddedIconLabelDisplay, spanX);\n\tconfig.spanY = ATMO_PROPERTY(EmbeddedIconLabelDisplay, spanY);\n    config.title = ATMO_PROPERTY(EmbeddedIconLabelDisplay, pageTitle);\n    config.titleHidden = ATMO_PROPERTY(EmbeddedIconLabelDisplay, titleHidden);\n\tATMO_UI_SINGLEICONTEXT_Init(&config);\n\tATMO_VARIABLE(EmbeddedIconLabelDisplay, pageHandle) = config.templateInstance;\n    ATMO_UI_SINGLEICONTEXT_SetMainText(config.templateInstance, ATMO_PROPERTY(EmbeddedIconLabelDisplay, label));\n    ATMO_UI_SINGLEICONTEXT_SetIcon(config.templateInstance, ATMO_PROPERTY(EmbeddedIconLabelDisplay, icon));\n    ATMO_UI_SINGLEICONTEXT_RegisterOnDisplayedAbilityHandle(ATMO_VARIABLE(EmbeddedIconLabelDisplay,pageHandle), ATMO_ABILITY(EmbeddedIconLabelDisplay, onDisplayed));\n    ATMO_UI_SINGLEICONTEXT_RegisterButtonAbilityHandle(ATMO_VARIABLE(EmbeddedIconLabelDisplay,pageHandle), 1, ATMO_ABILITY(EmbeddedIconLabelDisplay, topRightButtonPressed));\n\tATMO_UI_SINGLEICONTEXT_RegisterButtonAbilityHandle(ATMO_VARIABLE(EmbeddedIconLabelDisplay,pageHandle), 2, ATMO_ABILITY(EmbeddedIconLabelDisplay, bottomRightButtonPressed));\n\tATMO_UI_SINGLEICONTEXT_RegisterButtonAbilityHandle(ATMO_VARIABLE(EmbeddedIconLabelDisplay,pageHandle), 3, ATMO_ABILITY(EmbeddedIconLabelDisplay, topLeftButtonPressed));\n    ATMO_UI_SINGLEICONTEXT_RegisterButtonAbilityHandle(ATMO_VARIABLE(EmbeddedIconLabelDisplay,pageHandle), 4, ATMO_ABILITY(EmbeddedIconLabelDisplay, bottomLeftButtonPressed));\n    ATMO_UI_SINGLEICONTEXT_RegisterOnLeaveAbilityHandle(config.templateInstance, ATMO_ABILITY(EmbeddedIconLabelDisplay, onLeave));\n\treturn ATMO_Status_Success;\n    ",
              "onLeave": "\n\treturn ATMO_Status_Success;\n\t",
              "setLabel": "\n    char label[32];\n    if(ATMO_GetString(in, label, 32) == ATMO_Status_Success)\n    {\n        ATMO_UI_SINGLEICONTEXT_SetMainText(ATMO_VARIABLE(EmbeddedIconLabelDisplay,pageHandle), label);\n    }\n    else\n    {\n        return ATMO_Status_Fail;\n    }\n\n    return ATMO_Status_Success;\n    "
            },
            "variables": {
              "pageHandle": {
                "type": "ATMO_DriverInstanceHandle_t"
              }
            },
            "embeddedPropertyConversions": {
              "pageTitle": "string",
              "topRightButtonLabel": "string",
              "bottomRightButtonLabel": "string",
              "topLeftButtonLabel": "string",
              "bottomLeftButtonLabel": "string",
              "label": "string"
            },
            "codeUserChanged": {
              "displayPage": false,
              "onDisplayed": false,
              "topRightButtonPressed": false,
              "bottomRightButtonPressed": false,
              "topLeftButtonPressed": false,
              "bottomLeftButtonPressed": false,
              "setup": false,
              "onLeave": false,
              "setLabel": false
            },
            "textColor": "GUI_BLUE",
            "pageTitle": "Tap",
            "titleHidden": false,
            "pageHidden": false,
            "topRightButtonLabel": "",
            "topRightButtonEnabled": false,
            "bottomRightButtonLabel": "",
            "bottomRightButtonEnabled": false,
            "topLeftButtonLabel": "",
            "topLeftButtonEnabled": false,
            "bottomLeftButtonLabel": "",
            "bottomLeftButtonEnabled": false,
            "x": 0,
            "y": 0,
            "spanX": 1,
            "spanY": 1,
            "icon": "icon_applications_tap",
            "label": ""
          },
          "meta": {
            "editorX": 311,
            "editorY": 2,
            "lastTrigger": "onLeave"
          },
          "triggers": {
            "triggered": [],
            "onDisplayed": [
              {
                "mapping": {},
                "targetOrder": [],
                "targetElement": "FXOS8700AccelerometerMagnetometer",
                "targetAbility": "getSensorData"
              }
            ],
            "topRightButtonPressed": [],
            "bottomRightButtonPressed": [],
            "topLeftButtonPressed": [],
            "bottomLeftButtonPressed": [],
            "onLeave": [
              {
                "mapping": {},
                "targetOrder": [],
                "targetElement": "FXOS8700AccelerometerMagnetometer",
                "targetAbility": "disableDetection"
              }
            ]
          },
          "interruptAbilities": {
            "trigger": false,
            "displayPage": false,
            "onDisplayed": false,
            "topRightButtonPressed": false,
            "bottomRightButtonPressed": false,
            "topLeftButtonPressed": false,
            "bottomLeftButtonPressed": false,
            "setup": false,
            "onLeave": false,
            "setLabel": false
          },
          "abilities": [
            {
              "name": "trigger",
              "triggers": [
                "triggered"
              ]
            },
            {
              "name": "displayPage",
              "triggers": []
            },
            {
              "name": "onDisplayed",
              "triggers": [
                "onDisplayed"
              ]
            },
            {
              "name": "topRightButtonPressed",
              "triggers": [
                "topRightButtonPressed"
              ]
            },
            {
              "name": "bottomRightButtonPressed",
              "triggers": [
                "bottomRightButtonPressed"
              ]
            },
            {
              "name": "topLeftButtonPressed",
              "triggers": [
                "topLeftButtonPressed"
              ]
            },
            {
              "name": "bottomLeftButtonPressed",
              "triggers": [
                "bottomLeftButtonPressed"
              ]
            },
            {
              "name": "setup",
              "triggers": []
            },
            {
              "name": "onLeave",
              "triggers": [
                "onLeave"
              ]
            },
            {
              "name": "setLabel",
              "triggers": []
            }
          ]
        },
        {
          "name": "CountChar",
          "type": "EmbeddedBLECharacteristicCustom",
          "variants": [
            "embedded",
            "triggers",
            "abilities",
            "properties",
            "variables",
            "ble"
          ],
          "properties": {
            "errorData": {},
            "code": {
              "trigger": "\treturn ATMO_Status_Success;",
              "setup": "\n\tATMO_BLE_GATTSAddService(\n\t\tATMO_PROPERTY(CountChar, instance),\n\t\t&ATMO_VARIABLE(CountChar, bleServiceHandle), \n\t\tATMO_PROPERTY(CountChar, bleServiceUuid));\n\t\n\tuint8_t property = 0;\n\tuint8_t permission = 0;\n\t\n\tproperty |= ATMO_PROPERTY(CountChar, read) ? ATMO_BLE_Property_Read : 0;\n\tproperty |= ATMO_PROPERTY(CountChar, write) ? ATMO_BLE_Property_Write : 0;\n\tproperty |= ATMO_PROPERTY(CountChar, notify) ? ATMO_BLE_Property_Notify : 0;\n\n\tpermission |= ATMO_PROPERTY(CountChar, read) ? ATMO_BLE_Permission_Read : 0;\n\tpermission |= ATMO_PROPERTY(CountChar, write) ? ATMO_BLE_Permission_Write : 0;\n\n\tATMO_DATATYPE types[3] = {ATMO_PROPERTY(CountChar, writeDataType), ATMO_PROPERTY(CountChar, readDataType), ATMO_PROPERTY(CountChar, notifyDataType)};\n\t\n\tATMO_BLE_GATTSAddCharacteristic(\n\t\tATMO_PROPERTY(CountChar, instance),\n\t\t&ATMO_VARIABLE(CountChar, bleCharacteristicHandle), \n\t\tATMO_VARIABLE(CountChar, bleServiceHandle), \n\t\tATMO_PROPERTY(CountChar, bleCharacteristicUuid), \n\t\tproperty, permission, ATMO_GetMaxValueSize(3, 64, types));\n\t\n\tATMO_BLE_GATTSRegisterCharacteristicAbilityHandle(\n\t\tATMO_PROPERTY(CountChar, instance),\n\t\tATMO_VARIABLE(CountChar, bleCharacteristicHandle), \n\t\tATMO_BLE_Characteristic_Written, \n\t\tATMO_ABILITY(CountChar, written));\n\t\n\treturn ATMO_Status_Success;\n\t",
              "setValue": "\n\t\n\t// Convert to the desired write data type\n\tATMO_Value_t convertedValue;\n\tATMO_InitValue(&convertedValue);\n\tATMO_CreateValueConverted(&convertedValue, ATMO_PROPERTY(CountChar, readDataType), in);\n\n\tATMO_BLE_GATTSSetCharacteristic(\n\t\tATMO_PROPERTY(CountChar, instance),\n\t\tATMO_VARIABLE(CountChar, bleCharacteristicHandle),\n\t\tconvertedValue.size, \n\t\t(uint8_t *)convertedValue.data,\n\t\tNULL);\n\t\n\tATMO_FreeValue(&convertedValue);\n\t\t\n\treturn ATMO_Status_Success;\n\t",
              "written": "\n\tATMO_CreateValueConverted(out, ATMO_PROPERTY(CountChar, writeDataType), in);\n\treturn ATMO_Status_Success;\n\t",
              "subscibed": "\treturn ATMO_Status_Success;",
              "unsubscribed": "\treturn ATMO_Status_Success;"
            },
            "variables": {
              "bleServiceHandle": {
                "type": "ATMO_BLE_Handle_t"
              },
              "bleCharacteristicHandle": {
                "type": "ATMO_BLE_Handle_t"
              }
            },
            "embeddedPropertyConversions": {
              "bleServiceUuid": "string",
              "bleCharacteristicUuid": "string"
            },
            "codeUserChanged": {
              "setup": false,
              "setValue": false,
              "written": false,
              "subscibed": false,
              "unsubscribed": false
            },
            "instance": 0,
            "bleServiceUuid": "a3d74bf0-1f5d-4e76-a517-e629973d36c0",
            "bleCharacteristicUuid": "a3d74bf0-1f5d-4e76-a517-e629973d36c1",
            "read": true,
            "write": false,
            "notify": true,
            "readDataType": "ATMO_DATATYPE_STRING",
            "writeDataType": "ATMO_DATATYPE_STRING",
            "notifyDataType": "ATMO_DATATYPE_STRING"
          },
          "meta": {
            "editorX": 525,
            "editorY": 281,
            "lastTrigger": "written"
          },
          "triggers": {
            "triggered": [],
            "written": [],
            "subscibed": [],
            "unsubscribed": []
          },
          "interruptAbilities": {
            "trigger": false,
            "setup": false,
            "setValue": "valueSet",
            "written": true,
            "subscibed": true,
            "unsubscribed": true
          },
          "abilities": [
            {
              "name": "trigger",
              "triggers": [
                "triggered"
              ]
            },
            {
              "name": "setup",
              "triggers": []
            },
            {
              "name": "setValue",
              "triggers": []
            },
            {
              "name": "written",
              "triggers": [
                "written"
              ]
            },
            {
              "name": "subscibed",
              "triggers": [
                "subscibed"
              ]
            },
            {
              "name": "unsubscribed",
              "triggers": [
                "unsubscribed"
              ]
            }
          ]
        },
        {
          "name": "Tap_BT",
          "type": "EmbeddedFunction",
          "variants": [
            "embedded",
            "triggers",
            "abilities",
            "properties",
            "variables"
          ],
          "properties": {
            "errorData": {},
            "code": {
              "trigger": "\tstatic int x=0;\n\t\n\t    if(x==2)\n\t    {\n\t    ATMO_CreateValueString(out, \"Hello!\");\n\t    x++;\n\t    }\n\t    \n\t    else if(x==5)\n\t    {\n\t    ATMO_CreateValueString(out, \"Help me cross the road\");\n\t    x++;\n\t        \n\t    }\n\t    \n\t    else if(x==9)\n\t    {\n\t    ATMO_CreateValueString(out, \"Help me to the elevator!\");\n\t    x++;\n\t        \n\t    }\n\t    \n\t    else if(x==14)\n\t    {\n\t    ATMO_CreateValueString(out, \"Please guide me to the exit\");\n\t    x=0;\n\t    }\n\t    \n\t    else\n\t    {\n\t    ATMO_CreateValueString(out, \"Please Wait for my message!\");\n\t    x++;\n\t    }\n\treturn ATMO_Status_Success;"
            },
            "variables": {},
            "embeddedPropertyConversions": {},
            "codeUserChanged": {
              "trigger": true
            }
          },
          "meta": {
            "editorX": 395,
            "editorY": 278,
            "lastTrigger": "triggered"
          },
          "triggers": {
            "triggered": [
              {
                "mapping": {},
                "targetOrder": [],
                "targetElement": "CountChar",
                "targetAbility": "setValue"
              }
            ]
          },
          "interruptAbilities": {
            "trigger": false
          },
          "abilities": [
            {
              "name": "trigger",
              "triggers": [
                "triggered"
              ]
            }
          ]
        }
      ],
      "libraries": {
        "ens210": {
          "libName": "ens210",
          "description": "AMS ENS210 Humidity and Temperature Sensor",
          "type": "Humidity, Temperature Sensor",
          "icon": "",
          "manufacturer": "AMS",
          "image": "",
          "version": "",
          "eelVersion": "3",
          "shoppingCartLinks": {
            "digikey": {
              "links": {
                "info": "https://www.digikey.com/products/en/development-boards-kits-programmers/evaluation-boards-sensors/795?k=AMS%20ens210"
              },
              "cartData": {
                "part": "ENS210-QF_EK_ST-ND",
                "partid": "6490748",
                "source": "dkstudio",
                "qty": "1"
              }
            }
          },
          "requires": [
            "embedded",
            "i2c",
            "fpmath"
          ],
          "elements": [
            {
              "name": "ENS210TemperatureHumidity",
              "type": "EmbeddedENS210",
              "icon": "EmbeddedTempHumidity.svg",
              "defaultAbility": "readTemperature",
              "defaultTrigger": "temperatureRead",
              "hidden": false,
              "abilities": [
                {
                  "name": "setup",
                  "hidden": true,
                  "code": "\tATMO_ENS210_Config_t config;\n\tconfig.address = ATMO_PROPERTY(undefined, i2cAddress);\n\tconfig.i2cDriverInstance = ATMO_PROPERTY(undefined, i2cInstance);\n\tconfig.tempCalibrationOffset = ATMO_PROPERTY(undefined, tempCalibrationOffset);\n\n\treturn ( ATMO_ENS210_Init(&config) == ATMO_ENS210_Status_Success ) ? ATMO_Status_Success : ATMO_Status_Fail;\n"
                },
                {
                  "name": "setEnabled",
                  "triggers": [],
                  "code": "ATMO_ENS210_SetEnabled(true);\nreturn ATMO_Status_Success;"
                },
                {
                  "name": "setDisabled",
                  "triggers": [],
                  "code": "ATMO_ENS210_SetEnabled(false);\nreturn ATMO_Status_Success;"
                },
                {
                  "name": "setEnabledDisabled",
                  "triggers": [],
                  "code": "bool enabled = false;\nATMO_GetBool(in, &enabled);\nATMO_ENS210_SetEnabled(enabled);\nreturn ATMO_Status_Success;"
                },
                {
                  "name": "readTemperature",
                  "triggers": [
                    "temperatureRead"
                  ],
                  "code": "    float tempC;\n    \n    if(ATMO_ENS210_GetTemperatureFloat(&tempC) == ATMO_ENS210_Status_Success)\n    {\n        ATMO_CreateValueFloat(out, tempC);\n    }\n    else\n    {\n        ATMO_CreateValueVoid(out);\n    }\n    \n    return ATMO_Status_Success;"
                },
                {
                  "name": "readHumidity",
                  "triggers": [
                    "humidityRead"
                  ],
                  "code": "    float humidityPct;\n\n    if(ATMO_ENS210_GetHumidityFloat(&humidityPct) == ATMO_ENS210_Status_Success)\n    {\n        ATMO_CreateValueFloat(out, humidityPct);\n    }\n    else\n    {\n        ATMO_CreateValueVoid(out);\n    }\n    \n    return ATMO_Status_Success;"
                }
              ],
              "properties": [
                {
                  "name": "i2cInstance",
                  "input": "number",
                  "value": "ATMO_DEFAULT_I2C"
                },
                {
                  "name": "i2cAddress",
                  "input": "number",
                  "value": "0x43"
                },
                {
                  "name": "tempCalibrationOffset",
                  "input": "number",
                  "value": "0"
                }
              ],
              "triggers": [],
              "variables": [],
              "language": {
                "en-US": {
                  "EmbeddedENS210": "AMS ENS210",
                  "i2cInstance": "I2C Driver Instance",
                  "i2cAddress": "I2C Address",
                  "setEnabled": "Set Enabled",
                  "setDisabled": "Set Disabled",
                  "setEnabledDisabled": "Set Enabled State",
                  "readTemperature": "Read Temperature (C)",
                  "temperatureRead": "Temperature Read",
                  "readHumidity": "Read Humidity (%rh)",
                  "humidityRead": "Humidity Read",
                  "tempCalibrationOffset": "Temperature Calibration Offset"
                }
              }
            }
          ],
          "files": {
            "common": {
              "headers": {
                "ens210.h": "#ifndef _ATMO_ENS210_H_\n#define _ATMO_ENS210_H_\n\n#include \"../app_src/atmosphere_platform.h\"\n#include \"../i2c/i2c.h\"\n\ntypedef enum {\n    ATMO_ENS210_Status_Success              = 0x00u,  // Common - Operation was successful\n    ATMO_ENS210_Status_Fail                 = 0x01u,  // Common - Operation failed\n    ATMO_ENS210_Status_Initialized          = 0x02u,  // Common - Peripheral already initialized\n    ATMO_ENS210_Status_Invalid              = 0x03u,  // Common - Invalid operation or result\n    ATMO_ENS210_Status_NotSupported         = 0x04u,  // Common - Feature not supported by platform\n} ATMO_ENS210_Status_t;\n\ntypedef struct {\n    uint16_t address;\n    int16_t tempCalibrationOffset;\n    ATMO_DriverInstanceHandle_t i2cDriverInstance;\n} ATMO_ENS210_Config_t;\n\n/**\n * Initialize ENS210 Driver\n *\n * @param[in] config - Device configuration (optional)\n */\nATMO_ENS210_Status_t ATMO_ENS210_Init(ATMO_ENS210_Config_t *config);\n\n/**\n * Enable/Disable ENS210 Driver\n *\n * @param[in] enabled\n */\nATMO_ENS210_Status_t ATMO_ENS210_SetEnabled(bool enabled);\n\n/**\n * Get enabled/disabled status of ENS210 driver\n *\n * @param[out] enabled\n */\nATMO_ENS210_Status_t ATMO_ENS210_GetEnabled(bool *enabled);\n\n/**\n * Set basic device configuration\n *\n * @param[in] config\n */\nATMO_ENS210_Status_t ATMO_ENS210_SetConfiguration(const ATMO_ENS210_Config_t *config);\n\n/**\n * Get device configuration\n * \n * @param[out] config\n */\nATMO_ENS210_Status_t ATMO_ENS210_GetConfiguration(ATMO_ENS210_Config_t *config);\n\n/**\n * Get Temperature in degrees celsius\n * \n * @param[out] temperatureCelsius\n */\nATMO_ENS210_Status_t ATMO_ENS210_GetTemperature(int32_t *temperatureCelsius);\n\n/**\n * Get Humidity\n * \n * @param[out] humidityPct\n */\nATMO_ENS210_Status_t ATMO_ENS210_GetHumidity(int32_t *humidityPct);\n\n/**\n * Get Temperature in degrees celsius\n * \n * @param[out] temperatureCelsius\n */\nATMO_ENS210_Status_t ATMO_ENS210_GetTemperatureFloat(float *temperatureCelsius);\n\n/**\n * Get Humidity\n * \n * @param[out] humidityPct\n */\nATMO_ENS210_Status_t ATMO_ENS210_GetHumidityFloat(float *humidityPct);\n\n#endif\n",
                "ens210_internal.h": "/*\n*********************************************************************************\n * Copyright 2018 by ams AG                                                     *\n *                                                                              *\n * Redistribution and use in source and binary forms, with or without           *\n * modification, *are permitted provided that the following conditions are met: *\n *  1. Redistributions of source code must retain the above copyright notice,   *\n * this list of conditions and the following disclaimer.                        *\n *                                                                              *\n *  2. Redistributions in binary form must reproduce the above copyright notice,*\n *  this list of conditions and the following disclaimer in the documentation   *\n *  and/or other materials provided with the distribution.                      *\n *  3. Neither the name of the copyright holder nor the names of its            *\n * contributors may be used to endorse or promote products derived from this    *\n * software without specific prior written permission.                          *\n *                                                                              *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"  *\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE    *\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE   *\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE    *\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR          *\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF         *\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS     *\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN      *\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)      *\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE   *\n * POSSIBILITY OF SUCH DAMAGE.                                                  *\n ********************************************************************************\n*/\n\n\n#ifndef __ENS210_H_\n#define __ENS210_H_\n\n#include \"../app_src/atmosphere_platform.h\"\n\n/*! @addtogroup ens210   ENS210 Driver API\n * This module provides the API to operate an ENS210 relative humidity and temperature sensor with I2C interface.\n *\n * Basic steps to operate the sensor are as follows:\n * -# Set Run mode (#ENS210_SensRun_Set)\n * -# Start measurement (#ENS210_SensStart_Set)\n * -# Wait for measurement to complete\n * -# Read measurement (#ENS210_TVal_Get, #ENS210_HVal_Get, #ENS210_THVal_Get)\n *\n * Please refer to ENS210 Reference Driver and Porting Guide for more details on platform porting. In this module, names\n * T and H have been used to refer to temperature and relative humidity respectively to comply with ENS210 datasheet\n * naming convention.\n *\n * Example 1 - Sample application code to measure temperature and relative humidity without error checking\n * -------------------------------------------------------------------------------------------------------\n * @code\n * uint32_t T_Raw, H_Raw;\n * int32_t T_mCelsius, T_mFahrenheit, T_mKelvin, H_Percent;\n *\n * //Set runmode, start measurement, wait, read measurement (for both T and H)\n * ENS210_SensRun_Set(ENS210_SENSRUN_T_MODE_SINGLE_SHOT | ENS210_SENSRUN_H_MODE_SINGLE_SHOT);\n * ENS210_SensStart_Set(ENS210_SENSSTART_T_START | ENS210_SENSSTART_H_START);\n * WaitMsec(ENS210_T_H_CONVERSION_TIME_MS);\n * ENS210_THVal_Get(&T_Raw,&H_Raw);\n *\n * //Convert the raw temperature to milli Kelvin\n * T_mKelvin = ENS210_ConvertRawToKelvin(T_Raw, 1000);\n * //Convert the raw temperature to milli Celsius\n * T_mCelsius = ENS210_ConvertRawToCelsius(T_Raw, 1000);\n * //Convert the raw temperature to milli Fahrenheit\n * T_mFahrenheit = ENS210_ConvertRawToFahrenheit(T_Raw, 1000);\n * printf(\"T crc ok = %s\\n\", ENS210_IsCrcOk(T_Raw)  ? \"yes\" : \"no\");\n * printf(\"T valid = %s \\n\", ENS210_IsDataValid(T_Raw) ? \"yes\" : \"no\");\n * //Update the int32_t format specifier (%ld) based on platform word-size\n * printf(\"T = %ld mK %ld mC %ld mF \\n\", T_mKelvin, T_mCelsius, T_mFahrenheit);\n *\n * //Convert the raw relative humidity to milli %\n * H_Percent = ENS210_ConvertRawToPercentageH(H_Raw, 1000);\n * printf(\"H crc ok = %s\\n\", ENS210_IsCrcOk(H_Raw)  ? \"yes\" : \"no\");\n * printf(\"H valid = %s \\n\", ENS210_IsDataValid(H_Raw) ? \"yes\" : \"no\");\n * //Update the int32_t format specifier (%ld) based on platform word-size\n * printf(\"H = %ld m%%\\n\", H_Percent);\n *\n * @endcode\n *\n *\n * Example 2 - Sample application code to measure relative humidity with error checking\n * ------------------------------------------------------------------------------------\n * @code\n * uint32_t H_Raw;\n * int32_t H_Percent;\n * int status;\n * bool i2cOk;\n *\n * i2cOk = true; //Start accumulating I2C transaction errors\n *\n * status = ENS210_SensRun_Set(ENS210_SENSRUN_H_MODE_SINGLE_SHOT);\n * i2cOk &= status==I2C_RESULT_OK;\n *\n * status = ENS210_SensStart_Set(ENS210_SENSSTART_H_START);\n * i2cOk &= status==I2C_RESULT_OK;\n *\n * WaitMsec(ENS210_T_H_CONVERSION_TIME_MS);\n *\n * status = ENS210_HVal_Get(&H_Raw);\n * i2cOk &= status==I2C_RESULT_OK;\n *\n * if( !i2cOk ) {\n *     printf(\"H i2c error\\n\")\n * } else if( !ENS210_IsCrcOk(H_Raw) ) {\n *     printf(\"H crc error\\n\")\n * } else if( !ENS210_IsDataValid(H_Raw) ) {\n *     printf(\"H data invalid\\n\")\n * } else {\n *     //Convert the raw relative humidity to milli %\n *     H_Percent = ENS210_ConvertRawToPercentageH(H_Raw,1000);\n *     //Update the int32_t format specifier (%ld) based on platform word-size\n *     printf(\"H = %ld m%%\\n\", H_Percent);\n * }\n *\n * @endcode\n *\n * @{\n */\n/*****************************************************************************\n * Types/enumerations/variables\n ****************************************************************************/\n\n/*! @brief Status return codes. */\ntypedef enum ens210_status_ {\n    ens210_success = 0,             /*!< Function returned successfully. */\n    ens210_I2C_error = 1,           /*!< I2C Error. */\n    ens210_invalid_ID = 2,          /*!< Invalid ID. */\n    ens210_Tdata_CRC_error = 3,     /*!< CRC error for temperature data. */\n    ens210_Hdata_CRC_error = 4,     /*!< CRC error for humidity data. */\n    ens210_T_invalid_data = 5,      /*!< Temperature Data is invalid. */\n    ens210_H_invalid_data = 6,      /*!< Humidity Data is invalid. */\n    ens210_wrong_parameter = 7,     /*!< Wrong Parameter entered. */\n    ens210_noinit = 8               /*!< ENS210 was not initialized. */\n} ens210_status_t;\n\n/*! @brief Measurement mode of Sensor */\nenum measurement_mode {\n    mode_TH = 0,        /*!< ENS210 set to measure both temperature and humidity. */\n    mode_Tonly = 1,     /*!< ENS210 set to measure temperature only. */\n    mode_Honly = 2      /*!< ENS210 set to measure humidity only. */\n};\n\n/*! ENS210 os-free driver version info */\n#define ENS210_OSFREE_DRIVER_VERSION            2\n\n/*! ENS210 T and H conversion time in milliseconds. Refer to ENS210 data sheet for timing information. */\n#define ENS210_T_H_CONVERSION_TIME_MS           130\n\n/*! ENS210 T conversion time in milliseconds */\n#define ENS210_T_CONVERSION_TIME_MS             110\n\n/*! ENS210 Booting time in milliseconds. */\n#define ENS210_BOOTING_TIME_MS                  10\n\n/*! ENS210 Reset time in milliseconds. */\n#define ENS210_RESET_WAIT_TIME_MS               10\n\n/*! ENS210 I2C slave address */\n#define ENS210_I2C_SLAVE_ADDRESS                (uint8_t)0x43\n\n/*! ENS210 SysCtrl register: Low power enable */\n#define ENS210_SYSCTRL_LOWPOWER_ENABLE          (1 << 0)\n/*! ENS210 SysCtrl register: Low power disable */\n#define ENS210_SYSCTRL_LOWPOWER_DISABLE         (0 << 0)\n/*! ENS210 SysCtrl register: Reset enable */\n#define ENS210_SYSCTRL_RESET_ENABLE             (1 << 7)\n/*! ENS210 SysCtrl register: Reset disable */\n#define ENS210_SYSCTRL_RESET_DISABLE            (0 << 7)\n\n/*! ENS210 SysStat register: Standby or Booting mode */\n#define ENS210_SYSSTAT_MODE_STANDBY             (0 << 0)\n/*! ENS210 SysStat register: Active mode */\n#define ENS210_SYSSTAT_MODE_ACTIVE              (1 << 0)\n\n\n/*! ENS210 SensRun register: temperature single shot mode */\n#define ENS210_SENSRUN_T_MODE_SINGLE_SHOT       (0 << 0)\n/*! ENS210 SensRun register: temperature continuous mode */\n#define ENS210_SENSRUN_T_MODE_CONTINUOUS        (1 << 0)\n/*! ENS210 SensRun register: relative humidity single shot mode */\n#define ENS210_SENSRUN_H_MODE_SINGLE_SHOT       (0 << 1)\n/*! ENS210 SensRun register: relative humidity continuous mode */\n#define ENS210_SENSRUN_H_MODE_CONTINUOUS        (1 << 1)\n\n/*! ENS210  SensStart register: T sensor start */\n#define ENS210_SENSSTART_T_START                (1 << 0)\n/*! ENS210  SensStart register: H sensor start */\n#define ENS210_SENSSTART_H_START                (1 << 1)\n\n/*! ENS210  SensStop register: T sensor stop */\n#define ENS210_SENSSTOP_T_STOP                  (1 << 0)\n/*! ENS210  SensStop register: H sensor stop */\n#define ENS210_SENSSTOP_H_STOP                  (1 << 1)\n\n/*! ENS210  SensStat register: T sensor idle */\n#define ENS210_SENSSTAT_T_STAT_IDLE             (0 << 0)\n/*! ENS210  SensStat register: T sensor active */\n#define ENS210_SENSSTAT_T_STAT_ACTIVE           (1 << 0)\n/*! ENS210  SensStat register: H sensor idle */\n#define ENS210_SENSSTAT_H_STAT_IDLE             (0 << 1)\n/*! ENS210  SensStat register: H sensor active */\n#define ENS210_SENSSTAT_H_STAT_ACTIVE           (1 << 1)\n\n/* wrapper for the I2C write, I2C read and wait functions needed by the sensor driver */\n/* it is expected that the I2C_Read and I2C_Write functions return 0 if the I2C transaction is successful */\ntypedef struct _ens210_IoFunc_t\n{\n    uint8_t   (*I2C_Read)(uint8_t *writeBuf, uint32_t writeSize, uint8_t *readBuf, uint32_t readSize);  /*!< External I2C read function */\n    uint8_t   (*I2C_Write)(uint8_t *writeBuf, uint32_t writeSize);  /*!< External I2C write function */\n    void      (*WaitMsec)(uint32_t millisec); /*!< Wait function in milliseconds */\n} ens210_IoFunc_t, *pens210_IoFunc_t;\n\n/*! @brief    ENS210 ID block structure */\ntypedef struct ENS210_Ids_s\n{\n    uint16_t    partId;             /*!< Part ID */\n    uint8_t     uId[8];             /*!< Unique Identifier 8 bytes */\n} ENS210_Ids_t;\n\n/*! @brief Structure of measurement data. */\ntypedef struct ens210_meas_data_s\n{\n    int32_t T_Celsius;              /*!< Temperature in Celsius */\n    int32_t T_Fahrenheit;           /*!< Temperature in Fahrenheit */\n    int32_t T_Kelvin;               /*!< Temperature in Kelvin */\n    int32_t T_mCelsius;             /*!< Temperature in milliCelsius */\n    int32_t T_mFahrenheit;          /*!< Temperature in milliFahrenheit */\n    int32_t T_mKelvin;              /*!< Temperature in milliKelvin */\n    int32_t H_Percent;              /*!< Relative Humidity to % */\n    int32_t H_mPercent;             /*!< Relative Humidity to milli% */\n} ens210_meas_data_t;\n\n/****************************************************************************\n * Function Prototypes\n ****************************************************************************/\n\n/*!\n * @brief   Initialize ENS210 driver.\n * @param   pIoFunc     :   Pointer to a structure of external functions or values\n */\nvoid ENS210_Init_Driver(ens210_IoFunc_t* pIoFunc);\n\n/*!\n * @brief   De-initialize ENS210 driver.\n */\nvoid ENS210_Deinit_Driver();\n\n/*!\n * @brief   Initialize ENS210 hardware.\n * @return  The return status value (0 for success)\n */\nens210_status_t ENS210_Init_Hw(void);\n\n/*!\n * @brief   Set ENS210 SysCtrl register; enabling reset and/or low power.\n * @param   sysCtrl     :   Mask composed of  ENS210_SYSCTRL_xxx macros.\n * @return  The return status value (0 for success)\n *  */\nens210_status_t ENS210_SysCtrl_Set(uint8_t sysCtrl);\n\n/*!\n * @brief   Get ENS210 SysCtrl register.\n * @param   sysCtrl     :   Pointer to receive value of the register. Must not be null.\n * @return  The return status value (0 for success)\n * @note    If the return indicates I2C failure, the value of the out parameter is undefined.\n */\nens210_status_t ENS210_SysCtrl_Get(uint8_t *sysCtrl);\n\n/*!\n * @brief   Get ENS210 SysStat register.\n * @param   sysStat     :   Pointer to receive value of the register. Must not be null.\n * @return  The return status value (0 for success)\n * @note    If the return indicates I2C failure, the value of the out parameter is undefined.\n */\nens210_status_t ENS210_SysStat_Get(uint8_t *sysStat);\n\n/*!\n * @brief   Set ENS210 SensRun register; set the run mode single shot/continuous for T and H sensors.\n * @param   sensRun     :   Mask composed of ENS210_SENSRUN_xxx macros.\n * @return  The return status value (0 for success)\n */\nens210_status_t ENS210_SensRun_Set(uint8_t sensRun);\n\n/*!\n * @brief   Get ENS210 SensRun register.\n * @param   sensRun     :   Pointer to receive value of the register. Must not be null.\n * @return  The return status value (0 for success)\n * @note    If the return indicates I2C failure, the value of the out parameter is undefined.\n */\nens210_status_t ENS210_SensRun_Get(uint8_t *sensRun);\n\n/*!\n * @brief   Set ENS210 SensStart register; starts the measurement for T and/or H sensors.\n * @param   sensStart   :  Mask composed of ENS210_SENSSTART_xxx macros.\n * @return  The return status value (0 for success)\n */\nens210_status_t ENS210_SensStart_Set(uint8_t sensStart);\n\n/*!\n * @brief   Set ENS210 SensStop register; stops the measurement for T and/or H sensors.\n * @param   sensStop    :   Mask composed of ENS210_SENSSTOP_xxx macros.\n * @return  The return status value (0 for success)\n */\nens210_status_t ENS210_SensStop_Set(uint8_t sensStop);\n\n/*!\n * @brief   Get ENS210 SensStat register.\n * @param   sensStat    :   Pointer to receive value of the register. Must not be null.\n * @return  The return status value (0 for success)\n */\nens210_status_t ENS210_SensStat_Get(uint8_t *sensStat);\n\n/*!\n * @brief   Get ENS210 TVal register; raw measurement data as well as CRC and valid indication.\n * @param   traw         :   Pointer to receive value of the register. Must not be null.\n * @return  The return status value (0 for success)\n * @note\n * Use ENS210_IsCrcOk and ENS210_IsDataValid before using the measurement data.\\n\n * Use ENS210_ConvertRawToXXX to convert raw data to standard units.\\n\n * If the return indicates I2C failure, the value of the out parameter is undefined.\n */\nens210_status_t ENS210_TVal_Get(uint32_t *traw);\n\n/*!\n * @brief   Get ENS210 HVal register; raw measurement data as well as CRC and valid indication.\n * @param   hraw         :   Pointer to receive value of register. Must not be null.\n * @return  The return status value (0 for success)\n * @note\n * Use ENS210_IsCrcOk and ENS210_IsDataValid before using the measurement data.\\n\n * If the return indicates I2C failure, the value of the out parameter is undefined.\n */\nens210_status_t ENS210_HVal_Get(uint32_t *hraw);\n\n/*!\n * @brief   Get ENS210 TVal and HVal registers; raw measurement data as well as CRC and valid indication.\n * @param   traw         :   Pointer to receive value of TVal register. Must not be null.\n * @param   hraw         :   Pointer to receive value of HVal register. Must not be null.\n * @return  The return status value (0 for success)\n * @note\n * Use ENS210_IsCrcOk and ENS210_IsDataValid before using the measurement data.\\n\n * If the return indicates I2C failure, the value of the out parameter is undefined.\n */\nens210_status_t ENS210_THVal_Get(uint32_t *traw, uint32_t *hraw);\n\n/*!\n * @brief   Get ENS210 Part ID and UID.\n * @param   ids         :   Pointer to receive ids. Must not be null.\n * @return  The return status value (0 for success)\n * @note    If this function returns an error, it is suggested to reset the device to bring it to a known state.\n */\nens210_status_t ENS210_Ids_Get(ENS210_Ids_t *ids);\n\n/*!\n * @brief   Get ENS210 temperature and humidity measurements\n * @param   meas_mode    :   Measurement mode\n * @param   results      :   Pointer to the result structure\n * @return  The return status value (0 for success)\n * @note\n * mode = 0: temperature and humidity\\n\n * mode = 1: temperature only\\n\n * mode = 2: humidity only\n */\nens210_status_t ENS210_Measure(uint8_t meas_mode, ens210_meas_data_t *results);\n\n/*!\n * @}\n */\n\n#endif /* __ENS210_H_ */\n\n"
              },
              "objects": {
                "ens210.c": "#include \"ens210.h\"\n#include \"ens210_internal.h\"\n\ntypedef struct {\n    ATMO_ENS210_Config_t config;\n    bool configured;\n} ATMO_ENS210_Priv_Config;\n\nstatic ATMO_ENS210_Priv_Config _ATMO_ENS210_config;\n\nstatic ATMO_I2C_Peripheral_t _ATMO_ENS210_i2cConfig = {\n    .operatingMode = ATMO_I2C_OperatingMode_Master,\n    .baudRate = ATMO_I2C_BaudRate_Standard_Mode\n};\n\nstatic bool _ATMO_ENS210_Enabled = true;\n\nstatic uint8_t ATMO_ENS210_I2CRead_Simple(uint8_t *writeBuf, uint32_t writeSize, uint8_t *readBuf, uint32_t readSize)\n{\n\tATMO_I2C_Status_t status = ATMO_I2C_MasterRead(_ATMO_ENS210_config.config.i2cDriverInstance, _ATMO_ENS210_config.config.address, writeBuf, writeSize, readBuf, readSize, 1000);\n\treturn (status == ATMO_I2C_Status_Success) ? 0 : 1;\n}\n\nstatic uint8_t ATMO_ENS210_I2CWrite_Simple(uint8_t *writeBuf, uint32_t writeSize)\n{\n\tATMO_I2C_Status_t status = ATMO_I2C_MasterWrite(_ATMO_ENS210_config.config.i2cDriverInstance, _ATMO_ENS210_config.config.address, NULL, 0, writeBuf, writeSize, 1000);\n\treturn (status == ATMO_I2C_Status_Success) ? 0 : 1;\n}\n\nATMO_ENS210_Status_t ATMO_ENS210_Init(ATMO_ENS210_Config_t *config)\n{\n    // Did the user supply a configuration?\n    if( config )\n    {\n        ATMO_ENS210_SetConfiguration(config);\n    }\n    else\n    {\n        _ATMO_ENS210_config.configured = false;\n    }\n\n    ens210_IoFunc_t io;\n    io.I2C_Read = ATMO_ENS210_I2CRead_Simple;\n    io.I2C_Write = ATMO_ENS210_I2CWrite_Simple;\n    io.WaitMsec = ATMO_PLATFORM_DelayMilliseconds;\n    ENS210_Init_Driver(&io);\n    ENS210_Init_Hw();\n\n    return ATMO_ENS210_Status_Success;\n}\n\nATMO_ENS210_Status_t ATMO_ENS210_SetEnabled(bool enabled)\n{\n    _ATMO_ENS210_Enabled = enabled;\n    return ATMO_ENS210_Status_Success;\n}\n\nATMO_ENS210_Status_t ATMO_ENS210_GetEnabled(bool *enabled)\n{\n    *enabled = _ATMO_ENS210_Enabled;\n    return ATMO_ENS210_Status_Success;\n}\n\nATMO_ENS210_Status_t ATMO_ENS210_SetConfiguration(const ATMO_ENS210_Config_t *config)\n{\n    if( config == NULL )\n    {\n        return ATMO_ENS210_Status_Fail;\n    }\n\n    if( ATMO_I2C_SetConfiguration(config->i2cDriverInstance, &_ATMO_ENS210_i2cConfig) != ATMO_I2C_Status_Success )\n    {\n        return ATMO_ENS210_Status_Fail;\n    }\n    memcpy( &_ATMO_ENS210_config.config, config, sizeof(ATMO_ENS210_Config_t) );\n    _ATMO_ENS210_config.configured = true;\n\n    return ATMO_ENS210_Status_Success;\n}\n\nATMO_ENS210_Status_t ATMO_ENS210_GetConfiguration(ATMO_ENS210_Config_t *config)\n{\n    if( config == NULL || !_ATMO_ENS210_config.configured )\n    {\n        return ATMO_ENS210_Status_Fail;\n    }\n\n    memcpy(config, &_ATMO_ENS210_config.config, sizeof(ATMO_ENS210_Config_t));\n\n    return ATMO_ENS210_Status_Success;\n}\n\nATMO_ENS210_Status_t ATMO_ENS210_GetTemperature(int32_t *temperatureCelsius)\n{\n    if(!_ATMO_ENS210_Enabled || !_ATMO_ENS210_config.configured)\n    {\n        return ATMO_ENS210_Status_Fail;\n    }\n\n    ens210_meas_data_t results;\n    if( ENS210_Measure(mode_Tonly, &results) != 0 )\n    {\n        return ATMO_ENS210_Status_Fail;\n    }\n\n    *temperatureCelsius = results.T_Celsius + _ATMO_ENS210_config.config.tempCalibrationOffset;\n\n    return ATMO_ENS210_Status_Success;\n}\n\nATMO_ENS210_Status_t ATMO_ENS210_GetHumidity(int32_t *humidityPct)\n{\n    if(!_ATMO_ENS210_Enabled)\n    {\n        return ATMO_ENS210_Status_Fail;\n    }\n\n    ens210_meas_data_t results;\n    if( ENS210_Measure(mode_Honly, &results) != 0 )\n    {\n        return ATMO_ENS210_Status_Fail;\n    }\n\n    *humidityPct = results.H_Percent;\n\n    return ATMO_ENS210_Status_Success;\n}\n\nATMO_ENS210_Status_t ATMO_ENS210_GetTemperatureFloat(float *temperatureCelsius)\n{\n    if(!_ATMO_ENS210_Enabled || !_ATMO_ENS210_config.configured)\n    {\n        return ATMO_ENS210_Status_Fail;\n    }\n\n    ens210_meas_data_t results;\n    if( ENS210_Measure(mode_Tonly, &results) != 0 )\n    {\n        return ATMO_ENS210_Status_Fail;\n    }\n\n    *temperatureCelsius = (results.T_mCelsius / 1000.0) + _ATMO_ENS210_config.config.tempCalibrationOffset;\n\n    return ATMO_ENS210_Status_Success;\n}\n\nATMO_ENS210_Status_t ATMO_ENS210_GetHumidityFloat(float *humidityPct)\n{\n    if(!_ATMO_ENS210_Enabled)\n    {\n        return ATMO_ENS210_Status_Fail;\n    }\n\n    ens210_meas_data_t results;\n    if( ENS210_Measure(mode_Honly, &results) != 0 )\n    {\n        return ATMO_ENS210_Status_Fail;\n    }\n\n    *humidityPct = results.H_mPercent / 1000.0;\n\n    return ATMO_ENS210_Status_Success;\n}",
                "ens210_internal.c": "/*\n*********************************************************************************\n * Copyright 2018 by ams AG                                                     *\n *                                                                              *\n * Redistribution and use in source and binary forms, with or without           *\n * modification, *are permitted provided that the following conditions are met: *\n *  1. Redistributions of source code must retain the above copyright notice,   *\n * this list of conditions and the following disclaimer.                        *\n *                                                                              *\n *  2. Redistributions in binary form must reproduce the above copyright notice,*\n *  this list of conditions and the following disclaimer in the documentation   *\n *  and/or other materials provided with the distribution.                      *\n *  3. Neither the name of the copyright holder nor the names of its            *\n * contributors may be used to endorse or promote products derived from this    *\n * software without specific prior written permission.                          *\n *                                                                              *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"  *\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE    *\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE   *\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE    *\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR          *\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF         *\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS     *\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN      *\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)      *\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE   *\n * POSSIBILITY OF SUCH DAMAGE.                                                  *\n ********************************************************************************\n*/\n\n/**\n * @file\n * This is the source file for the temperature and humidity sensor ENS210 driver.\n */\n\n#include \"ens210_internal.h\"\n#include <string.h>\n#include <assert.h>\n\n/*****************************************************************************\n * Private macros and functions\n ****************************************************************************/\n/* Register addresses */\n#define ENS210_REG_PART_ID     0x00\n#define ENS210_REG_UID         0x04\n#define ENS210_REG_SYS_CTRL    0x10\n#define ENS210_REG_SYS_STAT    0x11\n#define ENS210_REG_SENS_RUN    0x21\n#define ENS210_REG_SENS_START  0x22\n#define ENS210_REG_SENS_STOP   0x23\n#define ENS210_REG_SENS_STAT   0x24\n#define ENS210_REG_T_VAL       0x30\n#define ENS210_REG_H_VAL       0x33\n\n/** Mask to extract 16-bit data from raw T and H values */\n#define ENS210_T_H_MASK        0xFFFFU\n\n/** Simplification macro, implementing integer division with simple rounding to closest number\n *  It supports both positive and negative numbers, but ONLY positive divisors */\n#define IDIV(n,d)              ((n)>0 ? ((n)+(d)/2)/(d) : ((n)-(d)/2)/(d))\n\n#define CRC7WIDTH              7     //7 bits CRC has polynomial of 7th order (has 8 terms)\n#define CRC7POLY               0x89  //The 8 coefficients of the polynomial\n#define CRC7IVEC               0x7F  //Initial vector has all 7 bits high\n\n#define DATA7WIDTH             17\n#define DATA7MASK              ((1UL << DATA7WIDTH) - 1)  //0b 1 1111 1111 1111 1111\n#define DATA7MSB               (1UL << (DATA7WIDTH - 1))  //0b 1 0000 0000 0000 0000\n\n/** When the ENS210 is soldered a correction on T needs to be applied (see application note).\n *  Typically the correction is 50mK. Units for raw T is 1/64K. */\n#define ENS210_TRAW_SOLDERCORRECTION  (50*64/1000)\n\n/*****************************************************************************\n * Variables\n ****************************************************************************/\n\nstatic ens210_IoFunc_t sENS210_Func;\nstatic bool initDriverDone = false;\nstatic bool initHwDone = false;\n\n/*****************************************************************************\n * Private functions prototypes\n ****************************************************************************/\n\n/*\n * @brief   Compute the CRC7 results.\n * @param   val   :   the value\n * @return  The CRC7 computed result\n */\nstatic uint32_t ENS210_ComputeCRC7(uint32_t val);\n\n/*\n * @brief   Verify the CRC of the raw temperature or relative humidity.\n * @param   raw         :  Raw temperature or relative humidity value to be verified (#ENS210_TVal_Get, #ENS210_HVal_Get, #ENS210_THVal_Get).\n * @return  True - Success,  False - Failure.\n * @note    This function can be used on raw T as well as raw H data (since they use the same format and CRC).\n */\nstatic bool ENS210_IsCrcOk(uint32_t raw);\n\n/*\n * @brief   Verify data validity of the raw temperature or relative humidity.\n * @param   raw         :  Raw  temperature or relative humidity value to be verified (#ENS210_TVal_Get, #ENS210_HVal_Get, #ENS210_THVal_Get).\n * @return  True - Valid,  False - Invalid.\n */\nstatic bool ENS210_IsDataValid(uint32_t raw);\n\n/*\n * @brief   Converts a raw temperature value into Kelvin.\n *          The output value is in Kelvin multiplied by parameter \"multiplier\".\n * @param   traw        :   The temperature value in the raw format (#ENS210_TVal_Get, #ENS210_THVal_Get).\n * @param   multiplier  :   The multiplication factor.\n * @return  The temperature value in 1/multiplier Kelvin.\n * @note    The multiplier should be between 1 and 1024 (inclusive) to avoid overflows.\n * @note    Typical values for multiplier are 1, 10, 100, 1000, or powers of 2.\n */\nstatic int32_t ENS210_ConvertRawToKelvin(uint32_t traw, int multiplier);\n\n/*\n * @brief   Converts a raw temperature value into Celsius.\n *          The output value is in Celsius multiplied by parameter \"multiplier\".\n * @param   traw         :   The temperature value in the raw format (#ENS210_TVal_Get, #ENS210_THVal_Get).\n * @param   multiplier   :   The multiplication factor.\n * @return  The temperature value in 1/multiplier Celsius.\n * @note    The multiplier should be between 1 and 1024 (inclusive) to avoid overflows.\n * @note    Typical values for multiplier are 1, 10, 100, 1000, or powers of 2.\n */\nstatic int32_t ENS210_ConvertRawToCelsius(uint32_t traw, int multiplier);\n\n/*\n * @brief   Converts a raw temperature value into Fahrenheit.\n *          The output value is in Fahrenheit multiplied by parameter \"multiplier\".\n * @param   traw         :   The temperature value in the raw format (#ENS210_TVal_Get, #ENS210_THVal_Get).\n * @param   multiplier   :   The multiplication factor of the converted temperature\n * @return  The temperature value in 1/multiplier Fahrenheit.\n * @note    The multiplier should be between 1 and 1024 (inclusive) to avoid overflows.\n * @note    Typical values for multiplier are 1, 10, 100, or powers of 2.\n */\nstatic int32_t ENS210_ConvertRawToFahrenheit(uint32_t traw, int multiplier);\n\n/*\n * @brief   Converts a raw relative humidity value into human readable format.\n * @param   hraw         :   The relative humidity value in the raw format (#ENS210_HVal_Get, #ENS210_THVal_Get).\n * @param   multiplier   :   The multiplication factor of the converted relative humidity.\n * @return  The converted relative humidity value\n * @note    The multiplier should be between 1 and 1024 (inclusive) to avoid overflows.\n * @note    Typical values for multiplier are 1, 10, 100, 1000, or powers of 2.\n */\nstatic int32_t ENS210_ConvertRawToPercentageH(uint32_t hraw, int multiplier);\n\n/*****************************************************************************\n * Private functions\n ****************************************************************************/\n\n//Compute the CRC-7 of 'val' (which should only have 17 bits)\nstatic uint32_t ENS210_ComputeCRC7(uint32_t val)\n{\n    //Setup polynomial\n    uint32_t pol= CRC7POLY;\n\n    //Align polynomial with data\n    pol = pol << (DATA7WIDTH-CRC7WIDTH-1);\n\n    //Loop variable (indicates which bit to test, start with highest)\n    uint32_t bit = DATA7MSB;\n\n    //Make room for CRC value\n    val = val << CRC7WIDTH;\n    bit = bit << CRC7WIDTH;\n    pol = pol << CRC7WIDTH;\n\n    //Insert initial vector\n    val |= CRC7IVEC;\n\n    //Apply division until all bits done\n    while( bit & (DATA7MASK<<CRC7WIDTH) )\n    {\n        if( bit & val )\n        {\n            val ^= pol;\n        }\n        bit >>= 1;\n        pol >>= 1;\n    }\n    return val;\n}\n\n//Verify the CRC\nstatic bool ENS210_IsCrcOk(uint32_t raw)\n{\n    uint32_t crc, data;\n\n    assert(raw <= 0xffffffUL);\n\n    //Extract 7-bit CRC(Bit-17 to Bit-23)\n    crc =  (raw >> 17) & 0x7F;\n\n    //Get the raw T/H and data valid indication.\n    data =  raw & 0x1ffff;\n\n    return ENS210_ComputeCRC7(data) == crc;\n}\n\n//Check the Data Valid Bit\nstatic bool ENS210_IsDataValid(uint32_t raw)\n{\n    assert(raw <= 0xffffffUL);\n\n    //Bit-16 is data valid bit. It will be set if data is valid\n    return (raw & (1UL << 16)) != 0;\n}\n\n//Convert raw temperature to Kelvin\n//The output value is in Kelvin multiplied by parameter \"multiplier\"\nstatic int32_t ENS210_ConvertRawToKelvin(uint32_t traw, int multiplier)\n{\n    int32_t t;\n\n    assert((1 <= multiplier) && (multiplier <= 1024));\n\n    //Get the raw temperature\n    t = traw & ENS210_T_H_MASK;\n\n    //Compensate for soldering effect\n    t-= ENS210_TRAW_SOLDERCORRECTION;\n\n    //We must compute and return m*K\n    //where m is the multiplier, R the raw value and K is temperature in Kelvin.\n    //K=R/64 (since raw has format 10.6).\n    //m*K =  m*R/64\n    return IDIV(t*multiplier, 64);\n}\n\n//Convert raw temperature to Celsius\n//The output value is in Celsius multiplied by parameter \"multiplier\"\nstatic int32_t ENS210_ConvertRawToCelsius(uint32_t traw, int multiplier)\n{\n    int32_t t;\n\n    assert((1 <= multiplier) && (multiplier <= 1024));\n\n    //Get the raw temperature\n    t = traw & ENS210_T_H_MASK;\n\n    //Compensate for soldering effect\n    t-= ENS210_TRAW_SOLDERCORRECTION;\n\n    //We must compute and return m*C\n    //where m is the multiplier, R the raw value and K, C, F temperature in various units.\n    //We use C=K-273.15 and K=R/64 (since raw has format 10.6).\n    //m*C = m*(K-273.15) = m*K - 27315*m/100 = m*R/64 - 27315*m/100\n\n    return IDIV(t*multiplier, 64) - IDIV(27315L*multiplier, 100);\n}\n\n//Convert raw temperature to Fahrenheit\n//The output value is in Fahrenheit multiplied by parameter \"multiplier\"\nstatic int32_t ENS210_ConvertRawToFahrenheit(uint32_t traw, int multiplier)\n{\n    int32_t t;\n\n    assert((1 <= multiplier) && (multiplier <= 1024));\n\n    //Get the raw temperature\n    t = traw & ENS210_T_H_MASK;\n\n    //Compensate for soldering effect\n    t-= ENS210_TRAW_SOLDERCORRECTION;\n\n    //We must compute and return m*F\n    //where m is the multiplier, R the raw value and K, C, F temperature in various units.\n    //We use F=1.8*(K-273.15)+32 and K=R/64 (since raw has format 10.6).\n\n    //m*F = m*(1.8*(K-273.15)+32) = m*(1.8*K-273.15*1.8+32) = 1.8*m*K-459.67*m = 9*m*K/5 - 45967*m/100 = 9*m*R/320 - 45967*m/100\n    return IDIV(9*multiplier*t, 320) - IDIV(45967L*multiplier, 100);\n\n    //The first multiplication stays below 32 bits (tRaw:16, multiplier:11, 9:4)\n    //The second  multiplication stays below 32 bits (multiplier:10, 45967:16)\n}\n\n//Convert raw relative humidity to readable format\n//The output value is in % multiplied by parameter \"multiplier\"\nstatic int32_t ENS210_ConvertRawToPercentageH(uint32_t hraw, int multiplier)\n{\n    int32_t h;\n\n    assert((1 <= multiplier) && (multiplier <= 1024));\n\n    //Get the raw relative humidity\n    h = hraw & ENS210_T_H_MASK;\n\n    //As raw format is 7.9, to obtain the relative humidity, it must be divided by 2^9\n    return IDIV(h*multiplier, 512);\n}\n\n/*****************************************************************************\n * Public functions\n ****************************************************************************/\n\n// wrap the low level function (I2C write, I2C read, WaitMsec) required by ENS210 driver\n// this function does not initialize the HW\nvoid ENS210_Init_Driver(ens210_IoFunc_t* pIoFunc){\n    assert((pIoFunc != NULL) &&\n            (pIoFunc->I2C_Read != NULL) &&\n            (pIoFunc->I2C_Write != NULL) &&\n            (pIoFunc->WaitMsec != NULL));\n    sENS210_Func = *pIoFunc;\n    initDriverDone = true;\n}\n\n// De-initialize the driver\nvoid ENS210_Deinit_Driver(){\n    if (initHwDone)\n    {\n        /* Deinit HW */\n        ENS210_SysCtrl_Set(ENS210_SYSCTRL_LOWPOWER_ENABLE); // skip error management\n    }\n\n    /* Deinit driver */\n    initDriverDone = false;\n    initHwDone = false;\n}\n\n// Initialize ENS210 hardware\nens210_status_t ENS210_Init_Hw(void)\n{\n    ens210_status_t status = ens210_success;\n\n    if (!initDriverDone) return ens210_noinit;\n\n    /* trick to allow calling internal public functions */\n    initHwDone = true;\n\n    //Reset the sensor\n    status = ENS210_SysCtrl_Set(ENS210_SYSCTRL_RESET_ENABLE | ENS210_SYSCTRL_LOWPOWER_ENABLE);\n    if (status != ens210_success) goto return_status;\n\n    //Wait for ENS210 to complete reset\n    sENS210_Func.WaitMsec(ENS210_RESET_WAIT_TIME_MS);\n\n    //Set the run mode of sensors\n    status = ENS210_SensRun_Set(ENS210_SENSRUN_T_MODE_SINGLE_SHOT | ENS210_SENSRUN_H_MODE_SINGLE_SHOT);\n    if (status != ens210_success) goto return_status;\n\n    return_status:\n    if (status != ens210_success) initHwDone = false;\n    return status;\n}\n\n//Set ENS210 SysCtrl register; enabling reset and/or low power\nens210_status_t ENS210_SysCtrl_Set(uint8_t sysCtrl)\n{\n    uint8_t wBuf[] = {ENS210_REG_SYS_CTRL, sysCtrl};\n\n    if (!initHwDone) return ens210_noinit;\n    assert((sysCtrl & ~(ENS210_SYSCTRL_LOWPOWER_ENABLE | ENS210_SYSCTRL_RESET_ENABLE)) == 0);\n\n    return (ens210_status_t)sENS210_Func.I2C_Write(wBuf, sizeof (wBuf));\n}\n\n//Get ENS210 SysCtrl register\nens210_status_t ENS210_SysCtrl_Get(uint8_t *sysCtrl)\n{\n    uint8_t wBuf[] = {ENS210_REG_SYS_CTRL};\n\n    if (!initHwDone) return ens210_noinit;\n    assert(sysCtrl != NULL);\n\n    return (ens210_status_t)sENS210_Func.I2C_Read(wBuf, sizeof (wBuf), sysCtrl, sizeof (*sysCtrl));\n}\n\n//Get ENS210 SysStat register.\nens210_status_t ENS210_SysStat_Get(uint8_t *sysStat)\n{\n    uint8_t wBuf[] = {ENS210_REG_SYS_STAT};\n\n    if (!initHwDone) return ens210_noinit;\n    assert(sysStat != NULL);\n\n    return (ens210_status_t)sENS210_Func.I2C_Read(wBuf, sizeof (wBuf), sysStat, sizeof (*sysStat));\n}\n\n//Set ENS210 SensRun register; set the run mode single shot/continuous for T and H sensors.\nens210_status_t ENS210_SensRun_Set(uint8_t sensRun)\n{\n    uint8_t wBuf[] = {ENS210_REG_SENS_RUN, sensRun};\n\n    if (!initHwDone) return ens210_noinit;\n    assert((sensRun & ~(ENS210_SENSRUN_T_MODE_CONTINUOUS | ENS210_SENSRUN_H_MODE_CONTINUOUS)) == 0);\n\n    return (ens210_status_t)sENS210_Func.I2C_Write(wBuf, sizeof wBuf);\n}\n\n//Get ENS210 SensRun register\nens210_status_t ENS210_SensRun_Get(uint8_t *sensRun)\n{\n    uint8_t wBuf[] = {ENS210_REG_SENS_RUN};\n\n    if (!initHwDone) return ens210_noinit;\n    assert(sensRun != NULL);\n\n    return (ens210_status_t)sENS210_Func.I2C_Read(wBuf, sizeof wBuf, sensRun, sizeof *sensRun);\n}\n\n//Set ENS210 SensStart register; starts the measurement for T and/or H sensors.\nens210_status_t ENS210_SensStart_Set(uint8_t sensStart)\n{\n    uint8_t wBuf[] = {ENS210_REG_SENS_START, sensStart};\n\n    if (!initHwDone) return ens210_noinit;\n    assert((sensStart & ~(ENS210_SENSSTART_T_START | ENS210_SENSSTART_H_START)) == 0);\n\n    return (ens210_status_t)sENS210_Func.I2C_Write(wBuf, sizeof wBuf);\n}\n\n//Set ENS210 SensStop register; stops the measurement for T and/or H sensors.\nens210_status_t ENS210_SensStop_Set(uint8_t sensStop)\n{\n    uint8_t wBuf[] = {ENS210_REG_SENS_STOP, sensStop};\n\n    if (!initHwDone) return ens210_noinit;\n    assert((sensStop & ~(ENS210_SENSSTOP_T_STOP | ENS210_SENSSTOP_H_STOP)) == 0);\n\n    return (ens210_status_t)sENS210_Func.I2C_Write(wBuf, sizeof wBuf);\n}\n\n//Get ENS210 SensStat register.\nens210_status_t ENS210_SensStat_Get(uint8_t *sensStat)\n{\n    uint8_t wBuf[] = {ENS210_REG_SENS_STAT};\n\n    if (!initHwDone) return ens210_noinit;\n    assert(sensStat != NULL);\n\n    return (ens210_status_t)sENS210_Func.I2C_Read(wBuf, sizeof wBuf, sensStat, sizeof *sensStat);\n}\n\n//Get ENS210 TVal register; raw measurement data as well as CRC and valid indication\nens210_status_t ENS210_TVal_Get(uint32_t *traw)\n{\n    uint8_t rBuf[3];\n    uint8_t wBuf[] = {ENS210_REG_T_VAL};\n    ens210_status_t status;\n\n    if (!initHwDone) return ens210_noinit;\n    assert(traw != NULL);\n\n    status = (ens210_status_t)sENS210_Func.I2C_Read(wBuf, sizeof wBuf, rBuf, sizeof rBuf);\n\n    *traw = ((uint32_t)rBuf[2]) << 16 | ((uint32_t)rBuf[1]) << 8 | (uint32_t)rBuf[0];\n\n    return status;\n}\n\n//Get ENS210 HVal register; raw measurement data as well as CRC and valid indication\nens210_status_t ENS210_HVal_Get(uint32_t *hraw)\n{\n    uint8_t rBuf[3];\n    uint8_t wBuf[] = {ENS210_REG_H_VAL};\n    ens210_status_t status;\n\n    if (!initHwDone) return ens210_noinit;\n    assert(hraw != NULL);\n\n    status = (ens210_status_t)sENS210_Func.I2C_Read(wBuf, sizeof wBuf, rBuf, sizeof rBuf);\n\n    *hraw = ((uint32_t)rBuf[2]) << 16 | ((uint32_t)rBuf[1]) << 8 | ((uint32_t)rBuf[0]) << 0;\n\n    return status;\n}\n\n//Get ENS210 TVal and Hval registers; raw measurement data as well as CRC and valid indication\nens210_status_t ENS210_THVal_Get(uint32_t *traw, uint32_t *hraw)\n{\n    uint8_t rBuf[6];\n    uint8_t wBuf[] = {ENS210_REG_T_VAL};\n    ens210_status_t status;\n\n    if (!initHwDone) return ens210_noinit;\n    assert((traw != NULL) && (hraw != NULL));\n\n    // Read 6 bytes starting from ENS210_REG_T_VAL\n    status = (ens210_status_t)sENS210_Func.I2C_Read(wBuf, sizeof wBuf, rBuf, sizeof rBuf);\n\n    *traw = ((uint32_t)rBuf[2]) << 16 | ((uint32_t)rBuf[1]) << 8 | (uint32_t)rBuf[0];\n    *hraw = ((uint32_t)rBuf[5]) << 16 | ((uint32_t)rBuf[4]) << 8 | (uint32_t)rBuf[3];\n\n    return status;\n}\n\n// Get ENS210 Part ID and UID.\nens210_status_t ENS210_Ids_Get(ENS210_Ids_t *ids)\n{\n    uint8_t rBuf[12];\n    uint8_t wBuf[] = {ENS210_REG_PART_ID};\n    ens210_status_t status;\n\n    if (!initHwDone) return ens210_noinit;\n    assert(ids != NULL);\n\n    // Special procedure needed to read ID's: put device in high power (see datasheet)\n    // Set the system in Active mode\n    status = ENS210_SysCtrl_Set(ENS210_SYSCTRL_LOWPOWER_DISABLE);\n    if (status != ens210_success) goto return_error_status;\n\n    // Wait for sensor to go to active mode\n    sENS210_Func.WaitMsec(ENS210_BOOTING_TIME_MS);\n\n    // Get the id's\n    status = (ens210_status_t)sENS210_Func.I2C_Read(wBuf, sizeof wBuf, rBuf, sizeof rBuf);\n    if (status != ens210_success) goto return_error_status;\n\n    // Copy id's (hw gives partid in little-endian format)\n    ids->partId = ((uint32_t)rBuf[1]) << 8 | ((uint32_t)rBuf[0]) << 0;\n    memcpy(&ids->uId[0], &rBuf[4], 8);\n\n    // Go back to low power mode\n    status = ENS210_SysCtrl_Set(ENS210_SYSCTRL_LOWPOWER_ENABLE);\n    if (status != ens210_success) goto return_error_status;\n\n    // Signal success\n    return status;\n\n    return_error_status:\n    // Make an attempt to restore low-power\n    ENS210_SysCtrl_Set(ENS210_SYSCTRL_LOWPOWER_ENABLE);\n    // Return original I2C error\n    return status;\n}\n\nens210_status_t ENS210_Measure(uint8_t meas_mode, ens210_meas_data_t *results){\n    ens210_status_t status;\n    uint8_t meas_status;\n    uint32_t T_Raw = 0, H_Raw = 0;\n    uint32_t conversion_time_ms = 0;\n    uint8_t start_meas = 0;\n\n    if (!initHwDone) return ens210_noinit;\n    assert(results != NULL);\n\n    switch (meas_mode){\n    case mode_TH :\n        conversion_time_ms = ENS210_T_H_CONVERSION_TIME_MS;\n        start_meas = ENS210_SENSSTART_T_START | ENS210_SENSSTART_H_START;\n        break;\n    case mode_Tonly :\n        conversion_time_ms = ENS210_T_CONVERSION_TIME_MS;\n        start_meas = ENS210_SENSSTART_T_START;\n        break;\n    case mode_Honly :\n        conversion_time_ms = ENS210_T_H_CONVERSION_TIME_MS;\n        start_meas = ENS210_SENSSTART_H_START;\n        break;\n    default :\n        return ens210_wrong_parameter;\n        break;\n    }\n\n    //check that the previous measurement is completed\n    status = ENS210_SensStat_Get(&meas_status);\n    if (status != ens210_success){\n        return status;\n    }\n    if(meas_status != 0){\n        // trying to start a measurement too early!\n        sENS210_Func.WaitMsec(conversion_time_ms);\n    }\n\n    //Start the measurement\n    status = ENS210_SensStart_Set(start_meas);\n    if(status != ens210_success){\n        //Start of measurement failed.\n        return status;\n    }\n\n    // wait for the measurement to be completed\n    sENS210_Func.WaitMsec(conversion_time_ms);\n\n    if (meas_mode == mode_TH){\n        //Get the temperature and humidity raw value\n        status = ENS210_THVal_Get(&T_Raw, &H_Raw);\n    }\n    else if (meas_mode == mode_Tonly){\n        status = ENS210_TVal_Get(&T_Raw);\n    }\n    else if (meas_mode == mode_Honly){\n        status = ENS210_HVal_Get(&H_Raw);\n    }\n    if(status != ens210_success){\n        //Getting T and/or H values failed\n        return status;\n    }\n\n    if ((meas_mode == mode_TH) || (meas_mode == mode_Tonly)){\n        // Verify the temperature raw value\n        if(!ENS210_IsCrcOk(T_Raw))    {\n            return ens210_Tdata_CRC_error;\n        }\n        else if(!ENS210_IsDataValid(T_Raw)){\n            return ens210_T_invalid_data;\n        }\n        else {\n            //Convert the raw temperature value to Kelvin\n            results->T_Kelvin = ENS210_ConvertRawToKelvin(T_Raw, 1);\n            //Convert the raw temperature value to Celsius\n            results->T_Celsius = ENS210_ConvertRawToCelsius(T_Raw, 1);\n            //Convert the raw temperature value to Fahrenheit\n            results->T_Fahrenheit = ENS210_ConvertRawToFahrenheit(T_Raw, 1);\n            //Convert the raw temperature value to milli Kelvin\n            results->T_mKelvin = ENS210_ConvertRawToKelvin(T_Raw, 1000);\n            //Convert the raw temperature value to milli Celsius\n            results->T_mCelsius = ENS210_ConvertRawToCelsius(T_Raw, 1000);\n            //Convert the raw temperature value to milli Fahrenheit\n            results->T_mFahrenheit = ENS210_ConvertRawToFahrenheit(T_Raw, 1000);\n        }\n    }\n\n    if ((meas_mode == mode_TH) || (meas_mode == mode_Honly)){\n        //Verify the relative humidity raw value\n        if(!ENS210_IsCrcOk(H_Raw)){\n            return ens210_Hdata_CRC_error;\n        }\n        else if(!ENS210_IsDataValid(H_Raw)){\n            return ens210_H_invalid_data;\n        }\n        else {\n            //Convert the raw relative humidity to %\n            results->H_Percent = ENS210_ConvertRawToPercentageH(H_Raw, 1);\n            //Convert the raw relative humidity to milli%\n            results->H_mPercent = ENS210_ConvertRawToPercentageH(H_Raw, 1000);\n        }\n    }\n    return ens210_success;\n}\n"
              }
            }
          },
          "md5": "516f35701bb297c9650a1630fd000cfa"
        },
        "ccs811": {
          "libName": "ccs811",
          "manufacturer": "AMS",
          "description": "Indoor Air Quality (IAQ) Sensor",
          "type": "Digital Gas Sensor",
          "icon": "",
          "image": "ccs811.jpg",
          "version": "",
          "eelVersion": "3",
          "shoppingCartLinks": {
            "digikey": {
              "links": {
                "info": "https://www.digikey.com/short/j21j7h"
              },
              "cartData": {
                "part": "CCS811-LG_EK_ST-ND",
                "partid": "6568935",
                "source": "dkstudio",
                "qty": "1"
              }
            }
          },
          "requires": [
            "embedded",
            "i2c",
            "fpmath"
          ],
          "elements": [
            {
              "name": "CCS811AirQuality",
              "type": "EmbeddedCCS811",
              "icon": "EmbeddedAirQuality.svg",
              "defaultAbility": "readTVOC",
              "defaultTrigger": "TVOCRead",
              "hidden": false,
              "abilities": [
                {
                  "name": "setup",
                  "hidden": true,
                  "code": "\tATMO_CCS811_Config_t config;\n\tconfig.operatingMode = ATMO_PROPERTY(undefined, operatingMode);\n\tconfig.address = ATMO_PROPERTY(undefined, i2cAddress);\n\tconfig.i2cDriverInstance = ATMO_PROPERTY(undefined, i2cInstance);\n\n\treturn ( ATMO_CCS811_Init(&config) == ATMO_CCS811_Status_Success ) ? ATMO_Status_Success : ATMO_Status_Fail;\n"
                },
                {
                  "name": "setEnabled",
                  "triggers": [],
                  "code": "ATMO_CCS811_SetEnabled(true);\nreturn ATMO_Status_Success;"
                },
                {
                  "name": "setDisabled",
                  "triggers": [],
                  "code": "ATMO_CCS811_SetEnabled(false);\nreturn ATMO_Status_Success;"
                },
                {
                  "name": "setEnabledDisabled",
                  "triggers": [],
                  "code": "bool enabled = false;\nATMO_GetBool(in, &enabled);\nATMO_CCS811_SetEnabled(enabled);\nreturn ATMO_Status_Success;"
                },
                {
                  "name": "readTVOC",
                  "triggers": [
                    "TVOCRead"
                  ],
                  "code": "    uint16_t tvoc;\n\n    if(ATMO_CCS811_GetTVOC(&tvoc) == ATMO_CCS811_Status_Success)\n    {\n        ATMO_CreateValueUnsignedInt(out, (unsigned int)tvoc);\n    }\n    else\n    {\n        ATMO_CreateValueVoid(out);\n    }\n    \n    return ATMO_Status_Success;"
                },
                {
                  "name": "readCO2",
                  "triggers": [
                    "CO2Read"
                  ],
                  "code": "    uint16_t co2;\n    \n    if(ATMO_CCS811_GetCO2(&co2) == ATMO_CCS811_Status_Success)\n    {\n        ATMO_CreateValueInt(out, (int)co2);\n    }\n    else\n    {\n        ATMO_CreateValueVoid(out);\n    }\n  \n    return ATMO_Status_Success;"
                }
              ],
              "properties": [
                {
                  "name": "i2cInstance",
                  "input": "number",
                  "value": "ATMO_DEFAULT_I2C"
                },
                {
                  "name": "i2cAddress",
                  "input": "number",
                  "value": "0x5A"
                },
                {
                  "name": "operatingMode",
                  "input": "number",
                  "value": "1"
                }
              ],
              "triggers": [],
              "variables": [],
              "language": {
                "en-US": {
                  "EmbeddedCCS811": "AMS CCS811",
                  "i2cInstance": "I2C Driver Instance",
                  "i2cAddress": "I2C Address",
                  "operatingMode": "Operating Mode",
                  "setEnabled": "Set Enabled",
                  "setDisabled": "Set Disabled",
                  "setEnabledDisabled": "Set Enabled State",
                  "readTVOC": "Read TVOC (ppb)",
                  "readCO2": "Read CO2 (ppm)",
                  "TVOCRead": "TVOC Read",
                  "CO2Read": "CO2 Read"
                }
              }
            }
          ],
          "files": {
            "common": {
              "headers": {
                "ccs811.h": "#ifndef _ATMO_CCS811_H_\r\n#define _ATMO_CCS811_H_\r\n\r\n#include \"../app_src/atmosphere_platform.h\"\r\n#include \"../i2c/i2c.h\"\r\n\r\n\r\ntypedef enum {\r\n    ATMO_CCS811_Status_Success              = 0x00u,  // Common - Operation was successful\r\n    ATMO_CCS811_Status_Fail                 = 0x01u,  // Common - Operation failed\r\n    ATMO_CCS811_Status_Initialized          = 0x02u,  // Common - Peripheral already initialized\r\n    ATMO_CCS811_Status_Invalid              = 0x03u,  // Common - Invalid operation or result\r\n    ATMO_CCS811_Status_NotSupported         = 0x04u,  // Common - Feature not supported by platform\r\n} ATMO_CCS811_Status_t;\r\n\r\ntypedef struct {\r\n\t//Mode 0 = Idle\r\n\t//Mode 1 = read every 1s\r\n\t//Mode 2 = every 10s\r\n\t//Mode 3 = every 60s\r\n\t//Mode 4 = RAW mode\r\n\tuint8_t operatingMode;\r\n    uint16_t address;\r\n    ATMO_DriverInstanceHandle_t i2cDriverInstance;\r\n} ATMO_CCS811_Config_t;\r\n\r\n\r\n/**\r\n * Initialize CCS811 Driver\r\n *\r\n * @param[in] config - Device configuration (optional)\r\n */\r\nATMO_CCS811_Status_t ATMO_CCS811_Init(ATMO_CCS811_Config_t *config);\r\n\r\n/**\r\n * Enable/Disable CCS811 Driver\r\n *\r\n * @param[in] enabled\r\n */\r\nATMO_CCS811_Status_t ATMO_CCS811_SetEnabled(bool enabled);\r\n\r\n/**\r\n * Get enabled/disabled status of CCS811 driver\r\n *\r\n * @param[out] enabled\r\n */\r\nATMO_CCS811_Status_t ATMO_CCS811_GetEnabled(bool *enabled);\r\n\r\n/**\r\n * Set basic device configuration\r\n *\r\n * @param[in] config\r\n */\r\nATMO_CCS811_Status_t ATMO_CCS811_SetConfiguration(const ATMO_CCS811_Config_t *config);\r\n\r\n/**\r\n * Get device configuration\r\n *\r\n * @param[out] config\r\n */\r\nATMO_CCS811_Status_t ATMO_CCS811_GetConfiguration(ATMO_CCS811_Config_t *config);\r\n\r\n/**\r\n * Set environmental data for more accurate readings\r\n *\r\n * @param[in] humidity - Pct from 0.0 to 100.0\r\n * @param[in] temperature - Degrees C\r\n */\r\nATMO_CCS811_Status_t ATMO_CCS811_SetEnvironmentalData(float humidity, float temperature);\r\n\r\n/**\r\n * Get Total Volatile Organic Compounds (TVOC) Reading\r\n *\r\n * @param[out] tvoc - TVOC reading in PPB\r\n */\r\nATMO_CCS811_Status_t ATMO_CCS811_GetTVOC(uint16_t *tvoc);\r\n\r\n/**\r\n * Get total CO2 Reading in ppm\r\n *\r\n * @param[out] CO2\r\n */\r\nATMO_CCS811_Status_t ATMO_CCS811_GetCO2(uint16_t *co2);\r\n\r\n/**\r\n * Get air quality in percentage based on TVOC reading\r\n *\r\n * @param[out] airQuality\r\n */\r\nATMO_CCS811_Status_t ATMO_CCS811_GetAirQuality(float *airQuality);\r\n\r\n\r\n#endif\r\n",
                "ccs811_internal.h": "/******************************************************************************\r\nDerivative Work of\r\nSparkFunCCS811.cpp\r\nCCS811 Arduino library\r\nMarshall Taylor @ SparkFun Electronics\r\nNathan Seidle @ SparkFun Electronics\r\nApril 4, 2017\r\nhttps://github.com/sparkfun/CCS811_Air_Quality_Breakout\r\nhttps://github.com/sparkfun/SparkFun_CCS811_Arduino_Library\r\nThis code is released under the [MIT License](http://opensource.org/licenses/MIT).\r\nPlease review the LICENSE.md file included with this example https://github.com/sparkfun/SparkFun_CCS811_Arduino_Library/blob/master/LICENSE.md .\r\nIf you have any questions or concerns with licensing, please contact techsupport@sparkfun.com.\r\nThe MIT License (MIT)\r\nCopyright (c) 2015 SparkFun Electronics\r\nCopyright (c) 2018 NXP\r\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\r\nto deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,\r\nand/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\r\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\r\nWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r\nDistributed as-is; no warranty is given.\r\n******************************************************************************/\r\n\r\n#ifndef CCS811_H_\r\n#define CCS811_H_\r\n\r\n/*!\r\n * @addtogroup ccs811 CCS811 air quality sensor\r\n * This module provides the API to control and monitor the CCS811 air quality sensor through an I2C interface.\r\n *\r\n * The basic steps to operate the CCS811 are as follows:\r\n * -# Initialize the driver with callback functions (#CCS811_Init_Driver)\r\n * -# Initialize the hardware (#CCS811_Init_Hw)\r\n * -# Check data availability (#CCS811_dataAvailable)\r\n * -# Trigger all data acquisition (#CCS811_readAlgorithmResults)\r\n * -# Read the relevant data (for example #CCS811_getCO2)\r\n * -# If the CCS811 is not needed anymore, de-initialize the driver (#CCS811_Deinit_Driver). The CCS811 will\r\n * be switched off. It allows to eventually release shared resources.\r\n *\r\n * Example - Sample application code to set CCS811 without error management\r\n * ------------------------------------------------------------------------\r\n * @code\r\n * \\#include \"CCS811.h\"\r\n *\r\n * CCS811_fct_t ccs811_fct;\r\n * uint8_t ready;\r\n * uint16_t uCO2;\r\n *\r\n * ccs811_fct.connect_hw = Ccs811_Connect;       // callback function to activate CCS811 hardware resource\r\n * ccs811_fct.disconnect_hw = Ccs811_Disconnect; // callback function to deactivate CCS811 hardware resource\r\n * ccs811_fct.I2C_Read = I2c_Read;               // callback function for I2C read\r\n * ccs811_fct.I2C_Write = I2c_Write;             // callback function for I2C write\r\n * ccs811_fct.WaitMsec = WaitMs;                 // wait callback function (in ms)\r\n *\r\n * CCS811_Init_Driver(&ccs811_fct);\r\n * CCS811_Init_Hw();\r\n * // check new data availability\r\n * CCS811_dataAvailable(&ready);\r\n * if (ready == 1) {\r\n *     CCS811_readAlgorithmResults();\r\n *     uCO2 = CCS811_getCO2();\r\n *     printf(\"The current CO2 value is: %d\\n\", uCO2);\r\n * }\r\n * [..]\r\n * // if the CCS811 is not needed anymore, the driver can be de-initialized\r\n * printf(\"Deinitialize CCS811 (it will be turned off)\\n\");\r\n * CCS811_Deinit_Driver();\r\n *\r\n * @endcode\r\n * @{\r\n */\r\n\r\n#include \"../app_src/atmosphere_platform.h\"\r\n#include <stdbool.h>\r\n\r\n#define CCS811_I2C_ADDRESS              0x5A\r\n\r\n/* Register addresses */\r\n#define CCS811_STATUS                   0x00\r\n#define CCS811_MEAS_MODE                0x01\r\n#define CCS811_ALG_RESULT_DATA          0x02\r\n#define CCS811_RAW_DATA                 0x03\r\n#define CCS811_ENV_DATA                 0x05\r\n#define CCS811_NTC                      0x06\r\n#define CCS811_THRESHOLDS               0x10\r\n#define CCS811_BASELINE                 0x11\r\n#define CCS811_HW_ID                    0x20\r\n#define CCS811_HW_VERSION               0x21\r\n#define CCS811_FW_BOOT_VERSION          0x23\r\n#define CCS811_FW_APP_VERSION           0x24\r\n#define CCS811_ERROR_ID                 0xE0\r\n#define CCS811_APP_START                0xF4\r\n#define CCS811_SW_RESET                 0xFF\r\n#define CCS811_INTERRUPT_DRIVEN         0x8\r\n#define CCS811_THRESHOLDS_ENABLED       0x4\r\n\r\n/*! @brief Status return codes. */\r\ntypedef enum _CCS811_status\r\n{\r\n    CCS811_SUCCESS,        /*!< Success */\r\n    CCS811_ID_ERROR,       /*!< Bad hardware identifier */\r\n    CCS811_I2C_ERROR,      /*!< I2C read/write error */\r\n    CCS811_INTERNAL_ERROR, /*!< Internal hardware error */\r\n    CCS811_NOINIT_ERROR,   /*!< Hardware or driver not initialized */\r\n    CCS811_GENERIC_ERROR   /*!< Generic error (settings not allowed) */\r\n} CCS811_status;\r\n\r\n/*! @brief Structure of external functions or values. */\r\ntypedef struct _CCS811_fct_t\r\n{\r\n    uint8_t (*I2C_Read)(uint8_t *writeBuf, uint32_t writeSize, uint8_t *readBuf, uint32_t readSize); /*!< External I2C read function */\r\n    uint8_t (*I2C_Write)(uint8_t *writeBuf, uint32_t writeSize); /*!< External I2C write function */\r\n    void (*WaitMsec)(uint32_t tms); /*!< Wait function in milliseconds */\r\n} CCS811_fct_t, *ptCCS811_fct_t;\r\n\r\n/*!\r\n * @brief Initialize CCS811 driver.\r\n *\r\n * @param FCT Pointer to a structure of external functions or values\r\n */\r\nvoid CCS811_Init_Driver(ptCCS811_fct_t FCT);\r\n\r\n/*!\r\n * @brief De-initialize CCS811 driver.\r\n *\r\n */\r\nvoid CCS811_Deinit_Driver();\r\n\r\n/*!\r\n * @brief Initialize CCS811 hardware.\r\n *\r\n * @return Status value (0 for success)\r\n */\r\nCCS811_status CCS811_Init_Hw(void);\r\n\r\n/*!\r\n * @brief Read algorithm results.\r\n * @note Update the total volatile organic compounds (TVOC) in parts per billion (PPB) and the CO2 value.\r\n *\r\n * @return Status value (0 for success)\r\n */\r\nCCS811_status CCS811_readAlgorithmResults(void);\r\n\r\n/*!\r\n * @brief Check if error bit is set.\r\n *\r\n * @param  StatusError Pointer to error status bit value\r\n * @return Status value (0 for success)\r\n */\r\nCCS811_status CCS811_checkForStatusError(uint8_t* StatusError);\r\n\r\n/*!\r\n * @brief Check if data is available.\r\n * @note Based on DATA_READ flag in the status register.\r\n *\r\n * @param  value Pointer to available data bit value\r\n * @return Status value (0 for success)\r\n */\r\nCCS811_status CCS811_dataAvailable(uint8_t* value);\r\n\r\n/*!\r\n * @brief Check if APP_VALID is set.\r\n * @note Based on APP_VALID flag in the status register.\r\n *\r\n * @param  value Pointer to APP_VALID bit value\r\n * @return Status value (0 for success)\r\n */\r\nCCS811_status CCS811_appValid(uint8_t* value);\r\n\r\n/*!\r\n * @brief Get the error register value.\r\n * @note Based on ERROR_ID register.\r\n *\r\n * @param  value Pointer to error value\r\n * @return Status value (0 for success)\r\n */\r\nCCS811_status CCS811_getErrorRegister(uint8_t* value);\r\n\r\n/*!\r\n * @brief Get the baseline value.\r\n * @note It is used for telling sensor what 'clean' air is.\r\n * @note Put the sensor in clean air and record this value.\r\n *\r\n * @param  baseline Pointer to baseline value\r\n * @return Status value (0 for success)\r\n */\r\nCCS811_status CCS811_getBaseline(unsigned int* baseline);\r\n\r\n/*!\r\n * @brief Set the baseline value.\r\n * @note It is used for telling sensor what 'clean' air is.\r\n * @note Put the sensor in clean air and record this value.\r\n *\r\n * @param  input Baseline value\r\n * @return Status value (0 for success)\r\n */\r\nCCS811_status CCS811_setBaseline(uint16_t input);\r\n\r\n/*!\r\n * @brief Enable or disable the interrupts.\r\n * @note It clears/sets the nINT signal.\r\n *\r\n * @param  fct Interrupt mode (0 for disable, 1 for enable)\r\n * @return Status value (0 for success)\r\n */\r\nCCS811_status CCS811_setInterrupts(uint8_t fct);\r\n\r\n/*!\r\n * @brief Enable or disable the interrupt thresholds.\r\n *\r\n * @param  fct Threshold mode (0 for disable, 1 for enable)\r\n * @return Status value (0 for success)\r\n */\r\nCCS811_status CCS811_setThresholds(uint8_t fct);\r\n\r\n/*!\r\n * @brief Set the drive mode.\r\n * @note\r\n * Mode 0 = Idle\\n\r\n * Mode 1 = read every 1s\\n\r\n * Mode 2 = every 10s\\n\r\n * Mode 3 = every 60s\\n\r\n * Mode 4 = RAW mode\r\n *\r\n * @param  mode Drive mode\r\n * @return Status value (0 for success)\r\n */\r\nCCS811_status CCS811_setDriveMode(uint8_t mode);\r\n\r\n/*!\r\n * @brief Set environmental data.\r\n * @note\r\n * Given a temperature and humidity, use these data for better compensation.\r\n *\r\n * @param  relativeHumidity Relative humidity, value within [0,100]\r\n * @param  temperature Temperature (Celsius), value within [-25,+50]\r\n * @return Status value (0 for success)\r\n */\r\nCCS811_status CCS811_setEnvironmentalData(float relativeHumidity, float temperature);\r\n\r\n/*!\r\n * @brief Set ref resistance.\r\n *\r\n * @param  input Ref resistance\r\n */\r\nvoid CCS811_setRefResistance(float input);\r\n\r\n/*!\r\n * @brief Read NTC.\r\n *\r\n * @return Status value (0 for success)\r\n */\r\nCCS811_status CCS811_readNTC(void);\r\n\r\n/*!\r\n * @brief Get Total Volatile Organic Compound (TVOC) value.\r\n *\r\n * @return TVOC value (0ppb to 1187ppb)\r\n */\r\nuint16_t CCS811_getTVOC(void);\r\n\r\n/*!\r\n * @brief Get the equivalent CO2 value.\r\n *\r\n * @return eCO2 value (400ppm to 8192ppm)\r\n */\r\nuint16_t CCS811_getCO2(void);\r\n\r\n/*!\r\n * @brief Get resistance value.\r\n *\r\n * @return Resistance value\r\n */\r\nfloat CCS811_getResistance(void);\r\n\r\n/*!\r\n * @brief Get temperature value.\r\n *\r\n * @return Temperature value (Celsius)\r\n */\r\nfloat CCS811_getTemperature(void);\r\n\r\n/*! @}*/\r\n\r\n#endif /* CCS811_H_ */\r\n"
              },
              "objects": {
                "ccs811.c": "#include \"ccs811.h\"\r\n#include \"ccs811_internal.h\"\r\n#include \"../app_src/atmosphere_platform.h\"\r\n\r\n#define CCS811_TVOC_MAX_PPB (1187)\r\n\r\n\r\ntypedef struct {\r\n    ATMO_CCS811_Config_t config;\r\n    bool configured;\r\n} ATMO_CCS811_Priv_Config;\r\n\r\nstatic ATMO_CCS811_Priv_Config _ATMO_CCS811_config;\r\n\r\nstatic ATMO_I2C_Peripheral_t i2cConfig = {\r\n    .operatingMode = ATMO_I2C_OperatingMode_Master,\r\n    .baudRate = ATMO_I2C_BaudRate_Standard_Mode\r\n};\r\n\r\nstatic bool _ATMO_CCS811_Enabled = true;\r\n\r\nstatic uint8_t ATMO_CCS811_I2CRead_Simple(uint8_t *writeBuf, uint32_t writeSize, uint8_t *readBuf, uint32_t readSize)\r\n{\r\n\tATMO_I2C_Status_t status = ATMO_I2C_MasterRead(_ATMO_CCS811_config.config.i2cDriverInstance, _ATMO_CCS811_config.config.address, writeBuf, writeSize, readBuf, readSize, 1000);\r\n\treturn (status == ATMO_I2C_Status_Success) ? 0 : 1;\r\n}\r\n\r\nstatic uint8_t ATMO_CCS811_I2CWrite_Simple(uint8_t *writeBuf, uint32_t writeSize)\r\n{\r\n\tATMO_I2C_Status_t status = ATMO_I2C_MasterWrite(_ATMO_CCS811_config.config.i2cDriverInstance, _ATMO_CCS811_config.config.address, NULL, 0, writeBuf, writeSize, 1000);\r\n\treturn (status == ATMO_I2C_Status_Success) ? 0 : 1;\r\n}\r\n\r\nATMO_CCS811_Status_t ATMO_CCS811_Init(ATMO_CCS811_Config_t *config)\r\n{\r\n\r\n    CCS811_fct_t io;\r\n    io.I2C_Read = ATMO_CCS811_I2CRead_Simple;\r\n    io.I2C_Write = ATMO_CCS811_I2CWrite_Simple;\r\n    io.WaitMsec = ATMO_PLATFORM_DelayMilliseconds;\r\n    CCS811_Init_Driver(&io);\r\n\r\n    // Did the user supply a configuration?\r\n    if( config )\r\n    {\r\n        ATMO_CCS811_SetConfiguration(config);\r\n    }\r\n    else\r\n    {\r\n        _ATMO_CCS811_config.configured = false;\r\n    }\r\n\r\n    if( CCS811_Init_Hw() != CCS811_SUCCESS )\r\n    {\r\n    \treturn ATMO_CCS811_Status_Fail;\r\n    }\r\n\r\n    // The configuration has to be set before the Init_HW routine is called\r\n    // But the Init_HW routine resets the device\r\n    // So, we need to just set the configuration one more time after this reset\r\n    if( config )\r\n    {\r\n        ATMO_CCS811_SetConfiguration(config);\r\n    }\r\n\r\n    return ATMO_CCS811_Status_Success;\r\n}\r\n\r\nATMO_CCS811_Status_t ATMO_CCS811_SetEnabled(bool enabled)\r\n{\r\n    _ATMO_CCS811_Enabled = enabled;\r\n    return ATMO_CCS811_Status_Success;\r\n}\r\n\r\nATMO_CCS811_Status_t ATMO_CCS811_GetEnabled(bool *enabled)\r\n{\r\n    *enabled = _ATMO_CCS811_Enabled;\r\n    return ATMO_CCS811_Status_Success;\r\n}\r\n\r\nATMO_CCS811_Status_t ATMO_CCS811_SetConfiguration(const ATMO_CCS811_Config_t *config)\r\n{\r\n    if( config == NULL )\r\n    {\r\n        return ATMO_CCS811_Status_Fail;\r\n    }\r\n\r\n    if( ATMO_I2C_SetConfiguration(config->i2cDriverInstance, &i2cConfig) != ATMO_I2C_Status_Success )\r\n    {\r\n        return ATMO_CCS811_Status_Fail;\r\n    }\r\n    memcpy( &_ATMO_CCS811_config.config, config, sizeof(ATMO_CCS811_Config_t) );\r\n    _ATMO_CCS811_config.configured = true;\r\n\r\n    if( CCS811_setDriveMode(config->operatingMode) != CCS811_SUCCESS )\r\n    {\r\n    \treturn ATMO_CCS811_Status_Fail;\r\n    }\r\n\r\n    return ATMO_CCS811_Status_Success;\r\n}\r\n\r\nATMO_CCS811_Status_t ATMO_CCS811_GetConfiguration(ATMO_CCS811_Config_t *config)\r\n{\r\n    if( config == NULL || !_ATMO_CCS811_config.configured )\r\n    {\r\n        return ATMO_CCS811_Status_Fail;\r\n    }\r\n\r\n    memcpy(config, &_ATMO_CCS811_config.config, sizeof(ATMO_CCS811_Config_t));\r\n\r\n    return ATMO_CCS811_Status_Success;\r\n}\r\n\r\n\r\nATMO_CCS811_Status_t ATMO_CCS811_GetTVOC(uint16_t *tvoc)\r\n{\r\n    if(!_ATMO_CCS811_Enabled)\r\n    {\r\n        return ATMO_CCS811_Status_Fail;\r\n    }\r\n\r\n\tif( CCS811_readAlgorithmResults() != CCS811_SUCCESS )\r\n\t{\r\n\t\treturn ATMO_CCS811_Status_Fail;\r\n\t}\r\n\r\n\t*tvoc = CCS811_getTVOC();\r\n\r\n\treturn ATMO_CCS811_Status_Success;\r\n}\r\n\r\nATMO_CCS811_Status_t ATMO_CCS811_GetCO2(uint16_t *co2)\r\n{\r\n    if(!_ATMO_CCS811_Enabled)\r\n    {\r\n        return ATMO_CCS811_Status_Fail;\r\n    }\r\n\r\n\tif( CCS811_readAlgorithmResults() != CCS811_SUCCESS )\r\n\t{\r\n\t\treturn ATMO_CCS811_Status_Fail;\r\n\t}\r\n\r\n\t*co2 = CCS811_getCO2();\r\n\r\n\treturn ATMO_CCS811_Status_Success;\r\n}\r\n\r\n/**\r\n * Get air quality in percentage based on TVOC reading\r\n *\r\n * @param[out] airQuality\r\n */\r\nATMO_CCS811_Status_t ATMO_CCS811_GetAirQuality(float *airQuality)\r\n{\r\n    if(!_ATMO_CCS811_Enabled)\r\n    {\r\n        return ATMO_CCS811_Status_Fail;\r\n    }\r\n    \r\n\tif( CCS811_readAlgorithmResults() != CCS811_SUCCESS )\r\n\t{\r\n\t\treturn ATMO_CCS811_Status_Fail;\r\n\t}\r\n\r\n\t*airQuality = (CCS811_getTVOC() * 100.0) / CCS811_TVOC_MAX_PPB;\r\n\r\n\treturn ATMO_CCS811_Status_Success;\r\n}\r\n",
                "ccs811_internal.c": "/******************************************************************************\r\nDerivative Work of\r\nSparkFunCCS811.cpp\r\nCCS811 Arduino library\r\nMarshall Taylor @ SparkFun Electronics\r\nNathan Seidle @ SparkFun Electronics\r\n\r\nApril 4, 2017\r\n\r\nhttps://github.com/sparkfun/CCS811_Air_Quality_Breakout\r\nhttps://github.com/sparkfun/SparkFun_CCS811_Arduino_Library\r\n\r\nThis code is released under the [MIT License](http://opensource.org/licenses/MIT).\r\n\r\nPlease review the LICENSE.md file included with this example https://github.com/sparkfun/SparkFun_CCS811_Arduino_Library/blob/master/LICENSE.md .\r\nIf you have any questions or concerns with licensing, please contact techsupport@sparkfun.com.\r\n\r\nThe MIT License (MIT)\r\n\r\nCopyright (c) 2015 SparkFun Electronics\r\nCopyright (c) 2018 NXP\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\r\nto deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,\r\nand/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\r\n\r\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\r\nWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r\n\r\n\r\nDistributed as-is; no warranty is given.\r\n******************************************************************************/\r\n\r\n//CCS811.h for additional topology notes.\r\n\r\n#include \"ccs811_internal.h\"\r\n#include <math.h>\r\n#include <stdbool.h>\r\n#include <assert.h>\r\n\r\n/*****************************************************************************\r\n * Variables\r\n ****************************************************************************/\r\nstatic CCS811_fct_t FCT_CCS811;\r\nstatic bool initDriverDone = false;\r\nstatic bool initHwDone = false;\r\n\r\n/* air quality values obtained from the sensor */\r\nstatic float refResistance;\r\nstatic float resistance = 10000;\r\nstatic uint16_t tVOC = 0;\r\nstatic uint16_t CO2 = 0;\r\nstatic uint16_t vrefCounts = 0;\r\nstatic uint16_t ntcCounts = 0;\r\nstatic float temperature = 0;\r\n\r\n/*****************************************************************************\r\n * Static functions\r\n ****************************************************************************/\r\n\r\n/*\r\n * @brief Read a CCS811 register.\r\n *\r\n * @param  Address of the register to read\r\n * @param  Pointer to the read value\r\n * @return Status value of I2C read function (0 for success)\r\n */\r\nstatic uint8_t CCS811_readRegister(uint8_t offset, uint8_t* outputPointer)\r\n{\r\n    uint8_t cmd[2];\r\n\r\n    cmd[0] = offset;\r\n    return FCT_CCS811.I2C_Read(cmd, 1, outputPointer, 1);\r\n}\r\n\r\n/*\r\n * @brief Read several CCS811 registers.\r\n *\r\n * @param  Start address of the registers to read\r\n * @param  Pointer to the read values\r\n * @param  Number of consecutive registers to read\r\n * @return Status value of I2C read function (0 for success)\r\n */\r\nstatic uint8_t CCS811_multiReadRegister(uint8_t offset, uint8_t *outputPointer, uint8_t length)\r\n{\r\n    uint8_t cmd[2];\r\n\r\n    cmd[0] = offset;\r\n    return FCT_CCS811.I2C_Read(cmd, 1, outputPointer, length);\r\n}\r\n\r\n/*\r\n * @brief Write to a CCS811 register.\r\n *\r\n * @param  Address of the register to write to\r\n * @param  Value to write\r\n * @return Status value of I2C read function (0 for success)\r\n */\r\nstatic uint8_t CCS811_writeRegister(uint8_t offset, uint8_t dataToWrite)\r\n{\r\n\r\n    uint8_t cmd[2];\r\n\r\n    cmd[0] = offset;\r\n    cmd[1] = dataToWrite;\r\n\r\n    return FCT_CCS811.I2C_Write(cmd, 2);\r\n}\r\n\r\n/*\r\n * @brief Write to several CCS811 registers.\r\n *\r\n * @param  Start address of the registers to write to\r\n * @param  Pointer to the values to be written\r\n * @param  Number of consecutive registers to write to\r\n * @return Status value of I2C read function (0 for success)\r\n */\r\nstatic uint8_t CCS811_multiWriteRegister(uint8_t offset, uint8_t *inputPointer, uint8_t length)\r\n{\r\n    uint8_t cmd[length+1];\r\n    cmd[0] = offset;\r\n    for( uint32_t i = 0; i < length; i++ ) //This waits > 1ms @ 80MHz clock\r\n    {\r\n        cmd[1+i] = inputPointer[i];\r\n    }\r\n    return FCT_CCS811.I2C_Write(cmd, length+1);\r\n}\r\n\r\n\r\n/*****************************************************************************\r\n * Public functions\r\n ****************************************************************************/\r\n\r\nvoid CCS811_Init_Driver(ptCCS811_fct_t FCT)\r\n{\r\n    assert((FCT != NULL) &&\r\n            (FCT->I2C_Read != NULL) &&\r\n            (FCT->I2C_Write != NULL) &&\r\n            (FCT->WaitMsec != NULL));\r\n    FCT_CCS811 = *FCT;\r\n    initDriverDone = true;\r\n}\r\n\r\nvoid CCS811_Deinit_Driver()\r\n{\r\n    /* Deinit driver */\r\n    initDriverDone = false;\r\n    initHwDone = false;\r\n}\r\n\r\nCCS811_status CCS811_Init_Hw(void)\r\n{\r\n    uint8_t data[4] = {0x11,0xE5,0x72,0x8A}; /* reset key */\r\n    uint8_t status;\r\n    uint8_t val = 0;\r\n    CCS811_status error_status = CCS811_SUCCESS;\r\n\r\n    if (!initDriverDone) return CCS811_NOINIT_ERROR;\r\n\r\n    /* trick to allow calling internal public functions */\r\n    initHwDone = true;\r\n\r\n    /* check HW ID */\r\n    if (CCS811_readRegister( CCS811_HW_ID,  &val) != 0)\r\n    {\r\n        error_status = CCS811_I2C_ERROR;\r\n        goto return_status;\r\n    }\r\n    if (val != 0x81)\r\n    {\r\n        error_status = CCS811_INTERNAL_ERROR;\r\n        goto return_status;\r\n    }\r\n\r\n    /* reset the device */\r\n    if (CCS811_multiWriteRegister(CCS811_SW_RESET, data, 4)!=0)\r\n    {\r\n        error_status =  CCS811_I2C_ERROR;\r\n        goto return_status;\r\n    }\r\n\r\n    FCT_CCS811.WaitMsec(10);\r\n\r\n    if (CCS811_checkForStatusError(&status) == CCS811_I2C_ERROR)\r\n    {\r\n        error_status = CCS811_I2C_ERROR;\r\n        goto return_status;\r\n    }\r\n    if (status == true) return CCS811_INTERNAL_ERROR;\r\n\r\n    error_status = CCS811_appValid(&val);\r\n    if (error_status != CCS811_SUCCESS) goto return_status;\r\n    if (val == 0)\r\n    {\r\n        error_status =  CCS811_INTERNAL_ERROR;\r\n        goto return_status;\r\n    }\r\n\r\n    /* write 0 byte to this register to start app */\r\n    //if (CCS811_writeRegister(CCS811_APP_START, 0)!=0) return CCS811_I2C_ERROR;\r\n    val = CCS811_APP_START;\r\n    if (FCT_CCS811.I2C_Write(&val, 1))\r\n    {\r\n        error_status = CCS811_I2C_ERROR;\r\n        goto return_status;\r\n    }\r\n\r\n    /* read every second */\r\n    if (CCS811_setDriveMode(1))\r\n    {\r\n        error_status = CCS811_I2C_ERROR;\r\n        goto return_status;\r\n    }\r\n\r\n    return_status:\r\n    if (error_status != CCS811_SUCCESS) initHwDone = false;\r\n    return error_status;\r\n}\r\n\r\nCCS811_status CCS811_readAlgorithmResults(void)\r\n{\r\n    if (!initHwDone) return CCS811_NOINIT_ERROR;\r\n\r\n    uint8_t data[4];\r\n    if (CCS811_multiReadRegister(CCS811_ALG_RESULT_DATA, data, 4)!=0) return CCS811_I2C_ERROR;\r\n\r\n    /* data ordered: co2MSB, co2LSB, tvocMSB, tvocLSB */\r\n    CO2 = ((uint16_t)data[0] << 8) | data[1];\r\n    tVOC = ((uint16_t)data[2] << 8) | data[3];\r\n    return CCS811_SUCCESS;\r\n}\r\n\r\nCCS811_status CCS811_checkForStatusError(uint8_t* StatusError)\r\n{\r\n    if (!initHwDone) return CCS811_NOINIT_ERROR;\r\n    assert(StatusError != NULL);\r\n\r\n    /* read the status bit */\r\n    if (CCS811_readRegister(CCS811_STATUS, StatusError )!=0) return CCS811_I2C_ERROR;\r\n    *StatusError = *StatusError & 1 << 0; // bit ERROR\r\n    return CCS811_SUCCESS;\r\n}\r\n\r\nCCS811_status CCS811_dataAvailable(uint8_t* value)\r\n{\r\n    if (!initHwDone) return CCS811_NOINIT_ERROR;\r\n    assert(value != NULL);\r\n\r\n    if (CCS811_readRegister(CCS811_STATUS, value )!=0) return CCS811_I2C_ERROR;\r\n    *value = (*value &  1 << 3)>>3; // bit DATA_READY\r\n    return CCS811_SUCCESS;\r\n}\r\n\r\nCCS811_status CCS811_appValid(uint8_t* value)\r\n{\r\n    if (!initHwDone) return CCS811_NOINIT_ERROR;\r\n    assert(value != NULL);\r\n\r\n    if (CCS811_readRegister(CCS811_STATUS, value )!=0) return CCS811_I2C_ERROR;\r\n    *value = (*value &  1 << 4)>>4; // bit APP_VALID\r\n    return CCS811_SUCCESS;\r\n}\r\n\r\nCCS811_status CCS811_getErrorRegister(uint8_t* value)\r\n{\r\n    if (!initHwDone) return CCS811_NOINIT_ERROR;\r\n    assert(value != NULL);\r\n\r\n    *value=0xFF;\r\n    if (CCS811_readRegister(CCS811_ERROR_ID, value )!=0) return CCS811_I2C_ERROR;\r\n    return CCS811_SUCCESS;\r\n}\r\n\r\nCCS811_status CCS811_getBaseline(unsigned int* baseline)\r\n{\r\n    if (!initHwDone) return CCS811_NOINIT_ERROR;\r\n    assert(baseline != NULL);\r\n\r\n    uint8_t data[2];\r\n    if (CCS811_multiReadRegister(CCS811_BASELINE,data, 2)!=0) return CCS811_I2C_ERROR;\r\n\r\n    *baseline = ((uint16_t)data[0] << 8) | data[1];\r\n    return CCS811_SUCCESS;\r\n}\r\n\r\nCCS811_status CCS811_setBaseline(uint16_t input)\r\n{\r\n    if (!initHwDone) return CCS811_NOINIT_ERROR;\r\n\r\n    uint8_t data[2];\r\n    data[0] = (input >> 8) & 0x00FF;\r\n    data[1] = input & 0x00FF;\r\n\r\n    if (CCS811_multiWriteRegister(CCS811_BASELINE, data, 2)!=0) return CCS811_I2C_ERROR;\r\n    return CCS811_SUCCESS;\r\n}\r\n\r\nCCS811_status CCS811_setInterrupts(uint8_t fct)\r\n{\r\n    if (!initHwDone) return CCS811_NOINIT_ERROR;\r\n\r\n    uint8_t value;\r\n    if (CCS811_readRegister(CCS811_MEAS_MODE, &value )!=0) return CCS811_I2C_ERROR;\r\n    if (fct == 0)\r\n    {\r\n        value &= ~(CCS811_INTERRUPT_DRIVEN); /* clear INTERRUPT bit */\r\n    }\r\n    else\r\n    {\r\n        value |= (CCS811_INTERRUPT_DRIVEN); /* set INTERRUPT bit */\r\n    }\r\n\r\n    if (CCS811_writeRegister(CCS811_MEAS_MODE, value)!=0) return CCS811_I2C_ERROR;\r\n    return CCS811_SUCCESS;\r\n}\r\n\r\nCCS811_status CCS811_setThresholds(uint8_t fct)\r\n{\r\n    if (!initHwDone) return CCS811_NOINIT_ERROR;\r\n\r\n    uint8_t value;\r\n    if (CCS811_readRegister(CCS811_MEAS_MODE, &value )!=0) return CCS811_I2C_ERROR;\r\n    if (fct == 0)\r\n    {\r\n        value &= ~(CCS811_THRESHOLDS_ENABLED); /* clear THRESHOLDS bit */\r\n    }\r\n    else\r\n    {\r\n        value |= (CCS811_THRESHOLDS_ENABLED); /* set THRESHOLDS bit */\r\n    }\r\n\r\n    if (CCS811_writeRegister(CCS811_MEAS_MODE, value)!=0) return CCS811_I2C_ERROR;\r\n    return CCS811_SUCCESS;\r\n}\r\n\r\nCCS811_status CCS811_setDriveMode(uint8_t mode)\r\n{\r\n    if (!initHwDone) return CCS811_NOINIT_ERROR;\r\n\r\n    if (mode > 4) mode = 4; /* sanitize input */\r\n\r\n    uint8_t value;\r\n    if (CCS811_readRegister(CCS811_MEAS_MODE, &value)!=0) return CCS811_I2C_ERROR;\r\n    value &= ~(0b00000111 << 4); /* clear DRIVE_MODE bits */\r\n    value |= (mode << 4); /* mask in mode */\r\n    if (CCS811_writeRegister(CCS811_MEAS_MODE, value)!=0) return CCS811_I2C_ERROR;\r\n    return CCS811_SUCCESS;\r\n}\r\n\r\nCCS811_status CCS811_setEnvironmentalData(float relativeHumidity, float temperature)\r\n{\r\n    if (!initHwDone) return CCS811_NOINIT_ERROR;\r\n\r\n    /* check for invalid temperatures */\r\n    if ((temperature < -25) || (temperature > 50)) return CCS811_GENERIC_ERROR;\r\n\r\n    /* check for invalid humidity */\r\n    if ((relativeHumidity < 0) || (relativeHumidity > 100)) return CCS811_GENERIC_ERROR;\r\n\r\n    uint32_t rH = relativeHumidity * 1000; /* 42.348 becomes 42348 */\r\n    uint32_t temp = temperature * 1000; /* 23.2 becomes 23200 */\r\n\r\n    uint8_t envData[4];\r\n\r\n    /* split value into 7-bit integer and 9-bit fractional */\r\n    envData[0] = ((rH % 1000) / 100) > 7 ? (rH / 1000 + 1) << 1 : (rH / 1000) << 1;\r\n    envData[1] = 0; /* support only increments of 0.5 so bits 7-0 will always be zero */\r\n    if (((rH % 1000) / 100) > 2 && (((rH % 1000) / 100) < 8))\r\n    {\r\n        envData[0] |= 1; /* set 9th bit of fractional to indicate 0.5% */\r\n    }\r\n\r\n    temp += 25000; /* add the 25C offset */\r\n    /* split value into 7-bit integer and 9-bit fractional */\r\n    envData[2] = ((temp % 1000) / 100) > 7 ? (temp / 1000 + 1) << 1 : (temp / 1000) << 1;\r\n    envData[3] = 0;\r\n    if (((temp % 1000) / 100) > 2 && (((temp % 1000) / 100) < 8))\r\n    {\r\n        envData[2] |= 1;  /* set 9th bit of fractional to indicate 0.5C */\r\n    }\r\n    if (CCS811_multiWriteRegister(CCS811_ENV_DATA, envData, 4)!=0) return CCS811_I2C_ERROR;\r\n    return CCS811_SUCCESS;\r\n}\r\n\r\nvoid CCS811_setRefResistance(float input)\r\n{\r\n    refResistance = input;\r\n}\r\n\r\nCCS811_status CCS811_readNTC(void)\r\n{\r\n    if (!initHwDone) return CCS811_NOINIT_ERROR;\r\n\r\n    uint8_t data[4];\r\n    if (CCS811_multiReadRegister(CCS811_NTC, data, 4)!=0) return CCS811_I2C_ERROR;\r\n\r\n    vrefCounts = ((uint16_t)data[0] << 8) | data[1];\r\n    ntcCounts = ((uint16_t)data[2] << 8) | data[3];\r\n    resistance = ((float)ntcCounts * refResistance / (float)vrefCounts);\r\n\r\n    temperature = log((long)resistance);\r\n    temperature = 1 / (0.001129148 + (0.000234125 * temperature) + (0.0000000876741 * temperature * temperature * temperature));\r\n    temperature = temperature - 273.15;  /* convert from Kelvin to Celsius */\r\n\r\n    return CCS811_SUCCESS;\r\n}\r\n\r\nuint16_t CCS811_getTVOC(void)\r\n{\r\n    return tVOC;\r\n}\r\n\r\nuint16_t CCS811_getCO2(void)\r\n{\r\n    return CO2;\r\n}\r\n\r\nfloat CCS811_getResistance(void)\r\n{\r\n    return resistance;\r\n}\r\n\r\nfloat CCS811_getTemperature(void)\r\n{\r\n    return temperature;\r\n}\r\n\r\n"
              }
            }
          },
          "md5": "f5b25f8c88b7a5f066ced85c5968931e"
        },
        "fxos8700": {
          "libName": "fxos8700",
          "manufacturer": "NXP Semiconductors",
          "description": "FXOS8700 Accelerometer/Magnetometer",
          "type": "Accelerometer + Magnetometer",
          "icon": "",
          "image": "",
          "version": "",
          "eelVersion": "3",
          "shoppingCartLinks": {
            "digikey": {
              "links": {
                "info": "https://www.digikey.com/product-detail/en/adafruit-industries-llc/3463/1528-2130-ND/7064490"
              },
              "cartData": {
                "part": " 1528-2130-ND",
                "partid": "3463",
                "source": "dkstudio",
                "qty": "1"
              }
            }
          },
          "requires": [
            "embedded",
            "i2c",
            "gpio"
          ],
          "elements": [
            {
              "name": "FXOS8700AccelerometerMagnetometer",
              "type": "EmbeddedFXOS8700",
              "icon": "EmbeddedAccelerometerMagnetometer.svg",
              "defaultAbility": "getSensorData",
              "defaultTrigger": "sensorDataRead",
              "hidden": false,
              "abilities": [
                {
                  "name": "setup",
                  "triggers": [],
                  "hidden": true,
                  "code": "\tATMO_FXOS8700_Config_t config;\n\tconfig.address = ATMO_PROPERTY(undefined, i2cAddress);\n\tconfig.i2cDriverInstance = ATMO_PROPERTY(undefined, i2cInstance);\n\tconfig.gpioDriverInstance = ATMO_PROPERTY(undefined, gpioInstance);\n\tconfig.int1En = ATMO_PROPERTY(undefined, interrupt1Enabled);\n    config.int2En = ATMO_PROPERTY(undefined, interrupt2Enabled);\n    config.int1Pin = ATMO_PROPERTY(undefined, interrupt1Gpio);\n    config.int2Pin = ATMO_PROPERTY(undefined, interrupt2Gpio);\n\n    switch(ATMO_PROPERTY(undefined, motionDetectType))\n    {\n        case FXOS8700_NoDetect:\n        {\n            config.freefallEnabled = false;\n            config.motionEnabled = false;\n            config.tapDetectionEnabled = false;\n            break;\n        }\n        case FXOS8700_FreefallDetect:\n        {\n            config.freefallEnabled = true;\n            config.motionEnabled = false;\n            config.tapDetectionEnabled = false;\n            break;\n        }\n        case FXOS8700_MotionDetect:\n        {\n            config.freefallEnabled = false;\n            config.motionEnabled = true;\n            config.tapDetectionEnabled = false;\n            break;\n        }\n        case FXOS8700_TapDetect:\n        {\n            config.freefallEnabled = false;\n            config.motionEnabled = false;\n            config.tapDetectionEnabled = true;\n            break; \n        }\n        default:\n        {\n            config.freefallEnabled = false;\n            config.motionEnabled = false;  \n            config.tapDetectionEnabled = false;\n            break;\n        }\n    }\n\n    ATMO_FXOS8700_SetMotionDetectedAbilityHandle(ATMO_ABILITY(undefined, detectMotion));\n    ATMO_FXOS8700_SetFreefallDetectedAbilityHandle(ATMO_ABILITY(undefined, detectFreefall));\n    ATMO_FXOS8700_SetTapDetectedAbilityHandle(ATMO_ABILITY(undefined, detectTap));\n\tATMO_FXOS8700_Init(&config);\n\n    return ATMO_Status_Success;\n\t"
                },
                {
                  "name": "setEnabled",
                  "triggers": [],
                  "code": "ATMO_FXOS8700_SetEnabled(true);\nreturn ATMO_Status_Success;"
                },
                {
                  "name": "setDisabled",
                  "triggers": [],
                  "code": "ATMO_FXOS8700_SetEnabled(false);\nreturn ATMO_Status_Success;"
                },
                {
                  "name": "setEnabledDisabled",
                  "triggers": [],
                  "code": "bool enabled = false;\nATMO_GetBool(in, &enabled);\nATMO_FXOS8700_SetEnabled(enabled);\nreturn ATMO_Status_Success;"
                },
                {
                  "name": "getSensorData",
                  "triggers": [
                    "sensorDataRead"
                  ],
                  "code": "\tATMO_FXOS8700_SensorData_t data;\n\n\tif(ATMO_FXOS8700_GetSensorData(&data) != ATMO_FXOS8700_Status_Success)\n\t{\n\t\tATMO_CreateValueVoid(out);\n\t\treturn ATMO_Status_Fail;\n\t}\n\n\tATMO_CreateValueBinary(out, &data, sizeof(data));\n\treturn ATMO_Status_Success;\n"
                },
                {
                  "name": "getAccelX",
                  "triggers": [
                    "accelXRead"
                  ],
                  "code": "\tATMO_FXOS8700_SensorData_t data;\n\n\tif(ATMO_FXOS8700_GetSensorData(&data) != ATMO_FXOS8700_Status_Success)\n\t{\n\t\tATMO_CreateValueVoid(out);\n\t\treturn ATMO_Status_Fail;\n\t}\n\n\tATMO_CreateValueFloat(out, data.accelX);\n\treturn ATMO_Status_Success;\n"
                },
                {
                  "name": "getAccelY",
                  "triggers": [
                    "accelYRead"
                  ],
...

This file has been truncated, please download it to see its full contents.

Credits

Ravi Teja Chappa

Ravi Teja Chappa

1 project • 0 followers

Comments