1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

add microcoap example application

This commit is contained in:
Lotte Steenbrink 2015-02-04 16:28:58 -08:00 committed by Lotte Steenbrink
parent 7bc5111e87
commit 7daa0c00f9
4 changed files with 374 additions and 0 deletions

32
microcoap/Makefile Normal file
View File

@ -0,0 +1,32 @@
# name of your application
APPLICATION = microcoap-example
# If no BOARD is found in the environment, use this default:
BOARD ?= native
# if you try to compile this for anything but the boards specified, it will break.
# This application has not been verified to work with any other boards-- proceed with caution.
BOARD_WHITELIST := native
# This has to be the absolute path to the RIOT base directory:
RIOTBASE ?= $(CURDIR)/../../RIOT
# Comment this out to disable code in RIOT that does safety checking
# which is not needed in a production environment but helps in the
# development process:
CFLAGS += -DRIOT -DMICROCOAP_DEBUG
# Change this to 0 show compiler invocation lines by default:
QUIET ?= 1
USEPKG=microcoap
USEMODULE += config
USEMODULE += uart0
USEMODULE += nativenet
USEMODULE += sixlowpan
USEMODULE += udp
include $(RIOTBASE)/Makefile.include

146
microcoap/README.md Normal file
View File

@ -0,0 +1,146 @@
Microcoap example
============
This is a small microcoap example application. It provides a server which only
answers GET requests to the resource /foo/bar.
## Setup
You can use [marz](https://github.com/sgso/marz) to tunnel CoAP messages into the RIOT native thread. This is a bit tricky, so maybe this walkthrough will help:
0. Build this application.
1. Install the copper plugin in your Firefox browser.
2. Run `sudo apt-get install bridge-utils`
3. In your RIOT directury, run
./cpu/native/tapsetup.sh create 2
This will set up two tap devices connected by a bridge. our RIOT application and
marz will each listen at one of these devices, and communicate over the bridge.
3. Open two terminal windows.
**In window #1**, start the microcoap-example application:
cd applications/microcoap
sudo ./bin/native/microcoap-example.elf tap1 -i 1
*Make sure to bind it to ``tap1``, since marz will be bound to ``tap0`!*
``-i 1`` forces your RIOT instance to match its id to the one specified in marz.config. You should **only** specify this for the **one** RIOT that marz tunnels to. This is sufficient for this example; if you need help running more than one RIOT with marz, please contact the author of this example.
You should see output similar to this.
RIOT native uart0 initialized.
RIOT native interrupts/signals initialized.
LED_GREEN_OFF
LED_RED_ON
RIOT native board initialized.
RIOT native hardware initialization complete.
kernel_init(): This is RIOT! (Version: 400e-microcoap)
kernel_init(): jumping into first task...
UART0 thread started.
uart0_init() [OK]
Initializing transport layer protocol: udp
Starting example microcoap server...
initializing 6LoWPAN...
initializing receive socket...
Ready to receive requests.
Welcome to RIOT
>
**In window #2**, first install Python development headers by running
sudo apt-get install python-dev
Afterwards you can install and run marz:
pip install --user Twisted &&
pip install --user bidict &&
git clone https://github.com/sgso/marz &&
cd marz &&
./setup.sh
./marz.py
You should see output similar to this.
WARNING: No route found for IPv6 destination :: (no default route?)
Listening on UDP ports: [5683, 2222]
Listening on tap interface tap0 with MAC address 9a:80:a3:fc:93:18
## Testing
The "Copper" firefox plugin is a convenient way to test CoAP endpoints. In the absence of a GUI you can also use Python to send test requests.
### Using python(3)
First, make sure Python 3 is installed, clone `aiocoap` into a directory of your choice and then change into it:
git clone git@github.com:chrysn/aiocoap.git &&
cd aiocoap
Open the `clientGET.py` file and change the line that reads
request.set_request_uri(<some url>)
to
request.set_request_uri('coap://[::1]/foo/bar')
Then run `clientGET.py`, which should print the following:
$ ./clientGET.py
Result: 2.05 Content
b'1337'
### Using the Firefox Copper plugin
Open Firefox and enter
coap://[::1]:5683/foo/bar
Into the browser window. Then, click the big gren ``GET`` button. This should
trigger a GET request to our microcoap-example application. Shortly after you've
clicked GET, **window #2** should read
make new connection
[UDP6 5683] Received 14 data bytes from ('::1', 54685): Relaying through 54685 to RiotEndpoint(hwaddr=1, ipv6='fe80::ff:fe00:1', port=5683)
[TAP] Received 12 data bytes on port 54685: Relaying through 5683 to IP6Endpoint(ipv6='::1', port=54685)
**window #1** should supply you with detailed information about the received
request and the reply our microcoap-example is sending:
> Received packet: 40 01 0B EC B3 66 6F 6F 03 62 61 72 C1 02
content:
Header:
ver 0x01
t 0x01
tkl 0x00
code 0x01
id 0x0BEC
Options:
0x0B [ 66 6F 6F ]
0x0B [ 62 61 72 ]
0x17 [ 02 ]
Payload:
Sending packet: 60 45 0B EC C2 00 00 FF 31 33 33 37
content:
Header:
ver 0x01
t 0x01
tkl 0x00
code 0x45
id 0x0BEC
Options:
0x0C [ 00 00 ]
Payload: 31 33 33 37
And finally, the big grey ``Payload`` box in your Firefox window should read:
1337
If this all works, you're good to go! :)

53
microcoap/endpoints.c Normal file
View File

@ -0,0 +1,53 @@
/*
* Copyright (C) 2015 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @{
*
* @file
* @brief microcoap example server endpoints
*
* @author Lotte Steenbrink <lotte.steenbrink@haw-hamburg.de>
*
* @}
*/
#include <stdbool.h>
#include <stdbool.h>
#include <string.h>
#include "coap.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
#define MAX_RESPONSE_LEN 1500
static uint8_t response[MAX_RESPONSE_LEN] = "";
static const coap_endpoint_path_t path = {2, {"foo", "bar"}};
void create_response_payload(const uint8_t *buffer)
{
char *response = "1337";
memcpy((void*)buffer, response, strlen(response));
}
/* The handler which handles the path /foo/bar */
static int handle_get_response(coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_packet_t *outpkt, uint8_t id_hi, uint8_t id_lo)
{
DEBUG("[endpoints] %s()\n", __func__);
create_response_payload(response);
/* NOTE: COAP_RSPCODE_CONTENT only works in a packet answering a GET. */
return coap_make_response(scratch, outpkt, response, strlen((char*)response),
id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CONTENT, COAP_CONTENTTYPE_TEXT_PLAIN);
}
const coap_endpoint_t endpoints[] =
{
{COAP_METHOD_GET, handle_get_response, &path, "ct=0"},
{(coap_method_t)0, NULL, NULL, NULL} /* marks the end of the endpoints array */
};

143
microcoap/main.c Normal file
View File

@ -0,0 +1,143 @@
/*
* Copyright (C) 2015 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @{
*
* @file
* @brief microcoap example server
*
* @author Lotte Steenbrink <lotte.steenbrink@haw-hamburg.de>
*
* @}
*/
#include <stdio.h>
#include "udp.h"
#include "net_help.h"
#include "net_if.h"
#include "periph/cpuid.h"
#include "board_uart0.h"
#include "thread.h"
#include "posix_io.h"
#include <coap.h>
#include "hashes.h"
#define ENABLE_DEBUG (1)
#include "debug.h"
#define PORT 5683
#define BUFSZ 128
#define RCV_MSG_Q_SIZE (64)
static void *_microcoap_server_thread(void *arg);
msg_t msg_q[RCV_MSG_Q_SIZE];
char _rcv_stack_buf[KERNEL_CONF_STACKSIZE_MAIN];
static ipv6_addr_t prefix;
int sock_rcv, if_id;
sockaddr6_t sa_rcv;
uint8_t buf[BUFSZ];
uint8_t scratch_raw[BUFSZ];
coap_rw_buffer_t scratch_buf = {scratch_raw, sizeof(scratch_raw)};
static void _init_tlayer(void);
static uint16_t get_hw_addr(void);
int main(void)
{
DEBUG("Starting example microcoap server...\n");
_init_tlayer();
thread_create(_rcv_stack_buf, KERNEL_CONF_STACKSIZE_MAIN, PRIORITY_MAIN, CREATE_STACKTEST, _microcoap_server_thread, NULL ,"_microcoap_server_thread");
DEBUG("Ready to receive requests.\n");
return 0;
}
static uint16_t get_hw_addr(void)
{
return sysconfig.id;
}
/* init transport layer & routing stuff*/
static void _init_tlayer(void)
{
msg_init_queue(msg_q, RCV_MSG_Q_SIZE);
net_if_set_hardware_address(0, get_hw_addr());
DEBUG("set hawddr to: %d\n", get_hw_addr());
printf("initializing 6LoWPAN...\n");
ipv6_addr_init(&prefix, 0xABCD, 0xEF12, 0, 0, 0, 0, 0, 0);
if_id = 0; /* having more than one interface isn't supported anyway */
sixlowpan_lowpan_init_interface(if_id);
}
static void *_microcoap_server_thread(void *arg)
{
(void)arg; /* make the compiler shut up about unused variables */
printf("initializing receive socket...\n");
sa_rcv = (sockaddr6_t) { .sin6_family = AF_INET6,
.sin6_port = HTONS(PORT) };
sock_rcv = socket_base_socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
if (-1 == socket_base_bind(sock_rcv, &sa_rcv, sizeof(sa_rcv))) {
printf("Error: bind to receive socket failed!\n");
socket_base_close(sock_rcv);
}
printf("Ready to receive requests.\n");
while(1)
{
int n, rc;
socklen_t len = sizeof(sa_rcv);
coap_packet_t pkt;
n = socket_base_recvfrom(sock_rcv, buf, sizeof(buf), 0, &sa_rcv, &len);
printf("Received packet: ");
coap_dump(buf, n, true);
printf("\n");
if (0 != (rc = coap_parse(&pkt, buf, n)))
printf("Bad packet rc=%d\n", rc);
else
{
size_t rsplen = sizeof(buf);
coap_packet_t rsppkt;
printf("content:\n");
coap_dumpPacket(&pkt);
coap_handle_req(&scratch_buf, &pkt, &rsppkt);
if (0 != (rc = coap_build(buf, &rsplen, &rsppkt)))
printf("coap_build failed rc=%d\n", rc);
else
{
printf("Sending packet: ");
coap_dump(buf, rsplen, true);
printf("\n");
printf("content:\n");
coap_dumpPacket(&rsppkt);
socket_base_sendto(sock_rcv, buf, rsplen, 0, &sa_rcv, sizeof(sa_rcv));
}
}
}
return NULL;
}