Commit f0c088a6 authored by Yann Stephen Mandza's avatar Yann Stephen Mandza Committed by Kishen Maloor

Arduino Port: Support for arduino AVR and ARM MCUs

The port target the arduino AVR (Mega2560) and ARM architectures.
Mostly arduino SAMD(arduino MKRZERO). However, any SAMD board
should work as well as  the arduino Due. The ipadapter for network
connectivity uses  Wiznet w5500 based shield( thus only IPV4 Ethernet
is supported as yet),required  arduino C++ libraries were adapted by
providing C wrappers. A FAT32 SD card is used to provide pesistant
storage for security build.

Note: iotivility lite stack have shown heavy  for the AVR
architecture. Thus the port allows the use of external
memory SRAM (up to 56KBytes).

Bug: https://github.com/yannS2016/iotivity-constrained-arduino/issuesSigned-off-by: yann's avatarYann Stephen Mandza <yann@tlabs.ac.za>
parent 51be7aba
#include "Ethernet2.h"
#include "serial.h"
#include "oc_api.h"
#include "oc_clock.h"
#include "oc_assert.h"
#include "oc_storage.h"
#include "oc_connectivity.h"
#include "util/oc_process.h"
#include "oc_network_events_mutex.h"
#ifdef __AVR__
#ifdef OC_XMEM
void extRAMinit(void)__attribute__ ((used, naked, section (".init3")));
void extRAMinit(void) {
// set up the xmem registers
XMCRB=0;
XMCRA=1<<SRE;
DDRD|=_BV(PD7);
DDRL|=(_BV(PL6)|_BV(PL7));
}
#endif
#endif
OC_PROCESS(sample_client_process, "client");
static int
app_init(void)
{
int ret = oc_init_platform("Apple", NULL, NULL);
ret |= oc_add_device("/oic/d", "oic.d.phone", "Kishen's IPhone", "ocf.1.0.0",
"ocf.res.1.0.0", NULL, NULL);
return ret;
}
#define MAX_URI_LENGTH (30)
static char a_light[MAX_URI_LENGTH];
static oc_endpoint_t *light_server;
static bool state;
static int power;
static oc_string_t name;
static oc_event_callback_retval_t
stop_observe(void *data)
{
(void)data;
OC_DBG("Stopping OBSERVE");
oc_stop_observe(a_light, light_server);
return OC_EVENT_DONE;
}
static void
observe_light(oc_client_response_t *data)
{
OC_DBG("OBSERVE_light:");
oc_rep_t *rep = data->payload;
while (rep != NULL) {
OC_DBG("key %s, value ", oc_string(rep->name));
switch (rep->type) {
case OC_REP_BOOL:
OC_DBG("%d", rep->value.boolean);
state = rep->value.boolean;
break;
case OC_REP_INT:
OC_DBG("%d", rep->value.integer);
power = rep->value.integer;
break;
case OC_REP_STRING:
OC_DBG("%s", oc_string(rep->value.string));
if (oc_string_len(name))
oc_free_string(&name);
oc_new_string(&name, oc_string(rep->value.string),
oc_string_len(rep->value.string));
break;
default:
break;
}
rep = rep->next;
}
}
static void
post2_light(oc_client_response_t *data)
{
OC_DBG("POST2_light:");
if (data->code == OC_STATUS_CHANGED)
OC_DBG("POST response: CHANGED");
else if (data->code == OC_STATUS_CREATED)
OC_DBG("POST response: CREATED");
else
OC_DBG("POST response code %d", data->code);
oc_do_observe(a_light, light_server, NULL, &observe_light, LOW_QOS, NULL);
oc_set_delayed_callback(NULL, &stop_observe, 30);
OC_DBG("Sent OBSERVE request");
}
static void
post_light(oc_client_response_t *data)
{
OC_DBG("POST_light:");
if (data->code == OC_STATUS_CHANGED)
OC_DBG("POST response: CHANGED");
else if (data->code == OC_STATUS_CREATED)
OC_DBG("POST response: CREATED");
else
OC_DBG("POST response code %d", data->code);
if (oc_init_post(a_light, light_server, NULL, &post2_light, LOW_QOS, NULL)) {
oc_rep_start_root_object();
oc_rep_set_boolean(root, state, true);
oc_rep_set_int(root, power, 55);
oc_rep_end_root_object();
if (oc_do_post())
OC_DBG("Sent POST request");
else
OC_DBG("Could not send POST request");
} else
OC_DBG("Could not init POST request");
}
static void
put_light(oc_client_response_t *data)
{
OC_DBG("PUT_light:");
if (data->code == OC_STATUS_CHANGED)
OC_DBG("PUT response: CHANGED");
else
OC_DBG("PUT response code %d", data->code);
if (oc_init_post(a_light, light_server, NULL, &post_light, LOW_QOS, NULL)) {
oc_rep_start_root_object();
oc_rep_set_boolean(root, state, false);
oc_rep_set_int(root, power, 105);
oc_rep_end_root_object();
if (oc_do_post())
OC_DBG("Sent POST request");
else
OC_DBG("Could not send POST request");
} else
OC_DBG("Could not init POST request");
}
static void
get_light(oc_client_response_t *data)
{
OC_DBG("GET_light:");
oc_rep_t *rep = data->payload;
while (rep != NULL) {
OC_DBG("key %s, value ", oc_string(rep->name));
switch (rep->type) {
case OC_REP_BOOL:
OC_DBG("%d", rep->value.boolean);
state = rep->value.boolean;
break;
case OC_REP_INT:
OC_DBG("%d", rep->value.integer);
power = rep->value.integer;
break;
case OC_REP_STRING:
OC_DBG("%s", oc_string(rep->value.string));
if (oc_string_len(name))
oc_free_string(&name);
oc_new_string(&name, oc_string(rep->value.string),
oc_string_len(rep->value.string));
break;
default:
break;
}
rep = rep->next;
}
if (oc_init_put(a_light, light_server, NULL, &put_light, LOW_QOS, NULL)) {
oc_rep_start_root_object();
oc_rep_set_boolean(root, state, true);
oc_rep_set_int(root, power, 15);
oc_rep_end_root_object();
if (oc_do_put())
OC_DBG("Sent PUT request");
else
OC_DBG("Could not send PUT request");
} else
OC_DBG("Could not init PUT request");
}
static oc_discovery_flags_t
discovery(const char *anchor, const char *uri, oc_string_array_t types,
oc_interface_mask_t interfaces, oc_endpoint_t *endpoint,
oc_resource_properties_t bm, void *user_data)
{
(void)anchor;
(void)user_data;
(void)interfaces;
(void)bm;
int i;
int uri_len = strlen(uri);
uri_len = (uri_len >= MAX_URI_LENGTH) ? MAX_URI_LENGTH - 1 : uri_len;
for (i = 0; i < (int)oc_string_array_get_allocated_size(types); i++) {
char *t = oc_string_array_get_item(types, i);
if (strlen(t) == 10 && strncmp(t, "core.light", 10) == 0) {
#ifdef OC_IPV4
#ifdef OC_ESP32 // this is experimental
light_server = endpoint;
#else
light_server = endpoint->next;
#endif
OC_DBG("IPV4 Resource ");
#else
light_server = endpoint;
OC_DBG("IPV6 Resource ");
#endif
strncpy(a_light, uri, uri_len);
a_light[uri_len] = '\0';
OC_DBG("Resource %s hosted at endpoints:", a_light);
oc_endpoint_t *ep = endpoint;
while (ep != NULL) {
PRINTipaddr(*ep);
PRINT("\n");
ep = ep->next;
}
oc_do_get(a_light, light_server, NULL, &get_light, LOW_QOS, NULL);
return OC_STOP_DISCOVERY;
}
}
oc_free_server_endpoints(endpoint);
return OC_CONTINUE_DISCOVERY;
}
static void
issue_requests(void)
{
oc_do_ip_discovery("core.light", &discovery, NULL);
}
static void
signal_event_loop(void)
{
oc_process_post(&sample_client_process, OC_PROCESS_EVENT_TIMER, NULL);
}
OC_PROCESS_THREAD(sample_client_process, ev, data)
{
(void)data;
static struct oc_etimer et;
static const oc_handler_t handler = {.init = app_init,
.signal_event_loop = signal_event_loop,
.requests_entry = issue_requests };
static oc_clock_time_t next_event;
oc_set_mtu_size(1024);
oc_set_max_app_data_size(1024);
OC_PROCESS_BEGIN();
OC_DBG("Initializing client for arduino");
while (ev != OC_PROCESS_EVENT_EXIT) {
oc_etimer_set(&et, (oc_clock_time_t)next_event);
if(ev == OC_PROCESS_EVENT_INIT){
int init = oc_main_init(&handler);
if (init < 0){
OC_DBG("Client Init failed!");
return init;
}
OC_DBG("Client process init!");
}
else if(ev == OC_PROCESS_EVENT_TIMER){
next_event = oc_main_poll();
next_event -= oc_clock_time();
}
OC_PROCESS_WAIT_EVENT();
}
OC_PROCESS_END();
}
// Arduino Ethernet Shield
uint8_t ConnectToNetwork()
{
// Note: ****Update the MAC address here with your shield's MAC address****
uint8_t ETHERNET_MAC[] = {0x90, 0xA2, 0xDA, 0x11, 0x44, 0xA9};
Ethernet.init(5); // CS Pin for MKRZERO
uint8_t error = Ethernet.begin(ETHERNET_MAC);
if (error == 0)
{
OC_ERR("Error connecting to Network: %d", error);
return -1;
}
IPAddress ip = Ethernet.localIP();
OC_DBG("Connected to Ethernet IP: %d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
return 0;
}
void setup() {
#if defined(__arm__) && defined(__SAMD21G18A__) || defined(__SAM3X8E__)
Serial.begin(250000);
#else
Serial.begin(115200);
#endif
#if defined(__SAMD21G18A__)
while (!Serial) {
}
#endif
if (ConnectToNetwork() != 0)
{
OC_ERR("Unable to connect to network");
return;
}
delay(500);
#ifdef OC_SECURITY
oc_storage_config("creds");
#endif /* OC_SECURITY */
oc_process_start(&sample_client_process, NULL);
delay(200);
}
void loop() {
oc_process_run();
}
#include "Ethernet2.h"
#include "serial.h"
#include "oc_api.h"
#include "oc_clock.h"
#include "oc_assert.h"
#include "oc_storage.h"
#include "oc_connectivity.h"
#include "util/oc_process.h"
#include "oc_network_events_mutex.h"
#ifdef __AVR__
#ifdef OC_XMEM
void extRAMinit(void)__attribute__ ((used, naked, section (".init3")));
void extRAMinit(void) {
// set up the xmem registers
XMCRB=0;
XMCRA=1<<SRE;
DDRD|=_BV(PD7);
DDRL|=(_BV(PL6)|_BV(PL7));
}
#endif
#endif
OC_PROCESS(sample_server_process, "server");
static bool state = false;
int power;
oc_string_t name;
static int
app_init(void)
{
int ret = oc_init_platform("Intel", NULL, NULL);
ret |= oc_add_device("/oic/d", "oic.d.light", "Lamp", "ocf.1.0.0",
"ocf.res.1.0.0", NULL, NULL);
return ret;
}
static void
get_light(oc_request_t *request, oc_interface_mask_t interface, void *user_data)
{
(void)user_data;
++power;
OC_DBG("GET_light:\n");
oc_rep_start_root_object();
switch (interface) {
case OC_IF_BASELINE:
oc_process_baseline_interface(request->resource);
/* fall through */
case OC_IF_RW:
oc_rep_set_boolean(root, state, state);
oc_rep_set_int(root, power, power);
oc_rep_set_text_string(root, name, oc_string(name));
break;
default:
break;
}
oc_rep_end_root_object();
oc_send_response(request, OC_STATUS_OK);
}
static void
post_light(oc_request_t *request, oc_interface_mask_t interface, void *user_data)
{
(void)interface;
(void)user_data;
OC_DBG("POST_light:\n");
oc_rep_t *rep = request->request_payload;
while (rep != NULL) {
OC_DBG(("key: %s "), oc_string(rep->name));
switch (rep->type) {
case OC_REP_BOOL:
state = rep->value.boolean;
OC_DBG("value: %d\n", state);
break;
case OC_REP_INT:
power = rep->value.integer;
OC_DBG("value: %d\n", power);
break;
case OC_REP_STRING:
oc_free_string(&name);
oc_new_string(&name, oc_string(rep->value.string),
oc_string_len(rep->value.string));
break;
default:
oc_send_response(request, OC_STATUS_BAD_REQUEST);
return;
break;
}
rep = rep->next;
}
oc_send_response(request, OC_STATUS_CHANGED);
}
static void
put_light(oc_request_t *request, oc_interface_mask_t interface,
void *user_data)
{
(void)interface;
(void)user_data;
post_light(request, interface, user_data);
}
static void
register_resources(void)
{
oc_resource_t *res = oc_new_resource("Yann's Light", "/a/light", 2, 0);
oc_resource_bind_resource_type(res, "core.light");
oc_resource_bind_resource_type(res, "core.brightlight");
oc_resource_bind_resource_interface(res, OC_IF_RW);
oc_resource_set_default_interface(res, OC_IF_RW);
oc_resource_set_discoverable(res, true);
oc_resource_set_periodic_observable(res, 1);
oc_resource_set_request_handler(res, OC_GET, get_light, NULL);
oc_resource_set_request_handler(res, OC_PUT, put_light, NULL);
oc_resource_set_request_handler(res, OC_POST, post_light, NULL);
oc_add_resource(res);
}
static void
signal_event_loop(void)
{
oc_process_post(&sample_server_process, OC_PROCESS_EVENT_TIMER, NULL);
}
OC_PROCESS_THREAD(sample_server_process, ev, data)
{
(void)data;
static struct oc_etimer et;
static const oc_handler_t handler = {.init = app_init,
.signal_event_loop = signal_event_loop,
.register_resources = register_resources };
static oc_clock_time_t next_event;
oc_set_mtu_size(512);
oc_set_max_app_data_size(880);
OC_PROCESS_BEGIN();
OC_DBG("Initializing server for arduino");
while (ev != OC_PROCESS_EVENT_EXIT) {
oc_etimer_set(&et, (oc_clock_time_t)next_event);
if(ev == OC_PROCESS_EVENT_INIT){
int init = oc_main_init(&handler);
if (init < 0){
OC_DBG("Server Init failed!");
return init;
}
OC_DBG("Server process init!");
}
else if(ev == OC_PROCESS_EVENT_TIMER){
next_event = oc_main_poll();
next_event -= oc_clock_time();
}
OC_PROCESS_WAIT_EVENT();
}
OC_PROCESS_END();
}
// Arduino Ethernet Shield
uint8_t ConnectToNetwork()
{
// Note: ****Update the MAC address here with your shield's MAC address****
uint8_t ETHERNET_MAC[] = {0x92, 0xA1, 0xDA, 0x11, 0x44, 0xA9};
#if defined(__SAMD21G18A__)
Ethernet.init(5); // CS Pin for MKRZERO
#endif
uint8_t error = Ethernet.begin(ETHERNET_MAC);
if (error == 0)
{
OC_ERR("Error connecting to Network: %d", error);
return -1;
}
IPAddress ip = Ethernet.localIP();
OC_DBG("Connected to Ethernet IP: %d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
return 0;
}
void setup() {
#if defined(__arm__) && defined(__SAMD21G18A__) || defined(__SAM3X8E__)
Serial.begin(250000);
#else
Serial.begin(115200);
#endif
#if defined(__SAMD21G18A__)
while (!Serial) {
}
#endif
if (ConnectToNetwork() != 0)
{
OC_ERR("Unable to connect to network");
return;
}
#ifdef OC_SECURITY
oc_storage_config("creds");
#endif /* OC_SECURITY */
oc_process_start(&sample_server_process, NULL);
delay(200);
}
void loop() {
oc_process_run();
}
include setup.mk
ROOT_DIR =../..
ifneq ($(ARCH),avr)
ifneq ($(ARCH),samd)
ifneq ($(ARCH),sam)
$(error Target Architecture must be define to proceed!)
endif
endif
endif
ifeq ($(APP),server)
LOCAL_CPP_SRCS += server_arduino.cpp
CXXFLAGS += -DOC_SERVER
TARGET = $(ARCH)_server
ifeq ($(XMEM),1)
CXXFLAGS += -DOC_XMEM
endif
else ifeq ($(APP),client)
CXXFLAGS += -DOC_CLIENT
ifeq ($(XMEM),1)
CXXFLAGS += -DOC_XMEM
endif
LOCAL_CPP_SRCS += client_arduino.cpp
TARGET = $ARCH_client
else
$(error Must define an app server/client to proceed!)
endif
ifeq ($(DYNAMIC),1)
CXXFLAGS += -DOC_DYNAMIC_ALLOCATION
endif
ifeq ($(XMEM),1)
CXXFLAGS += -DOC_XMEM
endif
ifeq ($(IPV4),1)
CXXFLAGS += -DOC_IPV4
endif
### Iotivity contrained includes
ifeq ($(ARCH),avr)
DEPS_HEADERS +=$(addprefix -Ideps/, pRNG wiz5500 serial sdFat)
else
DEPS_HEADERS +=$(addprefix -Ideps/, wiz5500 serial sdFat)
endif
CORE_HEADERS +=$(addprefix -I$(ROOT_DIR)/, . messaging/coap util util/pt include api port security deps/mbedtls/include/mbedtls)
LIB_HEADERS +=-I$(ARDUINO_DIR)/libraries/SdFat/src/FatLib
CXXFLAGS += $(DEPS_HEADERS) $(CORE_HEADERS) $(LIB_HEADERS) -Iadapter -Iapps/include
ifeq ($(SECURE),1)
CXXFLAGS +=$(addprefix -I$(ROOT_DIR)/deps/mbedtls/, include include/mbedtls)
CXXFLAGS += -DOC_SECURITY
endif
SERVER_ARCHIVE = build-$(BOARD_TAG)/libarduino-adapter.a
TIME_ARCHIVE = build-$(BOARD_TAG)/libarduino-time.a
WIZ5500_ARCHIVE = build-$(BOARD_TAG)/libarduino-wiz5500.a
SERIAL_ARCHIVE = build-$(BOARD_TAG)/libarduino-serial.a
SDFAT_ARCHIVE = build-$(BOARD_TAG)/libarduino-sdfat.a
DEPS_OBJ += $(TIME_ARCHIVE) $(WIZ5500_ARCHIVE) $(SDFAT_ARCHIVE) $(SERIAL_ARCHIVE)
ifeq ($(ARCH),avr)
PRNG_ARCHIVE = build-$(BOARD_TAG)/libarduino-prng.a
endif
DEPS_OBJ += $(PRNG_ARCHIVE)
SERVER_OBJ = adapter/build-$(BOARD_TAG)/libarduino-adapter.a
OTHER_OBJS += $(SERVER_OBJ)
ifeq ($(ARCH),avr)
OTHER_OBJS += deps/pRNG/$(PRNG_ARCHIVE)
endif
OTHER_OBJS += deps/Time/$(TIME_ARCHIVE)
OTHER_OBJS += deps/wiz5500/$(WIZ5500_ARCHIVE)
OTHER_OBJS += deps/serial/$(SERIAL_ARCHIVE)
OTHER_OBJS += deps/sdFat/$(SDFAT_ARCHIVE)
VPATH=apps/server:$(ROOT_DIR)/apps:
ifeq ($(ARCH),avr)
include avr.mk
else ifeq ($(ARCH),sam)
include sam.mk
else ifeq ($(ARCH),samd)
include samd.mk
else
$(error Target Architecture must be define to proceed!)
endif
$(SERVER_OBJ): $(DEPS_OBJ)
$(MAKE) -C adapter $(SERVER_ARCHIVE)
$(PRNG_ARCHIVE):
$(MAKE) -C deps/pRNG $@
$(TIME_ARCHIVE):
$(MAKE) -C deps/Time $@
$(WIZ5500_ARCHIVE):
$(MAKE) -C deps/wiz5500 $@
$(SERIAL_ARCHIVE) :