David Smart / NWSWeather
Committer:
WiredHome
Date:
Thu Nov 26 18:58:29 2015 +0000
Revision:
12:d70de07ca914
Parent:
11:98afc5abbfb8
Child:
13:a9ac9dde4f7f
Updated to add a User-Agent string, which became a required field to avoid an error return of "unauthorized".

Who changed what in which revision?

UserRevisionLine numberNew contents of line
WiredHome 2:eae60b64066e 1 //
WiredHome 2:eae60b64066e 2 // This file contains the interface for gathering forecast from NWS.
WiredHome 2:eae60b64066e 3 //
WiredHome 12:d70de07ca914 4 // attention: This program is copyright (c) 2014 - 2015 by Smartware Computing, all
WiredHome 2:eae60b64066e 5 // rights reserved.
WiredHome 2:eae60b64066e 6 //
WiredHome 2:eae60b64066e 7 // This software, and/or material is the property of Smartware Computing. All
WiredHome 2:eae60b64066e 8 // use, disclosure, and/or reproduction not specifically authorized by Smartware
WiredHome 2:eae60b64066e 9 // Computing is prohibited.
WiredHome 2:eae60b64066e 10 //
WiredHome 2:eae60b64066e 11 // This software may be freely used for non-commercial purposes, and any
WiredHome 2:eae60b64066e 12 // derivative work shall carry the original copyright. The author of
WiredHome 2:eae60b64066e 13 // a derivative work shall make clear that it is a derivative work.
WiredHome 2:eae60b64066e 14 //
WiredHome 2:eae60b64066e 15 // author David Smart, Smartware Computing
WiredHome 2:eae60b64066e 16 //
WiredHome 2:eae60b64066e 17 #include "NWSWeather.h"
WiredHome 0:4435c965d95d 18
WiredHome 12:d70de07ca914 19 //#define DEBUG "NWS "
WiredHome 2:eae60b64066e 20 // ...
WiredHome 2:eae60b64066e 21 // INFO("Stuff to show %d", var); // new-line is automatically appended
WiredHome 2:eae60b64066e 22 //
WiredHome 2:eae60b64066e 23 #if (defined(DEBUG) && !defined(TARGET_LPC11U24))
WiredHome 11:98afc5abbfb8 24 #define INFO(x, ...) std::printf("[INF %s %3d] " x "\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
WiredHome 11:98afc5abbfb8 25 #define WARN(x, ...) std::printf("[WRN %s %3d] " x "\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
WiredHome 11:98afc5abbfb8 26 #define ERR(x, ...) std::printf("[ERR %s %3d] " x "\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
WiredHome 2:eae60b64066e 27 #else
WiredHome 2:eae60b64066e 28 #define INFO(x, ...)
WiredHome 2:eae60b64066e 29 #define WARN(x, ...)
WiredHome 2:eae60b64066e 30 #define ERR(x, ...)
WiredHome 2:eae60b64066e 31 #endif
WiredHome 0:4435c965d95d 32
WiredHome 12:d70de07ca914 33 // 20151126 - Not sure when, but the NWS site stopped accepting requests unless a
WiredHome 12:d70de07ca914 34 // User-Agent was provided. It doesn't seem to matter the contents of
WiredHome 12:d70de07ca914 35 // the U-A string.
WiredHome 12:d70de07ca914 36 static const char * hdrs[] = {
WiredHome 12:d70de07ca914 37 "Connection", "keep-alive",
WiredHome 12:d70de07ca914 38 "Accept", "text/html",
WiredHome 12:d70de07ca914 39 "User-Agent", "SW_Client"
WiredHome 12:d70de07ca914 40 };
WiredHome 12:d70de07ca914 41 #define HDR_PAIRS 3
WiredHome 0:4435c965d95d 42
WiredHome 1:e077d6502c94 43 static NWSWeather::XMLItem_T WeatherData[] = {
WiredHome 1:e077d6502c94 44 {"observation_time_rfc822", NWSWeather::isString},
WiredHome 8:8a3371926b32 45 {"suggested_pickup", NWSWeather::isInt},
WiredHome 1:e077d6502c94 46 {"suggested_pickup_period", NWSWeather::isInt},
WiredHome 1:e077d6502c94 47 {"location", NWSWeather::isString},
WiredHome 1:e077d6502c94 48 {"weather", NWSWeather::isString},
WiredHome 1:e077d6502c94 49 {"temp_f", NWSWeather::isFloat},
WiredHome 1:e077d6502c94 50 {"temp_c", NWSWeather::isFloat},
WiredHome 1:e077d6502c94 51 {"relative_humidity", NWSWeather::isInt},
WiredHome 1:e077d6502c94 52 {"wind_degrees", NWSWeather::isInt},
WiredHome 1:e077d6502c94 53 {"wind_mph", NWSWeather::isFloat},
WiredHome 1:e077d6502c94 54 {"pressure_mb", NWSWeather::isFloat},
WiredHome 1:e077d6502c94 55 {"pressure_in", NWSWeather::isFloat},
WiredHome 1:e077d6502c94 56 {"dewpoint_f", NWSWeather::isFloat},
WiredHome 1:e077d6502c94 57 {"dewpoint_c", NWSWeather::isFloat},
WiredHome 1:e077d6502c94 58 {"windchill_f", NWSWeather::isFloat},
WiredHome 1:e077d6502c94 59 {"windchill_c", NWSWeather::isFloat},
WiredHome 1:e077d6502c94 60 {"visibility_mi", NWSWeather::isFloat},
WiredHome 1:e077d6502c94 61 {"icon_url_base", NWSWeather::isString},
WiredHome 1:e077d6502c94 62 {"icon_url_name", NWSWeather::isString},
WiredHome 1:e077d6502c94 63 {"latitude", NWSWeather::isFloat},
WiredHome 1:e077d6502c94 64 {"longitude", NWSWeather::isFloat},
WiredHome 0:4435c965d95d 65 };
WiredHome 0:4435c965d95d 66
WiredHome 0:4435c965d95d 67 #define MAXPARAMLEN 23
WiredHome 0:4435c965d95d 68
WiredHome 0:4435c965d95d 69 #define WeatherItemCount (sizeof(WeatherData)/sizeof(WeatherData[0]))
WiredHome 0:4435c965d95d 70
WiredHome 0:4435c965d95d 71 NWSWeather::NWSWeather(const char * baseURL)
WiredHome 0:4435c965d95d 72 {
WiredHome 0:4435c965d95d 73 setAlternateURL(baseURL);
WiredHome 0:4435c965d95d 74 }
WiredHome 0:4435c965d95d 75
WiredHome 0:4435c965d95d 76 NWSWeather::~NWSWeather()
WiredHome 0:4435c965d95d 77 {
WiredHome 0:4435c965d95d 78 ClearWeatherRecords();
WiredHome 0:4435c965d95d 79 }
WiredHome 0:4435c965d95d 80
WiredHome 1:e077d6502c94 81 NWSWeather::NWSReturnCode_T NWSWeather::setAlternateURL(const char * baseURL)
WiredHome 0:4435c965d95d 82 {
WiredHome 11:98afc5abbfb8 83 int n = strlen(baseURL)+1;
WiredHome 11:98afc5abbfb8 84
WiredHome 0:4435c965d95d 85 if (m_baseurl)
WiredHome 0:4435c965d95d 86 free(m_baseurl);
WiredHome 11:98afc5abbfb8 87 m_baseurl = (char *)malloc(n);
WiredHome 0:4435c965d95d 88 if (m_baseurl)
WiredHome 11:98afc5abbfb8 89 strncpy(m_baseurl, baseURL, n);
WiredHome 0:4435c965d95d 90 else {
WiredHome 11:98afc5abbfb8 91 ERR("failed to malloc(%d)", n);
WiredHome 0:4435c965d95d 92 return nomemory;
WiredHome 0:4435c965d95d 93 }
WiredHome 0:4435c965d95d 94 ClearWeatherRecords();
WiredHome 0:4435c965d95d 95 return noerror;
WiredHome 0:4435c965d95d 96 }
WiredHome 0:4435c965d95d 97
WiredHome 0:4435c965d95d 98 uint16_t NWSWeather::count(void)
WiredHome 0:4435c965d95d 99 {
WiredHome 0:4435c965d95d 100 return WeatherItemCount;
WiredHome 0:4435c965d95d 101 }
WiredHome 0:4435c965d95d 102
WiredHome 1:e077d6502c94 103 NWSWeather::NWSReturnCode_T NWSWeather::get(const char * site, int responseSize)
WiredHome 0:4435c965d95d 104 {
WiredHome 6:cf96f2787a4e 105 HTTPClient http;
WiredHome 2:eae60b64066e 106 NWSReturnCode_T retCode = nomemory;
WiredHome 2:eae60b64066e 107 char *url = NULL;
WiredHome 0:4435c965d95d 108 char *message = (char *)malloc(responseSize);
WiredHome 12:d70de07ca914 109
WiredHome 2:eae60b64066e 110 INFO("get(%s)", site);
WiredHome 2:eae60b64066e 111 if (!message)
WiredHome 11:98afc5abbfb8 112 ERR("failed to malloc(%d)", responseSize);
WiredHome 2:eae60b64066e 113 while (message) {
WiredHome 11:98afc5abbfb8 114 int n = strlen(m_baseurl) + strlen(site) + 5;
WiredHome 11:98afc5abbfb8 115
WiredHome 11:98afc5abbfb8 116 url = (char *)malloc(n);
WiredHome 0:4435c965d95d 117 if (url) {
WiredHome 0:4435c965d95d 118 strcpy(url, m_baseurl);
WiredHome 0:4435c965d95d 119 strcat(url, site);
WiredHome 0:4435c965d95d 120 strcat(url, ".xml");
WiredHome 2:eae60b64066e 121 INFO(" url: %s", url);
WiredHome 0:4435c965d95d 122 http.setMaxRedirections(3);
WiredHome 12:d70de07ca914 123 http.customHeaders(hdrs, HDR_PAIRS);
WiredHome 0:4435c965d95d 124 int ret = http.get(url, message, responseSize);
WiredHome 0:4435c965d95d 125 if (!ret) {
WiredHome 2:eae60b64066e 126 INFO("ret is %d", ret);
WiredHome 0:4435c965d95d 127 if (http.getHTTPResponseCode() >= 300 && http.getHTTPResponseCode() < 400) {
WiredHome 2:eae60b64066e 128 retCode = noerror; // redirection that was not satisfied.
WiredHome 2:eae60b64066e 129 break;
WiredHome 0:4435c965d95d 130 } else {
WiredHome 6:cf96f2787a4e 131 INFO("wx get %d bytes.\r\n", strlen(message));
WiredHome 0:4435c965d95d 132 ParseWeatherXML(message);
WiredHome 11:98afc5abbfb8 133 INFO("wx parse complete.\r\n");
WiredHome 2:eae60b64066e 134 retCode = noerror;
WiredHome 2:eae60b64066e 135 break;
WiredHome 0:4435c965d95d 136 }
WiredHome 0:4435c965d95d 137 } else {
WiredHome 2:eae60b64066e 138 WARN("get returned %d, no response?", ret);
WiredHome 2:eae60b64066e 139 retCode = noresponse;
WiredHome 2:eae60b64066e 140 break;
WiredHome 0:4435c965d95d 141 }
WiredHome 0:4435c965d95d 142 } else {
WiredHome 11:98afc5abbfb8 143 ERR("failed to malloc(%d)", n);
WiredHome 2:eae60b64066e 144 retCode = nomemory;
WiredHome 2:eae60b64066e 145 break;
WiredHome 2:eae60b64066e 146 }
WiredHome 2:eae60b64066e 147 } // while(...) but configured with break for only 1 pass.
WiredHome 2:eae60b64066e 148 INFO(" ret is %d", retCode);
WiredHome 2:eae60b64066e 149 if (url)
WiredHome 2:eae60b64066e 150 free(url);
WiredHome 2:eae60b64066e 151 if (message)
WiredHome 2:eae60b64066e 152 free(message);
WiredHome 2:eae60b64066e 153 INFO(" mem freed.");
WiredHome 2:eae60b64066e 154 return retCode;
WiredHome 2:eae60b64066e 155 }
WiredHome 2:eae60b64066e 156
WiredHome 2:eae60b64066e 157
WiredHome 2:eae60b64066e 158 NWSWeather::NWSReturnCode_T NWSWeather::isUpdated(uint16_t i)
WiredHome 2:eae60b64066e 159 {
WiredHome 2:eae60b64066e 160 if (i < WeatherItemCount) {
WiredHome 2:eae60b64066e 161 if (WeatherData[i].updated)
WiredHome 2:eae60b64066e 162 return noerror;
WiredHome 2:eae60b64066e 163 else
WiredHome 2:eae60b64066e 164 return noupdate;
WiredHome 2:eae60b64066e 165 } else {
WiredHome 2:eae60b64066e 166 return badparameter;
WiredHome 2:eae60b64066e 167 }
WiredHome 2:eae60b64066e 168 }
WiredHome 2:eae60b64066e 169
WiredHome 2:eae60b64066e 170
WiredHome 2:eae60b64066e 171 NWSWeather::NWSReturnCode_T NWSWeather::isUpdated(const char * name)
WiredHome 2:eae60b64066e 172 {
WiredHome 2:eae60b64066e 173 if (name) {
WiredHome 2:eae60b64066e 174 for (int i=0; i < WeatherItemCount; i++) {
WiredHome 2:eae60b64066e 175 if (strcmp(name, WeatherData[i].name) == 0) {
WiredHome 2:eae60b64066e 176 if (WeatherData[i].updated)
WiredHome 2:eae60b64066e 177 return noerror;
WiredHome 2:eae60b64066e 178 else
WiredHome 2:eae60b64066e 179 return noupdate;
WiredHome 2:eae60b64066e 180 }
WiredHome 0:4435c965d95d 181 }
WiredHome 0:4435c965d95d 182 }
WiredHome 2:eae60b64066e 183 return badparameter;
WiredHome 0:4435c965d95d 184 }
WiredHome 0:4435c965d95d 185
WiredHome 0:4435c965d95d 186
WiredHome 1:e077d6502c94 187 NWSWeather::NWSReturnCode_T NWSWeather::getParam(uint16_t i, char *name, Value_T *value, TypeOf_T *typeis)
WiredHome 0:4435c965d95d 188 {
WiredHome 0:4435c965d95d 189 if (i < WeatherItemCount) {
WiredHome 0:4435c965d95d 190 *name = *WeatherData[i].name;
WiredHome 0:4435c965d95d 191 *value = WeatherData[i].value;
WiredHome 0:4435c965d95d 192 if (typeis)
WiredHome 0:4435c965d95d 193 *typeis = WeatherData[i].typeis;
WiredHome 0:4435c965d95d 194 return noerror;
WiredHome 0:4435c965d95d 195 } else {
WiredHome 0:4435c965d95d 196 return badparameter;
WiredHome 0:4435c965d95d 197 }
WiredHome 0:4435c965d95d 198 }
WiredHome 0:4435c965d95d 199
WiredHome 0:4435c965d95d 200
WiredHome 1:e077d6502c94 201 NWSWeather::NWSReturnCode_T NWSWeather::getParam(const char *name, Value_T *value, TypeOf_T *typeis)
WiredHome 0:4435c965d95d 202 {
WiredHome 2:eae60b64066e 203 for (int i=0; i < WeatherItemCount; i++) {
WiredHome 2:eae60b64066e 204 if (strcmp(name, WeatherData[i].name) == 0) {
WiredHome 2:eae60b64066e 205 *value = WeatherData[i].value;
WiredHome 2:eae60b64066e 206 if (typeis)
WiredHome 2:eae60b64066e 207 *typeis = WeatherData[i].typeis;
WiredHome 2:eae60b64066e 208 return noerror;
WiredHome 0:4435c965d95d 209 }
WiredHome 0:4435c965d95d 210 }
WiredHome 0:4435c965d95d 211 return badparameter;
WiredHome 0:4435c965d95d 212 }
WiredHome 0:4435c965d95d 213
WiredHome 0:4435c965d95d 214
WiredHome 0:4435c965d95d 215 void NWSWeather::ClearWeatherRecords(void)
WiredHome 0:4435c965d95d 216 {
WiredHome 0:4435c965d95d 217 int i;
WiredHome 0:4435c965d95d 218 int count = WeatherItemCount;
WiredHome 0:4435c965d95d 219
WiredHome 0:4435c965d95d 220 for (i=0; i<count; i++) {
WiredHome 0:4435c965d95d 221 switch(WeatherData[i].typeis) {
WiredHome 0:4435c965d95d 222 case isFloat:
WiredHome 0:4435c965d95d 223 WeatherData[i].value.fValue = 0.0;
WiredHome 0:4435c965d95d 224 WeatherData[i].updated = false;
WiredHome 0:4435c965d95d 225 break;
WiredHome 0:4435c965d95d 226 case isInt:
WiredHome 0:4435c965d95d 227 WeatherData[i].value.iValue = 0;
WiredHome 0:4435c965d95d 228 WeatherData[i].updated = false;
WiredHome 0:4435c965d95d 229 break;
WiredHome 0:4435c965d95d 230 case isString:
WiredHome 0:4435c965d95d 231 if (WeatherData[i].value.sValue) {
WiredHome 0:4435c965d95d 232 free(WeatherData[i].value.sValue);
WiredHome 0:4435c965d95d 233 WeatherData[i].value.sValue = NULL;
WiredHome 0:4435c965d95d 234 }
WiredHome 0:4435c965d95d 235 WeatherData[i].updated = false;
WiredHome 0:4435c965d95d 236 break;
WiredHome 0:4435c965d95d 237 default:
WiredHome 0:4435c965d95d 238 break;
WiredHome 0:4435c965d95d 239 }
WiredHome 0:4435c965d95d 240 }
WiredHome 0:4435c965d95d 241 }
WiredHome 0:4435c965d95d 242
WiredHome 0:4435c965d95d 243 void NWSWeather::PrintWeatherRecord(uint16_t i)
WiredHome 0:4435c965d95d 244 {
WiredHome 0:4435c965d95d 245 if (i < WeatherItemCount) {
WiredHome 0:4435c965d95d 246 switch(WeatherData[i].typeis) {
WiredHome 0:4435c965d95d 247 case isFloat:
WiredHome 0:4435c965d95d 248 printf("%23s = %f\r\n", WeatherData[i].name, WeatherData[i].value.fValue);
WiredHome 0:4435c965d95d 249 break;
WiredHome 0:4435c965d95d 250 case isInt:
WiredHome 0:4435c965d95d 251 printf("%23s = %d\r\n", WeatherData[i].name, WeatherData[i].value.iValue);
WiredHome 0:4435c965d95d 252 break;
WiredHome 0:4435c965d95d 253 case isString:
WiredHome 0:4435c965d95d 254 printf("%23s = %s\r\n", WeatherData[i].name, WeatherData[i].value.sValue);
WiredHome 0:4435c965d95d 255 break;
WiredHome 0:4435c965d95d 256 default:
WiredHome 0:4435c965d95d 257 break;
WiredHome 0:4435c965d95d 258 }
WiredHome 0:4435c965d95d 259 }
WiredHome 0:4435c965d95d 260 }
WiredHome 0:4435c965d95d 261
WiredHome 0:4435c965d95d 262 void NWSWeather::PrintAllWeatherRecords(void)
WiredHome 0:4435c965d95d 263 {
WiredHome 0:4435c965d95d 264 for (int i=0; i<WeatherItemCount; i++) {
WiredHome 0:4435c965d95d 265 PrintWeatherRecord(i);
WiredHome 0:4435c965d95d 266 }
WiredHome 0:4435c965d95d 267 }
WiredHome 0:4435c965d95d 268
WiredHome 1:e077d6502c94 269 NWSWeather::NWSReturnCode_T NWSWeather::ParseWeatherRecord(char * p)
WiredHome 0:4435c965d95d 270 {
WiredHome 0:4435c965d95d 271 // <tag_name>value</tag_name>
WiredHome 0:4435c965d95d 272 // p1 p2 p3
WiredHome 0:4435c965d95d 273 char *p1, *p2, *p3;
WiredHome 0:4435c965d95d 274 int i;
WiredHome 11:98afc5abbfb8 275 int n;
WiredHome 0:4435c965d95d 276 int count = WeatherItemCount;
WiredHome 0:4435c965d95d 277
WiredHome 11:98afc5abbfb8 278 INFO("ParseWeatherRecord(%s)", p);
WiredHome 11:98afc5abbfb8 279 p1 = strchr(p, '<'); // Pattern Matching <key>value</key>
WiredHome 0:4435c965d95d 280 if (p1++) {
WiredHome 0:4435c965d95d 281 p2 = strchr(p1+1, '>');
WiredHome 0:4435c965d95d 282 if (p2) {
WiredHome 0:4435c965d95d 283 p3 = strchr(p2+1, '<');
WiredHome 0:4435c965d95d 284 if (p3) {
WiredHome 0:4435c965d95d 285 *p2++ = '\0';
WiredHome 0:4435c965d95d 286 *p3 = '\0';
WiredHome 0:4435c965d95d 287 for (i=0; i<count; i++) {
WiredHome 0:4435c965d95d 288 if (strcmp(p1, WeatherData[i].name) == 0) {
WiredHome 0:4435c965d95d 289 switch(WeatherData[i].typeis) {
WiredHome 0:4435c965d95d 290 case isFloat:
WiredHome 0:4435c965d95d 291 WeatherData[i].value.fValue = atof(p2);
WiredHome 0:4435c965d95d 292 WeatherData[i].updated = true;
WiredHome 0:4435c965d95d 293 break;
WiredHome 0:4435c965d95d 294 case isInt:
WiredHome 0:4435c965d95d 295 WeatherData[i].value.iValue = atoi(p2);
WiredHome 0:4435c965d95d 296 WeatherData[i].updated = true;
WiredHome 0:4435c965d95d 297 break;
WiredHome 0:4435c965d95d 298 case isString:
WiredHome 0:4435c965d95d 299 if (WeatherData[i].value.sValue)
WiredHome 0:4435c965d95d 300 free(WeatherData[i].value.sValue);
WiredHome 11:98afc5abbfb8 301 n = strlen(p2)+1;
WiredHome 11:98afc5abbfb8 302 WeatherData[i].value.sValue = (char *)malloc(n);
WiredHome 0:4435c965d95d 303 if (WeatherData[i].value.sValue) {
WiredHome 0:4435c965d95d 304 strcpy(WeatherData[i].value.sValue, p2);
WiredHome 0:4435c965d95d 305 WeatherData[i].updated = true;
WiredHome 11:98afc5abbfb8 306 } else {
WiredHome 11:98afc5abbfb8 307 ERR("failed to malloc(%d)", n);
WiredHome 11:98afc5abbfb8 308 break;
WiredHome 0:4435c965d95d 309 }
WiredHome 0:4435c965d95d 310 break;
WiredHome 0:4435c965d95d 311 default:
WiredHome 11:98afc5abbfb8 312 ERR("unknown type");
WiredHome 0:4435c965d95d 313 return badparameter;
WiredHome 0:4435c965d95d 314 //break;
WiredHome 0:4435c965d95d 315 }
WiredHome 11:98afc5abbfb8 316 INFO("pw end");
WiredHome 0:4435c965d95d 317 return noerror;
WiredHome 0:4435c965d95d 318 }
WiredHome 0:4435c965d95d 319 }
WiredHome 0:4435c965d95d 320 }
WiredHome 0:4435c965d95d 321 }
WiredHome 0:4435c965d95d 322 }
WiredHome 11:98afc5abbfb8 323 INFO("pw end");
WiredHome 0:4435c965d95d 324 return noparamfound;
WiredHome 0:4435c965d95d 325 }
WiredHome 0:4435c965d95d 326
WiredHome 0:4435c965d95d 327 void NWSWeather::ParseWeatherXML(char * message)
WiredHome 0:4435c965d95d 328 {
WiredHome 0:4435c965d95d 329 char * p = message;
WiredHome 0:4435c965d95d 330
WiredHome 11:98afc5abbfb8 331 INFO("ParseWeatherXML: %s", p);
WiredHome 0:4435c965d95d 332 ClearWeatherRecords();
WiredHome 11:98afc5abbfb8 333 INFO("cleared old");
WiredHome 0:4435c965d95d 334 while (*p) {
WiredHome 0:4435c965d95d 335 char * n = strchr(p, '\n');
WiredHome 0:4435c965d95d 336 if (*n) {
WiredHome 0:4435c965d95d 337 *n = '\0';
WiredHome 0:4435c965d95d 338 ParseWeatherRecord(p);
WiredHome 0:4435c965d95d 339 p = n + 1;
WiredHome 0:4435c965d95d 340 } else {
WiredHome 0:4435c965d95d 341 ParseWeatherRecord(p);
WiredHome 0:4435c965d95d 342 break;
WiredHome 0:4435c965d95d 343 }
WiredHome 0:4435c965d95d 344 }
WiredHome 0:4435c965d95d 345 }