Donald Meyers / Mbed OS evan
Committer:
djmeyers
Date:
Sat Mar 18 22:37:16 2017 +0000
Revision:
0:06ee5f8a484a
Initial commit

Who changed what in which revision?

UserRevisionLine numberNew contents of line
djmeyers 0:06ee5f8a484a 1 /*
djmeyers 0:06ee5f8a484a 2 * Copyright (c) 2015 ARM Limited. All rights reserved.
djmeyers 0:06ee5f8a484a 3 * SPDX-License-Identifier: Apache-2.0
djmeyers 0:06ee5f8a484a 4 * Licensed under the Apache License, Version 2.0 (the License); you may
djmeyers 0:06ee5f8a484a 5 * not use this file except in compliance with the License.
djmeyers 0:06ee5f8a484a 6 * You may obtain a copy of the License at
djmeyers 0:06ee5f8a484a 7 *
djmeyers 0:06ee5f8a484a 8 * http://www.apache.org/licenses/LICENSE-2.0
djmeyers 0:06ee5f8a484a 9 *
djmeyers 0:06ee5f8a484a 10 * Unless required by applicable law or agreed to in writing, software
djmeyers 0:06ee5f8a484a 11 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
djmeyers 0:06ee5f8a484a 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
djmeyers 0:06ee5f8a484a 13 * See the License for the specific language governing permissions and
djmeyers 0:06ee5f8a484a 14 * limitations under the License.
djmeyers 0:06ee5f8a484a 15 */
djmeyers 0:06ee5f8a484a 16 #include <stdlib.h>
djmeyers 0:06ee5f8a484a 17 #include "mbed-client/m2mresource.h"
djmeyers 0:06ee5f8a484a 18 #include "mbed-client/m2mconstants.h"
djmeyers 0:06ee5f8a484a 19 #include "mbed-client/m2mobservationhandler.h"
djmeyers 0:06ee5f8a484a 20 #include "mbed-client/m2mobject.h"
djmeyers 0:06ee5f8a484a 21 #include "mbed-client/m2mobjectinstance.h"
djmeyers 0:06ee5f8a484a 22 #include "include/m2mreporthandler.h"
djmeyers 0:06ee5f8a484a 23 #include "include/nsdllinker.h"
djmeyers 0:06ee5f8a484a 24 #include "mbed-client/m2mblockmessage.h"
djmeyers 0:06ee5f8a484a 25 #include "mbed-trace/mbed_trace.h"
djmeyers 0:06ee5f8a484a 26
djmeyers 0:06ee5f8a484a 27 #define TRACE_GROUP "mClt"
djmeyers 0:06ee5f8a484a 28
djmeyers 0:06ee5f8a484a 29 M2MResourceInstance::M2MResourceInstance(M2MResource &parent,
djmeyers 0:06ee5f8a484a 30 const String &res_name,
djmeyers 0:06ee5f8a484a 31 const String &resource_type,
djmeyers 0:06ee5f8a484a 32 M2MResourceInstance::ResourceType type,
djmeyers 0:06ee5f8a484a 33 const uint16_t object_instance_id,
djmeyers 0:06ee5f8a484a 34 char* path,
djmeyers 0:06ee5f8a484a 35 bool external_blockwise_store)
djmeyers 0:06ee5f8a484a 36 : M2MBase(res_name,
djmeyers 0:06ee5f8a484a 37 M2MBase::Dynamic,
djmeyers 0:06ee5f8a484a 38 resource_type,
djmeyers 0:06ee5f8a484a 39 path,
djmeyers 0:06ee5f8a484a 40 external_blockwise_store),
djmeyers 0:06ee5f8a484a 41 _parent_resource(parent),
djmeyers 0:06ee5f8a484a 42 _value(NULL),
djmeyers 0:06ee5f8a484a 43 _value_length(0),
djmeyers 0:06ee5f8a484a 44 _block_message_data(NULL),
djmeyers 0:06ee5f8a484a 45 _execute_callback(NULL),
djmeyers 0:06ee5f8a484a 46 _resource_callback(NULL),
djmeyers 0:06ee5f8a484a 47 _execute_function_pointer(NULL),
djmeyers 0:06ee5f8a484a 48 _notification_sent_function_pointer(NULL),
djmeyers 0:06ee5f8a484a 49 _incoming_block_message_cb(NULL),
djmeyers 0:06ee5f8a484a 50 _outgoing_block_message_cb(NULL),
djmeyers 0:06ee5f8a484a 51 _notification_sent_callback(NULL),
djmeyers 0:06ee5f8a484a 52 _object_instance_id(object_instance_id),
djmeyers 0:06ee5f8a484a 53 _resource_type(type)
djmeyers 0:06ee5f8a484a 54 {
djmeyers 0:06ee5f8a484a 55 M2MBase::set_base_type(M2MBase::ResourceInstance);
djmeyers 0:06ee5f8a484a 56 }
djmeyers 0:06ee5f8a484a 57
djmeyers 0:06ee5f8a484a 58 M2MResourceInstance::M2MResourceInstance(M2MResource &parent,
djmeyers 0:06ee5f8a484a 59 const String &res_name,
djmeyers 0:06ee5f8a484a 60 const String &resource_type,
djmeyers 0:06ee5f8a484a 61 M2MResourceInstance::ResourceType type,
djmeyers 0:06ee5f8a484a 62 const uint8_t *value,
djmeyers 0:06ee5f8a484a 63 const uint8_t value_length,
djmeyers 0:06ee5f8a484a 64 const uint16_t object_instance_id,
djmeyers 0:06ee5f8a484a 65 char* path,
djmeyers 0:06ee5f8a484a 66 bool external_blockwise_store)
djmeyers 0:06ee5f8a484a 67 : M2MBase(res_name,
djmeyers 0:06ee5f8a484a 68 M2MBase::Static,
djmeyers 0:06ee5f8a484a 69 resource_type,
djmeyers 0:06ee5f8a484a 70 path,
djmeyers 0:06ee5f8a484a 71 external_blockwise_store),
djmeyers 0:06ee5f8a484a 72 _parent_resource(parent),
djmeyers 0:06ee5f8a484a 73 _value(NULL),
djmeyers 0:06ee5f8a484a 74 _value_length(0),
djmeyers 0:06ee5f8a484a 75 _block_message_data(NULL),
djmeyers 0:06ee5f8a484a 76 _execute_callback(NULL),
djmeyers 0:06ee5f8a484a 77 _resource_callback(NULL),
djmeyers 0:06ee5f8a484a 78 _execute_function_pointer(NULL),
djmeyers 0:06ee5f8a484a 79 _notification_sent_function_pointer(NULL),
djmeyers 0:06ee5f8a484a 80 _incoming_block_message_cb(NULL),
djmeyers 0:06ee5f8a484a 81 _outgoing_block_message_cb(NULL),
djmeyers 0:06ee5f8a484a 82 _notification_sent_callback(NULL),
djmeyers 0:06ee5f8a484a 83 _object_instance_id(object_instance_id),
djmeyers 0:06ee5f8a484a 84 _resource_type(type)
djmeyers 0:06ee5f8a484a 85 {
djmeyers 0:06ee5f8a484a 86 M2MBase::set_base_type(M2MBase::Resource);
djmeyers 0:06ee5f8a484a 87 if (mode() == M2MBase::Dynamic) {
djmeyers 0:06ee5f8a484a 88 if( value != NULL && value_length > 0 ) {
djmeyers 0:06ee5f8a484a 89 _value = alloc_string_copy(value, value_length);
djmeyers 0:06ee5f8a484a 90 if(_value) {
djmeyers 0:06ee5f8a484a 91 _value_length = value_length;
djmeyers 0:06ee5f8a484a 92 }
djmeyers 0:06ee5f8a484a 93 }
djmeyers 0:06ee5f8a484a 94 }
djmeyers 0:06ee5f8a484a 95 // Copy resource value to struct since static resources are handled in mbed-client-c
djmeyers 0:06ee5f8a484a 96 else if (mode() == M2MBase::Static) {
djmeyers 0:06ee5f8a484a 97 sn_nsdl_dynamic_resource_parameters_s* res = get_nsdl_resource();
djmeyers 0:06ee5f8a484a 98 sn_nsdl_static_resource_parameters_s* params = (sn_nsdl_static_resource_parameters_s*)res->static_resource_parameters;
djmeyers 0:06ee5f8a484a 99 params->resource = alloc_string_copy(value, value_length);
djmeyers 0:06ee5f8a484a 100 params->resourcelen = value_length;
djmeyers 0:06ee5f8a484a 101 }
djmeyers 0:06ee5f8a484a 102 else {
djmeyers 0:06ee5f8a484a 103 // Directory, not supported
djmeyers 0:06ee5f8a484a 104 }
djmeyers 0:06ee5f8a484a 105 }
djmeyers 0:06ee5f8a484a 106
djmeyers 0:06ee5f8a484a 107 M2MResourceInstance::M2MResourceInstance(M2MResource &parent,
djmeyers 0:06ee5f8a484a 108 const lwm2m_parameters_s* s,
djmeyers 0:06ee5f8a484a 109 M2MResourceInstance::ResourceType type,
djmeyers 0:06ee5f8a484a 110 const uint16_t object_instance_id)
djmeyers 0:06ee5f8a484a 111 : M2MBase(s),
djmeyers 0:06ee5f8a484a 112 _parent_resource(parent),
djmeyers 0:06ee5f8a484a 113 _value(NULL),
djmeyers 0:06ee5f8a484a 114 _value_length(0),
djmeyers 0:06ee5f8a484a 115 _block_message_data(NULL),
djmeyers 0:06ee5f8a484a 116 _execute_callback(NULL),
djmeyers 0:06ee5f8a484a 117 _resource_callback(NULL),
djmeyers 0:06ee5f8a484a 118 _execute_function_pointer(NULL),
djmeyers 0:06ee5f8a484a 119 _notification_sent_function_pointer(NULL),
djmeyers 0:06ee5f8a484a 120 _incoming_block_message_cb(NULL),
djmeyers 0:06ee5f8a484a 121 _outgoing_block_message_cb(NULL),
djmeyers 0:06ee5f8a484a 122 _notification_sent_callback(NULL),
djmeyers 0:06ee5f8a484a 123 _object_instance_id(object_instance_id),
djmeyers 0:06ee5f8a484a 124 _resource_type(type)
djmeyers 0:06ee5f8a484a 125 {
djmeyers 0:06ee5f8a484a 126 //TBD: put to flash, or parse from the uri_path!!!!
djmeyers 0:06ee5f8a484a 127 //same for the _object_instance_id.
djmeyers 0:06ee5f8a484a 128 // TBD: we dont need _value here, because in c-struct there is resource field!!!!
djmeyers 0:06ee5f8a484a 129 if( s->dynamic_resource_params->static_resource_parameters->resource != NULL &&
djmeyers 0:06ee5f8a484a 130 s->dynamic_resource_params->static_resource_parameters->resourcelen > 0 ) {
djmeyers 0:06ee5f8a484a 131 _value = alloc_string_copy(s->dynamic_resource_params->static_resource_parameters->resource,
djmeyers 0:06ee5f8a484a 132 s->dynamic_resource_params->static_resource_parameters->resourcelen);
djmeyers 0:06ee5f8a484a 133 if(_value) {
djmeyers 0:06ee5f8a484a 134 _value_length = s->dynamic_resource_params->static_resource_parameters->resourcelen;
djmeyers 0:06ee5f8a484a 135 }
djmeyers 0:06ee5f8a484a 136 }
djmeyers 0:06ee5f8a484a 137 //M2MBase::set_base_type(M2MBase::ResourceInstance);
djmeyers 0:06ee5f8a484a 138 }
djmeyers 0:06ee5f8a484a 139
djmeyers 0:06ee5f8a484a 140 M2MResourceInstance::~M2MResourceInstance()
djmeyers 0:06ee5f8a484a 141 {
djmeyers 0:06ee5f8a484a 142 free(_value);
djmeyers 0:06ee5f8a484a 143 delete _execute_function_pointer;
djmeyers 0:06ee5f8a484a 144 delete _execute_callback;
djmeyers 0:06ee5f8a484a 145 delete _notification_sent_function_pointer;
djmeyers 0:06ee5f8a484a 146 delete _incoming_block_message_cb;
djmeyers 0:06ee5f8a484a 147 delete _outgoing_block_message_cb;
djmeyers 0:06ee5f8a484a 148 delete _notification_sent_callback;
djmeyers 0:06ee5f8a484a 149 delete _block_message_data;
djmeyers 0:06ee5f8a484a 150 }
djmeyers 0:06ee5f8a484a 151
djmeyers 0:06ee5f8a484a 152 M2MBase::BaseType M2MResourceInstance::base_type() const
djmeyers 0:06ee5f8a484a 153 {
djmeyers 0:06ee5f8a484a 154 return M2MBase::base_type();
djmeyers 0:06ee5f8a484a 155 }
djmeyers 0:06ee5f8a484a 156
djmeyers 0:06ee5f8a484a 157 M2MResourceInstance::ResourceType M2MResourceInstance::resource_instance_type() const
djmeyers 0:06ee5f8a484a 158 {
djmeyers 0:06ee5f8a484a 159 return _resource_type;
djmeyers 0:06ee5f8a484a 160 }
djmeyers 0:06ee5f8a484a 161
djmeyers 0:06ee5f8a484a 162 bool M2MResourceInstance::handle_observation_attribute(const char *query)
djmeyers 0:06ee5f8a484a 163 {
djmeyers 0:06ee5f8a484a 164 tr_debug("M2MResourceInstance::handle_observation_attribute - is_under_observation(%d)", is_under_observation());
djmeyers 0:06ee5f8a484a 165 bool success = false;
djmeyers 0:06ee5f8a484a 166
djmeyers 0:06ee5f8a484a 167 M2MReportHandler *handler = M2MBase::report_handler();
djmeyers 0:06ee5f8a484a 168 if (!handler) {
djmeyers 0:06ee5f8a484a 169 handler = M2MBase::create_report_handler();
djmeyers 0:06ee5f8a484a 170 }
djmeyers 0:06ee5f8a484a 171
djmeyers 0:06ee5f8a484a 172 if (handler) {
djmeyers 0:06ee5f8a484a 173 success = handler->parse_notification_attribute(query,
djmeyers 0:06ee5f8a484a 174 M2MBase::base_type(), _resource_type);
djmeyers 0:06ee5f8a484a 175 if(success) {
djmeyers 0:06ee5f8a484a 176 if (is_under_observation()) {
djmeyers 0:06ee5f8a484a 177 handler->set_under_observation(true);
djmeyers 0:06ee5f8a484a 178 }
djmeyers 0:06ee5f8a484a 179 } else {
djmeyers 0:06ee5f8a484a 180 handler->set_default_values();
djmeyers 0:06ee5f8a484a 181 }
djmeyers 0:06ee5f8a484a 182 }
djmeyers 0:06ee5f8a484a 183 return success;
djmeyers 0:06ee5f8a484a 184 }
djmeyers 0:06ee5f8a484a 185
djmeyers 0:06ee5f8a484a 186 void M2MResourceInstance::set_execute_function(execute_callback callback)
djmeyers 0:06ee5f8a484a 187 {
djmeyers 0:06ee5f8a484a 188 delete _execute_callback;
djmeyers 0:06ee5f8a484a 189 _execute_callback = new execute_callback(callback);
djmeyers 0:06ee5f8a484a 190 }
djmeyers 0:06ee5f8a484a 191
djmeyers 0:06ee5f8a484a 192 void M2MResourceInstance::set_execute_function(execute_callback_2 callback)
djmeyers 0:06ee5f8a484a 193 {
djmeyers 0:06ee5f8a484a 194 delete _execute_function_pointer;
djmeyers 0:06ee5f8a484a 195
djmeyers 0:06ee5f8a484a 196 _execute_function_pointer = new FP1<void, void*>(callback);
djmeyers 0:06ee5f8a484a 197 set_execute_function(execute_callback(_execute_function_pointer, &FP1<void, void*>::call));
djmeyers 0:06ee5f8a484a 198 }
djmeyers 0:06ee5f8a484a 199
djmeyers 0:06ee5f8a484a 200 void M2MResourceInstance::clear_value()
djmeyers 0:06ee5f8a484a 201 {
djmeyers 0:06ee5f8a484a 202 tr_debug("M2MResourceInstance::clear_value");
djmeyers 0:06ee5f8a484a 203
djmeyers 0:06ee5f8a484a 204 free(_value);
djmeyers 0:06ee5f8a484a 205 _value = NULL;
djmeyers 0:06ee5f8a484a 206 _value_length = 0;
djmeyers 0:06ee5f8a484a 207
djmeyers 0:06ee5f8a484a 208 report();
djmeyers 0:06ee5f8a484a 209 }
djmeyers 0:06ee5f8a484a 210
djmeyers 0:06ee5f8a484a 211 bool M2MResourceInstance::set_value(int64_t value)
djmeyers 0:06ee5f8a484a 212 {
djmeyers 0:06ee5f8a484a 213 bool success;
djmeyers 0:06ee5f8a484a 214 // max len of "-9223372036854775808" plus zero termination
djmeyers 0:06ee5f8a484a 215 char buffer[20+1];
djmeyers 0:06ee5f8a484a 216 uint32_t size = m2m::itoa_c(value, buffer);
djmeyers 0:06ee5f8a484a 217
djmeyers 0:06ee5f8a484a 218 success = set_value((const uint8_t*)buffer, size);
djmeyers 0:06ee5f8a484a 219
djmeyers 0:06ee5f8a484a 220 return success;
djmeyers 0:06ee5f8a484a 221 }
djmeyers 0:06ee5f8a484a 222
djmeyers 0:06ee5f8a484a 223 bool M2MResourceInstance::set_value(const uint8_t *value,
djmeyers 0:06ee5f8a484a 224 const uint32_t value_length)
djmeyers 0:06ee5f8a484a 225 {
djmeyers 0:06ee5f8a484a 226 tr_debug("M2MResourceInstance::set_value()");
djmeyers 0:06ee5f8a484a 227 bool success = false;
djmeyers 0:06ee5f8a484a 228 bool value_changed = false;
djmeyers 0:06ee5f8a484a 229 if(is_value_changed(value,value_length)) {
djmeyers 0:06ee5f8a484a 230 value_changed = true;
djmeyers 0:06ee5f8a484a 231 }
djmeyers 0:06ee5f8a484a 232 if( value != NULL && value_length > 0 ) {
djmeyers 0:06ee5f8a484a 233 success = true;
djmeyers 0:06ee5f8a484a 234
djmeyers 0:06ee5f8a484a 235 free(_value);
djmeyers 0:06ee5f8a484a 236 _value_length = 0;
djmeyers 0:06ee5f8a484a 237
djmeyers 0:06ee5f8a484a 238 _value = alloc_string_copy(value, value_length);
djmeyers 0:06ee5f8a484a 239 if(_value) {
djmeyers 0:06ee5f8a484a 240 _value_length = value_length;
djmeyers 0:06ee5f8a484a 241 if( value_changed ) { //
djmeyers 0:06ee5f8a484a 242 if (_resource_type == M2MResourceInstance::STRING) {
djmeyers 0:06ee5f8a484a 243 M2MReportHandler *report_handler = M2MBase::report_handler();
djmeyers 0:06ee5f8a484a 244 if(report_handler && is_under_observation()) {
djmeyers 0:06ee5f8a484a 245 report_handler->set_notification_trigger();
djmeyers 0:06ee5f8a484a 246 }
djmeyers 0:06ee5f8a484a 247 }
djmeyers 0:06ee5f8a484a 248 else {
djmeyers 0:06ee5f8a484a 249 report();
djmeyers 0:06ee5f8a484a 250 }
djmeyers 0:06ee5f8a484a 251 }
djmeyers 0:06ee5f8a484a 252 }
djmeyers 0:06ee5f8a484a 253 }
djmeyers 0:06ee5f8a484a 254 return success;
djmeyers 0:06ee5f8a484a 255 }
djmeyers 0:06ee5f8a484a 256
djmeyers 0:06ee5f8a484a 257 void M2MResourceInstance::report()
djmeyers 0:06ee5f8a484a 258 {
djmeyers 0:06ee5f8a484a 259 tr_debug("M2MResourceInstance::report()");
djmeyers 0:06ee5f8a484a 260 M2MBase::Observation observation_level = M2MBase::observation_level();
djmeyers 0:06ee5f8a484a 261 tr_debug("M2MResourceInstance::report() - level %d", observation_level);
djmeyers 0:06ee5f8a484a 262 if((M2MBase::O_Attribute & observation_level) == M2MBase::O_Attribute ||
djmeyers 0:06ee5f8a484a 263 (M2MBase::OI_Attribute & observation_level) == M2MBase::OI_Attribute) {
djmeyers 0:06ee5f8a484a 264 tr_debug("M2MResourceInstance::report() -- object/instance level");
djmeyers 0:06ee5f8a484a 265 M2MObjectInstance& object_instance = get_parent_resource().get_parent_object_instance();
djmeyers 0:06ee5f8a484a 266 object_instance.notification_update(observation_level);
djmeyers 0:06ee5f8a484a 267 }
djmeyers 0:06ee5f8a484a 268
djmeyers 0:06ee5f8a484a 269 if(M2MBase::Dynamic == mode() &&
djmeyers 0:06ee5f8a484a 270 (M2MBase::R_Attribute & observation_level) == M2MBase::R_Attribute) {
djmeyers 0:06ee5f8a484a 271 tr_debug("M2MResourceInstance::report() - resource level");
djmeyers 0:06ee5f8a484a 272 if(!_resource_callback && _resource_type != M2MResourceInstance::STRING) {
djmeyers 0:06ee5f8a484a 273 M2MReportHandler *report_handler = M2MBase::report_handler();
djmeyers 0:06ee5f8a484a 274 if (report_handler && is_observable()) {
djmeyers 0:06ee5f8a484a 275 if(_value) {
djmeyers 0:06ee5f8a484a 276 report_handler->set_value(atof((const char*)_value));
djmeyers 0:06ee5f8a484a 277 } else {
djmeyers 0:06ee5f8a484a 278 report_handler->set_value(0);
djmeyers 0:06ee5f8a484a 279 }
djmeyers 0:06ee5f8a484a 280 }
djmeyers 0:06ee5f8a484a 281 }
djmeyers 0:06ee5f8a484a 282 else {
djmeyers 0:06ee5f8a484a 283 if (_resource_callback && base_type() == M2MBase::ResourceInstance) {
djmeyers 0:06ee5f8a484a 284 _resource_callback->notification_update();
djmeyers 0:06ee5f8a484a 285 }
djmeyers 0:06ee5f8a484a 286 }
djmeyers 0:06ee5f8a484a 287 } else if(M2MBase::Static == mode()) {
djmeyers 0:06ee5f8a484a 288 M2MObservationHandler *observation_handler = M2MBase::observation_handler();
djmeyers 0:06ee5f8a484a 289 if(observation_handler) {
djmeyers 0:06ee5f8a484a 290 observation_handler->value_updated(this);
djmeyers 0:06ee5f8a484a 291 }
djmeyers 0:06ee5f8a484a 292 } else {
djmeyers 0:06ee5f8a484a 293 tr_debug("M2MResourceInstance::report() - mode = %d, is_observable = %d", mode(), is_observable());
djmeyers 0:06ee5f8a484a 294 }
djmeyers 0:06ee5f8a484a 295 }
djmeyers 0:06ee5f8a484a 296
djmeyers 0:06ee5f8a484a 297 bool M2MResourceInstance::is_value_changed(const uint8_t* value, const uint32_t value_len)
djmeyers 0:06ee5f8a484a 298 {
djmeyers 0:06ee5f8a484a 299 bool changed = false;
djmeyers 0:06ee5f8a484a 300 if(value_len != _value_length) {
djmeyers 0:06ee5f8a484a 301 changed = true;
djmeyers 0:06ee5f8a484a 302 } else if(value && !_value) {
djmeyers 0:06ee5f8a484a 303 changed = true;
djmeyers 0:06ee5f8a484a 304 } else if(_value && !value) {
djmeyers 0:06ee5f8a484a 305 changed = true;
djmeyers 0:06ee5f8a484a 306 } else {
djmeyers 0:06ee5f8a484a 307 if (_value) {
djmeyers 0:06ee5f8a484a 308 if (strcmp((char*)value, (char*)_value) != 0) {
djmeyers 0:06ee5f8a484a 309 changed = true;
djmeyers 0:06ee5f8a484a 310 }
djmeyers 0:06ee5f8a484a 311 }
djmeyers 0:06ee5f8a484a 312 }
djmeyers 0:06ee5f8a484a 313 tr_debug("M2MResourceInstance::is_value_changed() -- %s", changed ? "true" : "false");
djmeyers 0:06ee5f8a484a 314 return changed;
djmeyers 0:06ee5f8a484a 315 }
djmeyers 0:06ee5f8a484a 316
djmeyers 0:06ee5f8a484a 317 void M2MResourceInstance::execute(void *arguments)
djmeyers 0:06ee5f8a484a 318 {
djmeyers 0:06ee5f8a484a 319 tr_debug("M2MResourceInstance::execute");
djmeyers 0:06ee5f8a484a 320 if(_execute_callback) {
djmeyers 0:06ee5f8a484a 321 (*_execute_callback)(arguments);
djmeyers 0:06ee5f8a484a 322 }
djmeyers 0:06ee5f8a484a 323 }
djmeyers 0:06ee5f8a484a 324
djmeyers 0:06ee5f8a484a 325 void M2MResourceInstance::get_value(uint8_t *&value, uint32_t &value_length)
djmeyers 0:06ee5f8a484a 326 {
djmeyers 0:06ee5f8a484a 327 value_length = 0;
djmeyers 0:06ee5f8a484a 328 if(value) {
djmeyers 0:06ee5f8a484a 329 free(value);
djmeyers 0:06ee5f8a484a 330 value = NULL;
djmeyers 0:06ee5f8a484a 331 }
djmeyers 0:06ee5f8a484a 332 if(_value && _value_length > 0) {
djmeyers 0:06ee5f8a484a 333 value = alloc_string_copy(_value, _value_length);
djmeyers 0:06ee5f8a484a 334 if(value) {
djmeyers 0:06ee5f8a484a 335 value_length = _value_length;
djmeyers 0:06ee5f8a484a 336 }
djmeyers 0:06ee5f8a484a 337 }
djmeyers 0:06ee5f8a484a 338 }
djmeyers 0:06ee5f8a484a 339
djmeyers 0:06ee5f8a484a 340 int M2MResourceInstance::get_value_int()
djmeyers 0:06ee5f8a484a 341 {
djmeyers 0:06ee5f8a484a 342 int value_int = 0;
djmeyers 0:06ee5f8a484a 343 // Get the value and convert it into integer. This is not the most
djmeyers 0:06ee5f8a484a 344 // efficient way, as it takes pointless heap copy to get the zero termination.
djmeyers 0:06ee5f8a484a 345 uint8_t* buffer = NULL;
djmeyers 0:06ee5f8a484a 346 uint32_t length;
djmeyers 0:06ee5f8a484a 347 get_value(buffer,length);
djmeyers 0:06ee5f8a484a 348 if(buffer) {
djmeyers 0:06ee5f8a484a 349 value_int = atoi((const char*)buffer);
djmeyers 0:06ee5f8a484a 350 free(buffer);
djmeyers 0:06ee5f8a484a 351 }
djmeyers 0:06ee5f8a484a 352 return value_int;
djmeyers 0:06ee5f8a484a 353 }
djmeyers 0:06ee5f8a484a 354
djmeyers 0:06ee5f8a484a 355 String M2MResourceInstance::get_value_string() const
djmeyers 0:06ee5f8a484a 356 {
djmeyers 0:06ee5f8a484a 357 // XXX: do a better constructor to avoid pointless malloc
djmeyers 0:06ee5f8a484a 358 String value;
djmeyers 0:06ee5f8a484a 359 if (_value) {
djmeyers 0:06ee5f8a484a 360 value.append_raw((char*)_value, _value_length);
djmeyers 0:06ee5f8a484a 361 }
djmeyers 0:06ee5f8a484a 362
djmeyers 0:06ee5f8a484a 363 return value;
djmeyers 0:06ee5f8a484a 364 }
djmeyers 0:06ee5f8a484a 365
djmeyers 0:06ee5f8a484a 366 uint8_t* M2MResourceInstance::value() const
djmeyers 0:06ee5f8a484a 367 {
djmeyers 0:06ee5f8a484a 368 return _value;
djmeyers 0:06ee5f8a484a 369 }
djmeyers 0:06ee5f8a484a 370
djmeyers 0:06ee5f8a484a 371 uint32_t M2MResourceInstance::value_length() const
djmeyers 0:06ee5f8a484a 372 {
djmeyers 0:06ee5f8a484a 373 return _value_length;
djmeyers 0:06ee5f8a484a 374 }
djmeyers 0:06ee5f8a484a 375
djmeyers 0:06ee5f8a484a 376 sn_coap_hdr_s* M2MResourceInstance::handle_get_request(nsdl_s *nsdl,
djmeyers 0:06ee5f8a484a 377 sn_coap_hdr_s *received_coap_header,
djmeyers 0:06ee5f8a484a 378 M2MObservationHandler *observation_handler)
djmeyers 0:06ee5f8a484a 379 {
djmeyers 0:06ee5f8a484a 380 tr_debug("M2MResourceInstance::handle_get_request()");
djmeyers 0:06ee5f8a484a 381 sn_coap_msg_code_e msg_code = COAP_MSG_CODE_RESPONSE_CONTENT;
djmeyers 0:06ee5f8a484a 382 sn_coap_hdr_s *coap_response = sn_nsdl_build_response(nsdl,
djmeyers 0:06ee5f8a484a 383 received_coap_header,
djmeyers 0:06ee5f8a484a 384 msg_code);
djmeyers 0:06ee5f8a484a 385 if(received_coap_header) {
djmeyers 0:06ee5f8a484a 386 // process the GET if we have registered a callback for it
djmeyers 0:06ee5f8a484a 387 if ((operation() & SN_GRS_GET_ALLOWED) != 0) {
djmeyers 0:06ee5f8a484a 388 if(coap_response) {
djmeyers 0:06ee5f8a484a 389 if(_resource_type == M2MResourceInstance::OPAQUE) {
djmeyers 0:06ee5f8a484a 390 coap_response->content_format = sn_coap_content_format_e(COAP_CONTENT_OMA_OPAQUE_TYPE);
djmeyers 0:06ee5f8a484a 391 } else {
djmeyers 0:06ee5f8a484a 392 coap_response->content_format = sn_coap_content_format_e(0);
djmeyers 0:06ee5f8a484a 393 }
djmeyers 0:06ee5f8a484a 394 // fill in the CoAP response payload
djmeyers 0:06ee5f8a484a 395 coap_response->payload_ptr = NULL;
djmeyers 0:06ee5f8a484a 396 uint32_t payload_len = 0;
djmeyers 0:06ee5f8a484a 397
djmeyers 0:06ee5f8a484a 398 //If handler exists it means that resource value is stored in application side
djmeyers 0:06ee5f8a484a 399 if (block_message() && block_message()->is_block_message()) {
djmeyers 0:06ee5f8a484a 400 if(_outgoing_block_message_cb) {
djmeyers 0:06ee5f8a484a 401 String name = "";
djmeyers 0:06ee5f8a484a 402 if (received_coap_header->uri_path_ptr != NULL &&
djmeyers 0:06ee5f8a484a 403 received_coap_header->uri_path_len > 0) {
djmeyers 0:06ee5f8a484a 404 name.append_raw((char *)received_coap_header->uri_path_ptr,
djmeyers 0:06ee5f8a484a 405 received_coap_header->uri_path_len);
djmeyers 0:06ee5f8a484a 406 }
djmeyers 0:06ee5f8a484a 407 (*_outgoing_block_message_cb)(name, coap_response->payload_ptr, payload_len);
djmeyers 0:06ee5f8a484a 408 }
djmeyers 0:06ee5f8a484a 409 } else {
djmeyers 0:06ee5f8a484a 410 get_value(coap_response->payload_ptr,payload_len);
djmeyers 0:06ee5f8a484a 411 }
djmeyers 0:06ee5f8a484a 412
djmeyers 0:06ee5f8a484a 413 coap_response->payload_len = payload_len;
djmeyers 0:06ee5f8a484a 414 coap_response->options_list_ptr = sn_nsdl_alloc_options_list(nsdl, coap_response);
djmeyers 0:06ee5f8a484a 415
djmeyers 0:06ee5f8a484a 416 coap_response->options_list_ptr->max_age = max_age();
djmeyers 0:06ee5f8a484a 417
djmeyers 0:06ee5f8a484a 418 if(received_coap_header->options_list_ptr) {
djmeyers 0:06ee5f8a484a 419 if(received_coap_header->options_list_ptr->observe != -1) {
djmeyers 0:06ee5f8a484a 420 if (is_observable()) {
djmeyers 0:06ee5f8a484a 421 uint32_t number = 0;
djmeyers 0:06ee5f8a484a 422 uint8_t observe_option = 0;
djmeyers 0:06ee5f8a484a 423 observe_option = received_coap_header->options_list_ptr->observe;
djmeyers 0:06ee5f8a484a 424
djmeyers 0:06ee5f8a484a 425 if(START_OBSERVATION == observe_option) {
djmeyers 0:06ee5f8a484a 426 tr_debug("M2MResourceInstance::handle_get_request - Starts Observation");
djmeyers 0:06ee5f8a484a 427 // If the observe length is 0 means register for observation.
djmeyers 0:06ee5f8a484a 428 if(received_coap_header->options_list_ptr->observe != -1) {
djmeyers 0:06ee5f8a484a 429 number = received_coap_header->options_list_ptr->observe;
djmeyers 0:06ee5f8a484a 430 }
djmeyers 0:06ee5f8a484a 431 if(received_coap_header->token_ptr) {
djmeyers 0:06ee5f8a484a 432 tr_debug("M2MResourceInstance::handle_get_request - Sets Observation Token to resource");
djmeyers 0:06ee5f8a484a 433 set_observation_token(received_coap_header->token_ptr,
djmeyers 0:06ee5f8a484a 434 received_coap_header->token_len);
djmeyers 0:06ee5f8a484a 435 }
djmeyers 0:06ee5f8a484a 436 // If the observe value is 0 means register for observation.
djmeyers 0:06ee5f8a484a 437 if(number == 0) {
djmeyers 0:06ee5f8a484a 438 tr_debug("M2MResourceInstance::handle_get_request - Put Resource under Observation");
djmeyers 0:06ee5f8a484a 439 set_under_observation(true,observation_handler);
djmeyers 0:06ee5f8a484a 440 M2MBase::add_observation_level(M2MBase::R_Attribute);
djmeyers 0:06ee5f8a484a 441 coap_response->options_list_ptr->observe = observation_number();
djmeyers 0:06ee5f8a484a 442 }
djmeyers 0:06ee5f8a484a 443 } else if (STOP_OBSERVATION == observe_option) {
djmeyers 0:06ee5f8a484a 444 tr_debug("M2MResourceInstance::handle_get_request - Stops Observation");
djmeyers 0:06ee5f8a484a 445 set_under_observation(false,NULL);
djmeyers 0:06ee5f8a484a 446 M2MBase::remove_observation_level(M2MBase::R_Attribute);
djmeyers 0:06ee5f8a484a 447 }
djmeyers 0:06ee5f8a484a 448 } else {
djmeyers 0:06ee5f8a484a 449 msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED;
djmeyers 0:06ee5f8a484a 450 }
djmeyers 0:06ee5f8a484a 451 }
djmeyers 0:06ee5f8a484a 452 }
djmeyers 0:06ee5f8a484a 453 }
djmeyers 0:06ee5f8a484a 454 }else {
djmeyers 0:06ee5f8a484a 455 tr_error("M2MResourceInstance::handle_get_request - Return COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED");
djmeyers 0:06ee5f8a484a 456 // Operation is not allowed.
djmeyers 0:06ee5f8a484a 457 msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED;
djmeyers 0:06ee5f8a484a 458 }
djmeyers 0:06ee5f8a484a 459 } else {
djmeyers 0:06ee5f8a484a 460 msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED;
djmeyers 0:06ee5f8a484a 461 }
djmeyers 0:06ee5f8a484a 462 if(coap_response) {
djmeyers 0:06ee5f8a484a 463 coap_response->msg_code = msg_code;
djmeyers 0:06ee5f8a484a 464 }
djmeyers 0:06ee5f8a484a 465 return coap_response;
djmeyers 0:06ee5f8a484a 466 }
djmeyers 0:06ee5f8a484a 467
djmeyers 0:06ee5f8a484a 468 sn_coap_hdr_s* M2MResourceInstance::handle_put_request(nsdl_s *nsdl,
djmeyers 0:06ee5f8a484a 469 sn_coap_hdr_s *received_coap_header,
djmeyers 0:06ee5f8a484a 470 M2MObservationHandler *observation_handler,
djmeyers 0:06ee5f8a484a 471 bool &execute_value_updated)
djmeyers 0:06ee5f8a484a 472 {
djmeyers 0:06ee5f8a484a 473 tr_debug("M2MResourceInstance::handle_put_request()");
djmeyers 0:06ee5f8a484a 474
djmeyers 0:06ee5f8a484a 475
djmeyers 0:06ee5f8a484a 476 sn_coap_msg_code_e msg_code = COAP_MSG_CODE_RESPONSE_CHANGED; // 2.04
djmeyers 0:06ee5f8a484a 477 sn_coap_hdr_s *coap_response = sn_nsdl_build_response(nsdl,
djmeyers 0:06ee5f8a484a 478 received_coap_header,
djmeyers 0:06ee5f8a484a 479 msg_code);
djmeyers 0:06ee5f8a484a 480 // process the PUT if we have registered a callback for it
djmeyers 0:06ee5f8a484a 481 if(received_coap_header && coap_response) {
djmeyers 0:06ee5f8a484a 482 uint16_t coap_content_type = 0;
djmeyers 0:06ee5f8a484a 483 if(received_coap_header->content_format != COAP_CT_NONE) {
djmeyers 0:06ee5f8a484a 484 coap_content_type = received_coap_header->content_format;
djmeyers 0:06ee5f8a484a 485 }
djmeyers 0:06ee5f8a484a 486 if(received_coap_header->options_list_ptr &&
djmeyers 0:06ee5f8a484a 487 received_coap_header->options_list_ptr->uri_query_ptr) {
djmeyers 0:06ee5f8a484a 488 char *query = (char*)alloc_string_copy(received_coap_header->options_list_ptr->uri_query_ptr,
djmeyers 0:06ee5f8a484a 489 received_coap_header->options_list_ptr->uri_query_len);
djmeyers 0:06ee5f8a484a 490 if (query){
djmeyers 0:06ee5f8a484a 491 tr_debug("M2MResourceInstance::handle_put_request() - Query %s", query);
djmeyers 0:06ee5f8a484a 492
djmeyers 0:06ee5f8a484a 493 // if anything was updated, re-initialize the stored notification attributes
djmeyers 0:06ee5f8a484a 494 if (!handle_observation_attribute(query)){
djmeyers 0:06ee5f8a484a 495 tr_debug("M2MResourceInstance::handle_put_request() - Invalid query");
djmeyers 0:06ee5f8a484a 496 msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; // 4.00
djmeyers 0:06ee5f8a484a 497 }
djmeyers 0:06ee5f8a484a 498 free(query);
djmeyers 0:06ee5f8a484a 499 }
djmeyers 0:06ee5f8a484a 500 } else if ((operation() & SN_GRS_PUT_ALLOWED) != 0) {
djmeyers 0:06ee5f8a484a 501 tr_debug("M2MResourceInstance::handle_put_request() - Request Content-Type %d", coap_content_type);
djmeyers 0:06ee5f8a484a 502
djmeyers 0:06ee5f8a484a 503 if(COAP_CONTENT_OMA_TLV_TYPE == coap_content_type) {
djmeyers 0:06ee5f8a484a 504 msg_code = COAP_MSG_CODE_RESPONSE_UNSUPPORTED_CONTENT_FORMAT;
djmeyers 0:06ee5f8a484a 505 } else {
djmeyers 0:06ee5f8a484a 506 bool external_block_store = false;
djmeyers 0:06ee5f8a484a 507 if (block_message()) {
djmeyers 0:06ee5f8a484a 508 block_message()->set_message_info(received_coap_header);
djmeyers 0:06ee5f8a484a 509 if (block_message()->is_block_message()) {
djmeyers 0:06ee5f8a484a 510 external_block_store = true;
djmeyers 0:06ee5f8a484a 511 if(_incoming_block_message_cb) {
djmeyers 0:06ee5f8a484a 512 (*_incoming_block_message_cb)(_block_message_data);
djmeyers 0:06ee5f8a484a 513 }
djmeyers 0:06ee5f8a484a 514 if (block_message()->is_last_block()) {
djmeyers 0:06ee5f8a484a 515 block_message()->clear_values();
djmeyers 0:06ee5f8a484a 516 coap_response->coap_status = COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED;
djmeyers 0:06ee5f8a484a 517 } else {
djmeyers 0:06ee5f8a484a 518 coap_response->coap_status = COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVING;
djmeyers 0:06ee5f8a484a 519 }
djmeyers 0:06ee5f8a484a 520 if (block_message()->error_code() != M2MBlockMessage::ErrorNone) {
djmeyers 0:06ee5f8a484a 521 block_message()->clear_values();
djmeyers 0:06ee5f8a484a 522 }
djmeyers 0:06ee5f8a484a 523 }
djmeyers 0:06ee5f8a484a 524 }
djmeyers 0:06ee5f8a484a 525 if (!external_block_store) {
djmeyers 0:06ee5f8a484a 526 set_value(received_coap_header->payload_ptr, received_coap_header->payload_len);
djmeyers 0:06ee5f8a484a 527 }
djmeyers 0:06ee5f8a484a 528 if(received_coap_header->payload_ptr) {
djmeyers 0:06ee5f8a484a 529 tr_debug("M2MResourceInstance::handle_put_request() - Update Resource with new values");
djmeyers 0:06ee5f8a484a 530 if(observation_handler) {
djmeyers 0:06ee5f8a484a 531 String value = "";
djmeyers 0:06ee5f8a484a 532 if (received_coap_header->uri_path_ptr != NULL &&
djmeyers 0:06ee5f8a484a 533 received_coap_header->uri_path_len > 0) {
djmeyers 0:06ee5f8a484a 534 value.append_raw((char*)received_coap_header->uri_path_ptr, received_coap_header->uri_path_len);
djmeyers 0:06ee5f8a484a 535 }
djmeyers 0:06ee5f8a484a 536 execute_value_updated = true;
djmeyers 0:06ee5f8a484a 537 }
djmeyers 0:06ee5f8a484a 538 }
djmeyers 0:06ee5f8a484a 539 }
djmeyers 0:06ee5f8a484a 540 } else {
djmeyers 0:06ee5f8a484a 541 // Operation is not allowed.
djmeyers 0:06ee5f8a484a 542 tr_error("M2MResourceInstance::handle_put_request() - COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED");
djmeyers 0:06ee5f8a484a 543 msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED;
djmeyers 0:06ee5f8a484a 544 }
djmeyers 0:06ee5f8a484a 545 } else {
djmeyers 0:06ee5f8a484a 546 msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED;
djmeyers 0:06ee5f8a484a 547 }
djmeyers 0:06ee5f8a484a 548 if(coap_response) {
djmeyers 0:06ee5f8a484a 549 coap_response->msg_code = msg_code;
djmeyers 0:06ee5f8a484a 550 }
djmeyers 0:06ee5f8a484a 551
djmeyers 0:06ee5f8a484a 552 return coap_response;
djmeyers 0:06ee5f8a484a 553 }
djmeyers 0:06ee5f8a484a 554
djmeyers 0:06ee5f8a484a 555 void M2MResourceInstance::set_resource_observer(M2MResourceCallback *resource)
djmeyers 0:06ee5f8a484a 556 {
djmeyers 0:06ee5f8a484a 557 _resource_callback = resource;
djmeyers 0:06ee5f8a484a 558 }
djmeyers 0:06ee5f8a484a 559
djmeyers 0:06ee5f8a484a 560 uint16_t M2MResourceInstance::object_instance_id() const
djmeyers 0:06ee5f8a484a 561 {
djmeyers 0:06ee5f8a484a 562 return _object_instance_id;
djmeyers 0:06ee5f8a484a 563 }
djmeyers 0:06ee5f8a484a 564
djmeyers 0:06ee5f8a484a 565 M2MBlockMessage* M2MResourceInstance::block_message() const
djmeyers 0:06ee5f8a484a 566 {
djmeyers 0:06ee5f8a484a 567 return _block_message_data;
djmeyers 0:06ee5f8a484a 568 }
djmeyers 0:06ee5f8a484a 569
djmeyers 0:06ee5f8a484a 570 void M2MResourceInstance::set_incoming_block_message_callback(incoming_block_message_callback callback)
djmeyers 0:06ee5f8a484a 571 {
djmeyers 0:06ee5f8a484a 572 // copy the callback object. This will change on next version to be a direct pointer to a interface class,
djmeyers 0:06ee5f8a484a 573 // this FPn<> is just too heavy for this usage.
djmeyers 0:06ee5f8a484a 574 delete _incoming_block_message_cb;
djmeyers 0:06ee5f8a484a 575 _incoming_block_message_cb = new incoming_block_message_callback(callback);
djmeyers 0:06ee5f8a484a 576
djmeyers 0:06ee5f8a484a 577 delete _block_message_data;
djmeyers 0:06ee5f8a484a 578 _block_message_data = NULL;
djmeyers 0:06ee5f8a484a 579 _block_message_data = new M2MBlockMessage();
djmeyers 0:06ee5f8a484a 580 }
djmeyers 0:06ee5f8a484a 581
djmeyers 0:06ee5f8a484a 582 void M2MResourceInstance::set_outgoing_block_message_callback(outgoing_block_message_callback callback)
djmeyers 0:06ee5f8a484a 583 {
djmeyers 0:06ee5f8a484a 584 delete _outgoing_block_message_cb;
djmeyers 0:06ee5f8a484a 585 _outgoing_block_message_cb = new outgoing_block_message_callback(callback);
djmeyers 0:06ee5f8a484a 586 }
djmeyers 0:06ee5f8a484a 587
djmeyers 0:06ee5f8a484a 588 void M2MResourceInstance::set_notification_sent_callback(notification_sent_callback callback)
djmeyers 0:06ee5f8a484a 589 {
djmeyers 0:06ee5f8a484a 590 delete _notification_sent_callback;
djmeyers 0:06ee5f8a484a 591 _notification_sent_callback = new notification_sent_callback(callback);
djmeyers 0:06ee5f8a484a 592 }
djmeyers 0:06ee5f8a484a 593
djmeyers 0:06ee5f8a484a 594 void M2MResourceInstance::set_notification_sent_callback(notification_sent_callback_2 callback)
djmeyers 0:06ee5f8a484a 595 {
djmeyers 0:06ee5f8a484a 596 delete _notification_sent_function_pointer;
djmeyers 0:06ee5f8a484a 597
djmeyers 0:06ee5f8a484a 598 _notification_sent_function_pointer = new FP0<void>(callback);
djmeyers 0:06ee5f8a484a 599 set_notification_sent_callback(
djmeyers 0:06ee5f8a484a 600 notification_sent_callback(_notification_sent_function_pointer, &FP0<void>::call));
djmeyers 0:06ee5f8a484a 601 }
djmeyers 0:06ee5f8a484a 602
djmeyers 0:06ee5f8a484a 603 void M2MResourceInstance::notification_sent()
djmeyers 0:06ee5f8a484a 604 {
djmeyers 0:06ee5f8a484a 605 if (_notification_sent_callback) {
djmeyers 0:06ee5f8a484a 606 (*_notification_sent_callback)();
djmeyers 0:06ee5f8a484a 607 }
djmeyers 0:06ee5f8a484a 608 }
djmeyers 0:06ee5f8a484a 609
djmeyers 0:06ee5f8a484a 610 M2MResource& M2MResourceInstance::get_parent_resource() const
djmeyers 0:06ee5f8a484a 611 {
djmeyers 0:06ee5f8a484a 612 return _parent_resource;
djmeyers 0:06ee5f8a484a 613 }
djmeyers 0:06ee5f8a484a 614
djmeyers 0:06ee5f8a484a 615 const char* M2MResourceInstance::object_name() const
djmeyers 0:06ee5f8a484a 616 {
djmeyers 0:06ee5f8a484a 617 const M2MObjectInstance& parent_object_instance = _parent_resource.get_parent_object_instance();
djmeyers 0:06ee5f8a484a 618 const M2MObject& parent_object = parent_object_instance.get_parent_object();
djmeyers 0:06ee5f8a484a 619
djmeyers 0:06ee5f8a484a 620 return parent_object.name();
djmeyers 0:06ee5f8a484a 621 }