blob: b9ab6fbcc9b6a70f2b67b532c3c3f264fd53c4d1 [file] [log] [blame]
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2000-2020 Ericsson Telecom AB
//
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v2.0
// which accompanies this distribution, and is available at
// https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
///////////////////////////////////////////////////////////////////////////////
// File: LightweightM2M_CoAP_Binding.ttcn
// Description:
// Rev: R1A
// Prodnr: LPA 108 661
// Updated: 2020-03-04
// Contact: http://ttcn.ericsson.se
///////////////////////////////////////////////////////////////////////////////
module LightweightM2M_CoAP_Binding {
import from LightweightM2M_Types all;
import from CoAP_Types all;
import from LWM2M_TLV_EncDec all;
import from LWM2M_JSON_EncDec all;
import from LWM2M_Opaque_EncDec all;
import from LWM2M_Plain_EncDec all;
modulepar integer tsp_LightweightM2M_CoAP_Binding_defaultContentFormat := 11543;
function f_enc_LWM2M_to_COAP(in LWM2M_PDU p_lwm2m, inout CoAP_ReqResp p_coap)
return boolean
{
@try
{
if (ischosen(p_lwm2m.Register))
{
p_coap := valueof(t_coap_base(METHOD_POST, CONFIRMABLE));
f_addOption(p_coap, { uri_path := "rd" });
f_addOption(p_coap, { uri_query := "ep=" & p_lwm2m.Register.endpointClientName });
if (ispresent(p_lwm2m.Register.lifetime)) {
f_addOption(p_coap, { uri_query := "lt=" & int2str(p_lwm2m.Register.lifetime) });
}
if (ispresent(p_lwm2m.Register.version)) {
f_addOption(p_coap, { uri_query := "lwm2m=" & p_lwm2m.Register.version });
}
if (ispresent(p_lwm2m.Register.bindingMode)) {
f_addOption(p_coap, { uri_query := "b=" & f_BindingMode2str(p_lwm2m.Register.bindingMode) });
}
if (ispresent(p_lwm2m.Register.smsNumber)) {
f_addOption(p_coap, { uri_query := "sms=" & int2str(p_lwm2m.Register.smsNumber) });
}
if (sizeof(p_lwm2m.Register.objectsAndObjectInstances)>0) {
f_addOption(p_coap, { content_format := 40 });
p_coap.payload := char2oct(f_ObjectPathList2str(p_lwm2m.Register.objectsAndObjectInstances));
}
}
else if (ischosen(p_lwm2m.Update))
{
p_coap := valueof(t_coap_base(METHOD_POST, CONFIRMABLE));
f_addLocation(p_coap, p_lwm2m.Update.location);
if (ispresent(p_lwm2m.Update.lifetime)) {
f_addOption(p_coap, { uri_query := "lt=" & int2str(p_lwm2m.Update.lifetime) });
}
if (ispresent(p_lwm2m.Update.bindingMode)) {
f_addOption(p_coap, { uri_query := "b=" & f_BindingMode2str(p_lwm2m.Update.bindingMode) });
}
if (ispresent(p_lwm2m.Update.smsNumber)) {
f_addOption(p_coap, { uri_query := "sms=" & int2str(p_lwm2m.Update.smsNumber) });
}
if (sizeof(p_lwm2m.Update.objectsAndObjectInstances)>0) {
f_addOption(p_coap, { content_format := 40 });
p_coap.payload := char2oct(f_ObjectPathList2str(p_lwm2m.Update.objectsAndObjectInstances));
}
}
else if (ischosen(p_lwm2m.Deregister))
{
p_coap := valueof(t_coap_base(METHOD_DELETE, CONFIRMABLE));
f_addLocation(p_coap, p_lwm2m.Deregister.location);
}
else if (ischosen(p_lwm2m.Response))
{
p_coap := valueof(t_coap_base(f_int2Code(p_lwm2m.Response.code), ACKNOWLEDGEMENT));
f_addLocation(p_coap, p_lwm2m.Response.location);
if (sizeof(p_lwm2m.Response.resources)>0)
{
if (not ispresent(p_lwm2m.Response.contentFormat)) {
p_lwm2m.Response.contentFormat := tsp_LightweightM2M_CoAP_Binding_defaultContentFormat;
}
f_addContentFormat(p_coap, p_lwm2m.Response.contentFormat);
p_coap.payload := f_enc_LwM2M_Resources(p_lwm2m.Response.resources, p_lwm2m.Response.contentFormat);
}
}
else if (ischosen(p_lwm2m.Notification))
{
p_coap := valueof(t_coap_base(f_int2Code(p_lwm2m.Notification.code), ACKNOWLEDGEMENT));
if (sizeof(p_lwm2m.Notification.resources)>0)
{
if (not ispresent(p_lwm2m.Notification.contentFormat)) {
p_lwm2m.Notification.contentFormat := tsp_LightweightM2M_CoAP_Binding_defaultContentFormat;
}
f_addContentFormat(p_coap, p_lwm2m.Notification.contentFormat);
p_coap.payload := f_enc_LwM2M_Resources(p_lwm2m.Notification.resources, p_lwm2m.Notification.contentFormat);
}
}
else if (ischosen(p_lwm2m.Read_))
{
p_coap := valueof(t_coap_base(METHOD_GET, CONFIRMABLE));
f_addOption(p_coap, { uri_path := int2str(p_lwm2m.Read_.path.objectId) });
f_addOption(p_coap, { uri_path := int2str(p_lwm2m.Read_.path.objectInstanceId) });
f_addOption(p_coap, { uri_path := int2str(p_lwm2m.Read_.path.resourceId) });
for (var integer i:=0; i<sizeof(p_lwm2m.Read_.accept); i:=i+1)
{
f_addOption(p_coap, { accept := p_lwm2m.Read_.accept[i]});
}
}
else if(ischosen(p_lwm2m.Execute))
{
p_coap := valueof(t_coap_base(METHOD_POST, CONFIRMABLE));
p_coap.payload := char2oct(f_ObjectPathList2str({p_lwm2m.Execute.path}));
f_addOption(p_coap, { uri_path := int2str(p_lwm2m.Execute.path.objectId) });
f_addOption(p_coap, { uri_path := int2str(p_lwm2m.Execute.path.objectInstanceId) });
f_addOption(p_coap, { uri_path := int2str(p_lwm2m.Execute.path.resourceId) });
}
else if(ischosen(p_lwm2m.Write))
{
p_coap := valueof(t_coap_base(METHOD_PUT, CONFIRMABLE));
f_addOption(p_coap, { uri_path := int2str(p_lwm2m.Write.path.objectId) });
f_addOption(p_coap, { uri_path := int2str(p_lwm2m.Write.path.objectInstanceId) });
if(ispresent(p_lwm2m.Write.path.resourceId)) {
f_addOption(p_coap, { uri_path := int2str(p_lwm2m.Write.path.resourceId) });
}
if (not ispresent(p_lwm2m.Write.contentFormat)) {
p_lwm2m.Write.contentFormat := tsp_LightweightM2M_CoAP_Binding_defaultContentFormat;
}
f_addContentFormat(p_coap, p_lwm2m.Write.contentFormat);
if (ispresent(p_lwm2m.Write.block1)) {
f_addOption(p_coap, { block1 := p_lwm2m.Write.block1.option });
p_coap.payload := p_lwm2m.Write.block1.content;
}
if (not ispresent(p_lwm2m.Write.block1))
{
p_coap.payload := f_enc_LwM2M_Resources(p_lwm2m.Write.resources, p_lwm2m.Write.contentFormat);
}
}
else if(ischosen(p_lwm2m.Create))
{
p_coap := valueof(t_coap_base(METHOD_POST, CONFIRMABLE));
f_addOption(p_coap, { uri_path := int2str(p_lwm2m.Create.path.objectId) });
f_addContentFormat(p_coap, p_lwm2m.Create.contentFormat);
if(sizeof(p_lwm2m.Create.resources) == 0)
{
p_coap.payload := char2oct("{\"bn\":\"/" & int2str(p_lwm2m.Create.path.objectId) & "\",\"e\":[]}");
}
else
{
p_coap.payload := f_enc_LwM2M_Resources_to_JSON_create(p_lwm2m.Create.resources);
}
}
else if(ischosen(p_lwm2m.Delete) or ischosen(p_lwm2m.BS_Delete))
{
p_coap := valueof(t_coap_base(METHOD_DELETE, CONFIRMABLE));
if(ispresent(p_lwm2m.Delete.path.objectId)){
f_addOption(p_coap, { uri_path := int2str(p_lwm2m.Delete.path.objectId) });
}
if(ispresent(p_lwm2m.Delete.path.objectId)){
f_addOption(p_coap, { uri_path := int2str(p_lwm2m.Delete.path.objectInstanceId) });
}
}
else if(ischosen(p_lwm2m.BS_Request_Finish))
{
p_coap := valueof(t_coap_base(METHOD_POST, CONFIRMABLE));
f_addOption(p_coap, { uri_path := "bs" });
if(p_lwm2m.BS_Request_Finish.isRequest){
f_addOption(p_coap, { uri_query := p_lwm2m.BS_Request_Finish.endpointClientName});
}
}
else if(ischosen(p_lwm2m.BS_Discover))
{
p_coap := valueof(t_coap_base(METHOD_GET, CONFIRMABLE));
if(ispresent(p_lwm2m.BS_Discover.objectId)) {
f_addOption(p_coap, { uri_path := int2str(p_lwm2m.BS_Discover.objectId) });
}
else {
f_addOption(p_coap, { uri_path := "/" });
}
}
else
{
log(%definitionId," Unhandled message type in LWM2M_PDU");
return false;
}
}
@catch(err)
{
return false;
}
return true;
}
function f_dec_COAP_to_LWM2M(in CoAP_ReqResp p_coap, inout LWM2M_PDU p_lwm2m)
return boolean
{
@try
{
if (p_coap.header.code.class > 0)
{
p_lwm2m := c_LWM2M_Response_init;
p_lwm2m.Response.code := f_Code2int(p_coap.header.code);
p_lwm2m.Response.contentFormat := 40;
if (ispresent(p_coap.options)) {
f_fetchLocation(p_coap.options, p_lwm2m.Response.location);
f_fetchContentFormat(p_coap.options, p_lwm2m.Response.contentFormat);
}
if(ispresent(p_coap.payload)) {
f_dec_LwM2M_Resources(p_lwm2m.Response.contentFormat, p_coap.payload, p_lwm2m.Response.resources, p_lwm2m.Response.location);
}
return true;
}
else if (p_coap.header.code == METHOD_GET)
{
p_lwm2m := c_LWM2M_Read_init;
var Location v_loc := {};
f_fetchUriPath(p_coap.options, v_loc);
f_LocationToObjectPath(v_loc, p_lwm2m.Read_.path);
f_fetchAccept(p_coap.options, p_lwm2m.Read_.accept);
var integer p_obs := -1;
if (f_fetchObserve(p_coap.options, p_obs)) {
if (p_obs == 0) {p_lwm2m.Read_.observe := true }
else if (p_obs == 1) { p_lwm2m.Read_.observe := false }
}
return true;
}
else if (p_coap.header.code == METHOD_PUT)
{
p_lwm2m := c_LWM2M_Write_init;
var Location v_loc := {};
f_fetchUriPath(p_coap.options, v_loc);
f_LocationToObjectPath(v_loc, p_lwm2m.Write.path);
f_fetchContentFormat(p_coap.options, p_lwm2m.Write.contentFormat);
if (not f_fetchBlock1(p_coap.options, p_lwm2m.Write.block1.option)) { p_lwm2m.Write.block1 := omit; }
if (not ispresent(p_lwm2m.Write.block1))
{
f_dec_LwM2M_Resources(p_lwm2m.Write.contentFormat, p_coap.payload, p_lwm2m.Write.resources, v_loc);
}
else
{
p_lwm2m.Write.block1.content := p_coap.payload;
}
return true;
}
else if (p_coap.header.code == METHOD_POST)
{
var Location v_loc := {};
f_fetchUriPath(p_coap.options, v_loc);
if (sizeof(v_loc)==3)
{ // Execute
p_lwm2m := c_LWM2M_Execute_init;
f_LocationToObjectPath(v_loc, p_lwm2m.Execute.path);
}
else
{ // Create
p_lwm2m := c_LWM2M_Create_init;
f_LocationToObjectPath(v_loc, p_lwm2m.Create.path);
f_fetchContentFormat(p_coap.options, p_lwm2m.Create.contentFormat);
f_dec_LwM2M_Resources(p_lwm2m.Create.contentFormat, p_coap.payload, p_lwm2m.Create.resources, v_loc);
}
return true;
}
else if (p_coap.header.code == METHOD_DELETE)
{
var Location v_loc := {};
if(ispresent(p_coap.options)){
f_fetchUriPath(p_coap.options, v_loc);
}
p_lwm2m := c_LWM2M_Delete_init;
f_LocationToObjectPath(v_loc, p_lwm2m.Delete.path);
return true;
}
else if (p_coap.header.code == EMPTY_MESSAGE)
{
p_lwm2m := c_LWM2M_Response_init;
return false;
}
else
{
log(%definitionId," Unrecognized lwm2m pdu in coap ", p_coap);
return false;
}
}
@catch(err)
{
return false;
}
return false;
}
function f_dec_BS_COAP_to_LWM2M(in CoAP_ReqResp p_coap, inout LWM2M_PDU p_lwm2m)
return boolean
{
if (p_coap.header.code == METHOD_GET)
{
p_lwm2m := c_LWM2M_BS_Discover_init;
var Location v_loc := {};
f_fetchUriPath(p_coap.options, v_loc);
if(sizeof(v_loc) == 1)
{
p_lwm2m.BS_Discover.objectId := str2int(oct2char(unichar2oct(v_loc[0])));
}
else {
p_lwm2m.BS_Discover.objectId := omit;
}
return true;
}
else if (p_coap.header.code == METHOD_PUT)
{
p_lwm2m := c_LWM2M_Write_init;
var Location v_loc := {};
f_fetchUriPath(p_coap.options, v_loc);
f_LocationToObjectPath(v_loc, p_lwm2m.Write.path);
f_fetchContentFormat(p_coap.options, p_lwm2m.Write.contentFormat);
if(ispresent(p_coap.payload)){
f_dec_LwM2M_Resources(p_lwm2m.Write.contentFormat, p_coap.payload, p_lwm2m.Write.resources, v_loc);
}
return true;
}
else if (p_coap.header.code == METHOD_POST)
{
var URN v_client_name := ""
f_fetchUriQuery(p_coap.options, v_client_name);
if(v_client_name == ""){
p_lwm2m := c_LWM2M_BS_Finish_init;
}
else {
p_lwm2m := c_LWM2M_BS_Request_init;
p_lwm2m.BS_Request_Finish.endpointClientName := v_client_name;
}
return true;
}
else if (p_coap.header.code == METHOD_DELETE)
{
p_lwm2m := c_LWM2M_BS_Delete_init;
var Location v_loc := {};
if(ispresent(p_coap.options)){
f_fetchUriPath(p_coap.options, v_loc);
}
if(sizeof(v_loc) == 1){
p_lwm2m.BS_Delete.objectId := str2int(oct2char(unichar2oct(v_loc[0])));
}
return true;
}
else {
log(%definitionId," Unrecognized lwm2m pdu in coap ", p_coap);
return false;
}
}
function f_enc_LwM2M_Resources(in LwM2M_Resource_List p_res_list, in integer p_contentFormat)
return octetstring
{
if (p_contentFormat == 11543)
{
return f_enc_LwM2M_Resources_to_LwM2M_JSON(p_res_list);
}
else if (p_contentFormat == 110)
{
return f_enc_LwM2M_Resources_to_SenML_JSON(p_res_list);
}
else if (p_contentFormat == 0)
{
return f_enc_LwM2M_Resources_to_Plain(p_res_list);
}
else if (p_contentFormat == 42)
{
return f_enc_LwM2M_Resources_to_Opaque(p_res_list);
}
else
{
if (sizeof(p_res_list)>0)
{
log(%definitionId, " WARNING: Content format unknown for encoding: ", p_contentFormat);
}
}
return ''O
}
function f_dec_LwM2M_Resources(in integer p_contentFormat, in octetstring p_coapPayload, inout LwM2M_Resource_List resources, in Location p_loc)
return boolean
{
// JSON
if (p_contentFormat == 11543)
{
return f_dec_LwM2M_Resources_from_LwM2M_JSON(p_coapPayload, resources);
}
else if (p_contentFormat == 110)
{
return f_dec_LwM2M_Resources_from_SenML_JSON(p_coapPayload, resources);
}
//TLV
else if(p_contentFormat == 11542)
{
return f_LwM2M_TLV_decode(p_coapPayload, p_loc, resources);
}
//Plain
else if (p_contentFormat == 0)
{
return f_dec_LwM2M_Resources_from_Plain(p_coapPayload, resources);
}
//Opaque
else if (p_contentFormat == 42)
{
return f_dec_LwM2M_Resources_from_Opaque(p_coapPayload, resources);
}
else {
log(%definitionId," Unrecognized content format: ", p_contentFormat );
return false;
}
}
function f_ObjectPath2str(ObjectPath p_op)
return charstring
{
var charstring v_ret := "</" & int2str(p_op.objectId);
if (ispresent(p_op.objectInstanceId)) {
v_ret := v_ret & "/" & int2str(p_op.objectInstanceId);
}
if (ispresent(p_op.resourceId)) {
v_ret := v_ret & "/" & int2str(p_op.resourceId);
}
return v_ret & ">";
}
function f_ObjectPathList2str(ObjectPath_List p_ol)
return charstring
{
var charstring v_ret := "";
for (var integer i:=0; i<sizeof(p_ol); i:=i+1)
{
v_ret := v_ret & f_ObjectPath2str(p_ol[i]);
if (i != sizeof(p_ol)-1) { v_ret := v_ret & "," }
}
return v_ret;
}
template charstring specPath := pattern "[0-9]#(1,4)";
function f_LocationToObjectPath(in Location p_location, inout ObjectPath p_path)
{
if(match(oct2char(unichar2oct(p_location[0])), specPath))
{
if (sizeof(p_location) >= 1) { p_path.objectId := str2int(oct2char(unichar2oct(p_location[0]))); }
else { p_path.objectId := -1 }
if (sizeof(p_location) >= 2) { p_path.objectInstanceId := str2int(oct2char(unichar2oct(p_location[1]))); }
else { p_path.objectInstanceId := omit }
if (sizeof(p_location) >= 3) { p_path.resourceId := str2int(oct2char(unichar2oct(p_location[2]))); }
else { p_path.resourceId := omit }
}
else
{
p_path := {-1, omit, omit}
}
}
function f_BindingMode2str(BindingMode p_b)
return charstring
{
if (p_b == U) {
return "U";
}
else if (p_b == UQ) {
return "UQ";
}
else if (p_b == S) {
return "S";
}
else if (p_b == SQ) {
return "SQ";
}
else if (p_b == US) {
return "US";
}
else if (p_b == UQS) {
return "UQS";
}
else {
log(%definitionId," Unrecognized binding mode: ", p_b)
return "";
}
return "";
}
function f_addLocation(inout CoAP_ReqResp p_coap, in Location p_location)
{
for (var integer i:=0; i<sizeof(p_location); i:=i+1)
{
f_addOption(p_coap, { uri_path := p_location[i] } );
}
}
function f_addContentFormat(inout CoAP_ReqResp p_coap, in integer p_cf)
{
f_addOption(p_coap, { content_format := p_cf } );
}
function f_addOption(inout CoAP_ReqResp p_coap, in CoAP_Options p_option)
{
if (not ispresent(p_coap.options)) { p_coap.options := {} }
p_coap.options[sizeof(p_coap.options)] := p_option;
}
function f_Code2int(in Code p_code)
return integer
{
return p_code.class*100+p_code.detail;
}
function f_int2Code(in integer p_code)
return Code
{
var Code v_ret;
v_ret.class := p_code/100;
v_ret.detail := p_code rem 100;
return v_ret;
}
function f_fetchLocation(in CoAP_OptionsList p_options, inout Location p_location)
{
for (var integer i:=0; i<sizeof(p_options); i:=i+1) {
if (ischosen(p_options[i].location_path)) {
p_location[sizeof(p_location)] := p_options[i].location_path;
}
}
}
function f_fetchUriPath(in CoAP_OptionsList p_options, inout Location p_location)
{
for (var integer i:=0; i<sizeof(p_options); i:=i+1) {
if (ischosen(p_options[i].uri_path)) {
p_location[sizeof(p_location)] := p_options[i].uri_path;
}
}
}
function f_fetchAccept(in CoAP_OptionsList p_options, inout Integer_List p_accept)
{
for (var integer i:=0; i<sizeof(p_options); i:=i+1) {
if (ischosen(p_options[i].accept)) {
p_accept[sizeof(p_accept)] := p_options[i].accept;
}
}
}
function f_fetchObserve(in CoAP_OptionsList p_options, inout integer p_observe)
return boolean
{
for (var integer i:=0; i<sizeof(p_options); i:=i+1) {
if (ischosen(p_options[i].observe)) {
p_observe := p_options[i].observe;
return true;
}
}
return false;
}
function f_fetchBlock1(in CoAP_OptionsList p_options, inout BlockOption p_block1)
return boolean
{
for (var integer i:=0; i<sizeof(p_options); i:=i+1) {
if (ischosen(p_options[i].block1)) {
p_block1 := p_options[i].block1;
return true;
}
}
return false;
}
function f_fetchContentFormat(in CoAP_OptionsList p_options, inout integer p_cf)
{
for (var integer i:=0; i<sizeof(p_options); i:=i+1) {
if (ischosen(p_options[i].content_format)) {
p_cf := p_options[i].content_format;
}
}
}
function f_fetchUriQuery(in CoAP_OptionsList p_options, inout URN p_client_name)
{
for (var integer i:=0; i<sizeof(p_options); i:=i+1) {
if (ischosen(p_options[i].uri_query)) {
p_client_name := p_options[i].uri_query;
}
}
}
template CoAP_ReqResp t_coap_base(Code p_code, Type p_type) :=
{
header :=
{
version := 1,
msg_type := p_type,
code := p_code,
message_id := 0
},
token := ''O,
options := {},
payload := omit
}
}