Nassim Bettach
Published © Apache-2.0

Sens'it Morse

How to use Sens'it SDK and add new features? Here I show you how to implement a feature of sending messages from your sens'it to your phone.

IntermediateFull instructions provided2 hours717
Sens'it Morse

Things used in this project

Hardware components

Sigfox Sens'it
×1

Software apps and online services

Nexmo
Sigfox IoT Agency Platform
Sigfox Build Sens'it

Story

Read more

Code

Header

C Header File
Header file
/*!******************************************************************
 * \file button_morse.h
 * \brief Sample code to handle morse code with button
 * \author Sens'it Team, modified by Adoption Team
 * \copyright Copyright (c) 2018 Sigfox, All Rights Reserved.
 *******************************************************************/


/*!******************************************************************
 * \enum button_e
 * \brief Enumaration of button actions.
 *******************************************************************/
typedef enum {
    BUTTON_LONG_PRESS    = 0,
    BUTTON_ONE_PRESS     = 1,
    BUTTON_LAST
} button_e;


/*!************************************************************************
 * \fn void BUTTON_morse_handler(void)
 * \brief Count button presses.
 * \param[out] button_e* buttonArray      Pointer where to write the clicks
 *
 * Both falling edge interrupt & rising edge interrupt must be enabled.
 *
 * \retval array of button_e
 **************************************************************************/
int         BUTTON_morse_handler(button_e* buttonArray);

void        LED_control(bool blink, rgb_color_e color);
char        REGISTER_input(button_e *btn, u32 letter, int size);
int         CHECK_input(u32 letter);
void        STORE_input(u32 *buffer_final, u32 letter, int number_char);
void        RESIZE_buffer(u32 *buffer_final, u8 *payload);
void        INIT_values(u32 *buffer_final, u8 *payload);
int         BUTTON_morse_handler(button_e* buttonArray);

Makefile

Makefile
Makefile with morse rule
##############################
#    Sens'it SDK Makefile    #
##############################


# -----------
# SDK LIBRARY
# -----------
LIB_NAME = SENSIT_SDK_V2.0.0
LIB_PATH = lib


# --------------
# OUTPUT FOLDERS
# --------------
BIN_PATH = bin
OBJ_PATH = obj


# ------------
# OUTPUT FILES
# ------------
OUTPUT_NAME = sensit
MAP_OUTPUT  = $(OUTPUT_NAME).map
ELF_OUTPUT  = $(OUTPUT_NAME).elf
BIN_OUTPUT  = $(OUTPUT_NAME).bin
SIZE_OUTPUT = $(OUTPUT_NAME).siz


# ---------
# TOOLCHAIN
# ---------
CC = arm-none-eabi-gcc
BIN_TOOL  = arm-none-eabi-objcopy
SIZE_TOOL = arm-none-eabi-size


# -------------------
# COMPILATION OPTIONS
# -------------------
CC_OPT   = -mcpu=cortex-m0 -mthumb -mfloat-abi=soft -g -Os -Wall -fmessage-length=0 -ffunction-sections
CC_INC   = -Iinc -Iinc/sensit -Iinc/sigfox -Iinc/resources -Iinc/radio -Iinc/sensors -Iinc/tools -Isrc
CC_FLAGS = -DUSB -DUSE_RC1


# ---------------
# SOURCES FOLDERS
# ---------------
VPATH += \
src \
src/resources \
src/sensors \
src/radio \
src/tools


# ------------
# OBJECTS LIST
# ------------
OBJ_LIST = \
error.o \
button.o \
battery.o \
callback.o \
serial.o \
radio_api.o \
etsi.o \
fcc.o \
hts221.o \
ltr329.o \
fxos8700.o \
AT_parser.o \
AT_functions.o \
discovery.o \
button_morse.o

OBJS = $(addprefix $(OBJ_PATH)/,$(OBJ_LIST))


# ------------
# LINK OPTIONS
# ------------
LD_OPT  = -L$(LIB_PATH) -T "LinkerScript.ld" -nostartfiles -nodefaultlibs -nostdlib -Xlinker --gc-sections -Wl,-Map,"$(BIN_PATH)/$(MAP_OUTPUT)"


# -----------------
# COMPLETE BUILDING
# -----------------
all: clean dir $(OBJS) main bin

temperature: clean dir $(OBJS) main_TEMPERATURE bin
light: clean dir $(OBJS) main_LIGHT bin
vibration: clean dir $(OBJS) main_VIBRATION bin
magnet: clean dir $(OBJS) main_MAGNET bin
modem: clean dir $(OBJS) main_MODEM bin
morse: clean dir $(OBJS) main_MORSE bin


# ----------------
# OBJECTS BUILDING
# ----------------
$(OBJ_PATH)/%.o: %.c
	@echo 'Building file: $@'
	@echo 'Invoking: Cross ARM C Compiler'
	$(CC) $(CC_OPT) $(CC_FLAGS) $(CC_INC) -c -o $@ $<
	@echo 'Finished building: $@'
	@echo ' '

main:
	@echo 'Building file: $(OBJ_PATH)/main.o'
	@echo 'Invoking: Cross ARM C Compiler'
	$(CC) $(CC_OPT) $(CC_FLAGS) $(CC_INC) -c -o $(OBJ_PATH)/main.o src/main.c
	@echo 'Finished building: $(OBJ_PATH)/main.o'
	@echo ' '

main_TEMPERATURE:
	@echo 'Building file: $(OBJ_PATH)/main.o'
	@echo 'Invoking: Cross ARM C Compiler'
	$(CC) $(CC_OPT) $(CC_FLAGS) $(CC_INC) -c -o $(OBJ_PATH)/main.o src/main_TEMPERATURE.c
	@echo 'Finished building: $(OBJ_PATH)/main.o'
	@echo ' '

main_LIGHT:
	@echo 'Building file: $(OBJ_PATH)/main.o'
	@echo 'Invoking: Cross ARM C Compiler'
	$(CC) $(CC_OPT) $(CC_FLAGS) $(CC_INC) -c -o $(OBJ_PATH)/main.o src/main_LIGHT.c
	@echo 'Finished building: $(OBJ_PATH)/main.o'
	@echo ' '

main_VIBRATION:
	@echo 'Building file: $(OBJ_PATH)/main.o'
	@echo 'Invoking: Cross ARM C Compiler'
	$(CC) $(CC_OPT) $(CC_FLAGS) $(CC_INC) -c -o $(OBJ_PATH)/main.o src/main_VIBRATION.c
	@echo 'Finished building: $(OBJ_PATH)/main.o'
	@echo ' '

main_MAGNET:
	@echo 'Building file: $(OBJ_PATH)/main.o'
	@echo 'Invoking: Cross ARM C Compiler'
	$(CC) $(CC_OPT) $(CC_FLAGS) $(CC_INC) -c -o $(OBJ_PATH)/main.o src/main_MAGNET.c
	@echo 'Finished building: $(OBJ_PATH)/main.o'
	@echo ' '

main_MODEM:
	@echo 'Building file: $(OBJ_PATH)/main.o'
	@echo 'Invoking: Cross ARM C Compiler'
	$(CC) $(CC_OPT) $(CC_FLAGS) $(CC_INC) -c -o $(OBJ_PATH)/main.o src/main_MODEM.c
	@echo 'Finished building: $(OBJ_PATH)/main.o'
	@echo ' '

main_MORSE:
	@echo 'Building file: $(OBJ_PATH)/main.o'
	@echo 'Invoking: Cross ARM C Compiler'
	$(CC) $(CC_OPT) $(CC_FLAGS) $(CC_INC) -c -o $(OBJ_PATH)/main.o src/main_MORSE.c
	@echo 'Finished building: $(OBJ_PATH)/main.o'
	@echo ' '

# ------------------------
# ELF / BIN / SIZ BUILDING
# ------------------------
$(BIN_PATH)/$(ELF_OUTPUT):
	@echo 'Building target: $(ELF_OUTPUT)'
	@echo 'Invoking: Cross ARM C Linker'
	$(CC) $(CC_OPT) $(LD_OPT) -o $@ $(OBJS) $(OBJ_PATH)/main.o -l$(LIB_NAME)
	@echo 'Finished building: $(ELF_OUTPUT)'
	@echo ' '

$(BIN_PATH)/$(BIN_OUTPUT):
	@echo 'Building target: $(BIN_OUTPUT)'
	@echo 'Invoking: Cross ARM GNU Create Flash Image'
	$(BIN_TOOL) -O binary $(BIN_PATH)/$(ELF_OUTPUT) $@
	@echo 'Finished building: $(BIN_OUTPUT)'
	@echo ' '

$(BIN_PATH)/$(SIZE_OUTPUT):
	@echo 'Building target: $(SIZE_OUTPUT)'
	@echo 'Invoking: Cross ARM GNU Print Size'
	$(SIZE_TOOL) --format=berkeley "$(BIN_PATH)/$(ELF_OUTPUT)" > $@
	@cat $@
	@echo 'Finished building: $(SIZE_OUTPUT)'
	@echo ' '

bin: $(BIN_PATH)/$(ELF_OUTPUT) $(BIN_PATH)/$(BIN_OUTPUT) $(BIN_PATH)/$(SIZE_OUTPUT)


# -------------
# OTHER TARGETS
# -------------
clean:
	@echo 'Clean output folders'
	rm -rf $(BIN_PATH) $(OBJ_PATH)
	@echo ' '

dir:
	@echo 'Create output folders'
	mkdir -p $(BIN_PATH) $(OBJ_PATH)
	@echo ' '

# Rule for USB flashing using dfu file manager (vendor id 0483)
prog:
	dfu-util -a 0 -s 0x08000000:leave -D $(BIN_PATH)/$(BIN_OUTPUT)

main_MORSE.c

C/C++
Main program
/*!******************************************************************
 * \file main.c
 * \brief Sens'it SDK template
 * \author Sens'it Team
 * \copyright Copyright (c) 2018 Sigfox, All Rights Reserved.
 *
 * This file is an empty main template.
 * You can use it as a basis to develop your own firmware.
 *******************************************************************/
/******* INCLUDES **************************************************/
#include "sensit_types.h"
#include "sensit_api.h"
#include "error.h"
#include "button_morse.h"
#include "battery.h"
#include "radio_api.h"
#include "serial.h"
#include "AT_parser.h"


/******* GLOBAL VARIABLES ******************************************/
u8 firmware_version[] = "TEMPLATE";


/*******************************************************************/

int main()
{
    error_t     err;
    button_e    btn[5];
    u16         battery_level;
    u32         letter;
    char        number_char;
    u32         buffer_final[3] = {0, 0, 0};
	u8          payload[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    int         size;

    /* Start of initialization */

    /* Configure button */
    SENSIT_API_configure_button(INTERRUPT_BOTH_EGDE);
    /* Configure reed switch */
    SENSIT_API_configure_reed_switch(TRUE, INTERRUPT_BOTH_EGDE);
    /* Init Serial port */
    SERIAL_init();
    /* Initialize Sens'it radio */
    err = RADIO_API_init();
    ERROR_parser(err);
    /* Clear pending interrupt */
    pending_interrupt = 0;
    number_char = 0;
    /* End of initialization */

    while (TRUE)
    {
        /* Execution loop */

        /* Check of battery level */
        BATTERY_handler(&battery_level);

        /* RTC alarm interrupt handler */
        if ((pending_interrupt & INTERRUPT_MASK_RTC) == INTERRUPT_MASK_RTC)
        {
            /* Clear interrupt */
            pending_interrupt &= ~INTERRUPT_MASK_RTC;
        }

        /* Reed switch interrupt handler */
        if ((pending_interrupt & INTERRUPT_MASK_REED_SWITCH) == INTERRUPT_MASK_REED_SWITCH)
        {
            /* Reset the device */
            SENSIT_API_reset();
        }

        /* Button interrupt handler */
        if ((pending_interrupt & INTERRUPT_MASK_BUTTON) == INTERRUPT_MASK_BUTTON)
        {
            letter = 1;
            /* Array of clicks in btn[] */
            size = BUTTON_morse_handler(btn);

            /* Convert and register into a buffer btn[] | 6 bits per character */
            letter = REGISTER_input(btn, letter, size);
            /* Check if 4 long press or the buffer is full 15 char max, to send the message */ 
            if (letter == 16 || number_char == 15)
            {
                LED_control(1, RGB_WHITE);
                RESIZE_buffer(buffer_final, payload);
                RADIO_API_send_message(RGB_YELLOW, payload, 12, FALSE, NULL);
                number_char = 0;
                INIT_values(buffer_final, payload);
            }
            /* Check if the input is a correct morse character | LED feedback: Green OK, Red NOK*/
            else if (CHECK_input(letter))
            {
                number_char++;
                STORE_input(buffer_final, letter, number_char);
                LED_control(1, RGB_GREEN);
            }
            else
                LED_control(1, RGB_RED);
            
            /* Clear interrupt */
            pending_interrupt &= ~INTERRUPT_MASK_BUTTON;
        }

        /* Check if all interrupt have been clear */
        if (pending_interrupt == 0)
        {
            /* Wait for Interrupt */
            SENSIT_API_sleep(FALSE);
        }
    } /* End of while */
}

/*******************************************************************/

button_morse.c

C/C++
Button handler to save the input and all the function called in the main program
/*!******************************************************************
 * \file button_morse.c
 * \brief Sample code to handle morse code with button
 * \author Sens'it Team, modified by Adoption Team
 * \copyright Copyright (c) 2018 Sigfox, All Rights Reserved.
 *******************************************************************/
/******* INCLUDES **************************************************/
#include "sensit_types.h"
#include "sensit_api.h"
#include "button_morse.h"
#include "serial.h"
#include "AT_parser.h"


/******* DEFINES ***************************************************/
#define BUTTON_TIMEOUT          300 /* milliseconds */
#define LETTER_TIMEOUT          3 /* register letter 3 sec after last click */
#define MAX_CLICKS              5 /* 5 clicks max */


/*******************************************************************/
void    LED_control(bool blink, rgb_color_e color)
{
    char i;
	
    i = 7;
    if (blink)
    {
        while (i--)
        {
            SENSIT_API_set_rgb_led(color);
            SENSIT_API_wait(200);
            SENSIT_API_set_rgb_led(RGB_OFF);
            SENSIT_API_wait(200);
        }   
    }
    else
        SENSIT_API_set_rgb_led(color);
}

char    REGISTER_input(button_e *btn, u32 letter, int size)
{
    int     i;

    i = -1;
    while (++i < size)
    {
       if (btn[i] == 1)
            letter = (letter << 1) + 1;
       else
            letter = letter << 1;
    }
    return (letter);
}

int     CHECK_input(u32 letter)
{
    char *morse_bt =
		"**TEMNAIOGKDWRUS**QZYCXBJP*L*FVH09*8***7*****/=61****+**2***3*45";

	if (morse_bt[letter] != '*')
		return (1);
    else
		return (0);
}

void    RESIZE_buffer(u32 *buffer_final, u8 *payload)
{
	int i;
	int j;

	j = 0;
	i = -1;
	while (++i < 3)
	{
		payload[j++] = (buffer_final[i] & 0xFF000000) >> 24;
		payload[j++] = (buffer_final[i] & 0xFF0000) >> 16;
		payload[j++] = (buffer_final[i] & 0xFF00) >> 8;
		payload[j++] = (buffer_final[i] & 0xFF);
	}
}

void    INIT_values(u32 *buffer_final, u8 *payload)
{
    int i;

    i = -1;
    while (++i < 3)
        buffer_final[i] = 0;
    i = -1;
    while (++i < 12)
        payload[i] = 0;
}

void    STORE_input(u32 *buffer_final, u32 letter, int number_char)
{
	int shiftbits;

	if (number_char > 0 && number_char < 6)
	{
		shiftbits = 32 - (number_char * 6);
		buffer_final[0] += letter << shiftbits;
	}
	else if (number_char == 6)
	{
		buffer_final[0] += letter >> 4;
		buffer_final[1] += (letter & 0xF) << 28;
	}
	else if (number_char > 6 && number_char < 11)
	{
		shiftbits = 28 - ((number_char - 6) * 6);
		buffer_final[1] += letter << shiftbits;
	}
	else if (number_char == 11)
	{
		buffer_final[1] += letter >> 2;
		buffer_final[2] += (letter & 0x3) << 30;
	}
	else if (number_char > 11 && number_char < 17)
	{
		shiftbits = 30 - ((number_char - 11) * 6);
		buffer_final[2] += letter << shiftbits;
	}
}

int BUTTON_morse_handler(button_e* buttonArray)
{
    bool buttonState;
    bool lastState;
    u8 i = 0;

    char nbPresses[2]; // to store char value of nb of push

    // register clicks, loop ends on MAX_CLICKS or LETTER_TIMEOUT RTC interrupt
    while(i < MAX_CLICKS)
    {
        SENSIT_API_get_button_state(&buttonState);

        if (!buttonState && lastState) // button is pressed && was previously released
        {
            /* RGB Led ON during count of button presses */
            SENSIT_API_set_rgb_led(RGB_WHITE);

            pending_interrupt &= ~INTERRUPT_MASK_RTC; // clear RTC interrupt
            SENSIT_API_wait(BUTTON_TIMEOUT);
            SENSIT_API_get_button_state(&buttonState);

            if (buttonState) // button is released within BUTTON_TIMEOUT => short click
                buttonArray[i] = BUTTON_ONE_PRESS;
            else
                buttonArray[i] = BUTTON_LONG_PRESS;

            /* RGB Led OFF */
            SENSIT_API_set_rgb_led(RGB_OFF);

            // DEBUG
            //SERIAL_put_data((u8*)AT_itoa(buttonArray[i], nbPresses, 10), 2);
            //SERIAL_put_data((u8*)" - ", 3);

            i++; // Next click

  	        SENSIT_API_set_rtc_alarm(LETTER_TIMEOUT); // set RTC timeout
            /* Debounce wait */
            SENSIT_API_wait(5);
        }

        // if RTC interrupt (LETTER_TIMEOUT) => exit loop and returns array
        if ((pending_interrupt & INTERRUPT_MASK_RTC) == INTERRUPT_MASK_RTC)
        {
            /* Clear interrupt */
            pending_interrupt &= ~INTERRUPT_MASK_RTC;
            break;
        }

        lastState = buttonState;
    }

    //SERIAL_put_data((u8*)"EXIT LOOP\r\n", 11);
    return (i);
}

/*******************************************************************/

Credits

Nassim Bettach

Nassim Bettach

3 projects • 5 followers

Comments