monoZ docs
CO2 SENSOR EXAMPLE

Objectives of Example

  1. Demonstrate how to create a UART instance, configure and integrate the UART instance with monoZ_Lib
  2. Demonstrate how to use UART in interrupt mode for receiving data
  3. Demonstrate how to create a Application Thread using monoZ_Lib
  4. Demonstrate how to create single-shot and recursive timers, and use them.
  5. Demonstrate how to use lwm2m API's defined in monoZ_Lib to set Object/Resource values using mz_set_value_Ob19_X_X API, Read the new data received from server (in write event) using mz_read_value_Ob19_X_X API, Send the sensor data using mz_set_and_notify_Ob19_X_X API.
  6. Demonstrate how to handle post processing event from monoZ_Lib lwm2m client.
  7. Demonstrate how to use CLI for printing information.
  8. Sources for this example
    • MZ_Addon_board_CO2. c - Main Application, UART Driver and sensor Driver
    • MZ_Addon_board_CO2. h
  9. Other Linked files
    • MZ_hardware_config. c - Hardware Driver integration file
    • MZ_modem_config. c - Modem command integration file

1. monoZ_Lib context Setup

There are certain context variables provided by user to initialize all the context required by the monoZ_Lib.
i. Hardware related context[Mandatory]
ii. Modem related context[Optional]

i. Hardware related context

The definitions of all hardware context variables are present in “MZ_public.h” header file. The sample template for using is also provided in the same header file.

a. Main context variable

User must create this context variable for successful use of the library. In case the context variable is not created by user, The monoZ_Lib will not initialize and a linker error will occur.

  • monoZ Click tool user

    Incase using tool, this variable is created and placed in "MZ_hardware_config.c"

    Co2 Sample code implementation

    extern MZ_UART_INIT_ST co2_lpuart1_instance;
    
    uart_enableuart_enable_cfg =
    {
        .u3 = MZI_UART3,
        .u3p = 0,
        .lu1 = MZI_LPUART1,
        .lu1p = &co2_lpuart1_instance,
    };
    i2c_enable i2c_enable_cfg =
    {
        .i2 = MZI_I2C2,
        .i2p = 0,
        .i4 = MZI_I2C4,
        .i4p = 0,
    };
    

b. LPUART1 Peripheral context variable

User must create the peripheral context variable for the desired interface and use it in Main context variable. In case of the Co2 Addon board, it uses LPUART1 interface for sensor communication. monoZ_Lib takes all UART related initialization context through “uart_enable_cfg“ context variable. For the co2 application, we need to define a peripheral context variable. Let’s say “co2_lpuart1_instance”.

  • monoZ Click tool user

    Incase using tool, this variable is created and placed in "MZ_Addon_board_CO2.c"

    Co2 Sample code implementation

    MZ_UART_INIT_ST co2_lpuart1_instance =
    {
        .Instance = MZ_ADDONCO2_INSTANCE,
        .Init.BaudRate = MZ_ADDONCO2_INIT_BAUDRATE,
        .Init.WordLength = MZ_ADDONCO2_INIT_WORDLENGTH,
        .Init.StopBits = MZ_ADDONCO2_INIT_STOPBITS,
        .Init.Parity = MZ_ADDONCO2_INIT_PARITY,
        .Init.Mode = MZ_ADDONCO2_INIT_MODE,
        .Init.HwFlowCtl = MZ_ADDONCO2_INIT_HWFLOWCTL,
        .Init.OverSampling = MZ_ADDONCO2_INIT_OVERSAMPLING,
        .Init.OneBitSampling = MZ_ADDONCO2_INIT_ONEBITSAMPLING,
        .AdvancedInit.AdvFeatureInit = MZ_ADDONCO2_ADVANCEDINIT_ADVFEATUREINIT
    };
    



ii. Modem related context

User must create the modem context functions if wish to initialize modem with specific configuration. There are 2 function definitions present to provide flexibility. The names of the function are fixed. User need to define the function with this exact name. Prototype of the functions are as follows:

  • void mz_reset_sequence (void * arg) This function will execute all ATcommands required to initialize modem during Power ON.
  • void mz_reboot_sequence (void * arg) This function will execute all ATcommands required to initialize modem during Wakeup.
  • Here we are setting the configurations like power saving mode,Device Configurations and its control settings.
  • Also the time out for a particular API can also be defined and even the duration between API consecutive hits can be specified.
  • Access point can be defined to which we need to use.
  • LWM2M configurations are been defined and set using the AT commands. LWM2M commands are been set with different input params.
  • Device has been rebooted using Z AT command and and board is reinitialized using AT command. Once the Device is reinitialized, set of AT commands like AT command initialization, registration and reading the Clock value.
  • LWM2M initialization is done and command is issued.

Note: User must define the desired AT commands need to be executed during these actions.

  • monoZ Click tool user

    Incase using tool, these functions are created and placed in "MZ_modem_config.c"

    Co2 Sample code implementation

    void mz_reset_sequence(void * arg)
    {
        (void)arg;
        mz_power_config();
        mz_apn_set();
        mz_lwm2m_config();
        mz_device_reboot();
        mz_device_start();
        mz_lwm2m_start();
    }
    
    Void mz_reboot_sequence(void * arg)
    {
        (void)arg;
        mz_device_reboot();
        mz_device_start();
        mz_lwm2m_start();
    }
    
    Note
    1. In case no context function is defined by user, a default context is taken by monoZ_Lib to initialize the modem.
    2. In case blank context function is defined by user, Modem will be on without any initialization.
    3. In case of user wish to use any protocol related feature, its mandatory to define the context by user.

2. monoZ_Lib Initialization and start

User must initialize the monoZ_Lib before it can start using the library features. The monoZ Library can be initialized using the API MZ_init (). “MZ_main. h” header file provides a sample use of how to initialize the library.

  • monoZ Click tool user

    Incase using tool, monoZ Library initialization code is placed inside main() API present in "main.c"

    Co2 Sample code implementation

    mz_version ver = {
            ._major = MZ_SW_VERSION_MAJOR,
            ._minor = MZ_SW_VERSION_MINOR,
            ._patch = MZ_SW_VERSION_PATCH
      };
    if(MZ_OK != MZ_init(&ver))
    {
        Error_Handler();
    }
    
    Note
    The initialization function should be called prior to FreeRTOS kernel initialization.

3. Application creation and start

The Co2 Application initialization is done before the Main FreeRTOS kernel starts. User must create a user application using the monoZ Library API’s.

  • monoZ Click tool user

    Incase using tool, the code is generated and placed in MZ_Addon_board_CO2. c and the code is called within main in "main.c"

    Co2 Sample code implementation

    • The Co2 main user application function
        Static void co2_app_thread(void * arg)
        {
            …
        }
      


    • The Co2 main user application initialization function
        mz_error_tco2_app_init(void)
        {
            …
            /* Create the Co2 application thread */
            if(!mz_thread_create(&co2_thread_id,"co2 Scheduler",co2_app_thread,NULL,osPriorityNormal,co2_stack,CO2_APP_STACK_SIZE,&co2_cb_mem,sizeof(co2_cb_mem)))
            {
                _ret = MZ_THREAD_CREATE_FAIL;
            }
        …
        }
      


    • The Co2 main user application initialization function called from main.c
        /* creation of user task */
        if(MZ_OK != uv_app_init())
        {
            Error_Handler();
        }
      
    Note
    The user application must be created after FreeRTOS Kernel initialization and before FreeRTOS main scheduler start to avoid delay in application start. It will ensure the user application starts at the time of FreeRTOS scheduler starts.

4. Application process

User must design the application based on requirements. Following is the High-level requirement considered for building the Addon-board Co2 example.

  • Application should read co2 sensor data periodically (every 90 sec)
  • Application should send the sensor data to LWM2M server after successfully reading the data
  • Application should monitor LWM2M server status and reconfigure the client-server connection incase, the following case happens
    • If server did not send a Observe request within 3 mins of the device starts.
    • If client turned offline due to connection failure.

Co2 Sample code implementation

A. Application should read co2 sensor data periodically (every 90 sec)

  • Create and start the timer
      if(MZ_OK == mz_tm_create_start_recursive("Uart Read timer",CO2_SENSOR_READ_TIME,co2_sensor_read_timer_cb))
      {
          mz_puts("co2 sensor reading timer started\r\n");
      }
    


  • Call back function is provided while creating timer, this call back will be called by monoZ Library when the timer expires.
      static void co2_sensor_read_timer_cb(TimerHandle_txTimer)
      {
          /* Set the co2 sensor timer expire flag */
          co2_read_timer_expire_flag = CO2_READ_TIMER_EXPIRE_SET;
      }
    


  • Need to check the timer expiry flag periodically in co2 main application, execute and sensor reading when flag is set.
      if(CO2_READ_TIMER_EXPIRE_SET == co2_read_timer_expire_flag)
      {
          /* Process the co2 sensor read timer expire event */
      … 
      }
    


B. Application should send the sensor data to LWM2M server after successfully reading the data

/* Set the Object 19/0/0 Data and send the Notify request to monoZ_Lib */
mz_error_t status = mz_set_and_notify_Ob19_0_0(payload_string);



C. Application should monitor LWM2M server status and reconfigure the client-server connection incase, the following case happens

i. If server did not send a Observe request within 3 mins of the device starts.

  • Create and start the timer
      lwm2m_server_monitoring_timer_id =mz_tm_create_one("Server monitoring timer",LWM2M_SERVER_MONITORING_TIME,lwm2m_server_monitoring_timer_cb);
    
      (void)mz_tm_start(lwm2m_server_monitoring_timer_id);
    


  • Call back function is provided while creating timer, this call back will be called by monoZ Library when the timer expires. Check the Observer flag is set or clear and set re-registration/ reconfiguration flag. The Observe flag will be discussed later in this document.
      static void lwm2m_server_monitoring_timer_cb(TimerHandle_txTimer)
      {
          /* Check if observe has not started */
          if(OBSERVE_COMPLETE_CLEAR == observe_receive_flag)
          {
              /* Then set the server re-registration flag */
              lwm2m_server_rereg_flag = SERVER_REG_NEED_SET;
          }
      }
    


ii. If client turned offline due to connection failure.

All the protocols related events are passed from monoZ_Libto a predefined callback API name “mz_pro_default_callback”.User must implement this callback API to get real time post processing events from Lwm2m client present inside the monoZ Library. A dummy implementation is as follows.

void mz_pro_default_callback(void * evnt)
{
    st_lw_event * e = event;
        if(LW_EV_CLIENT_OFF == event)
        {
            /* set the server re-registration flag */
            lwm2m_server_rereg_flag = SERVER_REG_NEED_SET;
        }
        if(LW_EV_OBSERVE == event)
        {
            if(e->lw_Obj_id == 19 && e->lw_Obj_Ins_id == 0 &&
            e->lw_Res_id == 0)
            {
                /* Set the observed received flag */
                observe_receive_flag = OBSERVE_COMPLETE_SET;
            }
        }
}
Note
Incase user do not implement this API, after processing any lwm2m event by the client, no callback will be generated to user. Hence user cannot monitor any lwm2m events. Lwm2m client present inside the monoZ_Lib is self-sufficient and maintain its own context for application and data. User is not required to perform any event processing directly. The post processing events are just to inform the user about the status/activity of lwm2m client. Additional application requirement can be processed by monitoring the post processing events.

5. Miscellaneous

a. How to use UART in interrupt mode.

User must register uart event callback to use uart in interrupt mode.

  • Here is a sample code used in Co2 example to register receive event callback for lpuart1.
      MZ_UART_register_intr_cb_rx(MZ_ADDONCO2_UART_INSTANCE,co2_lpuart1_rx_intr);
    

The callback API co2_lpuart1_rx_intr () will be called by monoZ_Lib after uart receive interrupt is generated by MCU. User must first set the uart in receive interrupt mode when expecting data to be received on interface.

  • Here is a sample code used in Co2 example for receiving Co2 data on interrupt mode
      MZ_UART_Receive_IT(MZ_ADDONCO2_UART_INSTANCE,(uint8_t*)&resp21,sizeof(resp21));
    
    For more details user can check "MZ_uart.h"



b. How to use UART in polling mode.

  • Here is a sample code used in Co2 example for transmitting data on polling mode.
      MZ_UART_Transmit(MZ_ADDONCO2_UART_INSTANCE,(uint8_t *)&cmd21,sizeof(cmd21),1000);
    


c. How to perform modem reconfiguration with for reconnecting lwm2m server.

  • Here is a sample code used in Co2 example
      if(MZ_OK == MZ_modem_config_set(mz_reboot_sequence))
      {
          /* print the success in the CLI */
          mz_puts("Server re-reg sequence started\r\n");
      }
    
Note
The mz_reboot_sequence () API defines the sequence of AT commands need to be send for reconfiguring modem. These AT commands are depended on the specific type of modem. Please take a note to use appropriate AT commands.