1

Dependencies:   X_NUCLEO_IKS01A1 LoRaWAN-lib SX1276Lib mbed

Committer:
ubhat
Date:
Fri Aug 26 19:36:35 2016 +0000
Revision:
0:42863a11464a
Child:
2:78df92a365c2
SX1276 Shield based Applications

Who changed what in which revision?

UserRevisionLine numberNew contents of line
ubhat 0:42863a11464a 1 /*
ubhat 0:42863a11464a 2 / _____) _ | |
ubhat 0:42863a11464a 3 ( (____ _____ ____ _| |_ _____ ____| |__
ubhat 0:42863a11464a 4 \____ \| ___ | (_ _) ___ |/ ___) _ \
ubhat 0:42863a11464a 5 _____) ) ____| | | || |_| ____( (___| | | |
ubhat 0:42863a11464a 6 (______/|_____)_|_|_| \__)_____)\____)_| |_|
ubhat 0:42863a11464a 7 (C)2015 Semtech
ubhat 0:42863a11464a 8
ubhat 0:42863a11464a 9 Description: User-defined applications such as GPS, Temp, Accelerometer, LED indications etc.
ubhat 0:42863a11464a 10 Event based actions such as LED blink on Tx, LED toggle on downlink etc
ubhat 0:42863a11464a 11
ubhat 0:42863a11464a 12 License: Revised BSD License, see LICENSE.TXT file include in the project
ubhat 0:42863a11464a 13
ubhat 0:42863a11464a 14 Maintainer: Uttam Bhat
ubhat 0:42863a11464a 15 */
ubhat 0:42863a11464a 16
ubhat 0:42863a11464a 17 #include "LoRaApp.h"
ubhat 0:42863a11464a 18
ubhat 0:42863a11464a 19 bool VerticalStatus = false;
ubhat 0:42863a11464a 20
ubhat 0:42863a11464a 21
ubhat 0:42863a11464a 22 Application::Application( uint8_t * memptr )
ubhat 0:42863a11464a 23 {
ubhat 0:42863a11464a 24 BuffAddr = memptr;
ubhat 0:42863a11464a 25 memset( BuffAddr, 0, LORAWAN_APP_DATA_MAX_SIZE );
ubhat 0:42863a11464a 26 BuffPtr = 0;
ubhat 0:42863a11464a 27 }
ubhat 0:42863a11464a 28
ubhat 0:42863a11464a 29 Application::~Application( )
ubhat 0:42863a11464a 30 {
ubhat 0:42863a11464a 31 }
ubhat 0:42863a11464a 32
ubhat 0:42863a11464a 33 void Application::ApplicationAppendData( uint8_t *pData, uint8_t len )
ubhat 0:42863a11464a 34 {
ubhat 0:42863a11464a 35 memcpy( BuffAddr + BuffPtr, pData, len );
ubhat 0:42863a11464a 36 BuffPtr += len;
ubhat 0:42863a11464a 37 }
ubhat 0:42863a11464a 38
ubhat 0:42863a11464a 39 void Application::ApplicationPtrPos( uint8_t ptrPos )
ubhat 0:42863a11464a 40 {
ubhat 0:42863a11464a 41 BuffPtr = ptrPos;
ubhat 0:42863a11464a 42 }
ubhat 0:42863a11464a 43
ubhat 0:42863a11464a 44 void Application::ApplicationCall( eAppType App )
ubhat 0:42863a11464a 45 {
ubhat 0:42863a11464a 46 switch( App )
ubhat 0:42863a11464a 47 {
ubhat 0:42863a11464a 48 // Appends 8 Bytes (3 bytes longitude, 3 bytes latitude, 2 bytes altitude) to TX buffer
ubhat 0:42863a11464a 49 case AppGps:
ubhat 0:42863a11464a 50 {
ubhat 0:42863a11464a 51 /*
ubhat 0:42863a11464a 52 Gps.service( );
ubhat 0:42863a11464a 53
ubhat 0:42863a11464a 54 uint16_t altitudeGps = atoi( Gps.NmeaGpsData.NmeaAltitude );
ubhat 0:42863a11464a 55
ubhat 0:42863a11464a 56 if( ( BuffPtr + 8 ) <= LORAWAN_APP_DATA_SIZE )
ubhat 0:42863a11464a 57 {
ubhat 0:42863a11464a 58 BuffAddr[BuffPtr++] = ( Gps.LatitudeBinary >> 16 ) & 0xFF;
ubhat 0:42863a11464a 59 BuffAddr[BuffPtr++] = ( Gps.LatitudeBinary >> 8 ) & 0xFF;
ubhat 0:42863a11464a 60 BuffAddr[BuffPtr++] = Gps.LatitudeBinary & 0xFF;
ubhat 0:42863a11464a 61 BuffAddr[BuffPtr++] = ( Gps.LongitudeBinary >> 16 ) & 0xFF;
ubhat 0:42863a11464a 62 BuffAddr[BuffPtr++] = ( Gps.LongitudeBinary >> 8 ) & 0xFF;
ubhat 0:42863a11464a 63 BuffAddr[BuffPtr++] = Gps.LongitudeBinary & 0xFF;
ubhat 0:42863a11464a 64 BuffAddr[BuffPtr++] = ( altitudeGps >> 8 ) & 0xFF;
ubhat 0:42863a11464a 65 BuffAddr[BuffPtr++] = altitudeGps & 0xFF;
ubhat 0:42863a11464a 66 }
ubhat 0:42863a11464a 67 */
ubhat 0:42863a11464a 68 break;
ubhat 0:42863a11464a 69 }
ubhat 0:42863a11464a 70
ubhat 0:42863a11464a 71 // Appends 1 Byte to TX buffer
ubhat 0:42863a11464a 72 case AppTemp:
ubhat 0:42863a11464a 73 {
ubhat 0:42863a11464a 74 /*
ubhat 0:42863a11464a 75 Mpl3115a2.ReadTemperature( );
ubhat 0:42863a11464a 76 if( ( BuffPtr + 1 ) <= LORAWAN_APP_DATA_SIZE )
ubhat 0:42863a11464a 77 {
ubhat 0:42863a11464a 78 BuffAddr[BuffPtr++] = ( int32_t )Mpl3115a2.Temperature; // Signed degrees Celcius in half degree units. So, +/-63 °C
ubhat 0:42863a11464a 79 }
ubhat 0:42863a11464a 80 */
ubhat 0:42863a11464a 81 break;
ubhat 0:42863a11464a 82 }
ubhat 0:42863a11464a 83
ubhat 0:42863a11464a 84 // Appends 1 Byte to TX buffer
ubhat 0:42863a11464a 85 case AppBat:
ubhat 0:42863a11464a 86 {
ubhat 0:42863a11464a 87 if( ( BuffPtr + 1 ) <= LORAWAN_APP_DATA_SIZE )
ubhat 0:42863a11464a 88 {
ubhat 0:42863a11464a 89 BuffAddr[BuffPtr++] = BoardGetBatteryLevel( ); // Per LoRaWAN spec; 0 = Charging; 1...254 = level, 255 = N/A
ubhat 0:42863a11464a 90 }
ubhat 0:42863a11464a 91 break;
ubhat 0:42863a11464a 92 }
ubhat 0:42863a11464a 93
ubhat 0:42863a11464a 94 // Appends incremental values of 1 Byte each to TX buffer until Full
ubhat 0:42863a11464a 95 case AppRamp:
ubhat 0:42863a11464a 96 {
ubhat 0:42863a11464a 97 int32_t i, j;
ubhat 0:42863a11464a 98
ubhat 0:42863a11464a 99 // Populate Tx Buffer with increasing byte values starting from 0x00, 0x01, 0x02 ...
ubhat 0:42863a11464a 100 for( i = BuffPtr, j = 0; i < LORAWAN_APP_DATA_SIZE; i++ )
ubhat 0:42863a11464a 101 {
ubhat 0:42863a11464a 102 BuffAddr[i] = j++;
ubhat 0:42863a11464a 103 }
ubhat 0:42863a11464a 104 BuffPtr = LORAWAN_APP_DATA_SIZE;
ubhat 0:42863a11464a 105 break;
ubhat 0:42863a11464a 106 }
ubhat 0:42863a11464a 107
ubhat 0:42863a11464a 108 // Appends 2 Bytes to TX buffer
ubhat 0:42863a11464a 109 case AppAccl:
ubhat 0:42863a11464a 110 {
ubhat 0:42863a11464a 111 /*
ubhat 0:42863a11464a 112 uint8_t statusReg;
ubhat 0:42863a11464a 113
ubhat 0:42863a11464a 114 // Read the PS_STATUS register
ubhat 0:42863a11464a 115 statusReg = Mma8451q.read_single( MMA8451_PL_STATUS );
ubhat 0:42863a11464a 116
ubhat 0:42863a11464a 117 // Display Orientation of NAMote on Serial Port
ubhat 0:42863a11464a 118 SerialAcclMetrDisplay( statusReg );
ubhat 0:42863a11464a 119
ubhat 0:42863a11464a 120 // If Orientation of the Mote changed then let Green LED ON
ubhat 0:42863a11464a 121 if( ( statusReg & 0x80 ) != 0 )
ubhat 0:42863a11464a 122 {
ubhat 0:42863a11464a 123 AppLed = 1;
ubhat 0:42863a11464a 124 CtrlLED( Green, LED_ON );
ubhat 0:42863a11464a 125 }
ubhat 0:42863a11464a 126
ubhat 0:42863a11464a 127 // Read and populate device orientation in Tx Buffer
ubhat 0:42863a11464a 128 if( ( BuffPtr + 2 ) <= LORAWAN_APP_DATA_SIZE )
ubhat 0:42863a11464a 129 {
ubhat 0:42863a11464a 130 if( statusReg & 0x40 )
ubhat 0:42863a11464a 131 {
ubhat 0:42863a11464a 132 if( statusReg & 0x01 )
ubhat 0:42863a11464a 133 {
ubhat 0:42863a11464a 134 BuffAddr[BuffPtr++] = 0x66; // horizontal + faceup
ubhat 0:42863a11464a 135 }
ubhat 0:42863a11464a 136 else
ubhat 0:42863a11464a 137 {
ubhat 0:42863a11464a 138 BuffAddr[BuffPtr++] = 0x99; // horizontal + facedown
ubhat 0:42863a11464a 139 }
ubhat 0:42863a11464a 140
ubhat 0:42863a11464a 141 BuffAddr[BuffPtr++] = 0; // vertical = false
ubhat 0:42863a11464a 142 }
ubhat 0:42863a11464a 143 else
ubhat 0:42863a11464a 144 {
ubhat 0:42863a11464a 145 BuffAddr[BuffPtr++] = 0; // horizontal = false
ubhat 0:42863a11464a 146 BuffAddr[BuffPtr++] = 0x11; // vertical = true
ubhat 0:42863a11464a 147 }
ubhat 0:42863a11464a 148 }
ubhat 0:42863a11464a 149 */
ubhat 0:42863a11464a 150 break;
ubhat 0:42863a11464a 151 }
ubhat 0:42863a11464a 152
ubhat 0:42863a11464a 153 case AppAcclSenet:
ubhat 0:42863a11464a 154 {
ubhat 0:42863a11464a 155 /*
ubhat 0:42863a11464a 156 uint8_t statusReg;
ubhat 0:42863a11464a 157
ubhat 0:42863a11464a 158 // Read the PS_STATUS register
ubhat 0:42863a11464a 159 statusReg = Mma8451q.read_single( MMA8451_PL_STATUS );
ubhat 0:42863a11464a 160
ubhat 0:42863a11464a 161 // Display Orientation of NAMote on Serial Port
ubhat 0:42863a11464a 162 SerialAcclMetrDisplay( statusReg );
ubhat 0:42863a11464a 163
ubhat 0:42863a11464a 164 // If Orientation of the Mote changed then populate Upper Nibble of 0th Byte of Tx Buffer
ubhat 0:42863a11464a 165 if( ( statusReg & 0x40 ) != 0 )
ubhat 0:42863a11464a 166 {
ubhat 0:42863a11464a 167 AppLed = 0;
ubhat 0:42863a11464a 168 CtrlLED( Green, LED_OFF );
ubhat 0:42863a11464a 169 BuffAddr[BuffPtr++] = 0; // horizontal
ubhat 0:42863a11464a 170 }
ubhat 0:42863a11464a 171 else
ubhat 0:42863a11464a 172 {
ubhat 0:42863a11464a 173 AppLed = 1;
ubhat 0:42863a11464a 174 CtrlLED( Green, LED_ON );
ubhat 0:42863a11464a 175 BuffAddr[BuffPtr++] = 10; // vertical
ubhat 0:42863a11464a 176 }
ubhat 0:42863a11464a 177 */
ubhat 0:42863a11464a 178 break;
ubhat 0:42863a11464a 179 }
ubhat 0:42863a11464a 180
ubhat 0:42863a11464a 181 case AppPushButton:
ubhat 0:42863a11464a 182 {
ubhat 0:42863a11464a 183 uint16_t PushButtonCnt;
ubhat 0:42863a11464a 184 uint8_t *p = (uint8_t *) &PushButtonCnt;
ubhat 0:42863a11464a 185
ubhat 0:42863a11464a 186 PushButtonCnt = LoRaMacUplinkStatus.UplinkCounter;
ubhat 0:42863a11464a 187
ubhat 0:42863a11464a 188 memcpy( &BuffAddr[BuffPtr], p, sizeof(uint16_t) );
ubhat 0:42863a11464a 189
ubhat 0:42863a11464a 190 break;
ubhat 0:42863a11464a 191 }
ubhat 0:42863a11464a 192
ubhat 0:42863a11464a 193 default:
ubhat 0:42863a11464a 194 {
ubhat 0:42863a11464a 195 break;
ubhat 0:42863a11464a 196 }
ubhat 0:42863a11464a 197 }
ubhat 0:42863a11464a 198 }
ubhat 0:42863a11464a 199
ubhat 0:42863a11464a 200 /*
ubhat 0:42863a11464a 201 static void OnRedLedTimerEvent( void )
ubhat 0:42863a11464a 202 {
ubhat 0:42863a11464a 203 TimerStop( &RedLedTimer.LedTimer );
ubhat 0:42863a11464a 204
ubhat 0:42863a11464a 205 if( RedLed == LED_OFF )
ubhat 0:42863a11464a 206 {
ubhat 0:42863a11464a 207 RedLed = LED_ON;
ubhat 0:42863a11464a 208 }
ubhat 0:42863a11464a 209 else
ubhat 0:42863a11464a 210 {
ubhat 0:42863a11464a 211 RedLed = LED_OFF;
ubhat 0:42863a11464a 212 }
ubhat 0:42863a11464a 213 }
ubhat 0:42863a11464a 214
ubhat 0:42863a11464a 215 static void OnYellowLedTimerEvent( void )
ubhat 0:42863a11464a 216 {
ubhat 0:42863a11464a 217 TimerStop( &YellowLedTimer.LedTimer );
ubhat 0:42863a11464a 218
ubhat 0:42863a11464a 219 if( YellowLed == LED_OFF )
ubhat 0:42863a11464a 220 {
ubhat 0:42863a11464a 221 YellowLed = LED_ON;
ubhat 0:42863a11464a 222 }
ubhat 0:42863a11464a 223 else
ubhat 0:42863a11464a 224 {
ubhat 0:42863a11464a 225 YellowLed = LED_OFF;
ubhat 0:42863a11464a 226 }
ubhat 0:42863a11464a 227 }
ubhat 0:42863a11464a 228
ubhat 0:42863a11464a 229 static void OnGreenLedTimerEvent( void )
ubhat 0:42863a11464a 230 {
ubhat 0:42863a11464a 231 TimerStop( &GreenLedTimer.LedTimer );
ubhat 0:42863a11464a 232
ubhat 0:42863a11464a 233 if( GreenLed == LED_OFF )
ubhat 0:42863a11464a 234 {
ubhat 0:42863a11464a 235 GreenLed = LED_ON;
ubhat 0:42863a11464a 236 }
ubhat 0:42863a11464a 237 else
ubhat 0:42863a11464a 238 {
ubhat 0:42863a11464a 239 GreenLed = LED_OFF;
ubhat 0:42863a11464a 240 }
ubhat 0:42863a11464a 241 }
ubhat 0:42863a11464a 242
ubhat 0:42863a11464a 243 TimerLed::TimerLed( eLedType led )
ubhat 0:42863a11464a 244 {
ubhat 0:42863a11464a 245 switch( led )
ubhat 0:42863a11464a 246 {
ubhat 0:42863a11464a 247 case Red:
ubhat 0:42863a11464a 248 {
ubhat 0:42863a11464a 249 TimerInit( &LedTimer, OnRedLedTimerEvent );
ubhat 0:42863a11464a 250 break;
ubhat 0:42863a11464a 251 }
ubhat 0:42863a11464a 252
ubhat 0:42863a11464a 253 case Yellow:
ubhat 0:42863a11464a 254 {
ubhat 0:42863a11464a 255 TimerInit( &LedTimer, OnYellowLedTimerEvent );
ubhat 0:42863a11464a 256 break;
ubhat 0:42863a11464a 257 }
ubhat 0:42863a11464a 258
ubhat 0:42863a11464a 259 case Green:
ubhat 0:42863a11464a 260 {
ubhat 0:42863a11464a 261 TimerInit( &LedTimer, OnGreenLedTimerEvent );
ubhat 0:42863a11464a 262 break;
ubhat 0:42863a11464a 263 }
ubhat 0:42863a11464a 264 }
ubhat 0:42863a11464a 265
ubhat 0:42863a11464a 266 }
ubhat 0:42863a11464a 267
ubhat 0:42863a11464a 268 TimerLed::~TimerLed( )
ubhat 0:42863a11464a 269 {
ubhat 0:42863a11464a 270 }
ubhat 0:42863a11464a 271
ubhat 0:42863a11464a 272 void BlinkLED( eLedType led, uint32_t time )
ubhat 0:42863a11464a 273 {
ubhat 0:42863a11464a 274 switch( led )
ubhat 0:42863a11464a 275 {
ubhat 0:42863a11464a 276 case Red:
ubhat 0:42863a11464a 277 {
ubhat 0:42863a11464a 278 TimerSetValue( &RedLedTimer.LedTimer, time );
ubhat 0:42863a11464a 279 TimerStart( &RedLedTimer.LedTimer );
ubhat 0:42863a11464a 280 RedLed = LED_ON;
ubhat 0:42863a11464a 281 break;
ubhat 0:42863a11464a 282 }
ubhat 0:42863a11464a 283
ubhat 0:42863a11464a 284 case Yellow:
ubhat 0:42863a11464a 285 {
ubhat 0:42863a11464a 286 TimerSetValue( &YellowLedTimer.LedTimer, time );
ubhat 0:42863a11464a 287 TimerStart( &YellowLedTimer.LedTimer );
ubhat 0:42863a11464a 288 YellowLed = LED_ON;
ubhat 0:42863a11464a 289 break;
ubhat 0:42863a11464a 290 }
ubhat 0:42863a11464a 291
ubhat 0:42863a11464a 292 case Green:
ubhat 0:42863a11464a 293 {
ubhat 0:42863a11464a 294 TimerSetValue( &GreenLedTimer.LedTimer, time );
ubhat 0:42863a11464a 295 TimerStart( &GreenLedTimer.LedTimer );
ubhat 0:42863a11464a 296 GreenLed = LED_ON;
ubhat 0:42863a11464a 297 break;
ubhat 0:42863a11464a 298 }
ubhat 0:42863a11464a 299 }
ubhat 0:42863a11464a 300 }
ubhat 0:42863a11464a 301
ubhat 0:42863a11464a 302 void ToggleLED( eLedType led )
ubhat 0:42863a11464a 303 {
ubhat 0:42863a11464a 304 switch( led )
ubhat 0:42863a11464a 305 {
ubhat 0:42863a11464a 306 case Red:
ubhat 0:42863a11464a 307 {
ubhat 0:42863a11464a 308 if( RedLed == LED_OFF )
ubhat 0:42863a11464a 309 {
ubhat 0:42863a11464a 310 RedLed = LED_ON;
ubhat 0:42863a11464a 311 }
ubhat 0:42863a11464a 312 else
ubhat 0:42863a11464a 313 {
ubhat 0:42863a11464a 314 RedLed = LED_OFF;
ubhat 0:42863a11464a 315 }
ubhat 0:42863a11464a 316 break;
ubhat 0:42863a11464a 317 }
ubhat 0:42863a11464a 318
ubhat 0:42863a11464a 319 case Yellow:
ubhat 0:42863a11464a 320 {
ubhat 0:42863a11464a 321 if( YellowLed == LED_OFF )
ubhat 0:42863a11464a 322 {
ubhat 0:42863a11464a 323 YellowLed = LED_ON;
ubhat 0:42863a11464a 324 }
ubhat 0:42863a11464a 325 else
ubhat 0:42863a11464a 326 {
ubhat 0:42863a11464a 327 YellowLed = LED_OFF;
ubhat 0:42863a11464a 328 }
ubhat 0:42863a11464a 329 break;
ubhat 0:42863a11464a 330 }
ubhat 0:42863a11464a 331
ubhat 0:42863a11464a 332 case Green:
ubhat 0:42863a11464a 333 {
ubhat 0:42863a11464a 334 if( GreenLed == LED_OFF )
ubhat 0:42863a11464a 335 {
ubhat 0:42863a11464a 336 GreenLed = LED_ON;
ubhat 0:42863a11464a 337 }
ubhat 0:42863a11464a 338 else
ubhat 0:42863a11464a 339 {
ubhat 0:42863a11464a 340 GreenLed = LED_OFF;
ubhat 0:42863a11464a 341 }
ubhat 0:42863a11464a 342 break;
ubhat 0:42863a11464a 343 }
ubhat 0:42863a11464a 344 }
ubhat 0:42863a11464a 345 }
ubhat 0:42863a11464a 346
ubhat 0:42863a11464a 347 void CtrlLED( eLedType led, uint8_t state )
ubhat 0:42863a11464a 348 {
ubhat 0:42863a11464a 349 switch( led )
ubhat 0:42863a11464a 350 {
ubhat 0:42863a11464a 351 case Red:
ubhat 0:42863a11464a 352 {
ubhat 0:42863a11464a 353 RedLed = state;
ubhat 0:42863a11464a 354 break;
ubhat 0:42863a11464a 355 }
ubhat 0:42863a11464a 356
ubhat 0:42863a11464a 357 case Yellow:
ubhat 0:42863a11464a 358 {
ubhat 0:42863a11464a 359 YellowLed = state;
ubhat 0:42863a11464a 360 break;
ubhat 0:42863a11464a 361 }
ubhat 0:42863a11464a 362
ubhat 0:42863a11464a 363 case Green:
ubhat 0:42863a11464a 364 {
ubhat 0:42863a11464a 365 GreenLed = state;
ubhat 0:42863a11464a 366 break;
ubhat 0:42863a11464a 367 }
ubhat 0:42863a11464a 368
ubhat 0:42863a11464a 369 case Usr:
ubhat 0:42863a11464a 370 {
ubhat 0:42863a11464a 371 if( state )
ubhat 0:42863a11464a 372 {
ubhat 0:42863a11464a 373 UsrLed = LED_ON;
ubhat 0:42863a11464a 374 }
ubhat 0:42863a11464a 375 else
ubhat 0:42863a11464a 376 {
ubhat 0:42863a11464a 377 UsrLed = LED_OFF;
ubhat 0:42863a11464a 378 }
ubhat 0:42863a11464a 379 break;
ubhat 0:42863a11464a 380 }
ubhat 0:42863a11464a 381 }
ubhat 0:42863a11464a 382 }
ubhat 0:42863a11464a 383 */
ubhat 0:42863a11464a 384 void CheckOrientation( void )
ubhat 0:42863a11464a 385 {
ubhat 0:42863a11464a 386 /*
ubhat 0:42863a11464a 387 uint8_t statusReg;
ubhat 0:42863a11464a 388
ubhat 0:42863a11464a 389 // Read the PS_STATUS register
ubhat 0:42863a11464a 390 statusReg = Mma8451q.read_single( MMA8451_PL_STATUS );
ubhat 0:42863a11464a 391
ubhat 0:42863a11464a 392 // If Orientation of the Mote changed then populate Upper Nibble of 0th Byte of Tx Buffer
ubhat 0:42863a11464a 393 if( ( statusReg & 0x40 ) != 0 )
ubhat 0:42863a11464a 394 {
ubhat 0:42863a11464a 395 CtrlLED( Green, LED_OFF );
ubhat 0:42863a11464a 396 VerticalStatus = false; // horizontal
ubhat 0:42863a11464a 397 }
ubhat 0:42863a11464a 398 else
ubhat 0:42863a11464a 399 {
ubhat 0:42863a11464a 400 CtrlLED( Green, LED_ON );
ubhat 0:42863a11464a 401 VerticalStatus = true; // vertical
ubhat 0:42863a11464a 402 }
ubhat 0:42863a11464a 403 */
ubhat 0:42863a11464a 404 }