Etherios Cloud Connector very first porting for mbed. Tested in an LPC1768

Etherios Cloud Connector for Embedded v2.1.0.3 library for mbed. Early porting.

This port is centered mainly in the platform code. So it should work properly with the provided examples of send_data, device_request, data_points, RCI and firmware_update (stub implementation, not a real one... yet ;-)). Filesystem is not implemented yet, and some examples might need changes.

To run, it needs the following libraries: - mbed - mbed-rtos - EthernetInterface

Find more information (and the source code!) about Etherios Cloud Connector for Embedded here: http://www.etherios.com/products/devicecloud/support/connector and in: http://www.etherios.com

Committer:
spastor
Date:
Tue Dec 03 14:10:48 2013 +0000
Revision:
1:908afea5a49d
Parent:
0:1c358ea10753
Use internal Thread.h instead of Threads.h

Who changed what in which revision?

UserRevisionLine numberNew contents of line
spastor 0:1c358ea10753 1 /*
spastor 0:1c358ea10753 2 * Copyright (c) 2013 Digi International Inc.,
spastor 0:1c358ea10753 3 * All rights not expressly granted are reserved.
spastor 0:1c358ea10753 4 *
spastor 0:1c358ea10753 5 * This Source Code Form is subject to the terms of the Mozilla Public
spastor 0:1c358ea10753 6 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
spastor 0:1c358ea10753 7 * You can obtain one at http://mozilla.org/MPL/2.0/.
spastor 0:1c358ea10753 8 *
spastor 0:1c358ea10753 9 * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343
spastor 0:1c358ea10753 10 * =======================================================================
spastor 0:1c358ea10753 11 */
spastor 0:1c358ea10753 12
spastor 0:1c358ea10753 13 /* The data security coding schemes (a.k.a. encryption types)... */
spastor 0:1c358ea10753 14 #define SECURITY_PROTO_NONE 0x00 /* no encryption, no authentication */
spastor 0:1c358ea10753 15
spastor 0:1c358ea10753 16
spastor 0:1c358ea10753 17 /* Discovery layer opcodes */
spastor 0:1c358ea10753 18 #define DISC_OP_PAYLOAD 0
spastor 0:1c358ea10753 19 #define DISC_OP_DEVICETYPE 4
spastor 0:1c358ea10753 20 #define DISC_OP_INITCOMPLETE 5
spastor 0:1c358ea10753 21 #define DISC_OP_VENDOR_ID 6
spastor 0:1c358ea10753 22
spastor 0:1c358ea10753 23 #define tcp_is_send_active(connector_ptr) connector_bool(connector_ptr->edp_data.send_packet.total_length > 0)
spastor 0:1c358ea10753 24
spastor 0:1c358ea10753 25 static connector_status_t tcp_initiate_send_packet(connector_data_t * const connector_ptr, uint8_t * const edp_header,
spastor 0:1c358ea10753 26 size_t const length, uint16_t const type,
spastor 0:1c358ea10753 27 send_complete_cb_t send_complete_cb, void * const user_data)
spastor 0:1c358ea10753 28 {
spastor 0:1c358ea10753 29 connector_status_t status = connector_working;
spastor 0:1c358ea10753 30
spastor 0:1c358ea10753 31 /* Setup data to be sent. tcp_send_packet_process() will actually
spastor 0:1c358ea10753 32 * send out the data.
spastor 0:1c358ea10753 33 */
spastor 0:1c358ea10753 34
spastor 0:1c358ea10753 35 ASSERT_GOTO(edp_header != NULL, done);
spastor 0:1c358ea10753 36 ASSERT_GOTO(length <= UINT16_MAX, done);
spastor 0:1c358ea10753 37
spastor 0:1c358ea10753 38 if (connector_ptr->edp_data.send_packet.total_length > 0)
spastor 0:1c358ea10753 39 {
spastor 0:1c358ea10753 40 connector_debug_printf("tcp_initiate_send_packet: unable to trigger another send since previous data is still pending\n");
spastor 0:1c358ea10753 41 status = connector_pending;
spastor 0:1c358ea10753 42 goto done;
spastor 0:1c358ea10753 43 }
spastor 0:1c358ea10753 44
spastor 0:1c358ea10753 45 /*
spastor 0:1c358ea10753 46 * MTv2 (and later)...
spastor 0:1c358ea10753 47 * Packet format for MT version:
spastor 0:1c358ea10753 48 * ------------------------
spastor 0:1c358ea10753 49 * | 0 - 1 | 2 - 3 | 4 ... |
spastor 0:1c358ea10753 50 * ------------------------
spastor 0:1c358ea10753 51 * | type | length | data |
spastor 0:1c358ea10753 52 * ------------------------
spastor 0:1c358ea10753 53 * | EDP Header |
spastor 0:1c358ea10753 54 * ----------------
spastor 0:1c358ea10753 55 *
spastor 0:1c358ea10753 56 *
spastor 0:1c358ea10753 57 */
spastor 0:1c358ea10753 58
spastor 0:1c358ea10753 59 /* total bytes to be sent to Device Cloud (packet data length + the edp header length) */
spastor 0:1c358ea10753 60 connector_ptr->edp_data.send_packet.total_length = length + PACKET_EDP_HEADER_SIZE;
spastor 0:1c358ea10753 61 connector_ptr->edp_data.send_packet.ptr = edp_header;
spastor 0:1c358ea10753 62
spastor 0:1c358ea10753 63 message_store_be16(edp_header, type, type);
spastor 0:1c358ea10753 64
spastor 0:1c358ea10753 65 {
spastor 0:1c358ea10753 66 uint16_t const length16 = (uint16_t) length;
spastor 0:1c358ea10753 67
spastor 0:1c358ea10753 68 ASSERT(length <= UINT16_MAX);
spastor 0:1c358ea10753 69 message_store_be16(edp_header, length, length16);
spastor 0:1c358ea10753 70 }
spastor 0:1c358ea10753 71
spastor 0:1c358ea10753 72 /* clear the actual number of bytes to be sent */
spastor 0:1c358ea10753 73 connector_ptr->edp_data.send_packet.bytes_sent = 0;
spastor 0:1c358ea10753 74 connector_ptr->edp_data.send_packet.complete_cb = send_complete_cb;
spastor 0:1c358ea10753 75 connector_ptr->edp_data.send_packet.user_data = user_data;
spastor 0:1c358ea10753 76 done:
spastor 0:1c358ea10753 77 return status;
spastor 0:1c358ea10753 78 }
spastor 0:1c358ea10753 79
spastor 0:1c358ea10753 80 static connector_status_t tcp_initiate_send_facility_packet(connector_data_t * const connector_ptr, uint8_t * const edp_header,
spastor 0:1c358ea10753 81 size_t const length, uint16_t const facility,
spastor 0:1c358ea10753 82 send_complete_cb_t send_complete_cb, void * const user_data)
spastor 0:1c358ea10753 83 {
spastor 0:1c358ea10753 84 uint8_t * const edp_protocol = edp_header + PACKET_EDP_HEADER_SIZE;
spastor 0:1c358ea10753 85
spastor 0:1c358ea10753 86
spastor 0:1c358ea10753 87 /* this function is to set up a facility packet to be sent.
spastor 0:1c358ea10753 88 * Setup security coding, discovery payload & facility.
spastor 0:1c358ea10753 89 *
spastor 0:1c358ea10753 90 * facility packet:
spastor 0:1c358ea10753 91 * -------------------------------------------------------------------------------------
spastor 0:1c358ea10753 92 * | 0 - 1 | 2 - 3 | 4 | 5 | 6 - 7 | 8... |
spastor 0:1c358ea10753 93 * -------------------------------------------------------------------------------------
spastor 0:1c358ea10753 94 * | type | length | data security coding | discovery payload | facility | facility data|
spastor 0:1c358ea10753 95 * -------------------------------------------------------------------------------------
spastor 0:1c358ea10753 96 * | EDP Header | EDP Protocol |
spastor 0:1c358ea10753 97 * ----------------------------------------------------------------------
spastor 0:1c358ea10753 98 */
spastor 0:1c358ea10753 99 message_store_u8(edp_protocol, sec_coding, SECURITY_PROTO_NONE);
spastor 0:1c358ea10753 100 message_store_u8(edp_protocol, payload, DISC_OP_PAYLOAD);
spastor 0:1c358ea10753 101 message_store_be16(edp_protocol, facility, facility);
spastor 0:1c358ea10753 102
spastor 0:1c358ea10753 103
spastor 0:1c358ea10753 104 return tcp_initiate_send_packet(connector_ptr, edp_header,
spastor 0:1c358ea10753 105 (length + PACKET_EDP_PROTOCOL_SIZE),
spastor 0:1c358ea10753 106 E_MSG_MT2_TYPE_PAYLOAD,
spastor 0:1c358ea10753 107 send_complete_cb,
spastor 0:1c358ea10753 108 user_data);
spastor 0:1c358ea10753 109 }
spastor 0:1c358ea10753 110
spastor 0:1c358ea10753 111 static connector_callback_status_t tcp_send_buffer(connector_data_t * const connector_ptr, uint8_t * const buffer, size_t * const length)
spastor 0:1c358ea10753 112 {
spastor 0:1c358ea10753 113 connector_callback_status_t status;
spastor 0:1c358ea10753 114 connector_network_send_t send_data;
spastor 0:1c358ea10753 115 connector_request_id_t request_id;
spastor 0:1c358ea10753 116
spastor 0:1c358ea10753 117 send_data.buffer = buffer;
spastor 0:1c358ea10753 118 send_data.bytes_available = *length;
spastor 0:1c358ea10753 119 send_data.bytes_used = 0;
spastor 0:1c358ea10753 120 send_data.handle = connector_ptr->edp_data.network_handle;
spastor 0:1c358ea10753 121
spastor 0:1c358ea10753 122 request_id.network_request = connector_request_id_network_send;
spastor 0:1c358ea10753 123 status = connector_callback(connector_ptr->callback, connector_class_id_network_tcp, request_id, &send_data);
spastor 0:1c358ea10753 124 ASSERT(status != connector_callback_unrecognized);
spastor 0:1c358ea10753 125 switch (status)
spastor 0:1c358ea10753 126 {
spastor 0:1c358ea10753 127 case connector_callback_continue:
spastor 0:1c358ea10753 128 *length = send_data.bytes_used;
spastor 0:1c358ea10753 129 if (*length > 0)
spastor 0:1c358ea10753 130 {
spastor 0:1c358ea10753 131 /* Retain the "last (RX) message send" time. */
spastor 0:1c358ea10753 132 if (get_system_time(connector_ptr, &connector_ptr->edp_data.keepalive.last_rx_sent_time) != connector_working)
spastor 0:1c358ea10753 133 {
spastor 0:1c358ea10753 134 status = connector_callback_abort;
spastor 0:1c358ea10753 135 }
spastor 0:1c358ea10753 136 }
spastor 0:1c358ea10753 137 break;
spastor 0:1c358ea10753 138 case connector_callback_busy:
spastor 0:1c358ea10753 139 *length = 0;
spastor 0:1c358ea10753 140 break;
spastor 0:1c358ea10753 141 case connector_callback_unrecognized:
spastor 0:1c358ea10753 142 status = connector_callback_abort;
spastor 0:1c358ea10753 143 /* no break */
spastor 0:1c358ea10753 144 case connector_callback_abort:
spastor 0:1c358ea10753 145 break;
spastor 0:1c358ea10753 146 case connector_callback_error:
spastor 0:1c358ea10753 147 edp_set_close_status(connector_ptr, connector_close_status_device_error);
spastor 0:1c358ea10753 148 break;
spastor 0:1c358ea10753 149 }
spastor 0:1c358ea10753 150
spastor 0:1c358ea10753 151 return status;
spastor 0:1c358ea10753 152 }
spastor 0:1c358ea10753 153
spastor 0:1c358ea10753 154 static connector_status_t tcp_release_packet_buffer(connector_data_t * const connector_ptr, uint8_t const * const packet, connector_status_t const status, void * const user_data)
spastor 0:1c358ea10753 155 {
spastor 0:1c358ea10753 156 /* this is called when the Connector is done sending or after tcp_get_packet_buffer()
spastor 0:1c358ea10753 157 * is called to release connector_ptr->edp_data.send_packet.packet_buffer.buffer.
spastor 0:1c358ea10753 158 *
spastor 0:1c358ea10753 159 */
spastor 0:1c358ea10753 160 UNUSED_PARAMETER(status);
spastor 0:1c358ea10753 161 UNUSED_PARAMETER(packet);
spastor 0:1c358ea10753 162 UNUSED_PARAMETER(user_data);
spastor 0:1c358ea10753 163
spastor 0:1c358ea10753 164 ASSERT(connector_ptr->edp_data.send_packet.packet_buffer.buffer == packet);
spastor 0:1c358ea10753 165
spastor 0:1c358ea10753 166 connector_ptr->edp_data.send_packet.packet_buffer.in_use = connector_false;
spastor 0:1c358ea10753 167
spastor 0:1c358ea10753 168 return connector_working;
spastor 0:1c358ea10753 169 }
spastor 0:1c358ea10753 170 #if (defined CONNECTOR_DEBUG)
spastor 0:1c358ea10753 171 static unsigned int debug_count = 0;
spastor 0:1c358ea10753 172 #endif
spastor 0:1c358ea10753 173
spastor 0:1c358ea10753 174 static uint8_t * tcp_get_packet_buffer(connector_data_t * const connector_ptr, uint16_t const facility, uint8_t ** data_ptr, size_t * data_length)
spastor 0:1c358ea10753 175 {
spastor 0:1c358ea10753 176 #define MIN_EDP_MESSAGE_SIZE (PACKET_EDP_HEADER_SIZE +CLOUD_URL_LENGTH)
spastor 0:1c358ea10753 177 uint8_t * packet = NULL;
spastor 0:1c358ea10753 178 uint8_t * ptr = NULL;
spastor 0:1c358ea10753 179 size_t length = 0;
spastor 0:1c358ea10753 180
spastor 0:1c358ea10753 181 /* Return a pointer to caller to setup data to be sent to Device Cloud.
spastor 0:1c358ea10753 182 * Must call tcp_release_packet_buffer() to release the buffer (pass
spastor 0:1c358ea10753 183 * tcp_release_packet_buffer as complete_callback to tcp_initiate_send_packet()
spastor 0:1c358ea10753 184 * or tcp_initiate_send_facility_packet().
spastor 0:1c358ea10753 185 */
spastor 0:1c358ea10753 186
spastor 0:1c358ea10753 187
spastor 0:1c358ea10753 188 /* make sure no send is pending */
spastor 0:1c358ea10753 189 if ((connector_ptr->edp_data.send_packet.total_length == 0) &&
spastor 0:1c358ea10753 190 (!connector_ptr->edp_data.send_packet.packet_buffer.in_use))
spastor 0:1c358ea10753 191 {
spastor 0:1c358ea10753 192 connector_ptr->edp_data.send_packet.packet_buffer.in_use = connector_true;
spastor 0:1c358ea10753 193
spastor 0:1c358ea10753 194 packet = connector_ptr->edp_data.send_packet.packet_buffer.buffer;
spastor 0:1c358ea10753 195
spastor 0:1c358ea10753 196 /* set ptr to the data portion */
spastor 0:1c358ea10753 197 ptr = GET_PACKET_DATA_POINTER(packet, PACKET_EDP_HEADER_SIZE);
spastor 0:1c358ea10753 198
spastor 0:1c358ea10753 199 if (facility != E_MSG_MT2_MSG_NUM)
spastor 0:1c358ea10753 200 {
spastor 0:1c358ea10753 201 /* set ptr to the data portion of facility packet */
spastor 0:1c358ea10753 202 ptr += PACKET_EDP_PROTOCOL_SIZE;
spastor 0:1c358ea10753 203 }
spastor 0:1c358ea10753 204
spastor 0:1c358ea10753 205 {
spastor 0:1c358ea10753 206 size_t const max_packet_size = sizeof connector_ptr->edp_data.send_packet.packet_buffer.buffer;
spastor 0:1c358ea10753 207 size_t const header_size = (size_t)(ptr - packet);
spastor 0:1c358ea10753 208
spastor 0:1c358ea10753 209 ASSERT(max_packet_size >= MIN_EDP_MESSAGE_SIZE);
spastor 0:1c358ea10753 210 ASSERT(ptr > packet);
spastor 0:1c358ea10753 211 length = max_packet_size - header_size;
spastor 0:1c358ea10753 212 }
spastor 0:1c358ea10753 213 #if (defined CONNECTOR_DEBUG)
spastor 0:1c358ea10753 214 debug_count = 0;
spastor 0:1c358ea10753 215 #endif
spastor 0:1c358ea10753 216
spastor 0:1c358ea10753 217 }
spastor 0:1c358ea10753 218 #if (defined CONNECTOR_DEBUG)
spastor 0:1c358ea10753 219 else
spastor 0:1c358ea10753 220 {
spastor 0:1c358ea10753 221 if (debug_count == 0)
spastor 0:1c358ea10753 222 connector_debug_printf("tcp_get packet buffer: send pending\n");
spastor 0:1c358ea10753 223
spastor 0:1c358ea10753 224 debug_count++;
spastor 0:1c358ea10753 225 }
spastor 0:1c358ea10753 226 #endif
spastor 0:1c358ea10753 227 if (data_ptr != NULL)
spastor 0:1c358ea10753 228 {
spastor 0:1c358ea10753 229 *data_ptr = ptr;
spastor 0:1c358ea10753 230 }
spastor 0:1c358ea10753 231
spastor 0:1c358ea10753 232 if (data_length != NULL)
spastor 0:1c358ea10753 233 {
spastor 0:1c358ea10753 234 *data_length = length;
spastor 0:1c358ea10753 235 }
spastor 0:1c358ea10753 236
spastor 0:1c358ea10753 237 return packet;
spastor 0:1c358ea10753 238 }
spastor 0:1c358ea10753 239
spastor 0:1c358ea10753 240 static connector_status_t tcp_rx_keepalive_process(connector_data_t * const connector_ptr)
spastor 0:1c358ea10753 241 {
spastor 0:1c358ea10753 242 connector_status_t status = connector_idle;
spastor 0:1c358ea10753 243
spastor 0:1c358ea10753 244 if (edp_get_active_state(connector_ptr) == connector_transport_open)
spastor 0:1c358ea10753 245 {
spastor 0:1c358ea10753 246 goto done;
spastor 0:1c358ea10753 247 }
spastor 0:1c358ea10753 248
spastor 0:1c358ea10753 249 /* Sends rx keepalive if keepalive timing is expired.
spastor 0:1c358ea10753 250 *
spastor 0:1c358ea10753 251 * last_rx_keepalive_time is last time we sent Rx keepalive.
spastor 0:1c358ea10753 252 */
spastor 0:1c358ea10753 253 if (is_valid_timing_limit(connector_ptr, connector_ptr->edp_data.keepalive.last_rx_sent_time, GET_RX_KEEPALIVE_INTERVAL(connector_ptr)))
spastor 0:1c358ea10753 254 {
spastor 0:1c358ea10753 255 /* not expired yet. no need to send rx keepalive */
spastor 0:1c358ea10753 256 goto done;
spastor 0:1c358ea10753 257 }
spastor 0:1c358ea10753 258
spastor 0:1c358ea10753 259 connector_debug_printf("tcp_rx_keepalive_process: time to send Rx keepalive\n");
spastor 0:1c358ea10753 260
spastor 0:1c358ea10753 261 status = tcp_initiate_send_packet(connector_ptr, connector_ptr->edp_data.keepalive.send_rx_packet, 0, E_MSG_MT2_TYPE_KA_KEEPALIVE, NULL, NULL);
spastor 0:1c358ea10753 262
spastor 0:1c358ea10753 263 done:
spastor 0:1c358ea10753 264 return status;
spastor 0:1c358ea10753 265 }
spastor 0:1c358ea10753 266
spastor 0:1c358ea10753 267 static connector_status_t tcp_send_complete_callback(connector_data_t * const connector_ptr, connector_status_t status)
spastor 0:1c358ea10753 268 {
spastor 0:1c358ea10753 269 connector_status_t result = connector_working;
spastor 0:1c358ea10753 270 send_complete_cb_t callback = connector_ptr->edp_data.send_packet.complete_cb;
spastor 0:1c358ea10753 271
spastor 0:1c358ea10753 272 if (callback != NULL)
spastor 0:1c358ea10753 273 {
spastor 0:1c358ea10753 274 connector_ptr->edp_data.send_packet.complete_cb = NULL;
spastor 0:1c358ea10753 275 result = callback(connector_ptr, connector_ptr->edp_data.send_packet.ptr, status, connector_ptr->edp_data.send_packet.user_data);
spastor 0:1c358ea10753 276 ASSERT(result != connector_pending);
spastor 0:1c358ea10753 277 }
spastor 0:1c358ea10753 278
spastor 0:1c358ea10753 279 return result;
spastor 0:1c358ea10753 280 }
spastor 0:1c358ea10753 281
spastor 0:1c358ea10753 282 static connector_status_t edp_tcp_send_process(connector_data_t * const connector_ptr)
spastor 0:1c358ea10753 283 {
spastor 0:1c358ea10753 284 connector_status_t result = connector_idle;
spastor 0:1c358ea10753 285
spastor 0:1c358ea10753 286 /* if nothing needs to be sent, check whether we need to send rx keepalive */
spastor 0:1c358ea10753 287 if (connector_ptr->edp_data.send_packet.total_length == 0)
spastor 0:1c358ea10753 288 {
spastor 0:1c358ea10753 289
spastor 0:1c358ea10753 290 result = tcp_rx_keepalive_process(connector_ptr);
spastor 0:1c358ea10753 291 }
spastor 0:1c358ea10753 292
spastor 0:1c358ea10753 293 if (connector_ptr->edp_data.send_packet.total_length > 0)
spastor 0:1c358ea10753 294 {
spastor 0:1c358ea10753 295 /* We have something to be sent */
spastor 0:1c358ea10753 296
spastor 0:1c358ea10753 297 uint8_t * const buf = connector_ptr->edp_data.send_packet.ptr + connector_ptr->edp_data.send_packet.bytes_sent;
spastor 0:1c358ea10753 298 size_t length = connector_ptr->edp_data.send_packet.total_length;
spastor 0:1c358ea10753 299
spastor 0:1c358ea10753 300 connector_callback_status_t const status = tcp_send_buffer(connector_ptr, buf, &length);
spastor 0:1c358ea10753 301
spastor 0:1c358ea10753 302 switch (status)
spastor 0:1c358ea10753 303 {
spastor 0:1c358ea10753 304 case connector_callback_continue:
spastor 0:1c358ea10753 305 connector_ptr->edp_data.send_packet.total_length -= length;
spastor 0:1c358ea10753 306 connector_ptr->edp_data.send_packet.bytes_sent += length;
spastor 0:1c358ea10753 307
spastor 0:1c358ea10753 308 if (connector_ptr->edp_data.send_packet.total_length == 0)
spastor 0:1c358ea10753 309 { /* sent completed so let's call the complete callback */
spastor 0:1c358ea10753 310 result = tcp_send_complete_callback(connector_ptr, connector_success);
spastor 0:1c358ea10753 311 }
spastor 0:1c358ea10753 312 else if (connector_ptr->edp_data.send_packet.total_length > 0)
spastor 0:1c358ea10753 313 {
spastor 0:1c358ea10753 314 result = connector_pending;
spastor 0:1c358ea10753 315 }
spastor 0:1c358ea10753 316 break;
spastor 0:1c358ea10753 317
spastor 0:1c358ea10753 318 case connector_callback_busy:
spastor 0:1c358ea10753 319 result = connector_pending;
spastor 0:1c358ea10753 320 goto done;
spastor 0:1c358ea10753 321
spastor 0:1c358ea10753 322 case connector_callback_error:
spastor 0:1c358ea10753 323 edp_set_close_status(connector_ptr, connector_close_status_device_error);
spastor 0:1c358ea10753 324 edp_set_active_state(connector_ptr, connector_transport_close);
spastor 0:1c358ea10753 325 break;
spastor 0:1c358ea10753 326 case connector_callback_abort:
spastor 0:1c358ea10753 327 edp_set_close_status(connector_ptr, connector_close_status_abort);
spastor 0:1c358ea10753 328 edp_set_active_state(connector_ptr, connector_transport_close);
spastor 0:1c358ea10753 329 break;
spastor 0:1c358ea10753 330 default:
spastor 0:1c358ea10753 331 ASSERT(connector_false);
spastor 0:1c358ea10753 332 break;
spastor 0:1c358ea10753 333 }
spastor 0:1c358ea10753 334 }
spastor 0:1c358ea10753 335
spastor 0:1c358ea10753 336 done:
spastor 0:1c358ea10753 337 return result;
spastor 0:1c358ea10753 338
spastor 0:1c358ea10753 339 }
spastor 0:1c358ea10753 340
spastor 0:1c358ea10753 341
spastor 0:1c358ea10753 342