Proj 324 Final

Fork of ELEC351_Group_T by Plymouth ELEC351 Group T

Committer:
chills
Date:
Wed Dec 27 21:46:31 2017 +0000
Revision:
20:cbb71f84cff9
Parent:
19:54bc302a82ea
Child:
21:3c078c799caa
2017_12_27 21:43; LCD Class Implemented;

Who changed what in which revision?

UserRevisionLine numberNew contents of line
thomasmorris 6:97f586597310 1 /*
thomasmorris 6:97f586597310 2 ELEC 351 Group T
thomasmorris 6:97f586597310 3 Team Members : Christopher Hills, Thomas Morris
thomasmorris 8:0e4481b64353 4 Current Verision 3
thomasmorris 6:97f586597310 5 Overiew: Working Tasks 1,5,7
thomasmorris 8:0e4481b64353 6
thomasmorris 12:536eca338ae8 7 Last Revision: Added Mail Box to serial
thomasmorris 8:0e4481b64353 8 Todo:
thomasmorris 12:536eca338ae8 9 make a mailbox within SD card, LCD, network so they can be used from within
thomasmorris 12:536eca338ae8 10 Fix the network so it uses the mail box data.
thomasmorris 12:536eca338ae8 11 Place the LCD write functions in their own function
thomasmorris 6:97f586597310 12 */
thomasmorris 6:97f586597310 13
thomasmorris 8:0e4481b64353 14 //Includes and Definitions
noutram 1:e1cf7663f5ff 15 #include "sample_hardware.hpp"
noutram 3:a88838ff33e7 16 #include "Networkbits.hpp"
thomasmorris 5:2594b953f111 17 #include "rtos.h"
thomasmorris 5:2594b953f111 18 #include "LED.hpp"
thomasmorris 8:0e4481b64353 19 #include "DATA.hpp"
thomasmorris 8:0e4481b64353 20 #include "NETWORK.hpp"
chills 20:cbb71f84cff9 21 #include "LCD.hpp"
thomasmorris 5:2594b953f111 22 #define SamplingTime 1
thomasmorris 5:2594b953f111 23 #define NotSamplingTime 0
thomasmorris 7:dfe19413fdc2 24 #define Print_Time_to_LCD 1
thomasmorris 7:dfe19413fdc2 25 #define Dont_Print_Time_to_LCD 0
chills 15:c1592fc1a501 26 #define TimerInterval 1 //This is in seconds
thomasmorris 7:dfe19413fdc2 27 #define EDGE_RISEN 1
thomasmorris 7:dfe19413fdc2 28 #define EDGE_FALLEN 0
chills 16:067916791a25 29 #define mailsize 5
thomasmorris 8:0e4481b64353 30
thomasmorris 8:0e4481b64353 31
thomasmorris 5:2594b953f111 32 Serial pc(USBTX, USBRX);
thomasmorris 7:dfe19413fdc2 33 //SW1+SW2 are declared as interrupt ins in sample hardwarec.pp
thomasmorris 8:0e4481b64353 34
thomasmorris 8:0e4481b64353 35
thomasmorris 8:0e4481b64353 36 //Thread IDs
thomasmorris 5:2594b953f111 37 osThreadId idMain;
thomasmorris 5:2594b953f111 38 osThreadId id1;
thomasmorris 5:2594b953f111 39 osThreadId id2;
thomasmorris 5:2594b953f111 40 osThreadId id3;
thomasmorris 5:2594b953f111 41 osThreadId id4;
noutram 0:36e89e3ed7c4 42
thomasmorris 7:dfe19413fdc2 43 Timeout sw1TimeOut;//Used to prevent switch bounce
thomasmorris 7:dfe19413fdc2 44
thomasmorris 5:2594b953f111 45 LED Red_led(PE_15);
thomasmorris 5:2594b953f111 46 LED Yellow_led(PB_10);
thomasmorris 5:2594b953f111 47 LED Green_led(PB_11);
thomasmorris 5:2594b953f111 48
chills 20:cbb71f84cff9 49 LCD LCD(D8,D9,D4,A0,A1,A2,A3,D7,D6,D3,D1);
chills 20:cbb71f84cff9 50
thomasmorris 8:0e4481b64353 51 //Tickers
thomasmorris 8:0e4481b64353 52
thomasmorris 5:2594b953f111 53 Ticker Sample_timer;
thomasmorris 8:0e4481b64353 54
noutram 3:a88838ff33e7 55 //Threads
thomasmorris 5:2594b953f111 56 Thread t1;
thomasmorris 5:2594b953f111 57 Thread t2;
thomasmorris 7:dfe19413fdc2 58 Thread t5;
thomasmorris 7:dfe19413fdc2 59 Thread t6;
thomasmorris 7:dfe19413fdc2 60
thomasmorris 7:dfe19413fdc2 61 double temp = 0;
thomasmorris 7:dfe19413fdc2 62 double pressure = 0;
thomasmorris 7:dfe19413fdc2 63 double lux = 0;
chills 10:46946784326d 64 string buffer_time = 0;
thomasmorris 7:dfe19413fdc2 65
thomasmorris 7:dfe19413fdc2 66 char buffer[32];
chills 15:c1592fc1a501 67 char scom_time_buffer[32];
chills 17:37d883f40c3d 68 char msel_time_buffer[32];
thomasmorris 7:dfe19413fdc2 69
thomasmorris 7:dfe19413fdc2 70 void SW1FallingEdge();
thomasmorris 7:dfe19413fdc2 71 void SW1TimeOutHandler();
thomasmorris 7:dfe19413fdc2 72
thomasmorris 7:dfe19413fdc2 73 int mode = 0;
thomasmorris 7:dfe19413fdc2 74
chills 17:37d883f40c3d 75 Mail<DATA, mailsize> mail_box; //Mail Queue, Type DATA, Capacity mailsize(defined above), name mail_box
thomasmorris 8:0e4481b64353 76
chills 13:db857b3744c6 77 void Network() //Interrupt service routine for handling the timeout
thomasmorris 8:0e4481b64353 78 {
chills 13:db857b3744c6 79 osEvent evt_network = mail_box.get(); //Get the latest entry from "mail_box"
chills 13:db857b3744c6 80
chills 13:db857b3744c6 81 if (evt_network.status == osEventMail)
chills 13:db857b3744c6 82 {
chills 17:37d883f40c3d 83 DATA *Rec_Data_Network = (DATA*)evt_network.value.p; //Create pointer to mailbox
chills 17:37d883f40c3d 84 DATA msg_network; //Create temporary instance of DATA class
chills 13:db857b3744c6 85
chills 17:37d883f40c3d 86 msg_network.set_time(Rec_Data_Network->get_time()); //Copy time from mailbox to temporary instance
chills 17:37d883f40c3d 87 msg_network.set_temperature(Rec_Data_Network->get_temperature()); //Copy temperature from mailbox to temporary instance
chills 17:37d883f40c3d 88 msg_network.set_pressure(Rec_Data_Network->get_pressure()); //Copy pressure from mailbox to temporary instance
chills 17:37d883f40c3d 89 msg_network.set_light(Rec_Data_Network->get_light()); //Copy light from mailbox to temporary instance
chills 17:37d883f40c3d 90 mail_box.free(Rec_Data_Network); //Free space in the mailbox (delete earliest sample taken)
chills 13:db857b3744c6 91
thomasmorris 18:194a606ccd47 92 networktest();
chills 13:db857b3744c6 93 //NETWORK_Print(); //Runs the network
chills 13:db857b3744c6 94 }
chills 13:db857b3744c6 95 }
chills 13:db857b3744c6 96
thomasmorris 8:0e4481b64353 97 void SW1TimeOutHandler()
thomasmorris 8:0e4481b64353 98 {
thomasmorris 7:dfe19413fdc2 99 sw1TimeOut.detach(); //Stop the timeout counter firing
thomasmorris 7:dfe19413fdc2 100 SW1.fall(&SW1FallingEdge); //Now wait for a falling edge
thomasmorris 7:dfe19413fdc2 101 }
thomasmorris 12:536eca338ae8 102 void SDWrite()//End of skype chat
thomasmorris 12:536eca338ae8 103 {
chills 13:db857b3744c6 104 osEvent evt_sd = mail_box.get(); //Get the latest entry from "mail_box"
chills 13:db857b3744c6 105
chills 13:db857b3744c6 106 if (evt_sd.status == osEventMail)
chills 13:db857b3744c6 107 {
chills 17:37d883f40c3d 108 DATA *Rec_Data_SD = (DATA*)evt_sd.value.p; //Create pointer to mailbox
chills 17:37d883f40c3d 109 DATA msg_sd; //Create temporary instance of DATA class
chills 13:db857b3744c6 110
chills 17:37d883f40c3d 111 msg_sd.set_time(Rec_Data_SD->get_time()); //Copy time from mailbox to temporary instance
chills 17:37d883f40c3d 112 msg_sd.set_temperature(Rec_Data_SD->get_temperature()); //Copy temperature from mailbox to temporary instance
chills 17:37d883f40c3d 113 msg_sd.set_pressure(Rec_Data_SD->get_pressure()); //Copy pressure from mailbox to temporary instance
chills 17:37d883f40c3d 114 msg_sd.set_light(Rec_Data_SD->get_light()); //Copy light from mailbox to temporary instance
chills 17:37d883f40c3d 115 mail_box.free(Rec_Data_SD); //Free space in the mailbox (delete earliest sample taken)
chills 13:db857b3744c6 116 }
thomasmorris 12:536eca338ae8 117 }
thomasmorris 7:dfe19413fdc2 118 //Interrupt service routive for SW1 falling edge (release)
thomasmorris 19:54bc302a82ea 119 void SW1FallingEdge()
thomasmorris 19:54bc302a82ea 120 {
thomasmorris 7:dfe19413fdc2 121 SW1.fall(NULL); //Disable this interrupt
chills 16:067916791a25 122 Yellow_led.Toggle(); //Toggle LED
thomasmorris 7:dfe19413fdc2 123
thomasmorris 7:dfe19413fdc2 124 mode = mode +1;//Cycles through modes
thomasmorris 7:dfe19413fdc2 125 if(mode >1)
thomasmorris 7:dfe19413fdc2 126 {
thomasmorris 7:dfe19413fdc2 127 mode = 0;
thomasmorris 7:dfe19413fdc2 128 }
thomasmorris 7:dfe19413fdc2 129
thomasmorris 7:dfe19413fdc2 130 sw1TimeOut.attach(&SW1TimeOutHandler, 0.2); //Start timeout counter
thomasmorris 7:dfe19413fdc2 131 }
thomasmorris 7:dfe19413fdc2 132 void ModeSelection()
thomasmorris 7:dfe19413fdc2 133 {
thomasmorris 7:dfe19413fdc2 134 while(1){
chills 13:db857b3744c6 135
chills 16:067916791a25 136 //Thread::wait(1000);
chills 13:db857b3744c6 137
chills 13:db857b3744c6 138 osEvent evt_lcd = mail_box.get(); //Get the latest entry from "mail_box"
chills 13:db857b3744c6 139
chills 13:db857b3744c6 140 if (evt_lcd.status == osEventMail)
thomasmorris 7:dfe19413fdc2 141 {
chills 17:37d883f40c3d 142 DATA *Rec_Data_LCD = (DATA*)evt_lcd.value.p; //Create pointer to mailbox
chills 17:37d883f40c3d 143 DATA msg_lcd; //Create temporary instance of DATA class
chills 13:db857b3744c6 144
chills 17:37d883f40c3d 145 msg_lcd.set_time(Rec_Data_LCD->get_time()); //Copy time from mailbox to temporary instance
chills 17:37d883f40c3d 146 msg_lcd.set_temperature(Rec_Data_LCD->get_temperature()); //Copy temperature from mailbox to temporary instance
chills 17:37d883f40c3d 147 msg_lcd.set_pressure(Rec_Data_LCD->get_pressure()); //Copy pressure from mailbox to temporary instance
chills 17:37d883f40c3d 148 msg_lcd.set_light(Rec_Data_LCD->get_light()); //Copy light from mailbox to temporary instance
chills 17:37d883f40c3d 149 mail_box.free(Rec_Data_LCD); //Free space in the mailbox (delete earliest sample taken)
chills 13:db857b3744c6 150
chills 13:db857b3744c6 151 if(mode == 0)//Print values to the LCD
chills 13:db857b3744c6 152 {
chills 13:db857b3744c6 153 //Write new data to LCD (not fast!)
chills 13:db857b3744c6 154 lcd.cls();
chills 13:db857b3744c6 155 lcd.printf("Temp Pres li\n");
chills 13:db857b3744c6 156 lcd.printf("%1.1f ", msg_lcd.get_temperature()); //Print Temperature to LCD
chills 13:db857b3744c6 157 lcd.printf("%1.1f ", msg_lcd.get_pressure()); //Print Pressure to LCD
chills 13:db857b3744c6 158 lcd.printf("%1.1f\n", msg_lcd.get_light()); //Print Light to LCD
chills 13:db857b3744c6 159 }
chills 13:db857b3744c6 160 else if(mode == 1)//Print the Time to the LCD
chills 13:db857b3744c6 161 {
chills 17:37d883f40c3d 162 time_t msel_time = msg_lcd.get_time(); //Declare local variable for time
thomasmorris 18:194a606ccd47 163 strftime(scom_time_buffer, 32, "%I:%M %p", localtime(&msel_time)); //Format time as a string
chills 17:37d883f40c3d 164 lcd.cls(); //Write new data to LCD (not fast!)
thomasmorris 18:194a606ccd47 165 lcd.printf("Current Time:%s", scom_time_buffer);
chills 13:db857b3744c6 166 }
chills 13:db857b3744c6 167 else
chills 13:db857b3744c6 168 {
chills 13:db857b3744c6 169 mode = 0;
chills 13:db857b3744c6 170 }
thomasmorris 7:dfe19413fdc2 171 }
thomasmorris 7:dfe19413fdc2 172 }
thomasmorris 7:dfe19413fdc2 173 }
thomasmorris 7:dfe19413fdc2 174
thomasmorris 5:2594b953f111 175 void Serial_Comms()//Thread for Serial Communications
thomasmorris 5:2594b953f111 176 {
thomasmorris 5:2594b953f111 177 while(1)
thomasmorris 5:2594b953f111 178 {
chills 13:db857b3744c6 179 osEvent evt_serial = mail_box.get(); //Get the latest entry from "mail_box"
chills 10:46946784326d 180
chills 13:db857b3744c6 181 if (evt_serial.status == osEventMail)
thomasmorris 12:536eca338ae8 182 {
chills 17:37d883f40c3d 183 DATA *Rec_Data_Serial = (DATA*)evt_serial.value.p; //Create pointer to mailbox
chills 17:37d883f40c3d 184 DATA msg_serial; //Create temporary instance of DATA class
chills 11:e7b5ed6cd3cf 185
chills 17:37d883f40c3d 186 msg_serial.set_time(Rec_Data_Serial->get_time()); //Copy time from mailbox to temporary instance
chills 17:37d883f40c3d 187 msg_serial.set_temperature(Rec_Data_Serial->get_temperature()); //Copy teperature from mailbox to temporary instance
chills 17:37d883f40c3d 188 msg_serial.set_pressure(Rec_Data_Serial->get_pressure()); //Copy pressure from mailbox to temporary instance
chills 17:37d883f40c3d 189 msg_serial.set_light(Rec_Data_Serial->get_light()); //Copy light from mailbox to temporary instance
chills 17:37d883f40c3d 190 mail_box.free(Rec_Data_Serial); //Free space in the mailbox (delete earliest sample taken)
chills 11:e7b5ed6cd3cf 191
chills 17:37d883f40c3d 192 time_t scom_time = msg_serial.get_time(); //Declare local variable for time
chills 17:37d883f40c3d 193 strftime(scom_time_buffer, 32, "%I:%M %p\t", localtime(&scom_time)); //Format time as a string
chills 17:37d883f40c3d 194 pc.printf("Time = %s", scom_time_buffer); //Print the string formatted time
chills 15:c1592fc1a501 195
chills 13:db857b3744c6 196 pc.printf("Temperature = %f\t", msg_serial.get_temperature()); //Print Temperature
chills 13:db857b3744c6 197 pc.printf("Pressure = %f\t", msg_serial.get_pressure()); //Print Pressure
chills 13:db857b3744c6 198 pc.printf("Light = %f\n\r", msg_serial.get_light()); //Print Light
chills 10:46946784326d 199 }
thomasmorris 7:dfe19413fdc2 200 Green_led.Toggle();
chills 16:067916791a25 201 //Thread::wait(1000);
thomasmorris 5:2594b953f111 202 }
thomasmorris 5:2594b953f111 203 }
thomasmorris 5:2594b953f111 204
chills 10:46946784326d 205 void Sample_signal_set() //Sets the Signal for when to sample the sensors
thomasmorris 5:2594b953f111 206 {
chills 10:46946784326d 207 t1.signal_set(SamplingTime); //Set the sampling thread signal high
thomasmorris 5:2594b953f111 208 }
thomasmorris 5:2594b953f111 209 void Sample()//Samples the hardware and prints the result to the LCD
thomasmorris 5:2594b953f111 210 {
thomasmorris 5:2594b953f111 211 while(1)
thomasmorris 5:2594b953f111 212 {
chills 10:46946784326d 213 Thread::signal_wait(SamplingTime); //Set the time between samples
chills 10:46946784326d 214
chills 10:46946784326d 215 temp = sensor.getTemperature(); //Read Temperature
chills 10:46946784326d 216 pressure = sensor.getPressure(); //Read Pressure
chills 10:46946784326d 217 lux = adcIn.read(); //Read Light
chills 16:067916791a25 218 time_t buffer_time = time(NULL); //Read Time
thomasmorris 7:dfe19413fdc2 219
chills 16:067916791a25 220 DATA *Send_Data = mail_box.alloc(); //Allocate a block from the memory pool, Type Data
thomasmorris 5:2594b953f111 221
chills 16:067916791a25 222 if (Send_Data == NULL){ //If Data is empty
chills 16:067916791a25 223 //pc.printf("Out of memory\n\r"); //Print out of memory warning
chills 10:46946784326d 224 return;
chills 10:46946784326d 225 }
chills 10:46946784326d 226
chills 10:46946784326d 227 Send_Data->set_time(buffer_time); //Pass in Time
chills 10:46946784326d 228 Send_Data->set_temperature(temp); //Pass in Temp
chills 10:46946784326d 229 Send_Data->set_pressure(pressure); //Pass in Pres
chills 10:46946784326d 230 Send_Data->set_light(lux); //Pass in Light
chills 10:46946784326d 231
chills 10:46946784326d 232 osStatus stat = mail_box.put(Send_Data); //Puts "Send_Data" into the mailbox
chills 10:46946784326d 233
chills 10:46946784326d 234 if (stat == osErrorResource){ //If mailbox overfills
chills 10:46946784326d 235 //pc.printf("queue->put() Error code: %4Xh, Resource not available\r\n", stat); //Print error message
chills 10:46946784326d 236 mail_box.free(Send_Data); //Free the mail box
chills 10:46946784326d 237 return;
chills 10:46946784326d 238 }
thomasmorris 5:2594b953f111 239 Red_led.Toggle();
thomasmorris 5:2594b953f111 240 t1.signal_set(NotSamplingTime);
thomasmorris 5:2594b953f111 241 }
thomasmorris 5:2594b953f111 242 }
thomasmorris 5:2594b953f111 243 int main()
thomasmorris 5:2594b953f111 244 {
noutram 1:e1cf7663f5ff 245 //Greeting
chills 16:067916791a25 246 pc.printf("Test Start");
chills 16:067916791a25 247 pc.printf("\n\r");
chills 16:067916791a25 248
chills 10:46946784326d 249 set_time(1512940530); //Set RTC time to December 10 2017
chills 10:46946784326d 250 pc.baud(9600); //Sets the Serial Comms Baud Rate
thomasmorris 5:2594b953f111 251
chills 20:cbb71f84cff9 252 LCD.Initialise();
chills 20:cbb71f84cff9 253 LCD.DDRAM_Address(0x40);
chills 20:cbb71f84cff9 254 LCD.Write_String("Hi Tom 21:41");
chills 20:cbb71f84cff9 255
chills 20:cbb71f84cff9 256
chills 15:c1592fc1a501 257 /*
chills 10:46946784326d 258 post(); //Power on Self Test
noutram 1:e1cf7663f5ff 259
noutram 3:a88838ff33e7 260 //Initialise the SD card (this needs to move)
noutram 1:e1cf7663f5ff 261 if ( sd.init() != 0) {
noutram 1:e1cf7663f5ff 262 printf("Init failed \n");
noutram 3:a88838ff33e7 263 lcd.cls();
noutram 3:a88838ff33e7 264 lcd.printf("CANNOT INIT SD");
noutram 1:e1cf7663f5ff 265 errorCode(FATAL);
noutram 1:e1cf7663f5ff 266 }
noutram 1:e1cf7663f5ff 267
noutram 1:e1cf7663f5ff 268 //Create a filing system for SD Card
noutram 1:e1cf7663f5ff 269 FATFileSystem fs("sd", &sd);
noutram 0:36e89e3ed7c4 270
noutram 1:e1cf7663f5ff 271 //Open to WRITE
noutram 1:e1cf7663f5ff 272 FILE* fp = fopen("/sd/test.csv","a");
noutram 1:e1cf7663f5ff 273 if (fp == NULL) {
noutram 1:e1cf7663f5ff 274 error("Could not open file for write\n");
noutram 3:a88838ff33e7 275 lcd.cls();
noutram 3:a88838ff33e7 276 lcd.printf("CANNOT OPEN FILE\n\n");
noutram 1:e1cf7663f5ff 277 errorCode(FATAL);
noutram 1:e1cf7663f5ff 278 }
noutram 3:a88838ff33e7 279
noutram 3:a88838ff33e7 280 //Last message before sampling begins
noutram 3:a88838ff33e7 281 lcd.cls();
noutram 3:a88838ff33e7 282 lcd.printf("READY\n\n");
chills 15:c1592fc1a501 283 */
thomasmorris 5:2594b953f111 284
thomasmorris 5:2594b953f111 285 //Run interrupt
thomasmorris 5:2594b953f111 286 Sample_timer.attach(&Sample_signal_set,TimerInterval);
thomasmorris 7:dfe19413fdc2 287 SW1.fall(&SW1FallingEdge);
thomasmorris 5:2594b953f111 288 //Run Threads
thomasmorris 5:2594b953f111 289
thomasmorris 5:2594b953f111 290 t1.start(Sample);
thomasmorris 5:2594b953f111 291 t2.start(Serial_Comms);
chills 20:cbb71f84cff9 292 //t5.start(ModeSelection);
thomasmorris 18:194a606ccd47 293 t6.start(Network);
thomasmorris 5:2594b953f111 294 //Main thread ID
thomasmorris 5:2594b953f111 295
thomasmorris 5:2594b953f111 296 idMain = osThreadGetId(); //CMSIS RTOS call
thomasmorris 5:2594b953f111 297
thomasmorris 5:2594b953f111 298 //Thread ID
thomasmorris 5:2594b953f111 299 id1 = t1.gettid();
thomasmorris 5:2594b953f111 300 id2 = t2.gettid();
thomasmorris 8:0e4481b64353 301 //id5 = t5.gettid();
thomasmorris 5:2594b953f111 302
thomasmorris 5:2594b953f111 303 //Toggle Green LED after a button has been pressed
noutram 1:e1cf7663f5ff 304 //Press either switch to unmount
thomasmorris 7:dfe19413fdc2 305 DigitalIn onBoardSwitch(USER_BUTTON);
thomasmorris 7:dfe19413fdc2 306 while (onBoardSwitch == 0){
thomasmorris 7:dfe19413fdc2 307
noutram 1:e1cf7663f5ff 308 }
noutram 1:e1cf7663f5ff 309
noutram 1:e1cf7663f5ff 310 //Close File
chills 15:c1592fc1a501 311 /*
noutram 1:e1cf7663f5ff 312 fclose(fp);
noutram 1:e1cf7663f5ff 313
noutram 1:e1cf7663f5ff 314 //Close down
noutram 1:e1cf7663f5ff 315 sd.deinit();
noutram 1:e1cf7663f5ff 316 printf("Unmounted...\n");
noutram 1:e1cf7663f5ff 317 lcd.cls();
noutram 1:e1cf7663f5ff 318 lcd.printf("Unmounted...\n\n");
chills 15:c1592fc1a501 319 */
noutram 1:e1cf7663f5ff 320
noutram 1:e1cf7663f5ff 321 while(true) {
noutram 1:e1cf7663f5ff 322 greenLED = 1;
noutram 1:e1cf7663f5ff 323 wait(0.5);
noutram 1:e1cf7663f5ff 324 greenLED = 0;
noutram 1:e1cf7663f5ff 325 wait(0.1);
noutram 0:36e89e3ed7c4 326 }
noutram 0:36e89e3ed7c4 327 }
noutram 0:36e89e3ed7c4 328
noutram 1:e1cf7663f5ff 329
noutram 1:e1cf7663f5ff 330