mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-01-18 12:52:44 +01:00
add microcoap example application
This commit is contained in:
parent
7bc5111e87
commit
7daa0c00f9
32
microcoap/Makefile
Normal file
32
microcoap/Makefile
Normal 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
146
microcoap/README.md
Normal 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
53
microcoap/endpoints.c
Normal 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
143
microcoap/main.c
Normal 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;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user