GDP group 24 node core

Dependencies:   EthernetInterface SDFileSystem mbed-rtos mbed snail MbedJSONValue

Committer:
Trumple
Date:
Wed Jan 28 20:52:44 2015 +0000
Revision:
28:9c8d472c44b7
Parent:
27:61e67ab47da5
Child:
29:564b1eaf5b99
Change field ID to XBee MAC address of base node

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Trumple 0:fcab3b154e49 1 #include "mbed.h"
Trumple 0:fcab3b154e49 2 #include "snail.h"
Trumple 0:fcab3b154e49 3 #include "sensorinterface.h"
Trumple 0:fcab3b154e49 4 #include "sdcard.h"
Trumple 1:27b35752c5d0 5 #include "http.h"
Trumple 2:1cbb20dd1733 6 #include "MbedJSONValue.h"
Trumple 8:fd531fe7637b 7 #include <map>
Trumple 0:fcab3b154e49 8
Trumple 0:fcab3b154e49 9 #define DEBUG
Trumple 0:fcab3b154e49 10
Trumple 0:fcab3b154e49 11 time_t lastPollTime = 0;
Trumple 0:fcab3b154e49 12 time_t pollInterval = 30;
Trumple 2:1cbb20dd1733 13
jakehodges 23:b57a47c7862a 14 bool isBasenode = false;
Trumple 10:13176e7bd4c8 15
Trumple 2:1cbb20dd1733 16 http h = http();
Trumple 8:fd531fe7637b 17 sensorinterface* sif;
Trumple 8:fd531fe7637b 18
Trumple 1:27b35752c5d0 19 char localAddress[8];
Trumple 2:1cbb20dd1733 20 char baseNodeAddress[8];
Trumple 1:27b35752c5d0 21 bool networkParametersUpdated = false;
Trumple 1:27b35752c5d0 22 bool networkParametersTimedOut = false;
Trumple 0:fcab3b154e49 23
Trumple 0:fcab3b154e49 24 Serial pc(USBTX, USBRX);
Trumple 1:27b35752c5d0 25 snail xbee = snail();
Trumple 1:27b35752c5d0 26 Ticker networkParametersTimeout;
Trumple 0:fcab3b154e49 27
jakehodges 6:92ddc620a78f 28 queue<snail::sensordata> messageQueue;
jakehodges 6:92ddc620a78f 29
Trumple 25:fe273397ebb2 30 //commissioning button
Trumple 25:fe273397ebb2 31 DigitalOut commissioningOutput(p30);
Trumple 25:fe273397ebb2 32 InterruptIn commissioningInput(p16);
Trumple 25:fe273397ebb2 33
Trumple 10:13176e7bd4c8 34 string addressToString(char address[8])
Trumple 10:13176e7bd4c8 35 {
Trumple 10:13176e7bd4c8 36 string address_str;
Trumple 10:13176e7bd4c8 37 for(int i = 0; i < 8; i++)
Trumple 10:13176e7bd4c8 38 {
Trumple 10:13176e7bd4c8 39 char addressBuffer[2];
Trumple 10:13176e7bd4c8 40 sprintf(addressBuffer, "%.2X", address[i]);
Trumple 10:13176e7bd4c8 41 address_str += string(addressBuffer, 2);
Trumple 10:13176e7bd4c8 42 }
Trumple 10:13176e7bd4c8 43
Trumple 10:13176e7bd4c8 44 return address_str;
Trumple 10:13176e7bd4c8 45 }
Trumple 10:13176e7bd4c8 46
Trumple 2:1cbb20dd1733 47 void handleJoinNetworkReply(snail::message& message)
Trumple 1:27b35752c5d0 48 {
Trumple 2:1cbb20dd1733 49 pc.printf("[MAIN] Got join network reply...\r\n");
Trumple 2:1cbb20dd1733 50 snail::joinnetworkreply& reply = static_cast<snail::joinnetworkreply&>(message);
Trumple 2:1cbb20dd1733 51 set_time(reply.timestamp);
Trumple 2:1cbb20dd1733 52 memcpy(baseNodeAddress, reply.baseNodeAddress, sizeof(baseNodeAddress));
Trumple 2:1cbb20dd1733 53
Trumple 1:27b35752c5d0 54 networkParametersUpdated = true;
Trumple 1:27b35752c5d0 55 }
Trumple 1:27b35752c5d0 56
Trumple 2:1cbb20dd1733 57 void handleJoinNetworkRequest(snail::message& message)
Trumple 0:fcab3b154e49 58 {
Trumple 2:1cbb20dd1733 59 pc.printf("[MAIN] Got join network request...\r\n");
Trumple 1:27b35752c5d0 60 if (isBasenode)
Trumple 1:27b35752c5d0 61 {
Trumple 2:1cbb20dd1733 62 snail::joinnetworkrequest& request = static_cast<snail::joinnetworkrequest&>(message);
Trumple 2:1cbb20dd1733 63
Trumple 10:13176e7bd4c8 64 //report connected sensors to server
Trumple 10:13176e7bd4c8 65 MbedJSONValue j;
Trumple 10:13176e7bd4c8 66 j["sensors"];
Trumple 10:13176e7bd4c8 67 for (int i = 0; i < request.sensorCount; i++)
Trumple 10:13176e7bd4c8 68 {
Trumple 10:13176e7bd4c8 69 char sensorIDBuffer[3];
Trumple 10:13176e7bd4c8 70 sprintf(sensorIDBuffer, "%i", request.sensors[i].id);
Trumple 10:13176e7bd4c8 71 char fBuffer[3];
Trumple 10:13176e7bd4c8 72 sprintf(fBuffer, "%i", request.sensors[i].type);
Trumple 10:13176e7bd4c8 73 j["sensors"][i]["sensorID"] = string(sensorIDBuffer);
Trumple 10:13176e7bd4c8 74 j["sensors"][i]["sensortype"] = string(fBuffer);
Trumple 10:13176e7bd4c8 75 }
Trumple 10:13176e7bd4c8 76
Trumple 10:13176e7bd4c8 77 string address = addressToString(request.source);
Trumple 10:13176e7bd4c8 78 #ifdef DEBUG
Trumple 10:13176e7bd4c8 79 pc.printf( ("[MAIN] POSTing startup information: " + j.serialize() + "\r\n").c_str() );
Trumple 10:13176e7bd4c8 80 #endif
Trumple 28:9c8d472c44b7 81 h.post("178.62.84.55", 8888, "/field/" + string(localAddress) + "/" + address + "/startup/", j.serialize()).c_str();
Trumple 10:13176e7bd4c8 82
Trumple 2:1cbb20dd1733 83 snail::joinnetworkreply reply(request.source, time(NULL), localAddress);
Trumple 1:27b35752c5d0 84 xbee.send(reply, sizeof(reply));
Trumple 1:27b35752c5d0 85 }
Trumple 1:27b35752c5d0 86 }
Trumple 1:27b35752c5d0 87
Trumple 2:1cbb20dd1733 88 void handleSensorData(snail::message& message)
Trumple 2:1cbb20dd1733 89 {
Trumple 2:1cbb20dd1733 90 pc.printf("[MAIN] Got sensor data...\r\n");
Trumple 2:1cbb20dd1733 91 snail::sensordata& d = static_cast<snail::sensordata&>(message);
Trumple 2:1cbb20dd1733 92
Trumple 10:13176e7bd4c8 93 char sensorID[3];
Trumple 10:13176e7bd4c8 94 sprintf(sensorID, "%i", d.i2cAddress);
Trumple 10:13176e7bd4c8 95
Trumple 4:0bab12a0cc9a 96 MbedJSONValue j;
Trumple 4:0bab12a0cc9a 97 j["timestamp"] = (int)time(NULL);
jakehodges 23:b57a47c7862a 98
jakehodges 23:b57a47c7862a 99 for (int i = 0; i < d.payloadSize; i++)
jakehodges 23:b57a47c7862a 100 j["value"][i] = d.payload[i];
Trumple 10:13176e7bd4c8 101
Trumple 10:13176e7bd4c8 102 #ifdef DEBUG
Trumple 10:13176e7bd4c8 103 pc.printf( ("[MAIN] POSTing sensor reading: " + j.serialize() + "\r\n").c_str() );
Trumple 10:13176e7bd4c8 104 #endif
Trumple 10:13176e7bd4c8 105
Trumple 28:9c8d472c44b7 106 h.post("178.62.84.55", 8888, "/field/" + string(localAddress) + "/" + addressToString(d.source) + "/" + sensorID + "/", j.serialize()).c_str();
Trumple 2:1cbb20dd1733 107 }
Trumple 2:1cbb20dd1733 108
Trumple 1:27b35752c5d0 109 void handleNetworkParametersTimeout()
Trumple 1:27b35752c5d0 110 {
Trumple 1:27b35752c5d0 111 networkParametersTimedOut = true;
Trumple 1:27b35752c5d0 112 }
Trumple 1:27b35752c5d0 113
Trumple 1:27b35752c5d0 114 void getLocalAddress()
Trumple 1:27b35752c5d0 115 {
Trumple 2:1cbb20dd1733 116 pc.printf("[MAIN] Requesting lower address bits...\r\n");
Trumple 2:1cbb20dd1733 117 xbee.ATCommand("SL");
Trumple 2:1cbb20dd1733 118
Trumple 2:1cbb20dd1733 119 while (!xbee.isATCommandResponseWaiting())
Trumple 2:1cbb20dd1733 120 xbee.processIncomingData();
Trumple 2:1cbb20dd1733 121
Trumple 2:1cbb20dd1733 122 snail::atcommandresponse SLr = xbee.getATCommandResponse();
Trumple 2:1cbb20dd1733 123
Trumple 2:1cbb20dd1733 124 pc.printf("[MAIN] Requesting upper address bits...\r\n");
Trumple 2:1cbb20dd1733 125 xbee.ATCommand("SH");
Trumple 2:1cbb20dd1733 126
Trumple 2:1cbb20dd1733 127 while (!xbee.isATCommandResponseWaiting())
Trumple 2:1cbb20dd1733 128 xbee.processIncomingData();
Trumple 2:1cbb20dd1733 129
Trumple 2:1cbb20dd1733 130 snail::atcommandresponse SHr = xbee.getATCommandResponse();
Trumple 2:1cbb20dd1733 131
Trumple 2:1cbb20dd1733 132 string address(SHr.response);
Trumple 2:1cbb20dd1733 133 address += SLr.response;
Trumple 2:1cbb20dd1733 134
Trumple 2:1cbb20dd1733 135 pc.printf("[MAIN] Got local address: ");
Trumple 2:1cbb20dd1733 136
Trumple 2:1cbb20dd1733 137 for (int i = 0; i < address.size(); i++)
Trumple 2:1cbb20dd1733 138 pc.printf("%.2X", address[i]);
Trumple 2:1cbb20dd1733 139
Trumple 2:1cbb20dd1733 140 pc.printf("\r\n");
Trumple 2:1cbb20dd1733 141
Trumple 2:1cbb20dd1733 142 memcpy(localAddress, address.c_str(), sizeof(localAddress));
Trumple 1:27b35752c5d0 143 }
Trumple 1:27b35752c5d0 144
Trumple 1:27b35752c5d0 145 void getNetworkParameters()
Trumple 1:27b35752c5d0 146 {
Trumple 1:27b35752c5d0 147 #ifdef DEBUG
Trumple 2:1cbb20dd1733 148 pc.printf("[MAIN] Requesting to join network...\r\n");
Trumple 1:27b35752c5d0 149 #endif
Trumple 0:fcab3b154e49 150
Trumple 8:fd531fe7637b 151 //prepare for response from basenode
Trumple 2:1cbb20dd1733 152 xbee.registerMessageCallback(MESSAGE_JOIN_NETWORK_REPLY, handleJoinNetworkReply);
Trumple 2:1cbb20dd1733 153
Trumple 8:fd531fe7637b 154 //handle retrying after timeout
Trumple 2:1cbb20dd1733 155 networkParametersTimeout.attach(&handleNetworkParametersTimeout, 30.0);
Trumple 1:27b35752c5d0 156
Trumple 8:fd531fe7637b 157 //generate list of sensors attached
Trumple 8:fd531fe7637b 158 snail::joinnetworkrequest::sensor localSensors[32];
Trumple 8:fd531fe7637b 159 map<char, sensor>::iterator cs = sif->sensors.begin();
Trumple 8:fd531fe7637b 160 int i = 0;
Trumple 8:fd531fe7637b 161
Trumple 8:fd531fe7637b 162 //either loop until we reach the end of the sensors or until we hit the max
Trumple 8:fd531fe7637b 163 while (cs != sif->sensors.end() && i < 32)
Trumple 8:fd531fe7637b 164 {
Trumple 8:fd531fe7637b 165 localSensors[i].type = cs->second.type;
jakehodges 23:b57a47c7862a 166 localSensors[i].id = cs->second.type;
Trumple 8:fd531fe7637b 167 i++;
Trumple 8:fd531fe7637b 168 cs++;
Trumple 8:fd531fe7637b 169 }
Trumple 8:fd531fe7637b 170
Trumple 8:fd531fe7637b 171 #ifdef DEBUG
Trumple 8:fd531fe7637b 172 pc.printf("[MAIN] Informing basenode of %i attached devices\r\n", i);
Trumple 8:fd531fe7637b 173 #endif
Trumple 8:fd531fe7637b 174
Trumple 8:fd531fe7637b 175 //construct joinnetworkrequest, including the number of sensors attached
Trumple 8:fd531fe7637b 176 snail::joinnetworkrequest request(localSensors, i);
Trumple 1:27b35752c5d0 177
Trumple 1:27b35752c5d0 178 xbee.send(request, sizeof(request));
Trumple 0:fcab3b154e49 179
Trumple 1:27b35752c5d0 180 while(!networkParametersUpdated)
Trumple 1:27b35752c5d0 181 {
Trumple 1:27b35752c5d0 182 if (networkParametersTimedOut)
Trumple 1:27b35752c5d0 183 {
Trumple 1:27b35752c5d0 184 #ifdef DEBUG
Trumple 1:27b35752c5d0 185 pc.printf("[MAIN] Timed out, retrying...\r\n");
Trumple 1:27b35752c5d0 186 #endif
Trumple 1:27b35752c5d0 187 xbee.send(request, sizeof(request));
Trumple 1:27b35752c5d0 188 networkParametersTimedOut = false;
Trumple 1:27b35752c5d0 189 }
Trumple 2:1cbb20dd1733 190 xbee.processIncomingData();
Trumple 1:27b35752c5d0 191 }
Trumple 0:fcab3b154e49 192
Trumple 1:27b35752c5d0 193 #ifdef DEBUG
Trumple 2:1cbb20dd1733 194 pc.printf("[MAIN] Got network parameters. Time: %i, base node address: ", time(NULL));
Trumple 2:1cbb20dd1733 195
Trumple 2:1cbb20dd1733 196 for (int i = 0; i < sizeof(baseNodeAddress); i++)
Trumple 2:1cbb20dd1733 197 pc.printf("%.2X", baseNodeAddress[i]);
Trumple 2:1cbb20dd1733 198 pc.printf("\r\n");
Trumple 1:27b35752c5d0 199 #endif
Trumple 8:fd531fe7637b 200 //no longer need to handle timeout
Trumple 1:27b35752c5d0 201 networkParametersTimeout.detach();
Trumple 0:fcab3b154e49 202 }
Trumple 0:fcab3b154e49 203
Trumple 25:fe273397ebb2 204 void commissioningFall()
Trumple 25:fe273397ebb2 205 {
Trumple 25:fe273397ebb2 206 commissioningOutput = 0;
Trumple 25:fe273397ebb2 207 }
Trumple 25:fe273397ebb2 208
Trumple 25:fe273397ebb2 209 void commissioningRise()
Trumple 25:fe273397ebb2 210 {
Trumple 25:fe273397ebb2 211 commissioningOutput = 1;
Trumple 25:fe273397ebb2 212 }
Trumple 25:fe273397ebb2 213
Trumple 0:fcab3b154e49 214 int main()
Trumple 0:fcab3b154e49 215 {
Trumple 0:fcab3b154e49 216 #ifdef DEBUG
Trumple 0:fcab3b154e49 217 pc.printf("[MAIN] Starting up...\r\n");
Trumple 2:1cbb20dd1733 218 pc.printf(" . .\r\n");
Trumple 2:1cbb20dd1733 219 pc.printf(" / `. .' \\\r\n");
Trumple 2:1cbb20dd1733 220 pc.printf(" .---. < > < > .---.\r\n");
Trumple 2:1cbb20dd1733 221 pc.printf(" | \\ \\ - ~ ~ - / / |\r\n");
Trumple 2:1cbb20dd1733 222 pc.printf(" ~-..-~ ~-..-~\r\n");
Trumple 2:1cbb20dd1733 223 pc.printf(" \\~~~\\.' `./~~~/\r\n");
Trumple 2:1cbb20dd1733 224 pc.printf(" .-~~^-. \\__/ \\__/\r\n");
Trumple 2:1cbb20dd1733 225 pc.printf(" .' O \\ / / \\ \\\r\n");
Trumple 2:1cbb20dd1733 226 pc.printf("(_____, `._.' | } \\/~~~/\r\n");
Trumple 2:1cbb20dd1733 227 pc.printf(" `----. / } | / \\__/\r\n");
Trumple 2:1cbb20dd1733 228 pc.printf(" `-. | / | / `. ,~~|\r\n");
Trumple 2:1cbb20dd1733 229 pc.printf(" ~-.__| /_ - ~ ^| /- _ `..-' f: f:\r\n");
Trumple 2:1cbb20dd1733 230 pc.printf(" | / | / ~-. `-. _||_||_\r\n");
Trumple 2:1cbb20dd1733 231 pc.printf(" |_____| |_____| ~ - . _ _ _ _ _>\r\n");
Trumple 2:1cbb20dd1733 232 pc.printf("\r\n");
Trumple 2:1cbb20dd1733 233 pc.printf("\r\n");
Trumple 26:172b585fbb10 234 pc.printf(" Sensorsaurus | Team 24 GDP | Southampton | 2015\r\n");
Trumple 2:1cbb20dd1733 235 pc.printf("\r\n");
Trumple 2:1cbb20dd1733 236 pc.printf("\r\n");
Trumple 0:fcab3b154e49 237 #endif
jakehodges 23:b57a47c7862a 238 sdcard sd = sdcard();
Trumple 27:61e67ab47da5 239 h.connect();
Trumple 0:fcab3b154e49 240
Trumple 25:fe273397ebb2 241 //commissioning button
Trumple 25:fe273397ebb2 242 commissioningInput.fall(commissioningFall);
Trumple 25:fe273397ebb2 243 commissioningInput.rise(commissioningRise);
Trumple 25:fe273397ebb2 244
Trumple 25:fe273397ebb2 245 //check if local node is basenode
Trumple 27:61e67ab47da5 246 isBasenode = h.isEthernetConnected();
Trumple 0:fcab3b154e49 247 #ifdef DEBUG
Trumple 25:fe273397ebb2 248 pc.printf("[MAIN] Basenode status: %i\r\n", isBasenode);
Trumple 0:fcab3b154e49 249 #endif
Trumple 0:fcab3b154e49 250
Trumple 2:1cbb20dd1733 251 getLocalAddress();
Trumple 2:1cbb20dd1733 252
Trumple 0:fcab3b154e49 253 if (isBasenode)
Trumple 27:61e67ab47da5 254 {
Trumple 2:1cbb20dd1733 255 string timestampStr = h.get("time.bitnode.co.uk", 80, "/");
Trumple 2:1cbb20dd1733 256 time_t timestamp = atoi(timestampStr.c_str());
Trumple 2:1cbb20dd1733 257
Trumple 1:27b35752c5d0 258 set_time(timestamp);
Trumple 1:27b35752c5d0 259
Trumple 2:1cbb20dd1733 260 pc.printf("[MAIN] Got time: %i\r\n", timestamp);
Trumple 2:1cbb20dd1733 261
Trumple 2:1cbb20dd1733 262 xbee.registerMessageCallback(MESSAGE_JOIN_NETWORK_REQUEST, handleJoinNetworkRequest);
Trumple 2:1cbb20dd1733 263 xbee.registerMessageCallback(MESSAGE_SENSOR_DATA, handleSensorData);
Trumple 1:27b35752c5d0 264
Trumple 0:fcab3b154e49 265 while(1)
Trumple 0:fcab3b154e49 266 {
Trumple 0:fcab3b154e49 267 #ifdef DEBUG
Trumple 0:fcab3b154e49 268 pc.printf("[MAIN] Basenode is idle\r\n");
Trumple 0:fcab3b154e49 269 #endif
Trumple 0:fcab3b154e49 270
Trumple 2:1cbb20dd1733 271 wait(1);
Trumple 2:1cbb20dd1733 272 xbee.processIncomingData();
Trumple 0:fcab3b154e49 273 }
Trumple 1:27b35752c5d0 274 }
Trumple 0:fcab3b154e49 275 else
Trumple 8:fd531fe7637b 276 {
Trumple 1:27b35752c5d0 277 sensorinterface sensors = sensorinterface();
Trumple 8:fd531fe7637b 278 sif = &sensors;
Trumple 1:27b35752c5d0 279 getNetworkParameters();
Trumple 1:27b35752c5d0 280
Trumple 0:fcab3b154e49 281 while(1)
Trumple 0:fcab3b154e49 282 {
Trumple 2:1cbb20dd1733 283 xbee.processIncomingData();
jakehodges 6:92ddc620a78f 284
jakehodges 6:92ddc620a78f 285 //if xbee is awake send contents of message queue
jakehodges 6:92ddc620a78f 286 if (xbee.isCTS())
jakehodges 6:92ddc620a78f 287 {
jakehodges 6:92ddc620a78f 288 while(!messageQueue.empty())
jakehodges 6:92ddc620a78f 289 {
jakehodges 6:92ddc620a78f 290 snail::sensordata message = messageQueue.front();
jakehodges 6:92ddc620a78f 291 xbee.send(message, sizeof(message));
jakehodges 6:92ddc620a78f 292 messageQueue.pop();
jakehodges 6:92ddc620a78f 293 }
jakehodges 6:92ddc620a78f 294 }
Trumple 0:fcab3b154e49 295
Trumple 4:0bab12a0cc9a 296 //check if it's time to poll
Trumple 2:1cbb20dd1733 297 if (time(NULL) - lastPollTime > pollInterval)
Trumple 0:fcab3b154e49 298 {
Trumple 0:fcab3b154e49 299 #ifdef DEBUG
Trumple 0:fcab3b154e49 300 pc.printf("[MAIN] Requesting data...\r\n");
Trumple 0:fcab3b154e49 301 #endif
Trumple 0:fcab3b154e49 302 sensors.requestData();
Trumple 0:fcab3b154e49 303 lastPollTime = time(NULL);
Trumple 0:fcab3b154e49 304 }
Trumple 0:fcab3b154e49 305
Trumple 0:fcab3b154e49 306 //if there is data waiting for us...
Trumple 0:fcab3b154e49 307 if (sensors.isDataWaiting())
Trumple 0:fcab3b154e49 308 {
Trumple 0:fcab3b154e49 309 #ifdef DEBUG
Trumple 0:fcab3b154e49 310 pc.printf("[MAIN] Data waiting, reading data...\r\n");
Trumple 0:fcab3b154e49 311 #endif
Trumple 1:27b35752c5d0 312
Trumple 0:fcab3b154e49 313 d_reply data = sensors.readData();
Trumple 1:27b35752c5d0 314
Trumple 0:fcab3b154e49 315 #ifdef DEBUG
Trumple 4:0bab12a0cc9a 316 pc.printf("[MAIN] Got data: ");
Trumple 2:1cbb20dd1733 317 for (int i = 0; i < data.readings.size(); i++)
Trumple 21:a32666afce7a 318 pc.printf("0x%.4X|", data.readings[i]);
Trumple 4:0bab12a0cc9a 319 pc.printf("\r\n");
Trumple 0:fcab3b154e49 320 #endif
Trumple 1:27b35752c5d0 321
jakehodges 23:b57a47c7862a 322 int readings[16];
jakehodges 23:b57a47c7862a 323 for (int i = 0; i < data.readings.size(); i++)
jakehodges 23:b57a47c7862a 324 readings[i] = data.readings[i];
Trumple 4:0bab12a0cc9a 325
jakehodges 23:b57a47c7862a 326 snail::sensordata message(baseNodeAddress, data.type, data.type, time(NULL), readings, data.readings.size());
Trumple 10:13176e7bd4c8 327
jakehodges 6:92ddc620a78f 328 messageQueue.push(message);
Trumple 4:0bab12a0cc9a 329
Trumple 0:fcab3b154e49 330 //log
jakehodges 23:b57a47c7862a 331 sd.write(static_cast<long int>(time(NULL)), data);
Trumple 0:fcab3b154e49 332 }
Trumple 0:fcab3b154e49 333 }
Trumple 1:27b35752c5d0 334 }
Trumple 0:fcab3b154e49 335 }