Skip to content

Instantly share code, notes, and snippets.

@harrkout
Last active February 1, 2024 08:56
Show Gist options
  • Save harrkout/51279d08f499a90846bca7c143a21fdd to your computer and use it in GitHub Desktop.
Save harrkout/51279d08f499a90846bca7c143a21fdd to your computer and use it in GitHub Desktop.
Leshan OMA Lightweight M2M server for Zephyr with FOTA Delta updates custom for B-L475E-IOT01A w/ ARM Cortex®-M4 & 64-Mbit Quad-SPI (Macronix) Flash memory
/*
* Copyright (c) 2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
* Original concept was created by L. LINDH, for her thesis 'https://odr.chalmers.se/bitstreams/600cc344-f3b6-4ce0-b281-164b706b3d2e/download`
*
* This implementation took the original code, which was designed for the nRF52840 DK, which houses an ARM Cortex-M4F, and
* ported it for ST's L4 series of MCUs, which house the ARM Cortex-M4.
*
* Even though the M4F being single precision FPU and up to 15 times faster floating point performance than Cortex-M4, the M4 version
* is more commonly found, thus a porting was made.
*/
#include "delta.h"
/*
* IMAGE/FLASH MANAGEMENT
*/
uint8_t temp_buffer[4096] = {0};
static int erase_page(struct flash_mem* flash, off_t offset)
{
offset = offset - offset % PAGE_SIZE; /* find start of page */
if (flash_write_protection_set(flash->device, false)) { return -DELTA_CLEARING_ERROR; }
if (flash_erase(flash->device, offset, PAGE_SIZE)) { return -DELTA_CLEARING_ERROR; }
if (flash_write_protection_set(flash->device, true)) { return -DELTA_CLEARING_ERROR; }
return DELTA_OK;
}
static int delta_flash_write(void* arg_p, const uint8_t* buf_p, size_t size)
{
struct flash_mem* flash;
int page_multiples = 0 ;
uint32_t page_multiples_offset = 0;
uint32_t byte_offset = 0;
//uint8_t temp_buffer[4096] = {0};
size_t write_size = size;
uint32_t write_offset = 0;
int pad_size = 0;
memset(temp_buffer,0xff, 4096);
flash = (struct flash_mem*)arg_p;
flash->write_buf += size;
write_offset = flash->to_current;
if (flash->write_buf >= PAGE_SIZE) {
if (erase_page(flash, flash->to_current + (off_t)size)) {
printk("\n\n---DELTA.c---\n\n");
printk("\n--------10--------\n");
printk("\n\nDELTA CLEARING ERROR\n\n");
return -DELTA_CLEARING_ERROR;
}
flash->write_buf = 0;
}
if (!flash) { return -DELTA_CASTING_ERROR; }
if (flash_write_protection_set(flash->device, false)) {
printk("\n\n---DELTA.c---\n");
printk("\n--------11--------\n");
printk("\n///DELTA_WRITING_ERROR///\n\n");
return -DELTA_WRITING_ERROR;
}
//Mechanism to prevent Unaligned Writing
printk("\n\n\n-------------12.0---------------");
printk("\n\n\n------------ALIGNED-------------\n\n");
printk("\nBefore: Eight multiples: %d\n\n", page_multiples);
printk("Before: Eight multiples offset: 0x%08X\n\n", page_multiples_offset);
printk("WRITE offset: 0x%08X\n\n", write_offset);
printk("flash->to_current Offset: 0x%08X\n\n", flash->to_current);
if((flash->to_current % 8) != 0)
{
printk("\n\n\n---Unaligned----\n\n");
page_multiples = flash->to_current / 2048;
printk("Page multiples: %d\n\n", page_multiples);
page_multiples_offset = page_multiples * 2048;
printk("Page multiples offset: 0x%08X\n\n", page_multiples_offset);
if (flash_read(flash->device, page_multiples_offset, temp_buffer, 2048))
{
printk("\n--------OFFSET--------\n");
printk("Failed at page multiples offset: %08X\n\n", page_multiples_offset);
return -DELTA_READING_SOURCE_ERROR;
}
byte_offset = flash->to_current - page_multiples_offset;
memcpy((temp_buffer + byte_offset), buf_p, size);
// write_size += byte_offset;
write_offset = page_multiples_offset;
printk("Unaligned write offset: 0x%08X\n\n", write_offset);
printk("Unaligned flash->to_current Offset: 0x%08X\n\n", flash->to_current);
printk("\n\n----OK----\n\n");
printk("\n\n\n----------------END----------------\n\n\n");
flash_erase(flash->device, (page_multiples_offset), 4096);
if (flash_write(flash->device, write_offset, temp_buffer, 4096))
{
printk("\n\n---DELTA.c---\n");
printk("\n--------12--------\n");
printk("\n///DELTA_WRITING_ERROR///\n\n");
return -DELTA_WRITING_ERROR;
}
}
else
{
if((write_size % 8) != 0)
{
pad_size = 8 - (write_size % 8);
printk("Write_size % 8 = %d (!=0 ==> So padding is on order\n");
printk("Pad size: %d\n", pad_size);
}
printk("WRITE offset: 0x%08X\n\n", write_offset);
if (flash_write(flash->device, write_offset, buf_p, write_size + pad_size)) {
printk("\n\n---DELTA.c---\n");
printk("\n--------12--------\n");
printk("\n///DELTA_WRITING_ERROR///\n\n");
return -DELTA_WRITING_ERROR;
}
}
printk("\n\n\n-------------12.1---------------");
printk("\n\n\n------------ALIGNED-------------\n\n");
printk("\nAfter: Eight multiples: %d\n", page_multiples);
printk("After: Eight multiples offset: 0x%08X\n", page_multiples_offset);
// if((write_size % 8) != 0)
// {
// pad_size = 8 - (write_size % 8);
// printk("Pad size: %d\n", pad_size);
// }
printk("WRITE offset: 0x%08X\n\n", write_offset);
printk("flash->to_current Offset: 0x%08X\n\n", flash->to_current);
printk("\n--------------------\n");
// if (flash_write(flash->device, flash->to_current, buf_p, size + pad_size)) {
// printk("\n\n---DELTA.c---\n");
// printk("\n--------12--------\n");
// printk("\n///DELTA_WRITING_ERROR///\n\n");
// return -DELTA_WRITING_ERROR;
// }
if (flash_write_protection_set(flash->device, true)) { return -DELTA_WRITING_ERROR; }
flash->to_current += (off_t)size;
if (flash->to_current >= flash->to_end) {
printk("\nDELTA_SLOT1_OUT_OF_MEMORY\n");
return -DELTA_SLOT1_OUT_OF_MEMORY;
}
return DELTA_OK;
}
// static int delta_flash_write(void* arg_p, const uint8_t* buf_p, size_t size)
// {
// struct flash_mem* flash;
// int eight_multiples = 0 ;
// uint32_t eight_multiples_offset = 0;
// uint32_t byte_offset = 0;
// uint8_t temp_buffer[512] = {0};
// size_t write_size = size;
// uint32_t write_offset = 0;
// int pad_size = 0;
// flash = (struct flash_mem*)arg_p;
// flash->write_buf += size;
// write_offset = flash->to_current;
// if (flash->write_buf >= PAGE_SIZE) {
// if (erase_page(flash, flash->to_current + (off_t)size)) {
// printk("\n\n---DELTA.c---\n\n");
// printk("\n--------10--------\n");
// printk("\n\nDELTA CLEARING ERROR\n\n");
// return -DELTA_CLEARING_ERROR;
// }
// flash->write_buf = 0;
// }
// if (!flash) { return -DELTA_CASTING_ERROR; }
// if (flash_write_protection_set(flash->device, false)) {
// printk("\n\n---DELTA.c---\n");
// printk("\n--------11--------\n");
// printk("\n///DELTA_WRITING_ERROR///\n\n");
// return -DELTA_WRITING_ERROR;
// }
// //Mechanism to prevent Unaligned Writing
// printk("\n\n\n-------ALIGNMENT--------\n\n");
// printk("\nBefore: Eight multiples: %d\n\n", eight_multiples);
// printk("Before: Eight multiples offset: 0x%08X\n\n", eight_multiples_offset);
// printk("Offset: 0x%08X\n\n", flash->to_current);
// if((flash->to_current % 8) != 0)
// {
// printk("\n\n\n---Unaligned----\n\n");
// eight_multiples = flash->to_current / 8;
// printk("Eight multiples: %d\n\n", eight_multiples);
// eight_multiples_offset = eight_multiples * 8;
// printk("Eight multiples offset: 0x%08X\n\n", eight_multiples_offset);
// if (flash_read(flash->device, eight_multiples_offset, temp_buffer, 8))
// {
// printk("\n--------OFFSET--------\n");
// printk("Failed at eight multiples offset: %08X\n\n", eight_multiples_offset);
// return -DELTA_READING_SOURCE_ERROR;
// }
// byte_offset = flash->to_current - eight_multiples_offset;
// memcpy((temp_buffer + byte_offset), buf_p, size);
// write_size += byte_offset;
// write_offset = eight_multiples_offset;
// printk("\n\n\n----OK----\n\n\n");
// }
// printk("After: Eight multiples: %d\n\n", eight_multiples);
// printk("After: Eight multiples offset: 0x%08X\n\n", eight_multiples_offset);
// if((write_size % 8) != 0)
// {
// pad_size = 8 - (write_size % 8);
// printk("Pad size: %d\n", pad_size);
// }
// printk("WRITE offset: 0x%08X\n\n", write_offset);
// if (flash_write(flash->device, write_offset, temp_buffer, write_size + pad_size)) {
// printk("\n\n---DELTA.c---\n");
// printk("\n--------12--------\n");
// printk("\n///DELTA_WRITING_ERROR///\n\n");
// return -DELTA_WRITING_ERROR;
// }
// // if (flash_write(flash->device, flash->to_current, buf_p, size + pad_size)) {
// // printk("\n\n---DELTA.c---\n");
// // printk("\n--------12--------\n");
// // printk("\n///DELTA_WRITING_ERROR///\n\n");
// // return -DELTA_WRITING_ERROR;
// // }
// if (flash_write_protection_set(flash->device, true)) { return -DELTA_WRITING_ERROR; }
// flash->to_current += (off_t)size;
// if (flash->to_current >= flash->to_end) {
// printk("\nDELTA_SLOT1_OUT_OF_MEMORY\n");
// return -DELTA_SLOT1_OUT_OF_MEMORY;
// }
// return DELTA_OK;
// }
static int delta_flash_from_read(void* arg_p, uint8_t* buf_p, size_t size)
{
struct flash_mem* flash;
flash = (struct flash_mem*)arg_p;
if (!flash) { return -DELTA_CASTING_ERROR; }
if (size <= 0) { return -DELTA_INVALID_BUF_SIZE; }
if (flash_read(flash->device, flash->from_current, buf_p, size)) { return -DELTA_READING_SOURCE_ERROR; }
flash->from_current += (off_t)size;
printk("\n-----delta_flash_from_read-----\n\nflash->from_current: 0x%08x \n", flash->from_current);
if (flash->from_current >= flash->from_end) { return -DELTA_READING_SOURCE_ERROR; }
return DELTA_OK;
}
static int delta_flash_patch_read(void* arg_p, uint8_t* buf_p, size_t size)
{
struct flash_mem* flash;
flash = (struct flash_mem*)arg_p;
if (!flash) { return -DELTA_CASTING_ERROR; }
if (size <= 0) { return -DELTA_INVALID_BUF_SIZE; }
if (flash_read(flash->device, flash->patch_current, buf_p, size)) { return -DELTA_READING_PATCH_ERROR; }
flash->patch_current += (off_t)size;
if (flash->patch_current >= flash->patch_end) { return -DELTA_READING_PATCH_ERROR; }
printk("\n-------------------6-----------------\r\n");
printk("size: 0x%08x \n", size);
printk("flash->patch_current: 0x%08x \n", flash->patch_current);
printk("flash->patch_end (Patch_Offset - Patch_Size): 0x%08x \n", flash->patch_end);
return DELTA_OK;
}
static int delta_flash_seek(void* arg_p, int offset)
{
struct flash_mem* flash;
flash = (struct flash_mem*)arg_p;
if (!flash) { return -DELTA_CASTING_ERROR; }
flash->from_current += offset;
printk("offset: 0x%08x \n", offset);
if (flash->from_current >= flash->from_end) { return -DELTA_SEEKING_ERROR; }
return DELTA_OK;
}
/*
* INIT
*/
static int delta_init_flash_mem(struct flash_mem* flash)
{
if (!flash) { return -DELTA_NO_FLASH_FOUND; }
flash->from_current = PRIMARY_OFFSET;
flash->from_end = flash->from_current + PRIMARY_SIZE;
flash->to_current = SECONDARY_OFFSET;
flash->to_end = flash->to_current + SECONDARY_SIZE;
flash->patch_current = STORAGE_OFFSET + HEADER_SIZE;
flash->patch_end = flash->patch_current + STORAGE_SIZE;
flash->write_buf = 0;
printk("\n-------------------3-----------------\r\n");
printk("flash->patch_current = STORAGE_OFFSET + HEADER_SIZE: 0x%08x \n", flash->patch_current);
printk("STORAGE_OFFSET: 0x%08x \n", STORAGE_OFFSET);
printk("HEADER_SIZE: 0x%08x \n", HEADER_SIZE);
return DELTA_OK;
}
static int delta_init(struct flash_mem* flash)
{
int ret;
printk("\n-------------------4-----------------\r\n");
ret = delta_init_flash_mem(flash);
if (ret) { return ret; }
ret = erase_page(flash, flash->to_current);
if (ret) { return ret; }
printk("\n------delta_init in --> delta.c------\n");
printk("Flash to_current: 0x%08x \n", flash->to_current);
return DELTA_OK;
}
/*
* PUBLIC FUNCTIONS
*/
int delta_check_and_apply(struct flash_mem *flash)
{
// flash_erase(flash->device, (SECONDARY_OFFSET), 0x6c000); //pages
// printk("Flash erase complete \n\n");
// return 0;
uint32_t patch_size;
int ret;
printk("----------delta_check_and_apply-----------\n\n");
ret = delta_read_patch_header(flash,&patch_size);
printk("Patch_size: 0x%08x \n\n", patch_size);
if (ret < 0) {
printk("Ret < 0: %d \n\n", ret);
return ret;
} else if (patch_size > 0) {
ret = delta_init(flash);
printk("\n--delta_check_and_apply --> delta.c--\n");
printk("\n--Output_1--\n");
printk("Patch_size > 0 --> ret = %d \n\n", ret);
if (ret) {
printk("--Output_2--\n");
printk("Patch_size > 0 --> ret = %d \n\n", ret);
return ret;
}
ret = detools_apply_patch_callbacks(delta_flash_from_read,
delta_flash_seek,
delta_flash_patch_read,
(size_t) patch_size,
delta_flash_write,
flash);
if (ret <= 0) {
printk("\n---Entering: delta_check_and_apply ---> in delta.c----\n\n");
printk("\n--Output_3--\n\n");
printk("Ret = %d \n\n", ret);
return ret;
}
if (boot_request_upgrade(BOOT_UPGRADE_PERMANENT)) {
printk("Boot Request \n\n");
return -1;
}
//sys_reboot(SYS_REBOOT_COLD);
printk("Ret = %d \n\n", ret);
}
printk("Delta OK %d \n", DELTA_OK);
return DELTA_OK;
}
int delta_read_patch_header(struct flash_mem* flash, uint32_t *size)
{
//int offset = 0x00000000;
uint32_t new_patch, reset_msg[2] = {0}, patch_header[2] = {0}, page_buffer[2048];
new_patch = 0x5057454E; // ASCII for "NEWP" signaling new patch
reset_msg[0] = 0xFFFFFFFFU; // reset "NEWP"
printk("\n-------------------1-----------------\r\n");
printk("'NEWP' Patch Message in HEX: 0x%08x \n\n", new_patch);
printk("Reset Message [0]: 0x%08x \n", reset_msg[0]);
printk("Reset Message [1]: 0x%08x \n\n", reset_msg[1]);
printk("Patch Header[0] ('NEWP'): 0x%08x \n", patch_header[0]);
printk("Patch Header[1] (Patch Size): 0x%08x \n", patch_header[1]);
/*
for(int i = 0; i < (0x100000); i++)
{
if (flash_read(flash->device, offset, patch_header, 4)) { return -DELTA_PATCH_HEADER_ERROR; }
if(patch_header[0] == 0xefbeadba)
{
printk("Record found at offset 0x%08x\r\n", offset);
//break;
}
offset += 4;
//printk("Offset Count 0x%08x\r\n", offset);
}
*/
if (flash_read(flash->device, (STORAGE_OFFSET), patch_header, sizeof(patch_header))) { return -DELTA_PATCH_HEADER_ERROR; }
printk("\nOffset Count 0x%08x\r\n\n", STORAGE_OFFSET);
printk("Patch Header[0] ('NEWP'): 0x%08x \n", patch_header[0]);
printk("Patch Header[1] ('Patch Size'): 0x%08x \n", patch_header[1]);
printk("------------------------------------\r\n");
if (new_patch != patch_header[0]) {
return DELTA_OK;
printk("New_patch != patch_header[0] ???");
printk("------------------------------------\r\n");
}
reset_msg[1] = 0xFFFFFFFFU; //patch_header[1];
printk("Reset Message [0]: 0x%08x \n", reset_msg[0]);
printk("Reset Message [1]: 0x%08x \n\n", reset_msg[1]);
*size = patch_header[1];
printk("size = patch_header[1]: %p \n", size);
printk("------------------------------------\r\n");
//custom buffer
if (flash_read(flash->device, (STORAGE_OFFSET), page_buffer, 2048)) { return -DELTA_PATCH_HEADER_ERROR; }
//instead of reset_msg
page_buffer[0] = 0;
flash_erase(flash->device, (STORAGE_OFFSET), 2048);
flash_erase(flash->device, (SECONDARY_OFFSET), 442368); //0x8c000); //pages=1728
//return 0;
if (flash_write_protection_set(flash->device, false))
{
printk("Write protection SET\r\n");
return -DELTA_PATCH_HEADER_ERROR;
}
//if (flash_write(flash->device, STORAGE_OFFSET, reset_msg, sizeof(reset_msg)))
if (flash_write(flash->device, STORAGE_OFFSET, page_buffer, 2048))
{
printk("------------------------------------\r\n\n");
printk("Flash Write SET\r\n\n");
return -DELTA_PATCH_HEADER_ERROR;
}
if (flash_write_protection_set(flash->device, true))
{
printk("Write protection SET\r\n");
return -DELTA_PATCH_HEADER_ERROR;
}
return DELTA_OK;
}
const char* delta_error_as_string(int error)
{
if (error < 28) { return detools_error_as_string(error); }
if (error < 0) { error *= -1; }
switch (error) {
case DELTA_SLOT1_OUT_OF_MEMORY:
return "Slot 1 out of memory.";
case DELTA_READING_PATCH_ERROR:
return "Error reading patch.";
case DELTA_READING_SOURCE_ERROR:
return "Error reading source image.";
case DELTA_WRITING_ERROR:
return "Error writing to slot 1.";
case DELTA_SEEKING_ERROR:
return "Seek error.";
case DELTA_CASTING_ERROR:
return "Error casting to flash_mem.";
case DELTA_INVALID_BUF_SIZE:
return "Read/write buffer less or equal to 0.";
case DELTA_CLEARING_ERROR:
return "Could not clear slot 1.";
case DELTA_NO_FLASH_FOUND:
return "No flash found.";
case DELTA_PATCH_HEADER_ERROR:
return "Error reading patch header.";
default:
return "Unknown error.";
}
}
/*
* Copyright (c) 2017 Linaro Limited
* Copyright (c) 2017-2019 Foundries.io
*
* SPDX-License-Identifier: Apache-2.0
*/
#define LOG_MODULE_NAME net_lwm2m_client_app
#define LOG_LEVEL LOG_LEVEL_DBG
#include <logging/log.h>
LOG_MODULE_REGISTER(LOG_MODULE_NAME);
#include <drivers/hwinfo.h>
#include <zephyr.h>
#include <drivers/gpio.h>
#include <drivers/sensor.h>
#include <net/lwm2m.h>
#include <sys/reboot.h>
#include <device.h>
// #include "flash.h"
#include "delta/delta.h"
#include <drivers/gpio.h>
#include <sys/printk.h>
#include <sys/util.h>
#define APP_BANNER "Run LWM2M client"
#if !defined(CONFIG_NET_CONFIG_PEER_IPV4_ADDR)
#define CONFIG_NET_CONFIG_PEER_IPV4_ADDR ""
#endif
#if !defined(CONFIG_NET_CONFIG_PEER_IPV6_ADDR)
#define CONFIG_NET_CONFIG_PEER_IPV6_ADDR ""
#endif
#if defined(CONFIG_NET_IPV6)
#define SERVER_ADDR CONFIG_NET_CONFIG_PEER_IPV6_ADDR
#elif defined(CONFIG_NET_IPV4)
#define SERVER_ADDR CONFIG_NET_CONFIG_PEER_IPV4_ADDR
#else
#error LwM2M requires either IPV6 or IPV4 support
#endif
#define REBOOT_DELAY_SEC 1
#define GRN "\x1B[32m"
#define WAIT_TIME K_SECONDS(10)
#define CONNECT_TIME K_SECONDS(10)
#define CLIENT_MANUFACTURER "Zephyr"
#define CLIENT_MODEL_NUMBER "OMA-LWM2M Sample Client"
#define CLIENT_SERIAL_NUMBER "345000123"
#define CLIENT_FIRMWARE_VER "1.0"
#define CLIENT_DEVICE_TYPE "OMA-LWM2M Client"
#define CLIENT_HW_VER "1.0.1"
#define LIGHT_NAME "Test light"
#define TIMER_NAME "Test timer"
#define ENDPOINT_LEN 32
#if DT_NODE_HAS_STATUS(DT_ALIAS(led0), okay)
#define LED_GPIO_PORT DT_GPIO_LABEL(DT_ALIAS(led0), gpios)
#define LED_GPIO_PIN DT_GPIO_PIN(DT_ALIAS(led0), gpios)
#define LED_GPIO_FLAGS DT_GPIO_FLAGS(DT_ALIAS(led0), gpios)
#else
/* Not an error; the relevant IPSO object will simply not be created. */
#define LED_GPIO_PORT ""
#define LED_GPIO_PIN 0
#define LED_GPIO_FLAGS 0
#endif
static uint8_t bat_idx = LWM2M_DEVICE_PWR_SRC_TYPE_BAT_INT;
static int bat_mv = 3800;
static int bat_ma = 125;
static uint8_t usb_idx = LWM2M_DEVICE_PWR_SRC_TYPE_USB;
static int usb_mv = 5000;
static int usb_ma = 900;
static uint8_t bat_level = 95;
static uint8_t bat_status = LWM2M_DEVICE_BATTERY_STATUS_CHARGING;
static int mem_free = 15;
static int mem_total = 25;
//button
static bool btn_flag;
/* BUTTON */
#define SW0_NODE DT_ALIAS(sw0)
#if DT_NODE_HAS_STATUS(SW0_NODE, okay)
#define SW0_GPIO_LABEL DT_GPIO_LABEL(SW0_NODE, gpios)
#define SW0_GPIO_PIN DT_GPIO_PIN(SW0_NODE, gpios)
#define SW0_GPIO_FLAGS (GPIO_INPUT | DT_GPIO_FLAGS(SW0_NODE, gpios))
#else
#error "Unsupported board: sw0 devicetree alias is not defined"
#define SW0_GPIO_LABEL ""
#define SW0_GPIO_PIN 0
#define SW0_GPIO_FLAGS 0
#endif
static struct gpio_callback button_cb_data;
static bool btn_flag;
static const struct device *led_dev;
static uint32_t led_state;
/* LED */
#define SLEEP_TIME_MS 10000 // BLINKING SPEED
#define LED0_NODE DT_ALIAS(led0)
#if DT_NODE_HAS_STATUS(LED0_NODE, okay)
#define LED0 DT_GPIO_LABEL(LED0_NODE, gpios)
#define PIN DT_GPIO_PIN(LED0_NODE, gpios)
#define FLAGS DT_GPIO_FLAGS(LED0_NODE, gpios)
#else
/* A build error here means your board isn't set up to blink an LED. */
#error "Unsupported board: led0 devicetree alias is not defined"
#define LED0 ""
#define PIN 0
#define FLAGS 0
#endif
// Initiating button and led
static int config_devices(const struct device* button, const struct device* led);
// Responds to button 1 being pressed
void button_pressed(const struct device* dev, struct gpio_callback* cb, uint32_t pins);
/////////////////////////////////////////////////////////////
//progress bar
void DoProgress( char label[], float step, int total )
{
//progress width
const int pwidth = 72;
//minus label len
int width = pwidth - strlen( label );
float pos = ( step * width ) / total ;
int percent = ( step * 100 ) / total;
//fill progress bar with =
//printf("[");
for ( int i = 0; i < pos; i++ )
printf("%c", '|');
//fill progress bar with spaces
//printf( "% *c", width - pos + 1, ']' );
printf( " %3d%%\r", percent );
}
void DoSome()
{
int total = 1000;
float step = 0;
while ( step < total )
{
//do some action
// Sleep( 50 );
step+=1;
DoProgress( "Download: ", step, total );
}
printf( "\n" );
}
static struct lwm2m_ctx client;
#if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_SUPPORT)
/* Array with supported PULL firmware update protocols */
static uint8_t supported_protocol[1];
#endif
#if defined(CONFIG_LWM2M_DTLS_SUPPORT)
#define TLS_TAG 1
/* "000102030405060708090a0b0c0d0e0f" */
static unsigned char client_psk[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
static const char client_psk_id[] = "Client_identity";
#endif /* CONFIG_LWM2M_DTLS_SUPPORT */
static struct k_sem quit_lock;
#if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_OBJ_SUPPORT)
static uint8_t firmware_buf[64];
#endif
/* TODO: Move to a pre write hook that can handle ret codes once available */
static int led_on_off_cb(uint16_t obj_inst_id, uint16_t res_id, uint16_t res_inst_id, uint8_t *data,
uint16_t data_len, bool last_block, size_t total_size)
{
int ret = 0;
uint32_t led_val;
led_val = *(uint8_t *)data;
if (led_val != led_state) {
ret = gpio_pin_set(led_dev, LED_GPIO_PIN, (int)led_val);
if (ret) {
/*
* We need an extra hook in LWM2M to better handle
* failures before writing the data value and not in
* post_write_cb, as there is not much that can be
* done here.
*/
LOG_ERR("Fail to write to GPIO %d", LED_GPIO_PIN);
return ret;
}
led_state = led_val;
/* TODO: Move to be set by an internal post write function */
lwm2m_engine_set_s32("3311/0/5852", 0);
}
return ret;
}
static int init_led_device(void)
{
int ret;
led_dev = device_get_binding(LED_GPIO_PORT);
if (!led_dev) {
return -ENODEV;
}
ret = gpio_pin_configure(led_dev, LED_GPIO_PIN, LED_GPIO_FLAGS | GPIO_OUTPUT_INACTIVE);
if (ret) {
return ret;
}
return 0;
}
static int device_reboot_cb(uint16_t obj_inst_id, uint8_t *args, uint16_t args_len)
{
LOG_INF("DEVICE: REBOOT");
/* Add an error for testing */
lwm2m_device_add_err(LWM2M_DEVICE_ERROR_LOW_POWER);
/* Change the battery voltage for testing */
lwm2m_engine_set_s32("3/0/7/0", (bat_mv - 1));
return 0;
}
static int device_factory_default_cb(uint16_t obj_inst_id, uint8_t *args, uint16_t args_len)
{
LOG_INF("DEVICE: FACTORY DEFAULT");
/* Add an error for testing */
lwm2m_device_add_err(LWM2M_DEVICE_ERROR_GPS_FAILURE);
/* Change the USB current for testing */
lwm2m_engine_set_s32("3/0/8/1", (usb_ma - 1));
return 0;
}
#if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_SUPPORT)
static int firmware_update_cb(uint16_t obj_inst_id, uint8_t *args, uint16_t args_len)
{
LOG_DBG("UPDATE");
/* TODO: kick off update process */
/* If success, set the update result as RESULT_SUCCESS.
* In reality, it should be set at function lwm2m_setup()
*/
lwm2m_engine_set_u8("5/0/3", STATE_IDLE);
lwm2m_engine_set_u8("5/0/5", RESULT_SUCCESS);
return 0;
}
#endif
static void *temperature_get_buf(uint16_t obj_inst_id, uint16_t res_id, uint16_t res_inst_id,
size_t *data_len)
{
/* Last read temperature value, will use 25.5C if no sensor available */
static double v = 25.5;
const struct device *dev = NULL;
#if defined(CONFIG_FXOS8700_TEMP)
dev = device_get_binding(DT_LABEL(DT_INST(0, nxp_fxos8700)));
#endif
if (dev != NULL) {
struct sensor_value val;
if (sensor_sample_fetch(dev)) {
LOG_ERR("temperature data update failed");
}
sensor_channel_get(dev, SENSOR_CHAN_DIE_TEMP, &val);
v = sensor_value_to_double(&val);
LOG_DBG("LWM2M temperature set to %f", v);
}
/* echo the value back through the engine to update min/max values */
lwm2m_engine_set_float("3303/0/5700", &v);
*data_len = sizeof(v);
return &v;
}
#if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_OBJ_SUPPORT)
static void *firmware_get_buf(uint16_t obj_inst_id, uint16_t res_id, uint16_t res_inst_id,
size_t *data_len)
{
*data_len = sizeof(firmware_buf);
return firmware_buf;
}
static int firmware_block_received_cb(uint16_t obj_inst_id, uint16_t res_id, uint16_t res_inst_id,
uint8_t *data, uint16_t data_len, bool last_block,
size_t total_size)
{
LOG_INF("FIRMWARE: BLOCK RECEIVED: len:%u last_block:%d", data_len, last_block);
return 0;
}
#endif
/* An example data validation callback. */
static int timer_on_off_validate_cb(uint16_t obj_inst_id, uint16_t res_id, uint16_t res_inst_id,
uint8_t *data, uint16_t data_len, bool last_block,
size_t total_size)
{
LOG_INF("Validating On/Off data");
if (data_len != 1) {
return -EINVAL;
}
if (*data > 1) {
return -EINVAL;
}
return 0;
}
static int timer_digital_state_cb(uint16_t obj_inst_id, uint16_t res_id, uint16_t res_inst_id,
uint8_t *data, uint16_t data_len, bool last_block,
size_t total_size)
{
bool *digital_state = (bool *)data;
if (*digital_state) {
LOG_INF("TIMER: ON");
} else {
LOG_INF("TIMER: OFF");
}
return 0;
}
static int lwm2m_setup(void)
{
int ret;
char *server_url;
uint16_t server_url_len;
uint8_t server_url_flags;
/* setup SECURITY object */
/* Server URL */
ret = lwm2m_engine_get_res_data("0/0/0", (void **)&server_url, &server_url_len,
&server_url_flags);
if (ret < 0) {
return ret;
}
snprintk(server_url, server_url_len, "coap%s//%s%s%s",
IS_ENABLED(CONFIG_LWM2M_DTLS_SUPPORT) ? "s:" : ":",
strchr(SERVER_ADDR, ':') ? "[" : "", SERVER_ADDR,
strchr(SERVER_ADDR, ':') ? "]" : "");
/* Security Mode */
lwm2m_engine_set_u8("0/0/2", IS_ENABLED(CONFIG_LWM2M_DTLS_SUPPORT) ? 0 : 3);
#if defined(CONFIG_LWM2M_DTLS_SUPPORT)
lwm2m_engine_set_string("0/0/0", "coap://10.0.2.170:5683");
lwm2m_engine_set_string("0/0/3", (char *)client_psk_id);
lwm2m_engine_set_opaque("0/0/5", (void *)client_psk, sizeof(client_psk));
#endif /* CONFIG_LWM2M_DTLS_SUPPORT */
#if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)
/* Mark 1st instance of security object as a bootstrap server */
lwm2m_engine_set_u8("0/0/1", 1);
/* Create 2nd instance of security object needed for bootstrap */
lwm2m_engine_create_obj_inst("0/1");
#else
/* Match Security object instance with a Server object instance with
* Short Server ID.
*/
lwm2m_engine_set_u16("0/0/10", 101);
lwm2m_engine_set_u16("1/0/0", 101);
#endif
/* setup SERVER object */
/* setup DEVICE object */
lwm2m_engine_set_res_data("3/0/0", CLIENT_MANUFACTURER, sizeof(CLIENT_MANUFACTURER),
LWM2M_RES_DATA_FLAG_RO);
lwm2m_engine_set_res_data("3/0/1", CLIENT_MODEL_NUMBER, sizeof(CLIENT_MODEL_NUMBER),
LWM2M_RES_DATA_FLAG_RO);
lwm2m_engine_set_res_data("3/0/2", CLIENT_SERIAL_NUMBER, sizeof(CLIENT_SERIAL_NUMBER),
LWM2M_RES_DATA_FLAG_RO);
lwm2m_engine_set_res_data("3/0/3", CLIENT_FIRMWARE_VER, sizeof(CLIENT_FIRMWARE_VER),
LWM2M_RES_DATA_FLAG_RO);
lwm2m_engine_register_exec_callback("3/0/4", device_reboot_cb);
lwm2m_engine_register_exec_callback("3/0/5", device_factory_default_cb);
lwm2m_engine_set_res_data("3/0/9", &bat_level, sizeof(bat_level), 0);
lwm2m_engine_set_res_data("3/0/10", &mem_free, sizeof(mem_free), 0);
lwm2m_engine_set_res_data("3/0/17", CLIENT_DEVICE_TYPE, sizeof(CLIENT_DEVICE_TYPE),
LWM2M_RES_DATA_FLAG_RO);
lwm2m_engine_set_res_data("3/0/18", CLIENT_HW_VER, sizeof(CLIENT_HW_VER),
LWM2M_RES_DATA_FLAG_RO);
lwm2m_engine_set_res_data("3/0/20", &bat_status, sizeof(bat_status), 0);
lwm2m_engine_set_res_data("3/0/21", &mem_total, sizeof(mem_total), 0);
/* add power source resource instances */
lwm2m_engine_create_res_inst("3/0/6/0");
lwm2m_engine_set_res_data("3/0/6/0", &bat_idx, sizeof(bat_idx), 0);
lwm2m_engine_create_res_inst("3/0/7/0");
lwm2m_engine_set_res_data("3/0/7/0", &bat_mv, sizeof(bat_mv), 0);
lwm2m_engine_create_res_inst("3/0/8/0");
lwm2m_engine_set_res_data("3/0/8/0", &bat_ma, sizeof(bat_ma), 0);
lwm2m_engine_create_res_inst("3/0/6/1");
lwm2m_engine_set_res_data("3/0/6/1", &usb_idx, sizeof(usb_idx), 0);
lwm2m_engine_create_res_inst("3/0/7/1");
lwm2m_engine_set_res_data("3/0/7/1", &usb_mv, sizeof(usb_mv), 0);
lwm2m_engine_create_res_inst("3/0/8/1");
lwm2m_engine_set_res_data("3/0/8/1", &usb_ma, sizeof(usb_ma), 0);
/* setup FIRMWARE object */
#if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_OBJ_SUPPORT)
/* setup data buffer for block-wise transfer */
lwm2m_engine_register_pre_write_callback("5/0/0", firmware_get_buf);
lwm2m_firmware_set_write_cb(firmware_block_received_cb);
#endif
#if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_SUPPORT)
lwm2m_engine_create_res_inst("5/0/8/0");
lwm2m_engine_set_res_data("5/0/8/0", &supported_protocol[0], sizeof(supported_protocol[0]),
0);
lwm2m_firmware_set_update_cb(firmware_update_cb);
#endif
/* setup TEMP SENSOR object */
lwm2m_engine_create_obj_inst("3303/0");
lwm2m_engine_register_read_callback("3303/0/5700", temperature_get_buf);
/* IPSO: Light Control object */
if (init_led_device() == 0) {
lwm2m_engine_create_obj_inst("3311/0");
lwm2m_engine_register_post_write_callback("3311/0/5850", led_on_off_cb);
lwm2m_engine_set_res_data("3311/0/5750", LIGHT_NAME, sizeof(LIGHT_NAME),
LWM2M_RES_DATA_FLAG_RO);
}
/* IPSO: Timer object */
lwm2m_engine_create_obj_inst("3340/0");
lwm2m_engine_register_validate_callback("3340/0/5850", timer_on_off_validate_cb);
lwm2m_engine_register_post_write_callback("3340/0/5543", timer_digital_state_cb);
lwm2m_engine_set_res_data("3340/0/5750", TIMER_NAME, sizeof(TIMER_NAME),
LWM2M_RES_DATA_FLAG_RO);
return 0;
}
static void rd_client_event(struct lwm2m_ctx *client, enum lwm2m_rd_client_event client_event)
{
switch (client_event) {
case LWM2M_RD_CLIENT_EVENT_NONE:
/* do nothing */
break;
case LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_REG_FAILURE:
LOG_DBG("Bootstrap registration failure!");
break;
case LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_REG_COMPLETE:
LOG_DBG("Bootstrap registration complete");
break;
case LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_TRANSFER_COMPLETE:
LOG_DBG("Bootstrap transfer complete");
break;
case LWM2M_RD_CLIENT_EVENT_REGISTRATION_FAILURE:
LOG_DBG("Registration failure!");
break;
case LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE:
LOG_DBG("Registration complete");
break;
case LWM2M_RD_CLIENT_EVENT_REG_UPDATE_FAILURE:
LOG_DBG("Registration update failure!");
break;
case LWM2M_RD_CLIENT_EVENT_REG_UPDATE_COMPLETE:
LOG_DBG("Registration update complete");
break;
case LWM2M_RD_CLIENT_EVENT_DEREGISTER_FAILURE:
LOG_DBG("Deregister failure!");
break;
case LWM2M_RD_CLIENT_EVENT_DISCONNECT:
LOG_DBG("Disconnected");
break;
case LWM2M_RD_CLIENT_EVENT_QUEUE_MODE_RX_OFF:
LOG_DBG("Queue mode RX window closed");
break;
case LWM2M_RD_CLIENT_EVENT_NETWORK_ERROR:
LOG_ERR("LwM2M engine reported a network erorr.");
lwm2m_rd_client_stop(client, rd_client_event, true);
break;
}
}
static void observe_cb(enum lwm2m_observe_event event, struct lwm2m_obj_path *path, void *user_data)
{
char buf[LWM2M_MAX_PATH_STR_LEN];
switch (event) {
case LWM2M_OBSERVE_EVENT_OBSERVER_ADDED:
LOG_INF("Observer added for %s", lwm2m_path_log_strdup(buf, path));
break;
case LWM2M_OBSERVE_EVENT_OBSERVER_REMOVED:
LOG_INF("Observer removed for %s", lwm2m_path_log_strdup(buf, path));
break;
case LWM2M_OBSERVE_EVENT_NOTIFY_ACK:
LOG_INF("Notify acknowledged for %s", lwm2m_path_log_strdup(buf, path));
break;
case LWM2M_OBSERVE_EVENT_NOTIFY_TIMEOUT:
LOG_INF("Notify timeout for %s, trying registration update",
lwm2m_path_log_strdup(buf, path));
lwm2m_rd_client_update();
break;
}
}
void main(void)
{
uint32_t flags = IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP) ?
LWM2M_RD_CLIENT_FLAG_BOOTSTRAP :
0;
int ret;
LOG_INF(APP_BANNER);
k_sem_init(&quit_lock, 0, K_SEM_MAX_LIMIT);
ret = lwm2m_setup();
if (ret < 0) {
LOG_ERR("Cannot setup LWM2M fields (%d)", ret);
return;
}
(void)memset(&client, 0x0, sizeof(client));
#if defined(CONFIG_LWM2M_DTLS_SUPPORT)
client.tls_tag = TLS_TAG;
#endif
#if defined(CONFIG_HWINFO)
uint8_t dev_id[16];
char dev_str[33];
ssize_t length;
int i;
(void)memset(dev_id, 0x0, sizeof(dev_id));
/* Obtain the device id */
length = hwinfo_get_device_id(dev_id, sizeof(dev_id));
/* If this fails for some reason, use all zeros instead */
if (length <= 0) {
length = sizeof(dev_id);
}
/* Render the obtained serial number in hexadecimal representation */
for (i = 0; i < length; i++) {
sprintf(&dev_str[i * 2], "%02x", dev_id[i]);
}
lwm2m_rd_client_start(&client, dev_str, flags, rd_client_event, observe_cb);
#else
/* client.sec_obj_inst is 0 as a starting point */
lwm2m_rd_client_start(&client, CONFIG_BOARD, flags, rd_client_event, observe_cb);
#endif
/// @brief // Testing Begin
/// @param //
const struct device* dev = device_get_binding(DT_LABEL(DT_INST(0, st_vl53l0x)));
/////////////////////////////////
const struct device *led, *button;
bool led_is_on = true;
led = device_get_binding(LED0);
button = device_get_binding(SW0_GPIO_LABEL);
/////////////////////////////////
// struct for reading the sensor values (universal library in zephyr, I think?).
struct sensor_value dist, prox;
//
struct flash_mem* flash_pt;
flash_pt = k_malloc(sizeof(struct flash_mem));
flash_pt->device = device_get_binding(DT_CHOSEN_ZEPHYR_FLASH_CONTROLLER_LABEL);
// strings are used to save the data, because Golioth uses CoAP Protocol and can send only Plain Text.
char str_distance[64];
char str_proximity[32];
int err;
int dret;
////////////////////////////////////////////////////////////
if (!led || !button || !flash_pt->device) return;
if (config_devices(button, led)) return;
////////////////////////////////////////////////////////////
//// MCUboot ////
if (!boot_is_img_confirmed()) {
/*
* There is no shared context between previous update request
* and current boot, so treat current image 'confirmed' flag as
* an indication whether previous update process was successful
* or not.
*/
LOG_DBG("\n\n-----------------------------------------------------");
LOG_DBG("| Current Firware Version: (%s) |");
LOG_DBG("-----------------------------------------------------\n\n");
err = boot_write_img_confirmed();
if (err) { LOG_ERR("Failed to confirm image: %d", err); }
}
while (1) {
ret = sensor_sample_fetch(dev);
if (ret) {
printk("sensor_sample_fetch failed ret %d\n", ret);
return;
k_sleep(K_SECONDS(1));
continue;
}
str_distance[sizeof(sensor_value_to_double(&dist)) - 1] = '\0';
str_proximity[sizeof(prox)] = '\0';
// Proximity
// Variable ret saves the state of the data taken from the sensor.
ret = sensor_channel_get(dev, SENSOR_CHAN_PROX, &prox);
// Prints in UART the received data.
printk("=========================================================================================================================\n");
printk("\n \n\n");
printk("\n DELTA 1.0.4 ST_VL53L0X Data: \n\n");
printk(" -------------------------\n", prox);
printk(" | Proximity is %d |\n", prox);
// Distance
ret = sensor_channel_get(dev, SENSOR_CHAN_DISTANCE, &dist);
printf(" | Distance is %.3fm |\n", sensor_value_to_double(&dist));
printk(" -------------------------\n\n\n", prox);
printk("=========================================================================================================================\n");
// snprintk && snprintf(same usage in Zephyr, I think?) are necessary to send log to LightDB Stream.bx
// USAGE:
//
// Composes a string with the same text that would be printed if format was used on printf, but instead of being printed,
// the content is stored as a C string in the buffer pointed by s (taking n as the maximum buffer capacity to fill).
//
//
snprintf(str_proximity, sizeof(str_proximity), "%d", prox);
str_proximity[sizeof(str_proximity) - 1] = '\0';
snprintf(str_distance, sizeof(str_distance),
"%.3fm", sensor_value_to_double(&dist));
str_distance[sizeof(str_distance) - 1] = '\0';
// Message the is shown in UART if Golioth Client is correctly sending data.
LOG_DBG("Sending Distance %sm\ /| Proximity %s\n", log_strdup(str_distance), log_strdup(str_proximity));
// printk("================================================================================================\n");
k_sleep(K_MSEC(3000));
gpio_pin_set(led, PIN, (int)led_is_on);
k_msleep(SLEEP_TIME_MS);
if (btn_flag) {
led_is_on = !led_is_on;
dret = delta_check_and_apply(flash_pt);
long i;
//Progress bar --> taken from https://gist.github.com/napsternxg/302c4f859a27282e7ca5
DoSome();
//
if (dret) {
printk("%s", delta_error_as_string(dret));
return;
}
}
led_is_on = !led_is_on;
/////////////////////////////////
}
k_sem_take(&quit_lock, K_FOREVER);
}
//////////////////////////////////////////////////////
static int config_devices(const struct device* button, const struct device* led)
{
int dret;
dret = gpio_pin_configure(led, PIN, GPIO_OUTPUT_ACTIVE | FLAGS);
dret |= gpio_pin_configure(button, SW0_GPIO_PIN, SW0_GPIO_FLAGS);
if (dret) return -1;
if (gpio_pin_interrupt_configure(button, SW0_GPIO_PIN, GPIO_INT_EDGE_TO_ACTIVE)) return -1;
gpio_init_callback(&button_cb_data, button_pressed, BIT(SW0_GPIO_PIN));
gpio_add_callback(button, &button_cb_data);
btn_flag = false;
return 0;
}
void button_pressed(const struct device* dev, struct gpio_callback* cb, uint32_t pins)
{
printk("Checking for Delta Update \n");
btn_flag = true;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment