Bootload from SD card to sector 0, and jump to sector 24 where new firmware resides

Dependencies:   FatFS mbed

Fork of Panel-Controller-Bootloader by Emma

Committer:
bonchenko
Date:
Wed Apr 22 10:18:55 2015 +0000
Revision:
2:0fa89ba8f6fe
Parent:
0:c3a652eff606
Bootloader from SD card works perfectly. Compiled with offset in EmBlocks, ADE cannot print readings - but its happened without bootloader too. The problem is Emblocks compiler settings

Who changed what in which revision?

UserRevisionLine numberNew contents of line
bonchenko 0:c3a652eff606 1 /*-------------------------------------------------------------------------- */
bonchenko 0:c3a652eff606 2 /* RTC controls for STM32 */
bonchenko 0:c3a652eff606 3 /* Copyright (c) 2009, Martin Thomas 4/2009, 3BSD-license */
bonchenko 0:c3a652eff606 4 /* partly based on code from STMircoelectronics, Peter Dannegger, "LaLaDumm" */
bonchenko 0:c3a652eff606 5 /*-------------------------------------------------------------------------- */
bonchenko 0:c3a652eff606 6
bonchenko 0:c3a652eff606 7 #include <stdint.h>
bonchenko 0:c3a652eff606 8 #include <stdbool.h>
bonchenko 0:c3a652eff606 9 #include "stm32f10x.h"
bonchenko 0:c3a652eff606 10 #include "rtc.h"
bonchenko 0:c3a652eff606 11
bonchenko 0:c3a652eff606 12 #define FIRSTYEAR 2000 // start year
bonchenko 0:c3a652eff606 13 #define FIRSTDAY 6 // 0 = Sunday
bonchenko 0:c3a652eff606 14
bonchenko 0:c3a652eff606 15 static const uint8_t DaysInMonth[] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
bonchenko 0:c3a652eff606 16
bonchenko 0:c3a652eff606 17 /*******************************************************************************
bonchenko 0:c3a652eff606 18 * Function Name : isDST
bonchenko 0:c3a652eff606 19 * Description : checks if given time is in Daylight Saving time-span.
bonchenko 0:c3a652eff606 20 * Input : time-struct, must be fully populated including weekday
bonchenko 0:c3a652eff606 21 * Output : none
bonchenko 0:c3a652eff606 22 * Return : false: no DST ("winter"), true: in DST ("summer")
bonchenko 0:c3a652eff606 23 * DST according to German standard
bonchenko 0:c3a652eff606 24 * Based on code from Peter Dannegger found in the microcontroller.net forum.
bonchenko 0:c3a652eff606 25 *******************************************************************************/
bonchenko 0:c3a652eff606 26 static bool isDST( const RTC_t *t )
bonchenko 0:c3a652eff606 27 {
bonchenko 0:c3a652eff606 28 uint8_t wday, month; // locals for faster access
bonchenko 0:c3a652eff606 29
bonchenko 0:c3a652eff606 30 month = t->month;
bonchenko 0:c3a652eff606 31
bonchenko 0:c3a652eff606 32 if( month < 3 || month > 10 ) { // month 1, 2, 11, 12
bonchenko 0:c3a652eff606 33 return false; // -> Winter
bonchenko 0:c3a652eff606 34 }
bonchenko 0:c3a652eff606 35
bonchenko 0:c3a652eff606 36 wday = t->wday;
bonchenko 0:c3a652eff606 37
bonchenko 0:c3a652eff606 38 if( t->mday - wday >= 25 && (wday || t->hour >= 2) ) { // after last Sunday 2:00
bonchenko 0:c3a652eff606 39 if( month == 10 ) { // October -> Winter
bonchenko 0:c3a652eff606 40 return false;
bonchenko 0:c3a652eff606 41 }
bonchenko 0:c3a652eff606 42 } else { // before last Sunday 2:00
bonchenko 0:c3a652eff606 43 if( month == 3 ) { // March -> Winter
bonchenko 0:c3a652eff606 44 return false;
bonchenko 0:c3a652eff606 45 }
bonchenko 0:c3a652eff606 46 }
bonchenko 0:c3a652eff606 47
bonchenko 0:c3a652eff606 48 return true;
bonchenko 0:c3a652eff606 49 }
bonchenko 0:c3a652eff606 50
bonchenko 0:c3a652eff606 51 /*******************************************************************************
bonchenko 0:c3a652eff606 52 * Function Name : adjustDST
bonchenko 0:c3a652eff606 53 * Description : adjusts time to DST if needed
bonchenko 0:c3a652eff606 54 * Input : non DST time-struct, must be fully populated including weekday
bonchenko 0:c3a652eff606 55 * Output : time-stuct gets modified
bonchenko 0:c3a652eff606 56 * Return : false: no DST ("winter"), true: in DST ("summer")
bonchenko 0:c3a652eff606 57 * DST according to German standard
bonchenko 0:c3a652eff606 58 * Based on code from Peter Dannegger found in the microcontroller.net forum.
bonchenko 0:c3a652eff606 59 *******************************************************************************/
bonchenko 0:c3a652eff606 60 static bool adjustDST( RTC_t *t )
bonchenko 0:c3a652eff606 61 {
bonchenko 0:c3a652eff606 62 uint8_t hour, day, wday, month; // locals for faster access
bonchenko 0:c3a652eff606 63
bonchenko 0:c3a652eff606 64 hour = t->hour;
bonchenko 0:c3a652eff606 65 day = t->mday;
bonchenko 0:c3a652eff606 66 wday = t->wday;
bonchenko 0:c3a652eff606 67 month = t->month;
bonchenko 0:c3a652eff606 68
bonchenko 0:c3a652eff606 69 if ( isDST(t) ) {
bonchenko 0:c3a652eff606 70 t->dst = 1;
bonchenko 0:c3a652eff606 71 hour++; // add one hour
bonchenko 0:c3a652eff606 72 if( hour == 24 ){ // next day
bonchenko 0:c3a652eff606 73 hour = 0;
bonchenko 0:c3a652eff606 74 wday++; // next weekday
bonchenko 0:c3a652eff606 75 if( wday == 7 ) {
bonchenko 0:c3a652eff606 76 wday = 0;
bonchenko 0:c3a652eff606 77 }
bonchenko 0:c3a652eff606 78 if( day == DaysInMonth[month-1] ) { // next month
bonchenko 0:c3a652eff606 79 day = 0;
bonchenko 0:c3a652eff606 80 month++;
bonchenko 0:c3a652eff606 81 }
bonchenko 0:c3a652eff606 82 day++;
bonchenko 0:c3a652eff606 83 }
bonchenko 0:c3a652eff606 84 t->month = month;
bonchenko 0:c3a652eff606 85 t->hour = hour;
bonchenko 0:c3a652eff606 86 t->mday = day;
bonchenko 0:c3a652eff606 87 t->wday = wday;
bonchenko 0:c3a652eff606 88 return true;
bonchenko 0:c3a652eff606 89 } else {
bonchenko 0:c3a652eff606 90 t->dst = 0;
bonchenko 0:c3a652eff606 91 return false;
bonchenko 0:c3a652eff606 92 }
bonchenko 0:c3a652eff606 93 }
bonchenko 0:c3a652eff606 94
bonchenko 0:c3a652eff606 95 /*******************************************************************************
bonchenko 0:c3a652eff606 96 * Function Name : counter_to_struct
bonchenko 0:c3a652eff606 97 * Description : populates time-struct based on counter-value
bonchenko 0:c3a652eff606 98 * Input : - counter-value (unit seconds, 0 -> 1.1.2000 00:00:00),
bonchenko 0:c3a652eff606 99 * - Pointer to time-struct
bonchenko 0:c3a652eff606 100 * Output : time-struct gets populated, DST not taken into account here
bonchenko 0:c3a652eff606 101 * Return : none
bonchenko 0:c3a652eff606 102 * Based on code from Peter Dannegger found in the microcontroller.net forum.
bonchenko 0:c3a652eff606 103 *******************************************************************************/
bonchenko 0:c3a652eff606 104 static void counter_to_struct( uint32_t sec, RTC_t *t )
bonchenko 0:c3a652eff606 105 {
bonchenko 0:c3a652eff606 106 uint16_t day;
bonchenko 0:c3a652eff606 107 uint8_t year;
bonchenko 0:c3a652eff606 108 uint16_t dayofyear;
bonchenko 0:c3a652eff606 109 uint8_t leap400;
bonchenko 0:c3a652eff606 110 uint8_t month;
bonchenko 0:c3a652eff606 111
bonchenko 0:c3a652eff606 112 t->sec = sec % 60;
bonchenko 0:c3a652eff606 113 sec /= 60;
bonchenko 0:c3a652eff606 114 t->min = sec % 60;
bonchenko 0:c3a652eff606 115 sec /= 60;
bonchenko 0:c3a652eff606 116 t->hour = sec % 24;
bonchenko 0:c3a652eff606 117 day = (uint16_t)(sec / 24);
bonchenko 0:c3a652eff606 118
bonchenko 0:c3a652eff606 119 t->wday = (day + FIRSTDAY) % 7; // weekday
bonchenko 0:c3a652eff606 120
bonchenko 0:c3a652eff606 121 year = FIRSTYEAR % 100; // 0..99
bonchenko 0:c3a652eff606 122 leap400 = 4 - ((FIRSTYEAR - 1) / 100 & 3); // 4, 3, 2, 1
bonchenko 0:c3a652eff606 123
bonchenko 0:c3a652eff606 124 for(;;) {
bonchenko 0:c3a652eff606 125 dayofyear = 365;
bonchenko 0:c3a652eff606 126 if( (year & 3) == 0 ) {
bonchenko 0:c3a652eff606 127 dayofyear = 366; // leap year
bonchenko 0:c3a652eff606 128 if( year == 0 || year == 100 || year == 200 ) { // 100 year exception
bonchenko 0:c3a652eff606 129 if( --leap400 ) { // 400 year exception
bonchenko 0:c3a652eff606 130 dayofyear = 365;
bonchenko 0:c3a652eff606 131 }
bonchenko 0:c3a652eff606 132 }
bonchenko 0:c3a652eff606 133 }
bonchenko 0:c3a652eff606 134 if( day < dayofyear ) {
bonchenko 0:c3a652eff606 135 break;
bonchenko 0:c3a652eff606 136 }
bonchenko 0:c3a652eff606 137 day -= dayofyear;
bonchenko 0:c3a652eff606 138 year++; // 00..136 / 99..235
bonchenko 0:c3a652eff606 139 }
bonchenko 0:c3a652eff606 140 t->year = year + FIRSTYEAR / 100 * 100; // + century
bonchenko 0:c3a652eff606 141
bonchenko 0:c3a652eff606 142 if( dayofyear & 1 && day > 58 ) { // no leap year and after 28.2.
bonchenko 0:c3a652eff606 143 day++; // skip 29.2.
bonchenko 0:c3a652eff606 144 }
bonchenko 0:c3a652eff606 145
bonchenko 0:c3a652eff606 146 for( month = 1; day >= DaysInMonth[month-1]; month++ ) {
bonchenko 0:c3a652eff606 147 day -= DaysInMonth[month-1];
bonchenko 0:c3a652eff606 148 }
bonchenko 0:c3a652eff606 149
bonchenko 0:c3a652eff606 150 t->month = month; // 1..12
bonchenko 0:c3a652eff606 151 t->mday = day + 1; // 1..31
bonchenko 0:c3a652eff606 152 }
bonchenko 0:c3a652eff606 153
bonchenko 0:c3a652eff606 154 /*******************************************************************************
bonchenko 0:c3a652eff606 155 * Function Name : struct_to_counter
bonchenko 0:c3a652eff606 156 * Description : calculates second-counter from populated time-struct
bonchenko 0:c3a652eff606 157 * Input : Pointer to time-struct
bonchenko 0:c3a652eff606 158 * Output : none
bonchenko 0:c3a652eff606 159 * Return : counter-value (unit seconds, 0 -> 1.1.2000 00:00:00),
bonchenko 0:c3a652eff606 160 * Based on code from "LalaDumm" found in the microcontroller.net forum.
bonchenko 0:c3a652eff606 161 *******************************************************************************/
bonchenko 0:c3a652eff606 162 static uint32_t struct_to_counter( const RTC_t *t )
bonchenko 0:c3a652eff606 163 {
bonchenko 0:c3a652eff606 164 uint8_t i;
bonchenko 0:c3a652eff606 165 uint32_t result = 0;
bonchenko 0:c3a652eff606 166 uint16_t idx, year;
bonchenko 0:c3a652eff606 167
bonchenko 0:c3a652eff606 168 year = t->year;
bonchenko 0:c3a652eff606 169
bonchenko 0:c3a652eff606 170 /* Calculate days of years before */
bonchenko 0:c3a652eff606 171 result = (uint32_t)year * 365;
bonchenko 0:c3a652eff606 172 if (t->year >= 1) {
bonchenko 0:c3a652eff606 173 result += (year + 3) / 4;
bonchenko 0:c3a652eff606 174 result -= (year - 1) / 100;
bonchenko 0:c3a652eff606 175 result += (year - 1) / 400;
bonchenko 0:c3a652eff606 176 }
bonchenko 0:c3a652eff606 177
bonchenko 0:c3a652eff606 178 /* Start with 2000 a.d. */
bonchenko 0:c3a652eff606 179 result -= 730485UL;
bonchenko 0:c3a652eff606 180
bonchenko 0:c3a652eff606 181 /* Make month an array index */
bonchenko 0:c3a652eff606 182 idx = t->month - 1;
bonchenko 0:c3a652eff606 183
bonchenko 0:c3a652eff606 184 /* Loop thru each month, adding the days */
bonchenko 0:c3a652eff606 185 for (i = 0; i < idx; i++) {
bonchenko 0:c3a652eff606 186 result += DaysInMonth[i];
bonchenko 0:c3a652eff606 187 }
bonchenko 0:c3a652eff606 188
bonchenko 0:c3a652eff606 189 /* Leap year? adjust February */
bonchenko 0:c3a652eff606 190 if (year%400 == 0 || (year%4 == 0 && year%100 !=0)) {
bonchenko 0:c3a652eff606 191 ;
bonchenko 0:c3a652eff606 192 } else {
bonchenko 0:c3a652eff606 193 if (t->month > 1) {
bonchenko 0:c3a652eff606 194 result--;
bonchenko 0:c3a652eff606 195 }
bonchenko 0:c3a652eff606 196 }
bonchenko 0:c3a652eff606 197
bonchenko 0:c3a652eff606 198 /* Add remaining days */
bonchenko 0:c3a652eff606 199 result += t->mday;
bonchenko 0:c3a652eff606 200
bonchenko 0:c3a652eff606 201 /* Convert to seconds, add all the other stuff */
bonchenko 0:c3a652eff606 202 result = (result-1) * 86400L + (uint32_t)t->hour * 3600 +
bonchenko 0:c3a652eff606 203 (uint32_t)t->min * 60 + t->sec;
bonchenko 0:c3a652eff606 204
bonchenko 0:c3a652eff606 205 return result;
bonchenko 0:c3a652eff606 206 }
bonchenko 0:c3a652eff606 207
bonchenko 0:c3a652eff606 208 /*******************************************************************************
bonchenko 0:c3a652eff606 209 * Function Name : rtc_gettime
bonchenko 0:c3a652eff606 210 * Description : populates structure from HW-RTC, takes DST into account
bonchenko 0:c3a652eff606 211 * Input : None
bonchenko 0:c3a652eff606 212 * Output : time-struct gets modified
bonchenko 0:c3a652eff606 213 * Return : always true/not used
bonchenko 0:c3a652eff606 214 *******************************************************************************/
bonchenko 0:c3a652eff606 215 bool rtc_gettime (RTC_t *rtc)
bonchenko 0:c3a652eff606 216 {
bonchenko 0:c3a652eff606 217 uint32_t t;
bonchenko 0:c3a652eff606 218
bonchenko 0:c3a652eff606 219 while ( ( t = RTC_GetCounter() ) != RTC_GetCounter() ) { ; }
bonchenko 0:c3a652eff606 220 counter_to_struct( t, rtc ); // get non DST time
bonchenko 0:c3a652eff606 221 adjustDST( rtc );
bonchenko 0:c3a652eff606 222
bonchenko 0:c3a652eff606 223 return true;
bonchenko 0:c3a652eff606 224 }
bonchenko 0:c3a652eff606 225
bonchenko 0:c3a652eff606 226 /*******************************************************************************
bonchenko 0:c3a652eff606 227 * Function Name : my_RTC_SetCounter
bonchenko 0:c3a652eff606 228 * Description : sets the hardware-counter
bonchenko 0:c3a652eff606 229 * Input : new counter-value
bonchenko 0:c3a652eff606 230 * Output : None
bonchenko 0:c3a652eff606 231 * Return : None
bonchenko 0:c3a652eff606 232 *******************************************************************************/
bonchenko 0:c3a652eff606 233 static void my_RTC_SetCounter(uint32_t cnt)
bonchenko 0:c3a652eff606 234 {
bonchenko 0:c3a652eff606 235 /* Wait until last write operation on RTC registers has finished */
bonchenko 0:c3a652eff606 236 RTC_WaitForLastTask();
bonchenko 0:c3a652eff606 237 /* Change the current time */
bonchenko 0:c3a652eff606 238 RTC_SetCounter(cnt);
bonchenko 0:c3a652eff606 239 /* Wait until last write operation on RTC registers has finished */
bonchenko 0:c3a652eff606 240 RTC_WaitForLastTask();
bonchenko 0:c3a652eff606 241 }
bonchenko 0:c3a652eff606 242
bonchenko 0:c3a652eff606 243 /*******************************************************************************
bonchenko 0:c3a652eff606 244 * Function Name : rtc_settime
bonchenko 0:c3a652eff606 245 * Description : sets HW-RTC with values from time-struct, takes DST into
bonchenko 0:c3a652eff606 246 * account, HW-RTC always running in non-DST time
bonchenko 0:c3a652eff606 247 * Input : None
bonchenko 0:c3a652eff606 248 * Output : None
bonchenko 0:c3a652eff606 249 * Return : not used
bonchenko 0:c3a652eff606 250 *******************************************************************************/
bonchenko 0:c3a652eff606 251 bool rtc_settime (const RTC_t *rtc)
bonchenko 0:c3a652eff606 252 {
bonchenko 0:c3a652eff606 253 uint32_t cnt;
bonchenko 0:c3a652eff606 254 RTC_t ts;
bonchenko 0:c3a652eff606 255
bonchenko 0:c3a652eff606 256 cnt = struct_to_counter( rtc ); // non-DST counter-value
bonchenko 0:c3a652eff606 257 counter_to_struct( cnt, &ts ); // normalize struct (for weekday)
bonchenko 0:c3a652eff606 258 if ( isDST( &ts ) ) {
bonchenko 0:c3a652eff606 259 cnt -= 60*60; // Subtract one hour
bonchenko 0:c3a652eff606 260 }
bonchenko 0:c3a652eff606 261 PWR_BackupAccessCmd(ENABLE);
bonchenko 0:c3a652eff606 262 my_RTC_SetCounter( cnt );
bonchenko 0:c3a652eff606 263 PWR_BackupAccessCmd(DISABLE);
bonchenko 0:c3a652eff606 264
bonchenko 0:c3a652eff606 265 return true;
bonchenko 0:c3a652eff606 266 }
bonchenko 0:c3a652eff606 267
bonchenko 0:c3a652eff606 268 /*******************************************************************************
bonchenko 0:c3a652eff606 269 * Function Name : rtc_init
bonchenko 0:c3a652eff606 270 * Description : initializes HW RTC,
bonchenko 0:c3a652eff606 271 * sets default time-stamp if RTC has not been initialized before
bonchenko 0:c3a652eff606 272 * Input : None
bonchenko 0:c3a652eff606 273 * Output : None
bonchenko 0:c3a652eff606 274 * Return : not used
bonchenko 0:c3a652eff606 275 * Based on code from a STM RTC example in the StdPeriph-Library package
bonchenko 0:c3a652eff606 276 *******************************************************************************/
bonchenko 0:c3a652eff606 277 int rtc_init(void)
bonchenko 0:c3a652eff606 278 {
bonchenko 0:c3a652eff606 279 volatile uint16_t i;
bonchenko 0:c3a652eff606 280
bonchenko 0:c3a652eff606 281 /* Enable PWR and BKP clocks */
bonchenko 0:c3a652eff606 282 RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
bonchenko 0:c3a652eff606 283
bonchenko 0:c3a652eff606 284 /* LSI clock stabilization time */
bonchenko 0:c3a652eff606 285 for(i=0;i<5000;i++) { ; }
bonchenko 0:c3a652eff606 286
bonchenko 0:c3a652eff606 287 if (BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5) {
bonchenko 0:c3a652eff606 288 /* Backup data register value is not correct or not yet programmed (when
bonchenko 0:c3a652eff606 289 the first time the program is executed) */
bonchenko 0:c3a652eff606 290
bonchenko 0:c3a652eff606 291 /* Allow access to BKP Domain */
bonchenko 0:c3a652eff606 292 PWR_BackupAccessCmd(ENABLE);
bonchenko 0:c3a652eff606 293
bonchenko 0:c3a652eff606 294 /* Reset Backup Domain */
bonchenko 0:c3a652eff606 295 BKP_DeInit();
bonchenko 0:c3a652eff606 296
bonchenko 0:c3a652eff606 297 /* Enable LSE */
bonchenko 0:c3a652eff606 298 RCC_LSEConfig(RCC_LSE_ON);
bonchenko 0:c3a652eff606 299
bonchenko 0:c3a652eff606 300 /* Wait till LSE is ready */
bonchenko 0:c3a652eff606 301 while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET) { ; }
bonchenko 0:c3a652eff606 302
bonchenko 0:c3a652eff606 303 /* Select LSE as RTC Clock Source */
bonchenko 0:c3a652eff606 304 RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
bonchenko 0:c3a652eff606 305
bonchenko 0:c3a652eff606 306 /* Enable RTC Clock */
bonchenko 0:c3a652eff606 307 RCC_RTCCLKCmd(ENABLE);
bonchenko 0:c3a652eff606 308
bonchenko 0:c3a652eff606 309 /* Wait for RTC registers synchronization */
bonchenko 0:c3a652eff606 310 RTC_WaitForSynchro();
bonchenko 0:c3a652eff606 311
bonchenko 0:c3a652eff606 312 /* Wait until last write operation on RTC registers has finished */
bonchenko 0:c3a652eff606 313 RTC_WaitForLastTask();
bonchenko 0:c3a652eff606 314
bonchenko 0:c3a652eff606 315 /* Set RTC prescaler: set RTC period to 1sec */
bonchenko 0:c3a652eff606 316 RTC_SetPrescaler(32767); /* RTC period = RTCCLK/RTC_PR = (32.768 KHz)/(32767+1) */
bonchenko 0:c3a652eff606 317
bonchenko 0:c3a652eff606 318 /* Wait until last write operation on RTC registers has finished */
bonchenko 0:c3a652eff606 319 RTC_WaitForLastTask();
bonchenko 0:c3a652eff606 320
bonchenko 0:c3a652eff606 321 /* Set initial value */
bonchenko 0:c3a652eff606 322 RTC_SetCounter( (uint32_t)((11*60+55)*60) ); // here: 1st January 2000 11:55:00
bonchenko 0:c3a652eff606 323
bonchenko 0:c3a652eff606 324 /* Wait until last write operation on RTC registers has finished */
bonchenko 0:c3a652eff606 325 RTC_WaitForLastTask();
bonchenko 0:c3a652eff606 326
bonchenko 0:c3a652eff606 327 BKP_WriteBackupRegister(BKP_DR1, 0xA5A5);
bonchenko 0:c3a652eff606 328
bonchenko 0:c3a652eff606 329 /* Lock access to BKP Domain */
bonchenko 0:c3a652eff606 330 PWR_BackupAccessCmd(DISABLE);
bonchenko 0:c3a652eff606 331
bonchenko 0:c3a652eff606 332 } else {
bonchenko 0:c3a652eff606 333
bonchenko 0:c3a652eff606 334 /* Wait for RTC registers synchronization */
bonchenko 0:c3a652eff606 335 RTC_WaitForSynchro();
bonchenko 0:c3a652eff606 336
bonchenko 0:c3a652eff606 337 }
bonchenko 0:c3a652eff606 338
bonchenko 0:c3a652eff606 339 return 0;
bonchenko 0:c3a652eff606 340 }
bonchenko 0:c3a652eff606 341
bonchenko 0:c3a652eff606 342
bonchenko 0:c3a652eff606 343