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!
Ashok R
Published © GPL3+

Smart Walking Stick

This walking stick can control the home appliance with the help of IoT networks.

IntermediateShowcase (no instructions)20 hours1,619

Things used in this project

Hardware components

Default Stick
×1
Rapid IoT Prototyping Kit
NXP Rapid IoT Prototyping Kit
×1
Kinetis KW41Z
NXP Kinetis KW41Z
2 boards are my own design with KW41z module
×3
LED Light Bulb, Cool White
LED Light Bulb, Cool White
×1
RGB Cooling Fan
×1
Computer Speaker, Pro-Sound 2000
Computer Speaker, Pro-Sound 2000
×1
DF Mp3 Player
×1

Software apps and online services

Android Studio
Android Studio
Twilio API for WhatsApp
Twilio API for WhatsApp

Hand tools and fabrication machines

Soldering Station, 110 V
Soldering Station, 110 V
Axe Saw Blade
Hot glue gun (generic)
Hot glue gun (generic)

Story

Read more

Custom parts and enclosures

CAD Design

Just a reference

Schematics

Rapid IoT Kit

Code

Main

C/C++
Rapid IoT Kit
#include <raspi.h>
#include "board.h"
#include "fsl_uart.h"
#include <math.h>
#include "pin_mux.h"
#include "clock_config.h"
#include "uart.h"
#include "backlight.h"
#include "emwin_support.h"
#include "GUI.h"
#include "fsl_ili9341.h"
#include "port_interrupts.h"
#include "images.h"
#include "uidraw.h"
#include "button.h"
#include "pixy.h"

/*******************************************************************************
 * Definitions
 ******************************************************************************/
#define BOARD_SW_IRQ PORTE_IRQn
#define BOARD_SW_IRQ_HANDLER PORTE_IRQHandler
#define APP_MAX_COUNT 5
#define APP_TIMER 10
#define APP_LOCK_TIMER 2500
/*******************************************************************************
 * Prototypes
 ******************************************************************************/

/*******************************************************************************
 * Variables
 ******************************************************************************/

uint8_t txbuff[] = "version\r\n";
uint8_t ifconfig[] = "ifconfig\r\n";
uint8_t AIData[4] = {0};
/* Whether the SW button is pressed */
volatile bool g_ButtonPress = false;
volatile uint8_t g_ButtonValue = 0;
volatile uint32_t g_cloud_counter=0;
volatile uint32_t g_lock_counter=0;
volatile uint8_t g_AppIndex = 0;
volatile uint8_t g_AppLocked = 0;
volatile uint8_t g_AppLockDisable = 0;
volatile uint8_t g_AppStatus[5] = {0,0,0,0,0};
volatile uint8_t g_AppValue[5] = {0,0,0,0,0};
volatile uint32_t frame_update=500u;
extern uint8_t masterRxData[128];
extern uint8_t RxRpiBuffer[8];
extern volatile uint8_t rxRpiBlockReceived;
extern volatile uint8_t rxRpiDataCounter;

uint32_t color_array[] = {GUI_WHITE,GUI_MAGENTA, GUI_BLUE, GUI_GREEN, GUI_YELLOW};
pixy_colormode_t *pixy_cmode=masterRxData;
volatile uint16_t dx=0;
volatile uint16_t dy=0;
volatile uint16_t pdx=0;
volatile uint16_t pdy=0;
volatile uint8_t track_index=0;
volatile int8_t track_value=0;
volatile int8_t track_last_value=0;
/* Functions required for emwin / Display */
uint32_t DSPI2_GetFreq(void)
{
    return CLOCK_GetBusClkFreq();
}


void Init_Display()
{
    Display_Connect(); /* triggers GUI_Init() */
    Backlight_SetLevel(BLIGHT_LEVEL_HIGH);

    GUI_SetBkColor(GUI_BLACK);
    GUI_SetColor(GUI_WHITE);
}



#define GUI_FONT_TITLE  GUI_Font8x18
#define GUI_FONT_NORMAL GUI_Font8x16

uint8_t Init_Backlight(void)
{
	backlight_fct_t BACKLIGHT_fct;

    BACKLIGHT_fct.connect_hw = Backlight_Connect;
    BACKLIGHT_fct.disconnect_hw = Backlight_Disconnect;
    BACKLIGHT_fct.set_level = Backlight_Set_Level;

    Backlight_Init_Driver(&BACKLIGHT_fct);

    if (Backlight_Init_Hw())
        return 1;

    return 0;
}


/*******************************************************************************
 * Code
 ******************************************************************************/
/*!
 * @brief Main function
 */
int main(void)
{


	BOARD_InitPins();
    BOARD_Boot_Clock_RUN();

    BOARD_INIT_GPIOS();
    //BOARD_Init_SPI_2();


    BOARD_Init_RGB_BLIGHT();
    PORT_IRQ_EnablePortAIrq();
    PORT_IRQ_EnablePortEIrq();

    THR_UART_Init();

    //RPI_UART_Init();
    //PIXY_Init();
    Init_Backlight();

    Init_Display();
    GUI_Clear();
    GUI_SetColor(GUI_BLACK);
    GUI_SetBkColor(GUI_WHITE);
    GUI_SetFont(&GUI_Font20B_1);
    GUI_SetPenSize(8);
	GUI_Clear();

	//GUI_BMP_Draw(bglogo_176x176, 0, 0);
    //App_WaitMsec(3000);
	GUI_BMP_Draw(bg_176x176, 0, 0);
    //App_WaitMsec(100);
	draw_apppage(g_AppIndex,0,0);

	//PIXY_Send_Data(PIXY_GET_VERSION);
	//App_WaitMsec(1);
	//PIXY_Get_Data();
	//	PIXY_SetLED(0,0,255);
	 GPIO_PinWrite(GPIOA, 11, 0);
	 GPIO_PinWrite(GPIOB, 8, 0);
	 GPIO_PinWrite(GPIOA, 13, 0);
	 GPIO_PinWrite(GPIOA, 14, 0);
	while(1){


		 if(g_ButtonPress){

			switch(g_ButtonValue){

			case 0:

				break;

			case 1:
				g_AppIndex++;
				if(g_AppIndex>1){
					g_AppIndex=0;
				}
				draw_apppage(g_AppIndex,1,0);

				break;

			case 2:
				frame_update=frame_update-100;
				if(frame_update<=100){
					frame_update=500;
				}
				break;

			}

			g_ButtonValue = 0;
			g_ButtonPress = false;

		   }

		 getCCBlocks();
		 App_WaitMsec(1);
		 //PIXY_Get_Data();


		 if(0){//g_AppIndex==0){

			 switch(pixy_cmode->sign){

			 case 1:
				GUI_SetColor(GUI_MAGENTA);
				GUI_FillRect(0, 144, 176, 176);
				dx= ((315 - pixy_cmode->xpos)*176)/315;
				GUI_SetColor(GUI_WHITE);
				GUI_FillCircle(dx, 160, 10);
				track_index=1;
				 break;
			 case 2:

				GUI_SetColor(GUI_BLUE);
				GUI_FillRect(0, 144, 176, 176);
				dx= ((315 - pixy_cmode->xpos)*176)/315;
				GUI_SetColor(GUI_WHITE);
				GUI_FillCircle(dx, 160, 10);
				track_index=2;

				 break;

			 case 3:
				GUI_SetColor(GUI_GREEN);
				GUI_FillRect(0, 144, 176, 176);
				dx= ((315 - pixy_cmode->xpos)*176)/315;
				GUI_SetColor(GUI_WHITE);
				GUI_FillCircle(dx, 160, 10);
				track_index=3;

				 break;
			 case 4:
				GUI_SetColor(GUI_YELLOW);
				GUI_FillRect(0, 144, 176, 176);
				dx= ((315 - pixy_cmode->xpos)*176)/315;
				GUI_SetColor(GUI_WHITE);
				GUI_FillCircle(dx, 160, 10);
				track_index=4;
				 break;

			 }
		 }
		App_WaitMsec(frame_update);
	}


}

Node

C/C++
/*==================================================================================================
Include Files
==================================================================================================*/
/* General Includes */
#include "EmbeddedTypes.h"
#include <string.h>

/* FSL Framework */
#include "shell.h"
#include "Keyboard.h"
#include "RNG_Interface.h"
#include "PWR_Interface.h"

/* Network */
#include "ip_if_management.h"
#include "event_manager.h"

/* Application */
#include "end_device_app.h"
#include "shell_ip.h"
#include "thread_utils.h"
#include "thread_network.h"
#include "thread_app_callbacks.h"
#include "app_init.h"
#include "app_stack_config.h"
#include "app_thread_config.h"
#include "app_led.h"
#include "app_temp_sensor.h"
#include "coap.h"
#include "app_socket_utils.h"
#if THR_ENABLE_EVENT_MONITORING
#include "app_event_monitoring.h"
#endif
#if THR_ENABLE_MGMT_DIAGNOSTICS
#include "thread_mgmt.h"
#include "thci.h"
#endif
#if UDP_ECHO_PROTOCOL
#include "app_echo_udp.h"
#endif

/*==================================================================================================
Private macros
==================================================================================================*/
#ifndef APP_MSG_QUEUE_SIZE
    #define APP_MSG_QUEUE_SIZE                  20
#endif

#if (THREAD_USE_SHELL == FALSE)
    #define shell_write(a)
    #define shell_refresh()
    #define shell_printf(a,...)
#endif

#define gThrDefaultInstanceId_c                 0

#define APP_LED_URI_PATH                        "/led"
#define APP_TEMP_URI_PATH                       "/temp"
#define APP_SINK_URI_PATH                       "/sink"

#define APP_DEFAULT_DEST_ADDR                   in6addr_realmlocal_allthreadnodes

#define APP_SW_WAKE_UP_TIMEOUT                  5000 /* miliseconds */
/*==================================================================================================
Private type definitions
==================================================================================================*/

/*==================================================================================================
Private global variables declarations
==================================================================================================*/
static instanceId_t mThrInstanceId = gInvalidInstanceId_c;    /*!< Thread Instance ID */

static bool_t mJoiningIsAppInitiated = FALSE;

/*==================================================================================================
Private prototypes
==================================================================================================*/
static void App_HandleKeyboard(void *param);
static void App_UpdateStateLeds(appDeviceState_t deviceState);
static void APP_JoinEventsHandler(thrEvCode_t evCode);

static void APP_SwWakeUpCb(void *pParam);
static void APP_InitCoapDemo(void);
static void APP_ReportTemp(void *pParam);
static void APP_SendDataSinkCreate(void *pParam);
static void APP_SendDataSinkRelease(void *pParam);
#if gKBD_KeysCount_c > 1
static void APP_SendLedRgbOn(void *pParam);
static void APP_SendLedRgbOff(void *pParam);
static void APP_SendLedFlash(void *pParam);
static void APP_SendLedColorWheel(void *pParam);
#endif
static void APP_LocalDataSinkRelease(void *pParam);
static void APP_ProcessLedCmd(uint8_t *pCommand, uint8_t dataLen);
static void APP_CoapGenericCallback(coapSessionStatus_t sessionStatus, void *pData, coapSession_t *pSession, uint32_t dataLen);
static void APP_CoapLedCb(coapSessionStatus_t sessionStatus, void *pData, coapSession_t *pSession, uint32_t dataLen);
static void APP_CoapTempCb(coapSessionStatus_t sessionStatus, void *pData, coapSession_t *pSession, uint32_t dataLen);
static void APP_CoapSinkCb(coapSessionStatus_t sessionStatus, void *pData, coapSession_t *pSession, uint32_t dataLen);
/*==================================================================================================
Public global variables declarations
==================================================================================================*/
const coapUriPath_t gAPP_LED_URI_PATH  = {SizeOfString(APP_LED_URI_PATH), (uint8_t *)APP_LED_URI_PATH};
const coapUriPath_t gAPP_TEMP_URI_PATH = {SizeOfString(APP_TEMP_URI_PATH), (uint8_t *)APP_TEMP_URI_PATH};
const coapUriPath_t gAPP_SINK_URI_PATH = {SizeOfString(APP_SINK_URI_PATH), (uint8_t *)APP_SINK_URI_PATH};

/* Application state/mode */
appDeviceState_t gAppDeviceState[THR_MAX_INSTANCES];
appDeviceMode_t gAppDeviceMode[THR_MAX_INSTANCES];

/* Pointer application task message queue */
taskMsgQueue_t *mpAppThreadMsgQueue;

/* Flag used to stop the attaching retries */
bool_t gbRetryInterrupt = TRUE;

/* CoAP instance */
uint8_t mAppCoapInstId = THR_ALL_FFs8;
/* Destination address for CoAP commands */
ipAddr_t gCoapDestAddress;
/* Timer used to keep the device in Up state for an amount of time */
tmrTimerID_t gAppSwWakeUpTimer = gTmrInvalidTimerID_c;

extern bool_t gEnable802154TxLed;

/*==================================================================================================
Public functions
==================================================================================================*/
/*!*************************************************************************************************
\fn     void APP_Init(void)
\brief  This function is used to initialize application.

***************************************************************************************************/
void APP_Init
(
    void
)
{
    /* Initialize pointer to application task message queue */
    mpAppThreadMsgQueue = &appThreadMsgQueue;

    /* Initialize main thread message queue */
    ListInit(&appThreadMsgQueue.msgQueue,APP_MSG_QUEUE_SIZE);

    /* Set default device mode/state */
    APP_SetState(gThrDefaultInstanceId_c, gDeviceState_FactoryDefault_c);
    APP_SetMode(gThrDefaultInstanceId_c, gDeviceMode_Configuration_c);

    /* Initialize keyboard handler */
    pfAppKeyboardHandler = App_HandleKeyboard;

    /* Use one instance ID for application */
    mThrInstanceId = gThrDefaultInstanceId_c;

#if THR_ENABLE_EVENT_MONITORING
    /* Initialize event monitoring */
    APP_InitEventMonitor(mThrInstanceId);
#endif

    if(gThrStatus_Success_c == THR_StartInstance(mThrInstanceId, pStackCfg[0]))
    {
        /* Initialize CoAP demo */
        APP_InitCoapDemo();

#if USE_TEMPERATURE_SENSOR
        /* Initialize Temperature sensor/ADC module*/
        APP_InitADC(ADC_0);
#endif

#if THREAD_USE_THCI && THR_ENABLE_MGMT_DIAGNOSTICS
        (void)MgmtDiagnostic_RegisterAppCb(THCI_MgmtDiagnosticAppCb);
#endif

#if THREAD_USE_SHELL && SOCK_DEMO
        /* Initialize use sockets - used from shell */
        APP_InitUserSockets(mpAppThreadMsgQueue);
#endif

#if APP_AUTOSTART
       if(!THR_GetAttr_IsDevConnected(mThrInstanceId))
       {
          mJoiningIsAppInitiated = TRUE;

          if(THR_NwkJoin(mThrInstanceId, THR_APP_JOIN_DISCOVERY_METHOD) != gThrStatus_Success_c)
          {
              /* User can treat join failure according to their application */
          }
       }
#endif
    }
}

/*!*************************************************************************************************
\fn     void App_Handler(void)
\brief  Application Handler. In this configuration is called on the task with the lowest priority
***************************************************************************************************/
void APP_Handler
(
    void
)
{
    bool_t handleMsg = TRUE;

    while(handleMsg == TRUE)
    {
        handleMsg = NWKU_MsgHandler(&appThreadMsgQueue);
        /* For BareMetal break the while(1) after 1 run */
        if(!gUseRtos_c && MSG_Pending(&appThreadMsgQueue.msgQueue))
        {
            (void)OSA_EventSet(appThreadMsgQueue.taskEventId, NWKU_GENERIC_MSG_EVENT);
            break;
        }
    }
}

/*!*************************************************************************************************
\fn     void APP_NwkScanHandler(void *param)
\brief  This function is used to handle network scan results in asynchronous mode.
***************************************************************************************************/
void APP_NwkScanHandler
(
    void *param
)
{
    thrEvmParams_t *pEventParams = (thrEvmParams_t *)param;
    thrNwkScanResults_t *pScanResults = &pEventParams->pEventData->nwkScanCnf;

    /* Handle the network scan result here */
    if(pScanResults)
    {
#if THREAD_USE_SHELL
        SHELL_NwkScanPrint(pScanResults);
#endif
        MEM_BufferFree(pScanResults);
    }
    /* Free Event Buffer */
    MEM_BufferFree(pEventParams);
}

/*!*************************************************************************************************
\fn     void Stack_to_APP_Handler(void *param)
\brief  This function is used to handle stack events in asynchronous mode.

\param  [in]    param    Pointer to stack event
***************************************************************************************************/
void Stack_to_APP_Handler
(
    void *param
)
{
    thrEvmParams_t *pEventParams = (thrEvmParams_t *)param;

    /* Uncomment for multicast address */
    //ipAddr_t mCastGroup = MCAST_3EAD_ADDRESS;

    switch(pEventParams->code)
    {
        case gThrEv_GeneralInd_ResetToFactoryDefault_c:
            App_UpdateStateLeds(gDeviceState_FactoryDefault_c);
            break;

        case gThrEv_GeneralInd_InstanceRestoreStarted_c:
        case gThrEv_GeneralInd_ConnectingStarted_c:
            APP_SetMode(mThrInstanceId, gDeviceMode_Configuration_c);
            App_UpdateStateLeds(gDeviceState_JoiningOrAttaching_c);
            gEnable802154TxLed = FALSE;
            break;

        case gThrEv_NwkJoinCnf_Success_c:
        case gThrEv_NwkJoinCnf_Failed_c:
            APP_JoinEventsHandler(pEventParams->code);
            break;

        case gThrEv_GeneralInd_Connected_c:
            App_UpdateStateLeds(gDeviceState_NwkConnected_c);
            /* Set application CoAP destination to all nodes on connected network */
            gCoapDestAddress = APP_DEFAULT_DEST_ADDR;
            APP_SetMode(mThrInstanceId, gDeviceMode_Application_c);
            /* Enable LED for 80215.4 tx activity */
            gEnable802154TxLed = TRUE;
#if UDP_ECHO_PROTOCOL
            ECHO_ProtocolInit(mpAppThreadMsgQueue);
#endif
            /* Uncomment to register multicast address */
            //IP_IF_AddMulticastGroup6(gIpIfSlp0_c, &mCastGroup);
            break;

        case gThrEv_GeneralInd_ConnectingFailed_c:
        case gThrEv_GeneralInd_Disconnected_c:
            APP_SetMode(mThrInstanceId, gDeviceMode_Configuration_c);
            App_UpdateStateLeds(gDeviceState_NwkFailure_c);
            break;

#if gLpmIncluded_d
        case gThrEv_GeneralInd_AllowDeviceToSleep_c:
            PWR_AllowDeviceToSleep();
            break;

        case gThrEv_GeneralInd_DisallowDeviceToSleep_c:
            PWR_DisallowDeviceToSleep();
            break;
#endif
        default:
            break;
    }

    /* Free event buffer */
    MEM_BufferFree(pEventParams->pEventData);
    MEM_BufferFree(pEventParams);
}

/*!*************************************************************************************************
\fn     void APP_Commissioning_Handler(void *param)
\brief  This function is used to handle Commissioning events in synchronous mode.

\param  [in]    param    Pointer to Commissioning event
***************************************************************************************************/
void APP_Commissioning_Handler
(
    void *param
)
{
    thrEvmParams_t *pEventParams = (thrEvmParams_t *)param;

    switch(pEventParams->code)
    {
        /* Joiner Events */
        case gThrEv_MeshCop_JoinerDiscoveryStarted_c:
            break;
        case gThrEv_MeshCop_JoinerDiscoveryFailed_c:
            break;
        case gThrEv_MeshCop_JoinerDiscoveryFailedFiltered_c:
            break;
        case gThrEv_MeshCop_JoinerDiscoverySuccess_c:
            break;
        case gThrEv_MeshCop_JoinerDtlsSessionStarted_c:
            App_UpdateStateLeds(gDeviceState_JoiningOrAttaching_c);
            break;
        case gThrEv_MeshCop_JoinerDtlsError_c:
        case gThrEv_MeshCop_JoinerError_c:
            App_UpdateStateLeds(gDeviceState_FactoryDefault_c);
            break;
        case gThrEv_MeshCop_JoinerAccepted_c:
            break;
    }

    /* Free event buffer */
    MEM_BufferFree(pEventParams);
}

/*!*************************************************************************************************
\fn     void App_SedWakeUpFromKeyBoard(void)
\brief  This is a callback fuction called when the device is waked from keyboard.
***************************************************************************************************/
void App_SedWakeUpFromKeyBoard
(
    void
)
{
    /* Keep the device Up for 5 seconds - using a timer */
    if(gAppSwWakeUpTimer == gTmrInvalidTimerID_c) 
    {
        gAppSwWakeUpTimer = TMR_AllocateTimer();
    }

    if(gAppSwWakeUpTimer != gTmrInvalidTimerID_c)
    {
        TMR_StartTimer(gAppSwWakeUpTimer, gTmrSingleShotTimer_c, APP_SW_WAKE_UP_TIMEOUT, APP_SwWakeUpCb, NULL);
    }
}
/*==================================================================================================
Private functions
==================================================================================================*/
/*!*************************************************************************************************
\private
\fn     static void APP_InitCoapDemo(void)
\brief  Initialize CoAP demo.
***************************************************************************************************/
static void APP_InitCoapDemo
(
    void
)
{
    coapRegCbParams_t cbParams[] =  {{APP_CoapLedCb,  (coapUriPath_t *)&gAPP_LED_URI_PATH},
                                     {APP_CoapTempCb, (coapUriPath_t *)&gAPP_TEMP_URI_PATH},
                                     {APP_CoapSinkCb, (coapUriPath_t *)&gAPP_SINK_URI_PATH}};
    /* Register Services in COAP */
    coapStartUnsecParams_t coapParams = {COAP_DEFAULT_PORT, AF_INET6};
    mAppCoapInstId = COAP_CreateInstance(NULL, &coapParams, gIpIfSlp0_c, (coapRegCbParams_t *)cbParams,
                                         NumberOfElements(cbParams));
}

/*!*************************************************************************************************
\private
\fn     static void APP_ConfigModeHandleKeyboard(uint32_t keyEvent)
\brief  This is a handler for KBD module events. Device is in configuration mode.

\param  [in]    keyEvent    The keyboard module event
***************************************************************************************************/
static void APP_ConfigModeHandleKeyboard
(
    uint32_t keyEvent
)
{
    switch(keyEvent)
    {
        case gKBD_EventPB1_c:
#if gKBD_KeysCount_c > 1
        case gKBD_EventPB2_c:
        case gKBD_EventPB3_c:
        case gKBD_EventPB4_c:
#endif          
            if((APP_GetState(mThrInstanceId) == gDeviceState_FactoryDefault_c) ||
               (APP_GetState(mThrInstanceId) == gDeviceState_NwkFailure_c))
            {
                App_UpdateStateLeds(gDeviceState_JoiningOrAttaching_c);

                mJoiningIsAppInitiated = TRUE;

                /* join the network */
                if(THR_NwkJoin(mThrInstanceId, THR_APP_JOIN_DISCOVERY_METHOD) != gThrStatus_Success_c)
                {
                    /* User can treat join failure according to their application */
                }
            }
            break;
        case gKBD_EventLongPB1_c:
#if gKBD_KeysCount_c > 1
        case gKBD_EventLongPB2_c:
        case gKBD_EventLongPB3_c:
        case gKBD_EventLongPB4_c:
#endif
            break;
        /* Factory reset */
        case gKBD_EventVeryLongPB1_c:
#if gKBD_KeysCount_c > 1
        case gKBD_EventVeryLongPB2_c:
        case gKBD_EventVeryLongPB3_c:
        case gKBD_EventVeryLongPB4_c:
#endif
            THR_FactoryReset();
            break;
        default:
            break;
    }
}

/*!*************************************************************************************************
\private
\fn     static void APP_AppModeHandleKeyboard(uint32_t keyEvent)
\brief  This is a handler for KBD module events. Device is in application mode.

\param  [in]    keyEvent    The keyboard module event
***************************************************************************************************/
static void APP_AppModeHandleKeyboard
(
    uint32_t keyEvent
)
{
#if gLpmIncluded_d  
    /* restart wake up timer */
    App_SedWakeUpFromKeyBoard();
#endif 
  
    switch(keyEvent)
    {
        case gKBD_EventPB1_c:
            /* Data sink create */
            (void)NWKU_SendMsg(APP_SendDataSinkCreate, NULL, mpAppThreadMsgQueue);
            break;
#if gKBD_KeysCount_c > 1
        case gKBD_EventPB2_c:
            /* Report temperature */
            (void)NWKU_SendMsg(APP_ReportTemp, NULL, mpAppThreadMsgQueue);
            break;
        case gKBD_EventPB3_c:
            /* Remote led RGB - on */
            (void)NWKU_SendMsg(APP_SendLedRgbOn, NULL, mpAppThreadMsgQueue);
            break;
        case gKBD_EventPB4_c:
            /* Remote led RGB - off */
            (void)NWKU_SendMsg(APP_SendLedRgbOff, NULL, mpAppThreadMsgQueue);
            break;
#endif
        case gKBD_EventLongPB1_c:
            /* Remote data sink release */
            (void)NWKU_SendMsg(APP_SendDataSinkRelease, NULL, mpAppThreadMsgQueue);
            break;
#if gKBD_KeysCount_c > 1
        case gKBD_EventLongPB2_c:
            /* Local data sink release */
            (void)NWKU_SendMsg(APP_LocalDataSinkRelease, NULL, mpAppThreadMsgQueue);
            break;
        case gKBD_EventLongPB3_c:
            /* Remote led flash */
            (void)NWKU_SendMsg(APP_SendLedFlash, NULL, mpAppThreadMsgQueue);
            break;
        case gKBD_EventLongPB4_c:
            /* Remote led - color wheel */
            (void)NWKU_SendMsg(APP_SendLedColorWheel, NULL, mpAppThreadMsgQueue);
            break;
#endif
        case gKBD_EventVeryLongPB1_c:
#if gKBD_KeysCount_c > 1
        case gKBD_EventVeryLongPB2_c: 
        case gKBD_EventVeryLongPB3_c: 
        case gKBD_EventVeryLongPB4_c:
#endif
            /* Factory reset */
            THR_FactoryReset();
            break;
        default:
            break;
    }
}

/*!*************************************************************************************************
\private
\fn     static void App_HandleKeyboard(void *param)
\brief  This is a handler for KBD module events.

\param  [in]    param    The keyboard module event
***************************************************************************************************/
static void App_HandleKeyboard
(
    void *param
)
{
    uint32_t events = (uint32_t)(param);

    if(APP_GetMode(mThrInstanceId) == gDeviceMode_Configuration_c)
    {
        /* Device is in configuration mode */
        APP_ConfigModeHandleKeyboard(events);
    }
    else
    {
        /* Device is in application mode */
        APP_AppModeHandleKeyboard(events);
    }
}

/*!*************************************************************************************************
\private
\fn     static void App_UpdateLedState(appDeviceState_t deviceState)
\brief  Called when Application state and LEDs must be updated.

\param  [in]    deviceState    The current device state
***************************************************************************************************/
static void App_UpdateStateLeds
(
    appDeviceState_t deviceState
)
{
    APP_SetState(mThrInstanceId, deviceState);
    Led_SetState(APP_GetMode(mThrInstanceId), APP_GetState(mThrInstanceId));
}

/*!*************************************************************************************************
\private
\fn     static void APP_JoinEventsHandler(thrEvCode_t evCode)
\brief  This function is used to the handle join failed event.

\param  [in]    evCode    Event code
***************************************************************************************************/
static void APP_JoinEventsHandler
(
    thrEvCode_t evCode
)
{
    if(mJoiningIsAppInitiated)
    {
        if(evCode == gThrEv_NwkJoinCnf_Failed_c)
        {
            if(gbRetryInterrupt)
            {
                /* Retry to join the network */
                if(THR_NwkJoin(mThrInstanceId, THR_APP_JOIN_DISCOVERY_METHOD) != gThrStatus_Success_c)
                {
                    /* User can treat join failure according to their application */
                }
                return;
            }
            mJoiningIsAppInitiated = FALSE;
        }
        else if(evCode == gThrEv_NwkJoinCnf_Success_c)
        {
            mJoiningIsAppInitiated = FALSE;
        }
    }
}

/*!*************************************************************************************************
\fn     static void APP_SwWakeUpCb(void *pParam)
\brief  This is a callback fuction called when the device is waked from keyboard. 
        After this callback the device will enter in low power

\param  [in]    pParam    Not used
***************************************************************************************************/
static void APP_SwWakeUpCb
(
    void *pParam
)
{
    TMR_StopTimer(gAppSwWakeUpTimer);
#if gLpmIncluded_d
    PWR_AllowDeviceToSleep();
#endif
}

/*==================================================================================================
  Coap Demo functions:
==================================================================================================*/
/*!*************************************************************************************************
\private
\fn     static void APP_CoapGenericCallback(coapSessionStatus_t sessionStatus, void *pData,
                                            coapSession_t *pSession, uint32_t dataLen)
\brief  This function is the generic callback function for CoAP message.

\param  [in]    sessionStatus   Status for CoAP session
\param  [in]    pData           Pointer to CoAP message payload
\param  [in]    pSession        Pointer to CoAP session
\param  [in]    dataLen         Length of CoAP payload
***************************************************************************************************/
static void APP_CoapGenericCallback
(
    coapSessionStatus_t sessionStatus,
    void *pData,
    coapSession_t *pSession,
    uint32_t dataLen
)
{
    /* If no ACK was received, try again */
    if(sessionStatus == gCoapFailure_c)
    {
        if(FLib_MemCmp(pSession->pUriPath->pUriPath, (coapUriPath_t*)&gAPP_TEMP_URI_PATH.pUriPath,
                       pSession->pUriPath->length))
        {
            (void)NWKU_SendMsg(APP_ReportTemp, NULL, mpAppThreadMsgQueue);
        }
    }
    /* Process data, if any */
}

/*!*************************************************************************************************
\private
\fn     static void APP_ReportTemp(void *pParam)
\brief  This open a socket and report the temperature to gCoapDestAddress.

\param  [in]    pParam    Not used
***************************************************************************************************/
static void APP_ReportTemp
(
    void *pParam
)
{
    coapSession_t *pSession = NULL;
    /* Get Temperature */
    uint8_t *pTempString = App_GetTempDataString();
    uint32_t ackPloadSize;
    ifHandle_t ifHandle = THR_GetIpIfPtrByInstId(mThrInstanceId);

    if(!IP_IF_IsMyAddr(ifHandle->ifUniqueId, &gCoapDestAddress))
    {
        pSession = COAP_OpenSession(mAppCoapInstId);

        if(NULL != pSession)
        {
            coapMsgTypesAndCodes_t coapMessageType = gCoapMsgTypeNonPost_c;

            pSession->pCallback = NULL;
            FLib_MemCpy(&pSession->remoteAddr, &gCoapDestAddress, sizeof(ipAddr_t));
            ackPloadSize = strlen((char *)pTempString);
            COAP_SetUriPath(pSession, (coapUriPath_t *)&gAPP_TEMP_URI_PATH);

            if(!IP6_IsMulticastAddr(&gCoapDestAddress))
            {
                coapMessageType = gCoapMsgTypeConPost_c;
                pSession->pCallback = APP_CoapGenericCallback;
            }

            COAP_Send(pSession, coapMessageType, pTempString, ackPloadSize);
        }
    }
    /* Print temperature in shell */
    shell_write("\r");
    shell_write((char *)pTempString);
    shell_refresh();
    MEM_BufferFree(pTempString);
}

/*!*************************************************************************************************
\private
\fn     static nwkStatus_t APP_SendDataSinkCommand(uint8_t *pCommand, uint8_t dataLen)
\brief  This function is used to send a Data Sink command to APP_DEFAULT_DEST_ADDR.

\param  [in]    pCommand       Pointer to command data
\param  [in]    dataLen        Data length

\return         nwkStatus_t    Status of the command
***************************************************************************************************/
static nwkStatus_t APP_SendDataSinkCommand
(
    uint8_t *pCommand,
    uint8_t dataLen
)
{
    nwkStatus_t status = gNwkStatusFail_c;
    coapSession_t *pSession = COAP_OpenSession(mAppCoapInstId);

    if(pSession)
    {
        ipAddr_t coapDestAddress = APP_DEFAULT_DEST_ADDR;

        pSession->pCallback = NULL;
        FLib_MemCpy(&pSession->remoteAddr, &coapDestAddress, sizeof(ipAddr_t));
        COAP_SetUriPath(pSession, (coapUriPath_t*)&gAPP_SINK_URI_PATH);
        status = COAP_Send(pSession, gCoapMsgTypeNonPost_c, pCommand, dataLen);
    }

    return status;
}

/*!*************************************************************************************************
\private
\fn     static void APP_SendDataSinkCreate(void *pParam)
\brief  This function is used to send a Data Sink Create command to APP_DEFAULT_DEST_ADDR.

\param  [in]    pParam    Not used
***************************************************************************************************/
static void APP_SendDataSinkCreate
(
    void *pParam
)
{
    uint8_t aCommand[] = {"create"};

    /* Send command over the air */
    if(APP_SendDataSinkCommand(aCommand, sizeof(aCommand)) == gNwkStatusSuccess_c)
    {
        /* Local data sink create */
        (void)THR_GetIP6Addr(mThrInstanceId, gMLEIDAddr_c, &gCoapDestAddress, NULL);
    }
}

/*!*************************************************************************************************
\private
\fn     static void APP_SendDataSinkRelease(void *pParam)
\brief  This function is used to send a Data Sink Release command to APP_DEFAULT_DEST_ADDR.

\param  [in]    pParam    Pointer to stack event
***************************************************************************************************/
static void APP_SendDataSinkRelease
(
    void *pParam
)
{

    uint8_t aCommand[] = {"release"};

    /* Send command over the air */
    if(APP_SendDataSinkCommand(aCommand, sizeof(aCommand)) == gNwkStatusSuccess_c)
    {
        /* Local data sink release */
        APP_LocalDataSinkRelease(pParam);
    }
}

#if gKBD_KeysCount_c > 1
/*!*************************************************************************************************
\private
\fn     static void APP_SendLedCommand(uint8_t *pCommand, uint8_t dataLen)
\brief  This function is used to send a Led command to gCoapDestAddress.

\param  [in]    pCommand    Pointer to command data
\param  [in]    dataLen     Data length
***************************************************************************************************/
static void APP_SendLedCommand
(
    uint8_t *pCommand,
    uint8_t dataLen
)
{
    ifHandle_t ifHandle = THR_GetIpIfPtrByInstId(mThrInstanceId);

    if(!IP_IF_IsMyAddr(ifHandle->ifUniqueId, &gCoapDestAddress))
    {
        coapSession_t *pSession = COAP_OpenSession(mAppCoapInstId);

        if(pSession)
        {
            coapMsgTypesAndCodes_t coapMessageType = gCoapMsgTypeNonPost_c;

            pSession->pCallback = NULL;
            FLib_MemCpy(&pSession->remoteAddr, &gCoapDestAddress, sizeof(ipAddr_t));
            COAP_SetUriPath(pSession,(coapUriPath_t *)&gAPP_LED_URI_PATH);

            if(!IP6_IsMulticastAddr(&gCoapDestAddress))
            {
                coapMessageType = gCoapMsgTypeConPost_c;
                pSession->pCallback = APP_CoapGenericCallback;
            }
            else
            {
                APP_ProcessLedCmd(pCommand, dataLen);
            }
            COAP_Send(pSession, coapMessageType, pCommand, dataLen);
        }
    }
    else
    {
        APP_ProcessLedCmd(pCommand, dataLen);
    }
}

/*!*************************************************************************************************
\private
\fn     static void APP_SendLedRgbOn(void *pParam)
\brief  This function is used to send a Led RGB On command over the air.

\param  [in]    pParam    Not used
***************************************************************************************************/
static void APP_SendLedRgbOn
(
    void *pParam
)
{
    uint8_t aCommand[] = {"rgb r000 g000 b000"};
    uint8_t redValue, greenValue, blueValue;

    /* Red value on: 0x01 - 0xFF */
    redValue = (uint8_t)NWKU_GetRandomNoFromInterval(0x01, THR_ALL_FFs8);

    /* Green value on: 0x01 - 0xFF */
    greenValue = (uint8_t)NWKU_GetRandomNoFromInterval(0x01, THR_ALL_FFs8);

    /* Blue value on: 0x01 - 0xFF */
    blueValue = (uint8_t)NWKU_GetRandomNoFromInterval(0x01, THR_ALL_FFs8);

    NWKU_PrintDec(redValue, aCommand + 5, 3, TRUE);     //aCommand + strlen("rgb r")
    NWKU_PrintDec(greenValue, aCommand + 10, 3, TRUE);  //aCommand + strlen("rgb r000 g")
    NWKU_PrintDec(blueValue, aCommand + 15, 3, TRUE);   //aCommand + strlen("rgb r000 g000 b")

    APP_SendLedCommand(aCommand, sizeof(aCommand));
}

/*!*************************************************************************************************
\private
\fn     static void APP_SendLedRgbOff(void *pParam)
\brief  This function is used to send a Led RGB Off command over the air.

\param  [in]    pParam    Not used
***************************************************************************************************/
static void APP_SendLedRgbOff
(
    void *pParam
)
{
    uint8_t aCommand[] = {"rgb r000 g000 b000"};

    APP_SendLedCommand(aCommand, sizeof(aCommand));
}

/*!*************************************************************************************************
\private
\fn     static void APP_SendLedFlash(void *pParam)
\brief  This function is used to send a Led flash command over the air.

\param  [in]    pParam    Not used
***************************************************************************************************/
static void APP_SendLedFlash
(
    void *pParam
)
{
    uint8_t aCommand[] = {"flash"};

    APP_SendLedCommand(aCommand, sizeof(aCommand));
}

/*!*************************************************************************************************
\private
\fn     static void APP_SendLedColorWheel(void *pParam)
\brief  This function is used to send a Led color wheel command over the air.

\param  [in]    pParam    Pointer to stack event
***************************************************************************************************/
static void APP_SendLedColorWheel
(
    void *pParam
)
{
    uint8_t aCommand[] = {"color wheel"};

    APP_SendLedCommand(aCommand, sizeof(aCommand));
}
#endif

/*!*************************************************************************************************
\private
\fn     static void APP_LocalDataSinkRelease(void *pParam)
\brief  This function is used to restore the default destination address for CoAP messages.

\param  [in]    pParam    Pointer to stack event
***************************************************************************************************/
static void APP_LocalDataSinkRelease
(
    void *pParam
)
{
    ipAddr_t defaultDestAddress = APP_DEFAULT_DEST_ADDR;

    FLib_MemCpy(&gCoapDestAddress, &defaultDestAddress, sizeof(ipAddr_t));
    (void)pParam;
}

/*!*************************************************************************************************
\private
\fn     static void APP_CoapLedCb(coapSessionStatus_t sessionStatus, void *pData,
                                  coapSession_t *pSession, uint32_t dataLen)
\brief  This function is the callback function for CoAP LED message.
\brief  It performs the required operations and sends back a CoAP ACK message.

\param  [in]    sessionStatus   Status for CoAP session
\param  [in]    pData           Pointer to CoAP message payload
\param  [in]    pSession        Pointer to CoAP session
\param  [in]    dataLen         Length of CoAP payload
***************************************************************************************************/
static void APP_CoapLedCb
(
    coapSessionStatus_t sessionStatus,
    void *pData,
    coapSession_t *pSession,
    uint32_t dataLen
)
{
    /* Process the command only if it is a POST method */
    if((pData) && (sessionStatus == gCoapSuccess_c) && (pSession->code == gCoapPOST_c))
    {
        APP_ProcessLedCmd(pData, dataLen);
    }

    /* Send the reply if the status is Success or Duplicate */
    if((gCoapFailure_c != sessionStatus) && (gCoapConfirmable_c == pSession->msgType))
    {
        /* Send CoAP ACK */
        COAP_Send(pSession, gCoapMsgTypeAckSuccessChanged_c, NULL, 0);
    }
}

/*!*************************************************************************************************
\private
\fn     static void APP_ProcessLedCmd(uint8_t *pCommand, uint8_t dataLen)
\brief  This function is used to process a LED command (on, off, flash, toggle, rgb, color wheel).

\param  [in]    pCommand    Pointer to command data
\param  [in]    dataLen     Data length
***************************************************************************************************/
static void APP_ProcessLedCmd
(
    uint8_t *pCommand,
    uint8_t dataLen
)
{
    /* Set mode state */
    APP_SetMode(mThrInstanceId, gDeviceMode_Application_c);

    /* Process command */
    if(FLib_MemCmp(pCommand, "on", 2))
    {
        App_UpdateStateLeds(gDeviceState_AppLedOn_c);
    }
    else if(FLib_MemCmp(pCommand, "off", 3))
    {
        App_UpdateStateLeds(gDeviceState_AppLedOff_c);
    }
    else if(FLib_MemCmp(pCommand, "toggle", 6))
    {
        App_UpdateStateLeds(gDeviceState_AppLedToggle_c);
    }
    else if(FLib_MemCmp(pCommand, "flash", 5))
    {
        App_UpdateStateLeds(gDeviceState_AppLedFlash_c);
    }
    else if(FLib_MemCmp(pCommand, "rgb", 3))
    {
        char* p = (char *)pCommand + strlen("rgb");
        uint8_t redValue = 0, greenValue = 0, blueValue = 0;
        appDeviceState_t appState = gDeviceState_AppLedRgb_c;

        dataLen -= strlen("rgb");

        while(dataLen != 0)
        {
            if(*p == 'r')
            {
                p++;
                dataLen--;
                redValue = NWKU_atoi(p);
            }

...

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

Credits

Ashok R

Ashok R

37 projects • 102 followers
Hobbyist/Engineer/Director/Animatior

Comments