* initial commit

This commit is contained in:
Danyi Dávid 2017-10-17 21:44:35 +02:00
commit b67069fc45
10 changed files with 1752 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
.idea
cmake-build-debug

33
CMakeLists.txt Normal file
View File

@ -0,0 +1,33 @@
cmake_minimum_required (VERSION 3.0)
project (lightclient)
add_definitions(-DSerialOut=SerialUSB)
if(DTLS)
message(FATAL_ERROR "DTLS option is not supported." )
endif()
include(${CMAKE_CURRENT_LIST_DIR}/../wakaama-core/src/wakaama.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/../wakaama-shared/src/arduino-base.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/../wakaama-shared/src/shared.cmake)
add_definitions(-DLWM2M_CLIENT_MODE)
add_definitions(${SHARED_DEFINITIONS} ${WAKAAMA_DEFINITIONS})
include_directories (${WAKAAMA_SOURCES_DIR} ${SHARED_INCLUDE_DIRS} ${ARDUINO_INCLUDE_DIRS})
SET(SOURCES
${CMAKE_CURRENT_LIST_DIR}/wakaama-client.cpp
${CMAKE_CURRENT_LIST_DIR}/object_security.c
${CMAKE_CURRENT_LIST_DIR}/object_server.c
${CMAKE_CURRENT_LIST_DIR}/object_device.c
${CMAKE_CURRENT_LIST_DIR}/test_object.c
)
add_executable(${PROJECT_NAME} ${SOURCES} ${WAKAAMA_SOURCES} ${SHARED_SOURCES})
# Add WITH_LOGS to debug variant
set_property(TARGET ${PROJECT_NAME} APPEND PROPERTY COMPILE_DEFINITIONS $<$<CONFIG:Debug>:WITH_LOGS>)
SOURCE_GROUP(wakaama FILES ${WAKAAMA_SOURCES})

10
library.properties Normal file
View File

@ -0,0 +1,10 @@
name=Wakaama Client
version=0.1.1
author=DavidDanyi,Ericsson
maintainer=David Danyi <david.danyi@ericsson.com>
sentence=Eclipse Wakaama client
paragraph=
category=Communication
url=
architectures=samd
includes=wakaama-client.h

307
src/object_device.c Normal file
View File

@ -0,0 +1,307 @@
/*******************************************************************************
*
* Copyright (c) 2013, 2014, 2015 Intel Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* The Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* David Navarro, Intel Corporation - initial API and implementation
* domedambrosio - Please refer to git log
* Fabien Fleutot - Please refer to git log
* Axel Lorente - Please refer to git log
* Bosch Software Innovations GmbH - Please refer to git log
* Pascal Rieux - Please refer to git log
*
*******************************************************************************/
/*
Copyright (c) 2013, 2014 Intel Corporation
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of Intel Corporation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGE.
David Navarro <david.navarro@intel.com>
*/
/*
* This object is single instance only, and is mandatory to all LWM2M device as it describe the object such as its
* manufacturer, model, etc...
*
* Here we implement only some of the optional resources.
*
*/
#include "liblwm2m.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define PRV_MANUFACTURER "Open Mobile Alliance"
#define PRV_MODEL_NUMBER "Lightweight M2M Client"
#define PRV_BINDING_MODE "U"
// Resource Id's:
#define RES_O_MANUFACTURER 0
#define RES_O_MODEL_NUMBER 1
#define RES_O_SERIAL_NUMBER 2
#define RES_O_FIRMWARE_VERSION 3
#define RES_M_REBOOT 4
#define RES_O_FACTORY_RESET 5
#define RES_O_AVL_POWER_SOURCES 6
#define RES_O_POWER_SOURCE_VOLTAGE 7
#define RES_O_POWER_SOURCE_CURRENT 8
#define RES_O_BATTERY_LEVEL 9
#define RES_O_MEMORY_FREE 10
#define RES_M_ERROR_CODE 11
#define RES_O_RESET_ERROR_CODE 12
#define RES_O_CURRENT_TIME 13
#define RES_O_UTC_OFFSET 14
#define RES_O_TIMEZONE 15
#define RES_M_BINDING_MODES 16
#define RES_O_DEVICE_TYPE 17
#define RES_O_HARDWARE_VERSION 18
#define RES_O_SOFTWARE_VERSION 19
#define RES_O_BATTERY_STATUS 20
#define RES_O_MEMORY_TOTAL 21
static uint8_t prv_set_value(lwm2m_data_t * dataP)
{
// a simple switch structure is used to respond at the specified resource asked
switch (dataP->id)
{
case RES_O_MANUFACTURER:
lwm2m_data_encode_string(PRV_MANUFACTURER, dataP);
return COAP_205_CONTENT;
case RES_O_MODEL_NUMBER:
lwm2m_data_encode_string(PRV_MODEL_NUMBER, dataP);
return COAP_205_CONTENT;
case RES_M_REBOOT:
return COAP_405_METHOD_NOT_ALLOWED;
case RES_M_BINDING_MODES:
lwm2m_data_encode_string(PRV_BINDING_MODE, dataP);
return COAP_205_CONTENT;
default:
return COAP_404_NOT_FOUND;
}
}
static uint8_t prv_device_read(uint16_t instanceId,
int * numDataP,
lwm2m_data_t ** dataArrayP,
lwm2m_object_t * objectP)
{
uint8_t result;
int i;
// this is a single instance object
if (instanceId != 0)
{
return COAP_404_NOT_FOUND;
}
// is the server asking for the full object ?
if (*numDataP == 0)
{
uint16_t resList[] = {
RES_O_MANUFACTURER,
RES_O_MODEL_NUMBER,
RES_M_BINDING_MODES
};
int nbRes = sizeof(resList)/sizeof(uint16_t);
*dataArrayP = lwm2m_data_new(nbRes);
if (*dataArrayP == NULL) return COAP_500_INTERNAL_SERVER_ERROR;
*numDataP = nbRes;
for (i = 0 ; i < nbRes ; i++)
{
(*dataArrayP)[i].id = resList[i];
}
}
i = 0;
do
{
result = prv_set_value((*dataArrayP) + i);
i++;
} while (i < *numDataP && result == COAP_205_CONTENT);
return result;
}
static uint8_t prv_device_discover(uint16_t instanceId,
int * numDataP,
lwm2m_data_t ** dataArrayP,
lwm2m_object_t * objectP)
{
uint8_t result;
int i;
// this is a single instance object
if (instanceId != 0)
{
return COAP_404_NOT_FOUND;
}
result = COAP_205_CONTENT;
// is the server asking for the full object ?
if (*numDataP == 0)
{
uint16_t resList[] = {
RES_O_MANUFACTURER,
RES_O_MODEL_NUMBER,
RES_M_BINDING_MODES,
RES_M_REBOOT
};
int nbRes = sizeof(resList)/sizeof(uint16_t);
*dataArrayP = lwm2m_data_new(nbRes);
if (*dataArrayP == NULL) return COAP_500_INTERNAL_SERVER_ERROR;
*numDataP = nbRes;
for (i = 0 ; i < nbRes ; i++)
{
(*dataArrayP)[i].id = resList[i];
}
}
else
{
for (i = 0; i < *numDataP && result == COAP_205_CONTENT; i++)
{
switch ((*dataArrayP)[i].id)
{
case RES_O_MANUFACTURER:
case RES_O_MODEL_NUMBER:
case RES_M_BINDING_MODES:
case RES_M_REBOOT:
break;
default:
result = COAP_404_NOT_FOUND;
}
}
}
return result;
}
static uint8_t prv_device_execute(uint16_t instanceId,
uint16_t resourceId,
uint8_t * buffer,
int length,
lwm2m_object_t * objectP)
{
// this is a single instance object
if (instanceId != 0)
{
return COAP_404_NOT_FOUND;
}
if (length != 0) return COAP_400_BAD_REQUEST;
if (resourceId == RES_M_REBOOT)
{
// fprintf(stdout, "\n\t REBOOT\r\n\n");
return COAP_204_CHANGED;
}
return COAP_405_METHOD_NOT_ALLOWED;
}
lwm2m_object_t * get_object_device()
{
/*
* The get_object_device function create the object itself and return a pointer to the structure that represent it.
*/
lwm2m_object_t * deviceObj;
deviceObj = (lwm2m_object_t *)lwm2m_malloc(sizeof(lwm2m_object_t));
if (NULL != deviceObj)
{
memset(deviceObj, 0, sizeof(lwm2m_object_t));
/*
* It assigns his unique ID
* The 3 is the standard ID for the mandatory object "Object device".
*/
deviceObj->objID = LWM2M_DEVICE_OBJECT_ID;
/*
* and its unique instance
*
*/
deviceObj->instanceList = (lwm2m_list_t *)lwm2m_malloc(sizeof(lwm2m_list_t));
if (NULL != deviceObj->instanceList)
{
memset(deviceObj->instanceList, 0, sizeof(lwm2m_list_t));
}
else
{
lwm2m_free(deviceObj);
return NULL;
}
/*
* And the private function that will access the object.
* Those function will be called when a read/write/execute query is made by the server. In fact the library don't need to
* know the resources of the object, only the server does.
*/
deviceObj->readFunc = prv_device_read;
deviceObj->executeFunc = prv_device_execute;
deviceObj->discoverFunc = prv_device_discover;
}
return deviceObj;
}
void free_object_device(lwm2m_object_t * objectP)
{
if (NULL != objectP->userData)
{
lwm2m_free(objectP->userData);
objectP->userData = NULL;
}
if (NULL != objectP->instanceList)
{
lwm2m_free(objectP->instanceList);
objectP->instanceList = NULL;
}
lwm2m_free(objectP);
}

253
src/object_security.c Normal file
View File

@ -0,0 +1,253 @@
/*******************************************************************************
*
* Copyright (c) 2013, 2014, 2015 Intel Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* The Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* David Navarro, Intel Corporation - initial API and implementation
* Bosch Software Innovations GmbH - Please refer to git log
* Pascal Rieux - Please refer to git log
*
*******************************************************************************/
/*
* Resources:
*
* Name | ID | Operations | Instances | Mandatory | Type | Range | Units |
* Server URI | 0 | | Single | Yes | String | | |
* Bootstrap Server | 1 | | Single | Yes | Boolean | | |
* Security Mode | 2 | | Single | Yes | Integer | 0-3 | |
* Public Key or ID | 3 | | Single | Yes | Opaque | | |
* Server Public Key or ID | 4 | | Single | Yes | Opaque | | |
* Secret Key | 5 | | Single | Yes | Opaque | | |
* SMS Security Mode | 6 | | Single | Yes | Integer | 0-255 | |
* SMS Binding Key Param. | 7 | | Single | Yes | Opaque | 6 B | |
* SMS Binding Secret Keys | 8 | | Single | Yes | Opaque | 32-48 B | |
* Server SMS Number | 9 | | Single | Yes | Integer | | |
* Short Server ID | 10 | | Single | No | Integer | 1-65535 | |
* Client Hold Off Time | 11 | | Single | Yes | Integer | | s |
*
*/
/*
* Here we implement a very basic LWM2M Security Object which only knows NoSec security mode.
*/
#include "liblwm2m.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
typedef struct _security_instance_
{
struct _security_instance_ * next; // matches lwm2m_list_t::next
uint16_t instanceId; // matches lwm2m_list_t::id
char * uri;
bool isBootstrap;
uint16_t shortID;
uint32_t clientHoldOffTime;
} security_instance_t;
static uint8_t prv_get_value(lwm2m_data_t * dataP,
security_instance_t * targetP)
{
switch (dataP->id)
{
case LWM2M_SECURITY_URI_ID:
lwm2m_data_encode_string(targetP->uri, dataP);
return COAP_205_CONTENT;
case LWM2M_SECURITY_BOOTSTRAP_ID:
lwm2m_data_encode_bool(targetP->isBootstrap, dataP);
return COAP_205_CONTENT;
case LWM2M_SECURITY_SECURITY_ID:
lwm2m_data_encode_int(LWM2M_SECURITY_MODE_NONE, dataP);
return COAP_205_CONTENT;
case LWM2M_SECURITY_PUBLIC_KEY_ID:
// Here we return an opaque of 1 byte containing 0
{
uint8_t value = 0;
lwm2m_data_encode_opaque(&value, 1, dataP);
}
return COAP_205_CONTENT;
case LWM2M_SECURITY_SERVER_PUBLIC_KEY_ID:
// Here we return an opaque of 1 byte containing 0
{
uint8_t value = 0;
lwm2m_data_encode_opaque(&value, 1, dataP);
}
return COAP_205_CONTENT;
case LWM2M_SECURITY_SECRET_KEY_ID:
// Here we return an opaque of 1 byte containing 0
{
uint8_t value = 0;
lwm2m_data_encode_opaque(&value, 1, dataP);
}
return COAP_205_CONTENT;
case LWM2M_SECURITY_SMS_SECURITY_ID:
lwm2m_data_encode_int(LWM2M_SECURITY_MODE_NONE, dataP);
return COAP_205_CONTENT;
case LWM2M_SECURITY_SMS_KEY_PARAM_ID:
// Here we return an opaque of 6 bytes containing a buggy value
{
char * value = "12345";
lwm2m_data_encode_opaque((uint8_t *)value, 6, dataP);
}
return COAP_205_CONTENT;
case LWM2M_SECURITY_SMS_SECRET_KEY_ID:
// Here we return an opaque of 32 bytes containing a buggy value
{
char * value = "1234567890abcdefghijklmnopqrstu";
lwm2m_data_encode_opaque((uint8_t *)value, 32, dataP);
}
return COAP_205_CONTENT;
case LWM2M_SECURITY_SMS_SERVER_NUMBER_ID:
lwm2m_data_encode_int(0, dataP);
return COAP_205_CONTENT;
case LWM2M_SECURITY_SHORT_SERVER_ID:
lwm2m_data_encode_int(targetP->shortID, dataP);
return COAP_205_CONTENT;
case LWM2M_SECURITY_HOLD_OFF_ID:
lwm2m_data_encode_int(targetP->clientHoldOffTime, dataP);
return COAP_205_CONTENT;
default:
return COAP_404_NOT_FOUND;
}
}
static uint8_t prv_security_read(uint16_t instanceId,
int * numDataP,
lwm2m_data_t ** dataArrayP,
lwm2m_object_t * objectP)
{
security_instance_t * targetP;
uint8_t result;
int i;
targetP = (security_instance_t *)lwm2m_list_find(objectP->instanceList, instanceId);
if (NULL == targetP) return COAP_404_NOT_FOUND;
// is the server asking for the full instance ?
if (*numDataP == 0)
{
uint16_t resList[] = {LWM2M_SECURITY_URI_ID,
LWM2M_SECURITY_BOOTSTRAP_ID,
LWM2M_SECURITY_SECURITY_ID,
LWM2M_SECURITY_PUBLIC_KEY_ID,
LWM2M_SECURITY_SERVER_PUBLIC_KEY_ID,
LWM2M_SECURITY_SECRET_KEY_ID,
LWM2M_SECURITY_SMS_SECURITY_ID,
LWM2M_SECURITY_SMS_KEY_PARAM_ID,
LWM2M_SECURITY_SMS_SECRET_KEY_ID,
LWM2M_SECURITY_SMS_SERVER_NUMBER_ID,
LWM2M_SECURITY_SHORT_SERVER_ID,
LWM2M_SECURITY_HOLD_OFF_ID};
int nbRes = sizeof(resList)/sizeof(uint16_t);
*dataArrayP = lwm2m_data_new(nbRes);
if (*dataArrayP == NULL) return COAP_500_INTERNAL_SERVER_ERROR;
*numDataP = nbRes;
for (i = 0 ; i < nbRes ; i++)
{
(*dataArrayP)[i].id = resList[i];
}
}
i = 0;
do
{
result = prv_get_value((*dataArrayP) + i, targetP);
i++;
} while (i < *numDataP && result == COAP_205_CONTENT);
return result;
}
lwm2m_object_t * get_security_object(const char * uri)
{
lwm2m_object_t * securityObj;
securityObj = (lwm2m_object_t *)lwm2m_malloc(sizeof(lwm2m_object_t));
if (NULL != securityObj)
{
security_instance_t * targetP;
memset(securityObj, 0, sizeof(lwm2m_object_t));
securityObj->objID = 0;
// Manually create an hardcoded instance
targetP = (security_instance_t *)lwm2m_malloc(sizeof(security_instance_t));
if (NULL == targetP)
{
lwm2m_free(securityObj);
return NULL;
}
memset(targetP, 0, sizeof(security_instance_t));
targetP->instanceId = 0;
targetP->uri = strdup(uri);
targetP->isBootstrap = false;
targetP->shortID = 123;
targetP->clientHoldOffTime = 10;
securityObj->instanceList = LWM2M_LIST_ADD(securityObj->instanceList, targetP);
securityObj->readFunc = prv_security_read;
}
return securityObj;
}
void free_security_object(lwm2m_object_t * objectP)
{
while (objectP->instanceList != NULL)
{
security_instance_t * securityInstance = (security_instance_t *)objectP->instanceList;
objectP->instanceList = objectP->instanceList->next;
if (NULL != securityInstance->uri)
{
lwm2m_free(securityInstance->uri);
}
lwm2m_free(securityInstance);
}
lwm2m_free(objectP);
}
char * get_server_uri(lwm2m_object_t * objectP,
uint16_t secObjInstID)
{
security_instance_t * targetP = (security_instance_t *)LWM2M_LIST_FIND(objectP->instanceList, secObjInstID);
if (NULL != targetP)
{
return lwm2m_strdup(targetP->uri);
}
return NULL;
}

425
src/object_server.c Normal file
View File

@ -0,0 +1,425 @@
/*******************************************************************************
*
* Copyright (c) 2013, 2014 Intel Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* The Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* David Navarro, Intel Corporation - initial API and implementation
* Julien Vermillard, Sierra Wireless
* Bosch Software Innovations GmbH - Please refer to git log
* Pascal Rieux - Please refer to git log
*
*******************************************************************************/
/*
* Resources:
*
* Name | ID | Operations | Instances | Mandatory | Type | Range | Units |
* Short ID | 0 | R | Single | Yes | Integer | 1-65535 | |
* Lifetime | 1 | R/W | Single | Yes | Integer | | s |
* Default Min Period | 2 | R/W | Single | No | Integer | | s |
* Default Max Period | 3 | R/W | Single | No | Integer | | s |
* Disable | 4 | E | Single | No | | | |
* Disable Timeout | 5 | R/W | Single | No | Integer | | s |
* Notification Storing | 6 | R/W | Single | Yes | Boolean | | |
* Binding | 7 | R/W | Single | Yes | String | | |
* Registration Update | 8 | E | Single | Yes | | | |
*
*/
#include "liblwm2m.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct _server_instance_
{
struct _server_instance_ * next; // matches lwm2m_list_t::next
uint16_t instanceId; // matches lwm2m_list_t::id
uint16_t shortServerId;
uint32_t lifetime;
bool storing;
char binding[4];
} server_instance_t;
static uint8_t prv_get_value(lwm2m_data_t * dataP,
server_instance_t * targetP)
{
switch (dataP->id)
{
case LWM2M_SERVER_SHORT_ID_ID:
lwm2m_data_encode_int(targetP->shortServerId, dataP);
return COAP_205_CONTENT;
case LWM2M_SERVER_LIFETIME_ID:
lwm2m_data_encode_int(targetP->lifetime, dataP);
return COAP_205_CONTENT;
case LWM2M_SERVER_DISABLE_ID:
return COAP_405_METHOD_NOT_ALLOWED;
case LWM2M_SERVER_STORING_ID:
lwm2m_data_encode_bool(targetP->storing, dataP);
return COAP_205_CONTENT;
case LWM2M_SERVER_BINDING_ID:
lwm2m_data_encode_string(targetP->binding, dataP);
return COAP_205_CONTENT;
case LWM2M_SERVER_UPDATE_ID:
return COAP_405_METHOD_NOT_ALLOWED;
default:
return COAP_404_NOT_FOUND;
}
}
static uint8_t prv_server_read(uint16_t instanceId,
int * numDataP,
lwm2m_data_t ** dataArrayP,
lwm2m_object_t * objectP)
{
server_instance_t * targetP;
uint8_t result;
int i;
targetP = (server_instance_t *)lwm2m_list_find(objectP->instanceList, instanceId);
if (NULL == targetP) return COAP_404_NOT_FOUND;
// is the server asking for the full instance ?
if (*numDataP == 0)
{
uint16_t resList[] = {
LWM2M_SERVER_SHORT_ID_ID,
LWM2M_SERVER_LIFETIME_ID,
LWM2M_SERVER_STORING_ID,
LWM2M_SERVER_BINDING_ID
};
int nbRes = sizeof(resList)/sizeof(uint16_t);
*dataArrayP = lwm2m_data_new(nbRes);
if (*dataArrayP == NULL) return COAP_500_INTERNAL_SERVER_ERROR;
*numDataP = nbRes;
for (i = 0 ; i < nbRes ; i++)
{
(*dataArrayP)[i].id = resList[i];
}
}
i = 0;
do
{
result = prv_get_value((*dataArrayP) + i, targetP);
i++;
} while (i < *numDataP && result == COAP_205_CONTENT);
return result;
}
static uint8_t prv_server_discover(uint16_t instanceId,
int * numDataP,
lwm2m_data_t ** dataArrayP,
lwm2m_object_t * objectP)
{
uint8_t result;
int i;
result = COAP_205_CONTENT;
// is the server asking for the full object ?
if (*numDataP == 0)
{
uint16_t resList[] = {
LWM2M_SERVER_SHORT_ID_ID,
LWM2M_SERVER_LIFETIME_ID,
LWM2M_SERVER_MIN_PERIOD_ID,
LWM2M_SERVER_MAX_PERIOD_ID,
LWM2M_SERVER_DISABLE_ID,
LWM2M_SERVER_TIMEOUT_ID,
LWM2M_SERVER_STORING_ID,
LWM2M_SERVER_BINDING_ID,
LWM2M_SERVER_UPDATE_ID
};
int nbRes = sizeof(resList)/sizeof(uint16_t);
*dataArrayP = lwm2m_data_new(nbRes);
if (*dataArrayP == NULL) return COAP_500_INTERNAL_SERVER_ERROR;
*numDataP = nbRes;
for (i = 0 ; i < nbRes ; i++)
{
(*dataArrayP)[i].id = resList[i];
}
}
else
{
for (i = 0; i < *numDataP && result == COAP_205_CONTENT; i++)
{
switch ((*dataArrayP)[i].id)
{
case LWM2M_SERVER_SHORT_ID_ID:
case LWM2M_SERVER_LIFETIME_ID:
case LWM2M_SERVER_MIN_PERIOD_ID:
case LWM2M_SERVER_MAX_PERIOD_ID:
case LWM2M_SERVER_DISABLE_ID:
case LWM2M_SERVER_TIMEOUT_ID:
case LWM2M_SERVER_STORING_ID:
case LWM2M_SERVER_BINDING_ID:
case LWM2M_SERVER_UPDATE_ID:
break;
default:
result = COAP_404_NOT_FOUND;
}
}
}
return result;
}
static uint8_t prv_set_int_value(lwm2m_data_t * dataArray,
uint32_t * data)
{
uint8_t result;
int64_t value;
if (1 == lwm2m_data_decode_int(dataArray, &value))
{
if (value >= 0 && value <= 0xFFFFFFFF)
{
*data = value;
result = COAP_204_CHANGED;
}
else
{
result = COAP_406_NOT_ACCEPTABLE;
}
}
else
{
result = COAP_400_BAD_REQUEST;
}
return result;
}
static uint8_t prv_server_write(uint16_t instanceId,
int numData,
lwm2m_data_t * dataArray,
lwm2m_object_t * objectP)
{
server_instance_t * targetP;
int i;
uint8_t result;
targetP = (server_instance_t *)lwm2m_list_find(objectP->instanceList, instanceId);
if (NULL == targetP)
{
return COAP_404_NOT_FOUND;
}
i = 0;
do
{
switch (dataArray[i].id)
{
case LWM2M_SERVER_SHORT_ID_ID:
{
uint32_t value;
result = prv_set_int_value(dataArray + i, &value);
if (COAP_204_CHANGED == result)
{
if (0 < value && value <= 0xFFFF)
{
targetP->shortServerId = value;
}
else
{
result = COAP_406_NOT_ACCEPTABLE;
}
}
}
break;
case LWM2M_SERVER_LIFETIME_ID:
result = prv_set_int_value(dataArray + i, (uint32_t *)&(targetP->lifetime));
break;
case LWM2M_SERVER_DISABLE_ID:
result = COAP_405_METHOD_NOT_ALLOWED;
break;
case LWM2M_SERVER_STORING_ID:
{
bool value;
if (1 == lwm2m_data_decode_bool(dataArray + i, &value))
{
targetP->storing = value;
result = COAP_204_CHANGED;
}
else
{
result = COAP_400_BAD_REQUEST;
}
}
break;
case LWM2M_SERVER_BINDING_ID:
if ((dataArray[i].type == LWM2M_TYPE_STRING || dataArray[i].type == LWM2M_TYPE_OPAQUE)
&& dataArray[i].value.asBuffer.length > 0 && dataArray[i].value.asBuffer.length <= 3
&& (strncmp((char*)dataArray[i].value.asBuffer.buffer, "U", dataArray[i].value.asBuffer.length) == 0
|| strncmp((char*)dataArray[i].value.asBuffer.buffer, "UQ", dataArray[i].value.asBuffer.length) == 0
|| strncmp((char*)dataArray[i].value.asBuffer.buffer, "S", dataArray[i].value.asBuffer.length) == 0
|| strncmp((char*)dataArray[i].value.asBuffer.buffer, "SQ", dataArray[i].value.asBuffer.length) == 0
|| strncmp((char*)dataArray[i].value.asBuffer.buffer, "US", dataArray[i].value.asBuffer.length) == 0
|| strncmp((char*)dataArray[i].value.asBuffer.buffer, "UQS", dataArray[i].value.asBuffer.length) == 0))
{
strncpy(targetP->binding, (char*)dataArray[i].value.asBuffer.buffer, dataArray[i].value.asBuffer.length);
result = COAP_204_CHANGED;
}
else
{
result = COAP_400_BAD_REQUEST;
}
break;
case LWM2M_SERVER_UPDATE_ID:
result = COAP_405_METHOD_NOT_ALLOWED;
break;
default:
return COAP_404_NOT_FOUND;
}
i++;
} while (i < numData && result == COAP_204_CHANGED);
return result;
}
static uint8_t prv_server_execute(uint16_t instanceId,
uint16_t resourceId,
uint8_t * buffer,
int length,
lwm2m_object_t * objectP)
{
server_instance_t * targetP;
targetP = (server_instance_t *)lwm2m_list_find(objectP->instanceList, instanceId);
if (NULL == targetP) return COAP_404_NOT_FOUND;
switch (resourceId)
{
case LWM2M_SERVER_DISABLE_ID:
// executed in core, if COAP_204_CHANGED is returned
return COAP_204_CHANGED;
case LWM2M_SERVER_UPDATE_ID:
// executed in core, if COAP_204_CHANGED is returned
return COAP_204_CHANGED;
default:
return COAP_405_METHOD_NOT_ALLOWED;
}
}
static uint8_t prv_server_delete(uint16_t id,
lwm2m_object_t * objectP)
{
server_instance_t * serverInstance;
objectP->instanceList = lwm2m_list_remove(objectP->instanceList, id, (lwm2m_list_t **)&serverInstance);
if (NULL == serverInstance) return COAP_404_NOT_FOUND;
lwm2m_free(serverInstance);
return COAP_202_DELETED;
}
static uint8_t prv_server_create(uint16_t instanceId,
int numData,
lwm2m_data_t * dataArray,
lwm2m_object_t * objectP)
{
server_instance_t * serverInstance;
uint8_t result;
serverInstance = (server_instance_t *)lwm2m_malloc(sizeof(server_instance_t));
if (NULL == serverInstance) return COAP_500_INTERNAL_SERVER_ERROR;
memset(serverInstance, 0, sizeof(server_instance_t));
serverInstance->instanceId = instanceId;
objectP->instanceList = LWM2M_LIST_ADD(objectP->instanceList, serverInstance);
result = prv_server_write(instanceId, numData, dataArray, objectP);
if (result != COAP_204_CHANGED)
{
(void)prv_server_delete(instanceId, objectP);
}
else
{
result = COAP_201_CREATED;
}
return result;
}
lwm2m_object_t * get_server_object()
{
lwm2m_object_t * serverObj;
serverObj = (lwm2m_object_t *)lwm2m_malloc(sizeof(lwm2m_object_t));
if (NULL != serverObj)
{
server_instance_t * serverInstance;
memset(serverObj, 0, sizeof(lwm2m_object_t));
serverObj->objID = 1;
// Manually create an hardcoded server
serverInstance = (server_instance_t *)lwm2m_malloc(sizeof(server_instance_t));
if (NULL == serverInstance)
{
lwm2m_free(serverObj);
return NULL;
}
memset(serverInstance, 0, sizeof(server_instance_t));
serverInstance->instanceId = 0;
serverInstance->shortServerId = 123;
serverInstance->lifetime = 300;
serverInstance->storing = false;
serverInstance->binding[0] = 'U';
serverObj->instanceList = LWM2M_LIST_ADD(serverObj->instanceList, serverInstance);
serverObj->readFunc = prv_server_read;
serverObj->writeFunc = prv_server_write;
serverObj->createFunc = prv_server_create;
serverObj->deleteFunc = prv_server_delete;
serverObj->executeFunc = prv_server_execute;
serverObj->discoverFunc = prv_server_discover;
}
return serverObj;
}
void free_server_object(lwm2m_object_t * object)
{
while (object->instanceList != NULL)
{
server_instance_t * serverInstance = (server_instance_t *)object->instanceList;
object->instanceList = object->instanceList->next;
lwm2m_free(serverInstance);
}
lwm2m_free(object);
}

20
src/serialout.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef LIGHTCLIENT_SERIALOUT_H
#define LIGHTCLIENT_SERIALOUT_H
#if defined(ARDUINO_AVR_LEONARDO)
#define SerialOut Serial
#define UBLOX Serial1
#elif defined(ARDUINO_SAMD_ZERO)
#define SerialOut SerialUSB
#define UBLOX Serial
#elif defined(ARDUINO_SAM_ZERO)
#define SerialOut SerialUSB
#define UBLOX Serial1
#else
#error "Add your board."
#endif
#endif //LIGHTCLIENT_SERIALOUT_H

391
src/test_object.c Normal file
View File

@ -0,0 +1,391 @@
/*******************************************************************************
*
* Copyright (c) 2013, 2014 Intel Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* The Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* David Navarro, Intel Corporation - initial API and implementation
* domedambrosio - Please refer to git log
* Fabien Fleutot - Please refer to git log
* Axel Lorente - Please refer to git log
* Achim Kraus, Bosch Software Innovations GmbH - Please refer to git log
* Pascal Rieux - Please refer to git log
* Ville Skyttä - Please refer to git log
*
*******************************************************************************/
/*
Copyright (c) 2013, 2014 Intel Corporation
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of Intel Corporation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGE.
David Navarro <david.navarro@intel.com>
*/
/*
* Implements an object for testing purpose
*
* Multiple
* Object | ID | Instances | Mandatoty |
* Test | 31024 | Yes | No |
*
* Resources:
* Supported Multiple
* Name | ID | Operations | Instances | Mandatory | Type | Range | Units | Description |
* test | 1 | R/W | No | Yes | Integer | 0-255 | | |
* exec | 2 | E | No | Yes | | | | |
* dec | 3 | R/W | No | Yes | Float | | | |
* sig | 4 | R/W | No | Yes | Integer | | | 16-bit signed integer |
*
*/
#include "liblwm2m.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
static void prv_output_buffer(uint8_t * buffer,
int length)
{
int i;
uint8_t array[16];
i = 0;
while (i < length)
{
int j;
fprintf(stderr, " ");
memcpy(array, buffer+i, 16);
for (j = 0 ; j < 16 && i+j < length; j++)
{
fprintf(stderr, "%02X ", array[j]);
}
while (j < 16)
{
fprintf(stderr, " ");
j++;
}
fprintf(stderr, " ");
for (j = 0 ; j < 16 && i+j < length; j++)
{
if (isprint(array[j]))
fprintf(stderr, "%c ", array[j]);
else
fprintf(stderr, ". ");
}
fprintf(stderr, "\n");
i += 16;
}
}
/*
* Multiple instance objects can use userdata to store data that will be shared between the different instances.
* The lwm2m_object_t object structure - which represent every object of the liblwm2m as seen in the single instance
* object - contain a chained list called instanceList with the object specific structure prv_instance_t:
*/
typedef struct _prv_instance_
{
/*
* The first two are mandatories and represent the pointer to the next instance and the ID of this one. The rest
* is the instance scope user data (uint8_t test in this case)
*/
struct _prv_instance_ * next; // matches lwm2m_list_t::next
uint16_t shortID; // matches lwm2m_list_t::id
uint8_t test;
double dec;
int16_t sig;
} prv_instance_t;
static uint8_t prv_read(uint16_t instanceId,
int * numDataP,
lwm2m_data_t ** dataArrayP,
lwm2m_object_t * objectP)
{
prv_instance_t * targetP;
int i;
targetP = (prv_instance_t *)lwm2m_list_find(objectP->instanceList, instanceId);
if (NULL == targetP) return COAP_404_NOT_FOUND;
if (*numDataP == 0)
{
*dataArrayP = lwm2m_data_new(3);
if (*dataArrayP == NULL) return COAP_500_INTERNAL_SERVER_ERROR;
*numDataP = 3;
(*dataArrayP)[0].id = 1;
(*dataArrayP)[1].id = 3;
(*dataArrayP)[2].id = 4;
}
for (i = 0 ; i < *numDataP ; i++)
{
switch ((*dataArrayP)[i].id)
{
case 1:
lwm2m_data_encode_int(targetP->test, *dataArrayP + i);
break;
case 2:
return COAP_405_METHOD_NOT_ALLOWED;
case 3:
lwm2m_data_encode_float(targetP->dec, *dataArrayP + i);
break;
case 4:
lwm2m_data_encode_int(targetP->sig, *dataArrayP + i);
break;
default:
return COAP_404_NOT_FOUND;
}
}
return COAP_205_CONTENT;
}
static uint8_t prv_discover(uint16_t instanceId,
int * numDataP,
lwm2m_data_t ** dataArrayP,
lwm2m_object_t * objectP)
{
int i;
// is the server asking for the full object ?
if (*numDataP == 0)
{
*dataArrayP = lwm2m_data_new(4);
if (*dataArrayP == NULL) return COAP_500_INTERNAL_SERVER_ERROR;
*numDataP = 4;
(*dataArrayP)[0].id = 1;
(*dataArrayP)[1].id = 2;
(*dataArrayP)[2].id = 3;
(*dataArrayP)[3].id = 4;
}
else
{
for (i = 0; i < *numDataP; i++)
{
switch ((*dataArrayP)[i].id)
{
case 1:
case 2:
case 3:
case 4:
break;
default:
return COAP_404_NOT_FOUND;
}
}
}
return COAP_205_CONTENT;
}
static uint8_t prv_write(uint16_t instanceId,
int numData,
lwm2m_data_t * dataArray,
lwm2m_object_t * objectP)
{
prv_instance_t * targetP;
int i;
targetP = (prv_instance_t *)lwm2m_list_find(objectP->instanceList, instanceId);
if (NULL == targetP) return COAP_404_NOT_FOUND;
for (i = 0 ; i < numData ; i++)
{
switch (dataArray[i].id)
{
case 1:
{
int64_t value;
if (1 != lwm2m_data_decode_int(dataArray + i, &value) || value < 0 || value > 0xFF)
{
return COAP_400_BAD_REQUEST;
}
targetP->test = (uint8_t)value;
}
break;
case 2:
return COAP_405_METHOD_NOT_ALLOWED;
case 3:
if (1 != lwm2m_data_decode_float(dataArray + i, &(targetP->dec)))
{
return COAP_400_BAD_REQUEST;
}
break;
case 4:
{
int64_t value;
if (1 != lwm2m_data_decode_int(dataArray + i, &value) || value < INT16_MIN || value > INT16_MAX)
{
return COAP_400_BAD_REQUEST;
}
targetP->sig = (int16_t)value;
}
break;
default:
return COAP_404_NOT_FOUND;
}
}
return COAP_204_CHANGED;
}
static uint8_t prv_delete(uint16_t id,
lwm2m_object_t * objectP)
{
prv_instance_t * targetP;
objectP->instanceList = lwm2m_list_remove(objectP->instanceList, id, (lwm2m_list_t **)&targetP);
if (NULL == targetP) return COAP_404_NOT_FOUND;
lwm2m_free(targetP);
return COAP_202_DELETED;
}
static uint8_t prv_create(uint16_t instanceId,
int numData,
lwm2m_data_t * dataArray,
lwm2m_object_t * objectP)
{
prv_instance_t * targetP;
uint8_t result;
targetP = (prv_instance_t *)lwm2m_malloc(sizeof(prv_instance_t));
if (NULL == targetP) return COAP_500_INTERNAL_SERVER_ERROR;
memset(targetP, 0, sizeof(prv_instance_t));
targetP->shortID = instanceId;
objectP->instanceList = LWM2M_LIST_ADD(objectP->instanceList, targetP);
result = prv_write(instanceId, numData, dataArray, objectP);
if (result != COAP_204_CHANGED)
{
(void)prv_delete(instanceId, objectP);
}
else
{
result = COAP_201_CREATED;
}
return result;
}
static uint8_t prv_exec(uint16_t instanceId,
uint16_t resourceId,
uint8_t * buffer,
int length,
lwm2m_object_t * objectP)
{
if (NULL == lwm2m_list_find(objectP->instanceList, instanceId)) return COAP_404_NOT_FOUND;
switch (resourceId)
{
case 1:
return COAP_405_METHOD_NOT_ALLOWED;
case 2:
// fprintf(stdout, "\r\n-----------------\r\n"
// "Execute on %hu/%d/%d\r\n"
// " Parameter (%d bytes):\r\n",
// objectP->objID, instanceId, resourceId, length);
prv_output_buffer((uint8_t*)buffer, length);
// fprintf(stdout, "-----------------\r\n\r\n");
return COAP_204_CHANGED;
case 3:
return COAP_405_METHOD_NOT_ALLOWED;
default:
return COAP_404_NOT_FOUND;
}
}
lwm2m_object_t * get_test_object(void)
{
lwm2m_object_t * testObj;
testObj = (lwm2m_object_t *)lwm2m_malloc(sizeof(lwm2m_object_t));
if (NULL != testObj)
{
int i;
prv_instance_t * targetP;
memset(testObj, 0, sizeof(lwm2m_object_t));
testObj->objID = 31024;
for (i=0 ; i < 3 ; i++)
{
targetP = (prv_instance_t *)lwm2m_malloc(sizeof(prv_instance_t));
if (NULL == targetP) return NULL;
memset(targetP, 0, sizeof(prv_instance_t));
targetP->shortID = 10 + i;
targetP->test = 20 + i;
targetP->dec = -30 + i + (double)i/100.0;
targetP->sig = 0 - i;
testObj->instanceList = LWM2M_LIST_ADD(testObj->instanceList, targetP);
}
/*
* From a single instance object, two more functions are available.
* - The first one (createFunc) create a new instance and filled it with the provided informations. If an ID is
* provided a check is done for verifying his disponibility, or a new one is generated.
* - The other one (deleteFunc) delete an instance by removing it from the instance list (and freeing the memory
* allocated to it)
*/
testObj->readFunc = prv_read;
testObj->writeFunc = prv_write;
testObj->executeFunc = prv_exec;
testObj->createFunc = prv_create;
testObj->deleteFunc = prv_delete;
testObj->discoverFunc = prv_discover;
}
return testObj;
}
void free_test_object(lwm2m_object_t * object)
{
LWM2M_LIST_FREE(object->instanceList);
if (object->userData != NULL)
{
lwm2m_free(object->userData);
object->userData = NULL;
}
lwm2m_free(object);
}

258
src/wakaama-client.cpp Normal file
View File

@ -0,0 +1,258 @@
#include "wakaama-client.h"
#include <liblwm2m.h>
#include <USB/USBAPI.h>
#include <Dns.h>
#include <Ethernet.h>
#ifndef LWM2M_WITH_LOGS
// Same usage as C89 printf()
extern void lwm2m_printf(const char * format, ...);
#endif
/**
* "coap://localhost:5683"
* @param uri
* @todo init and use uri in security object
*/
void ArduinoClient::init() {
SerialOut.println(F("init():start"));
memset(&data, 0, sizeof(client_data_t));
const __FlashStringHelper * objFail = F("Failed to create object");
// create udp listener
data.udp = new EthernetUDP();
data.udp->begin(localPort);
// init objects
SerialOut.println(F("*object:security"));
objArray[0] = get_security_object(uri);
if (nullptr == objArray[0])
{
SerialOut.println(objFail);
exit(0);
}
data.securityObjP = objArray[0];
SerialOut.println(F("*object:server"));
objArray[1] = get_server_object();
if (nullptr == objArray[1])
{
SerialOut.println(objFail);
exit(0);
}
SerialOut.println(F("*object:device"));
objArray[2] = get_object_device();
if (nullptr == objArray[2])
{
SerialOut.println(objFail);
exit(0);
}
SerialOut.println(F("*object:test"));
objArray[3] = get_test_object();
if (nullptr == objArray[3])
{
SerialOut.println(objFail);
exit(0);
}
/*
* The liblwm2m library is now initialized with the functions that will be in
* charge of communication
*/
SerialOut.println(F("*lwm2m_init()"));
lwm2mH = lwm2m_init(&data);
if (NULL == lwm2mH)
{
SerialOut.println(F("lwm2m_init() failed"));
exit(0);
}
/*
* We configure the liblwm2m library with the name of the client - which shall be unique for each client -
* the number of objects we will be passing through and the objects array
*/
SerialOut.println(F("*lwm2m_configure()"));
result = lwm2m_configure(lwm2mH, name, NULL, NULL, OBJ_COUNT, objArray);
if (result != 0)
{
SerialOut.println(F("lwm2m_configure() failed"));
exit(0);
}
SerialOut.println(F("init():done"));
}
void ArduinoClient::doWorkStep() {
SerialOut.println(F("doWorkStep():start"));
/*
* This function does two things:
* - first it does the work needed by liblwm2m (eg. (re)sending some packets).
* - Secondly it adjusts the timeout value (default 60s) depending on the state of the transaction
* (eg. retransmission) and the time before the next operation
*/
SerialOut.println(F("lwm2m_step()"));
result = lwm2m_step(lwm2mH, &step_delay);
if (result != 0)
{
SerialOut.print(F("lwm2m_step() failed"));
exit(0);
}
// wait for socket event
SerialOut.println(F("parsePacket()"));
int packetSize = data.udp->parsePacket();
if (packetSize) {
int numBytes = data.udp->read(packetBuffer, UDP_TX_PACKET_MAX_SIZE);
connection_t * connP;
connP = connection_find(data.connList, data.udp);
if (connP != nullptr)
{
/*
* Let liblwm2m respond to the query depending on the context
*/
lwm2m_handle_packet(lwm2mH, (uint8_t*)packetBuffer, numBytes, connP);
}
}
SerialOut.println(F("doWorkStep():done"));
}
/**
* Destructor, actually this won't ever run on arduino...
*/
ArduinoClient::~ArduinoClient() {
lwm2m_close(lwm2mH);
data.udp->stop();
connection_free(data.connList);
free_security_object(objArray[0]);
free_server_object(objArray[1]);
free_object_device(objArray[2]);
free_test_object(objArray[3]);
}
/**
* called from registration.c prv_register()
*
* @param secObjInstID
* @param userData
* @return
*/
void * lwm2m_connect_server(uint16_t secObjInstID, void *userData) {
client_data_t * dataP;
char * uri;
char * host;
char * port;
connection_t * newConnP = nullptr;
dataP = (client_data_t *)userData;
uri = get_server_uri(dataP->securityObjP, secObjInstID);
if (uri == nullptr) return nullptr;
SerialOut.print(F("Connecting to "));
SerialOut.println(uri);
// parse uri in the form "coaps://[host]:[port]"
if (0 == strncmp(uri, "coaps://", strlen("coaps://")))
{
host = uri+strlen("coaps://");
}
else if (0 == strncmp(uri, "coap://", strlen("coap://")))
{
host = uri+strlen("coap://");
}
else
{
lwm2m_free(uri);
return (void *)newConnP;
}
port = strrchr(host, ':');
if (port == nullptr) {
lwm2m_free(uri);
return (void *)newConnP;
}
// remove brackets
if (host[0] == '[')
{
host++;
if (*(port - 1) == ']')
{
*(port - 1) = 0;
}
else {
lwm2m_free(uri);
return (void *)newConnP;
}
}
// split strings
*port = 0;
port++;
auto * remoteIp = new IPAddress();
if(!remoteIp->fromString(host)) {
DNSClient dns;
dns.begin(Ethernet.dnsServerIP());
dns.getHostByName(host, *remoteIp);
}
String portStr = port;
newConnP = connection_create(dataP->connList, dataP->udp, remoteIp, portStr.toInt());
if (newConnP == nullptr) {
SerialOut.println(F("Connection creation failed"));
}
else {
dataP->connList = newConnP;
}
SerialOut.println(F("Connection created"));
lwm2m_free(uri);
return (void *)newConnP;
};
/**
* called from
*
* @param sessionH
* @param userData
*/
void lwm2m_close_connection(void *sessionH, void *userData) {
client_data_t * app_data;
connection_t * targetP;
app_data = (client_data_t *)userData;
targetP = (connection_t *)sessionH;
if (targetP == app_data->connList)
{
app_data->connList = targetP->next;
lwm2m_free(targetP);
}
else
{
connection_t * parentP;
parentP = app_data->connList;
while (parentP != nullptr && parentP->next != targetP)
{
parentP = parentP->next;
}
if (parentP != nullptr)
{
parentP->next = targetP->next;
lwm2m_free(targetP);
}
}
};
void lwm2m_printf(const char * format, ...)
{
SerialOut.println(format);
}

53
src/wakaama-client.h Normal file
View File

@ -0,0 +1,53 @@
#ifndef WAKAAMA_CLIENT_H_
#define WAKAAMA_CLIENT_H_
#include <Udp.h>
#include <EthernetUdp.h>
#include <connection.h>
#include <serialout.h>
#define OBJ_COUNT 4
extern "C" {
extern lwm2m_object_t * get_object_device(void);
extern void free_object_device(lwm2m_object_t * objectP);
extern lwm2m_object_t * get_server_object(void);
extern void free_server_object(lwm2m_object_t * object);
extern lwm2m_object_t * get_security_object(const char * uri);
extern void free_security_object(lwm2m_object_t * objectP);
extern char * get_server_uri(lwm2m_object_t * objectP, uint16_t secObjInstID);
extern lwm2m_object_t * get_test_object(void);
extern void free_test_object(lwm2m_object_t * object);
};
typedef struct
{
lwm2m_object_t * securityObjP;
connection_t * connList;
EthernetUDP * udp;
} client_data_t;
class ArduinoClient {
public:
ArduinoClient(const char *uri) : uri(uri) {};
void init();
~ArduinoClient();
void doWorkStep();
private:
const char * uri;
const uint16_t localPort = 56830;
const char * name = "wakaamArduino";
time_t step_delay = 60;
int result;
char packetBuffer[UDP_TX_PACKET_MAX_SIZE];
client_data_t data;
lwm2m_context_t * lwm2mH = nullptr;
lwm2m_object_t * objArray[OBJ_COUNT];
};
#endif