-
-
Notifications
You must be signed in to change notification settings - Fork 49
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
update from https://github.com/hirotakaster/CoAP/blob/arduino.
- Loading branch information
1 parent
fce26ac
commit 76f0eea
Showing
8 changed files
with
785 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,32 @@ | ||
# CoAP-library | ||
# CoAP client, server library for Arduino. | ||
<a href="http://coap.technology/" target=_blank>CoAP</a> simple server, client library for Arduino. | ||
|
||
## Source Code | ||
This lightweight library source code are only 2 files. coap.cpp, coap.h. | ||
|
||
## Example | ||
Some sample sketches for Arduino included(/examples/). | ||
|
||
- coaptest.ino : simple request/response sample. | ||
- coapserver.ino : server endpoint url callback sample. | ||
|
||
## How to use | ||
Download this source code branch zip file and extract to the Arduino libraries directory or checkout repository. Here is checkout on MacOS X. | ||
|
||
cd $HOME/Documents/Arduino/libraries/ | ||
git clone https://github.com/hirotakaster/CoAP-simple-library | ||
# restart Arduino IDE, you can find CoAP-simple-library examples. | ||
|
||
In this exmples need CoAP server libcoap or microcoap server for check the example program. There is setting the libcoap on Ubuntu Linux. But if there don't use CoAP server(request/reseponse), following setting don't be needed. | ||
|
||
git clone https://github.com/obgm/libcoap | ||
cd libcoap/ | ||
./autogen.sh | ||
./configure --disable-examples | ||
gcc -o coap-server ./examples/coap-server.c -I./include/coap/ -I. -L.libs -lcoap-1 -DWITH_POSIX | ||
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.libs | ||
./coap-server | ||
# next start Arduino and check the request/response. | ||
|
||
## Particle Photon, Core compatible | ||
This library is Particle Photon, Core compatible. That's version is <a href="https://github.com/hirotakaster/CoAP">here</a>. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,323 @@ | ||
#include "coap.h" | ||
|
||
#if defined(ARDUINO) | ||
#include "Arduino.h" | ||
#elif defined(SPARK) | ||
#include "application.h" | ||
#endif | ||
|
||
#define LOGGING | ||
|
||
|
||
Coap::Coap( | ||
#if defined(ARDUINO) | ||
UDP& udp | ||
#endif | ||
) { | ||
|
||
#if defined(ARDUINO) | ||
this->_udp = &udp; | ||
#elif defined(SPARK) | ||
this->_udp = new UDP(); | ||
#endif | ||
|
||
} | ||
|
||
bool Coap::start() { | ||
this->start(COAP_DEFAULT_PORT); | ||
return true; | ||
} | ||
|
||
bool Coap::start(int port) { | ||
this->_udp->begin(port); | ||
return true; | ||
} | ||
|
||
uint16_t Coap::sendPacket(CoapPacket &packet, IPAddress ip) { | ||
return this->sendPacket(packet, ip, COAP_DEFAULT_PORT); | ||
} | ||
|
||
uint16_t Coap::sendPacket(CoapPacket &packet, IPAddress ip, int port) { | ||
uint8_t buffer[BUF_MAX_SIZE]; | ||
uint8_t *p = buffer; | ||
uint16_t running_delta = 0; | ||
uint16_t packetSize = 0; | ||
|
||
// make coap packet base header | ||
*p = 0x01 << 6; | ||
*p |= (packet.type & 0x03) << 4; | ||
*p++ |= (packet.tokenlen & 0x0F); | ||
*p++ = packet.code; | ||
*p++ = (packet.messageid >> 8); | ||
*p++ = (packet.messageid & 0xFF); | ||
p = buffer + COAP_HEADER_SIZE; | ||
packetSize += 4; | ||
|
||
// make token | ||
if (packet.token != NULL && packet.tokenlen <= 0x0F) { | ||
memcpy(p, packet.token, packet.tokenlen); | ||
p += packet.tokenlen; | ||
packetSize += packet.tokenlen; | ||
} | ||
|
||
// make option header | ||
for (int i = 0; i < packet.optionnum; i++) { | ||
uint32_t optdelta; | ||
uint8_t len, delta; | ||
|
||
if (packetSize + 5 + packet.options[i].length >= BUF_MAX_SIZE) { | ||
return 0; | ||
} | ||
optdelta = packet.options[i].number - running_delta; | ||
COAP_OPTION_DELTA(optdelta, &delta); | ||
COAP_OPTION_DELTA((uint32_t)packet.options[i].length, &len); | ||
|
||
*p++ = (0xFF & (delta << 4 | len)); | ||
if (delta == 13) { | ||
*p++ = (optdelta - 13); | ||
packetSize++; | ||
} else if (delta == 14) { | ||
*p++ = ((optdelta - 269) >> 8); | ||
*p++ = (0xFF & (optdelta - 269)); | ||
packetSize+=2; | ||
} if (len == 13) { | ||
*p++ = (packet.options[i].length - 13); | ||
packetSize++; | ||
} else if (len == 14) { | ||
*p++ = (packet.options[i].length >> 8); | ||
*p++ = (0xFF & (packet.options[i].length - 269)); | ||
packetSize+=2; | ||
} | ||
|
||
memcpy(p, packet.options[i].buffer, packet.options[i].length); | ||
p += packet.options[i].length; | ||
packetSize += packet.options[i].length + 1; | ||
running_delta = packet.options[i].number; | ||
} | ||
|
||
// make payload | ||
if (packet.payloadlen > 0) { | ||
if ((packetSize + 1 + packet.payloadlen) >= BUF_MAX_SIZE) { | ||
return 0; | ||
} | ||
*p++ = 0xFF; | ||
memcpy(p, packet.payload, packet.payloadlen); | ||
packetSize += 1 + packet.payloadlen; | ||
} | ||
|
||
_udp->beginPacket(ip, port); | ||
_udp->write(buffer, packetSize); | ||
_udp->endPacket(); | ||
|
||
return packet.messageid; | ||
} | ||
|
||
uint16_t Coap::get(IPAddress ip, int port, char *url) { | ||
return this->send(ip, port, url, COAP_CON, COAP_GET, NULL, 0, NULL, 0); | ||
} | ||
|
||
uint16_t Coap::put(IPAddress ip, int port, char *url, char *payload) { | ||
return this->send(ip, port, url, COAP_CON, COAP_PUT, NULL, 0, (uint8_t *)payload, strlen(payload)); | ||
} | ||
|
||
uint16_t Coap::put(IPAddress ip, int port, char *url, char *payload, int payloadlen) { | ||
return this->send(ip, port, url, COAP_CON, COAP_PUT, NULL, 0, (uint8_t *)payload, payloadlen); | ||
} | ||
|
||
uint16_t Coap::send(IPAddress ip, int port, char *url, COAP_TYPE type, COAP_METHOD method, uint8_t *token, uint8_t tokenlen, uint8_t *payload, uint32_t payloadlen) { | ||
|
||
// make packet | ||
CoapPacket packet; | ||
|
||
packet.type = type; | ||
packet.code = method; | ||
packet.token = token; | ||
packet.tokenlen = tokenlen; | ||
packet.payload = payload; | ||
packet.payloadlen = payloadlen; | ||
packet.optionnum = 0; | ||
packet.messageid = rand(); | ||
|
||
// if more options? | ||
packet.options[packet.optionnum].buffer = (uint8_t *)url; | ||
packet.options[packet.optionnum].length = strlen(url); | ||
packet.options[packet.optionnum].number = COAP_URI_PATH; | ||
packet.optionnum++; | ||
|
||
// send packet | ||
return this->sendPacket(packet, ip, port); | ||
} | ||
|
||
int Coap::parseOption(CoapOption *option, uint16_t *running_delta, uint8_t **buf, size_t buflen) { | ||
uint8_t *p = *buf; | ||
uint8_t headlen = 1; | ||
uint16_t len, delta; | ||
|
||
if (buflen < headlen) return -1; | ||
|
||
delta = (p[0] & 0xF0) >> 4; | ||
len = p[0] & 0x0F; | ||
|
||
if (delta == 13) { | ||
headlen++; | ||
if (buflen < headlen) return -1; | ||
delta = p[1] + 13; | ||
p++; | ||
} else if (delta == 14) { | ||
headlen += 2; | ||
if (buflen < headlen) return -1; | ||
delta = ((p[1] << 8) | p[2]) + 269; | ||
p+=2; | ||
} else if (delta == 15) return -1; | ||
|
||
if (len == 13) { | ||
headlen++; | ||
if (buflen < headlen) return -1; | ||
len = p[1] + 13; | ||
p++; | ||
} else if (len == 14) { | ||
headlen += 2; | ||
if (buflen < headlen) return -1; | ||
len = ((p[1] << 8) | p[2]) + 269; | ||
p+=2; | ||
} else if (len == 15) | ||
return -1; | ||
|
||
if ((p + 1 + len) > (*buf + buflen)) return -1; | ||
option->number = delta + *running_delta; | ||
option->buffer = p+1; | ||
option->length = len; | ||
*buf = p + 1 + len; | ||
*running_delta += delta; | ||
|
||
return 0; | ||
} | ||
|
||
bool Coap::loop() { | ||
|
||
uint8_t buffer[BUF_MAX_SIZE]; | ||
int32_t packetlen = _udp->parsePacket(); | ||
|
||
while (packetlen > 0) { | ||
packetlen = _udp->read(buffer, packetlen >= BUF_MAX_SIZE ? BUF_MAX_SIZE : packetlen); | ||
|
||
CoapPacket packet; | ||
|
||
// parse coap packet header | ||
if (packetlen < COAP_HEADER_SIZE || (((buffer[0] & 0xC0) >> 6) != 1)) { | ||
packetlen = _udp->parsePacket(); | ||
continue; | ||
} | ||
|
||
packet.type = (buffer[0] & 0x30) >> 4; | ||
packet.tokenlen = buffer[0] & 0x0F; | ||
packet.code = buffer[1]; | ||
packet.messageid = 0xFF00 & (buffer[2] << 8); | ||
packet.messageid |= 0x00FF & buffer[3]; | ||
|
||
if (packet.tokenlen == 0) packet.token = NULL; | ||
else if (packet.tokenlen <= 8) packet.token = buffer + 4; | ||
else { | ||
packetlen = _udp->parsePacket(); | ||
continue; | ||
} | ||
|
||
// parse packet options/payload | ||
if (COAP_HEADER_SIZE + packet.tokenlen < packetlen) { | ||
int optionIndex = 0; | ||
uint16_t delta = 0; | ||
uint8_t *end = buffer + packetlen; | ||
uint8_t *p = buffer + COAP_HEADER_SIZE + packet.tokenlen; | ||
while(optionIndex < MAX_OPTION_NUM && *p != 0xFF && p < end) { | ||
packet.options[optionIndex]; | ||
if (0 != parseOption(&packet.options[optionIndex], &delta, &p, end-p)) | ||
return false; | ||
optionIndex++; | ||
} | ||
packet.optionnum = optionIndex; | ||
|
||
if (p+1 < end && *p == 0xFF) { | ||
packet.payload = p+1; | ||
packet.payloadlen = end-(p+1); | ||
} else { | ||
packet.payload = NULL; | ||
packet.payloadlen= 0; | ||
} | ||
} | ||
|
||
if (packet.type == COAP_ACK) { | ||
// call response function | ||
resp(packet, _udp->remoteIP(), _udp->remotePort()); | ||
|
||
} else if (packet.type == COAP_CON) { | ||
// call endpoint url function | ||
for (int i = 0; i < packet.optionnum; i++) { | ||
if (packet.options[i].number == COAP_URI_PATH && packet.options[i].length > 0) { | ||
char urlname[packet.options[i].length + 1]; | ||
memcpy(urlname, packet.options[i].buffer, packet.options[i].length); | ||
urlname[packet.options[i].length] = NULL; | ||
String url = urlname; | ||
#if defined(ARDUINO) | ||
if (!uri.find(url)) { | ||
#elif defined(SPARK) | ||
if (uri.find(url) == uri.end()) { | ||
#endif | ||
sendResponse(_udp->remoteIP(), _udp->remotePort(), packet.messageid, NULL, 0, | ||
COAP_NOT_FOUNT, COAP_NONE, NULL, 0); | ||
} else { | ||
#if defined(ARDUINO) | ||
uri.find(url)(packet, _udp->remoteIP(), _udp->remotePort()); | ||
#elif defined(SPARK) | ||
uri[url](packet, _udp->remoteIP(), _udp->remotePort()); | ||
#endif | ||
} | ||
} | ||
} | ||
} | ||
|
||
// next packet | ||
packetlen = _udp->parsePacket(); | ||
} | ||
|
||
return true; | ||
} | ||
|
||
uint16_t Coap::sendResponse(IPAddress ip, int port, uint16_t messageid) { | ||
this->sendResponse(ip, port, messageid, NULL, 0, COAP_CONTENT, COAP_TEXT_PLAIN, NULL, 0); | ||
} | ||
|
||
uint16_t Coap::sendResponse(IPAddress ip, int port, uint16_t messageid, char *payload) { | ||
this->sendResponse(ip, port, messageid, payload, strlen(payload), COAP_CONTENT, COAP_TEXT_PLAIN, NULL, 0); | ||
} | ||
|
||
uint16_t Coap::sendResponse(IPAddress ip, int port, uint16_t messageid, char *payload, int payloadlen) { | ||
this->sendResponse(ip, port, messageid, payload, payloadlen, COAP_CONTENT, COAP_TEXT_PLAIN, NULL, 0); | ||
} | ||
|
||
|
||
uint16_t Coap::sendResponse(IPAddress ip, int port, uint16_t messageid, char *payload, int payloadlen, | ||
COAP_RESPONSE_CODE code, COAP_CONTENT_TYPE type, uint8_t *token, int tokenlen) { | ||
// make packet | ||
CoapPacket packet; | ||
|
||
packet.type = COAP_ACK; | ||
packet.code = code; | ||
packet.token = token; | ||
packet.tokenlen = tokenlen; | ||
packet.payload = (uint8_t *)payload; | ||
packet.payloadlen = payloadlen; | ||
packet.optionnum = 0; | ||
packet.messageid = messageid; | ||
|
||
// if more options? | ||
char optionBuffer[2]; | ||
optionBuffer[0] = ((uint16_t)type & 0xFF00) >> 8; | ||
optionBuffer[1] = ((uint16_t)type & 0x00FF) ; | ||
packet.options[packet.optionnum].buffer = (uint8_t *)optionBuffer; | ||
packet.options[packet.optionnum].length = 2; | ||
packet.options[packet.optionnum].number = COAP_CONTENT_FORMAT; | ||
packet.optionnum++; | ||
|
||
return this->sendPacket(packet, ip, port); | ||
} | ||
|
Oops, something went wrong.