Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: mbed BufferedSerial SX1276GenericLib OLED_SSD1306 HELIOS_Si7021 NVProperty RadioShuttle-STM32L4 USBDeviceHT
utils.cpp
00001 /* 00002 * Copyright (c) 2019 Helmut Tschemernjak 00003 * 30826 Garbsen (Hannover) Germany 00004 */ 00005 #include "main.h" 00006 #include "GenericPingPong.h" 00007 #include "RadioTest.h" 00008 #ifdef TOOLCHAIN_GCC 00009 #include <malloc.h> 00010 #endif 00011 volatile uint32_t PendingInterrupts; // global interrupt mask of received interrupts 00012 00013 time_t cvt_date(char const *date, char const *time); 00014 00015 static float GetBrownOutVolt(void); 00016 #ifdef FEATURE_SI7021 00017 HELIOS_Si7021 *sensorSI7021; 00018 #endif 00019 BufferedSerial *ser; 00020 #ifdef FEATURE_USBSERIAL 00021 USBSerialBuffered *usb; 00022 #endif 00023 bool _useDprintf; 00024 00025 void InitSerial(int timeout, DigitalOut *led, InterruptIn *intr) 00026 { 00027 _useDprintf = true; 00028 bool uartActive = true; 00029 00030 #ifdef FEATURE_USBSERIAL 00031 DigitalOut rx(USBRX); // need to turn rx low to avoid floating signal 00032 rx = 0; 00033 DigitalIn uartRX(USBRX); 00034 uartActive = uartRX.read(); 00035 if (!uartActive) { 00036 usb = new USBSerialBuffered(); 00037 Timer t; 00038 t.start(); 00039 while(!usb->connected()) { 00040 if (led) 00041 *led = !*led; 00042 wait_ms(100); 00043 if (timeout) { 00044 if (t.read_ms() >= timeout || (intr && intr->read())) { 00045 delete usb; 00046 usb = NULL; 00047 DigitalOut rx(USBRX); 00048 rx = 0; // need to turn tx low to avoid floating signal 00049 break; 00050 } 00051 } 00052 } 00053 } 00054 #endif 00055 if (uartActive) { 00056 ser = new BufferedSerial(USBTX, USBRX); 00057 ser->baud(230400); 00058 ser->format(8); 00059 } 00060 00061 time_t t = cvt_date(__DATE__, __TIME__); 00062 if (t > time(NULL)) { 00063 set_time(t); 00064 } 00065 } 00066 00067 void RunStartup(void) 00068 { 00069 rprintf("\r\n"); 00070 int mbedversion = 9999; 00071 #ifdef MBED_LIBRARY_VERSION // not available in mbed head compiles 00072 mbedversion = MBED_LIBRARY_VERSION; 00073 #endif 00074 dprintf("Turtle: %d.%d (%s %s mbed: v%d)", MAJOR_VERSION, MINOR_VERSION, __DATE__, __TIME__, mbedversion); 00075 00076 dprintf("SysClock: %u Hz.", (unsigned int)SystemCoreClock); 00077 #ifdef __ARMCC_VERSION 00078 dprintf("ARM Compiler Version: 0x%x", __ARMCC_VERSION); 00079 #elif __GNUC__ 00080 dprintf("GCC Compiler Version: %d.%d.%d", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__); 00081 #endif 00082 00083 const char *errstr; 00084 if (__HAL_RCC_GET_FLAG(RCC_FLAG_BORRST) != RESET) 00085 errstr = "RESET OCCURRED"; 00086 else 00087 errstr = "initalized"; 00088 00089 dprintf("Brown Out Reset %s (%1.1f V)", errstr, GetBrownOutVolt()); 00090 dprintf("Voltage: %.2f (%s powered)", BatteryVoltage(), BatterySource()); 00091 dprintf("InitDefaults Done"); 00092 MemoryAvailable(true); 00093 __HAL_RCC_CLEAR_RESET_FLAGS(); 00094 #ifdef FEATURE_SI7021 00095 sensorSI7021 = new HELIOS_Si7021(SI7021_SDA, SI7021_SCL); 00096 if (sensorSI7021->hasSensor()) { 00097 dprintf("%s: Rev(%d) %.2f°C Humidity: %.2f%%", sensorSI7021->getModelName(), sensorSI7021->getRevision(), sensorSI7021->readTemperature(), sensorSI7021->readHumidity()); 00098 } 00099 #endif 00100 00101 } 00102 void printTimeStamp() 00103 { 00104 static LowPowerTimer *timer; 00105 if (!timer) { 00106 timer = new LowPowerTimer(); 00107 timer->start(); 00108 } 00109 time_t seconds = time(NULL); 00110 struct tm *tm = localtime(&seconds); 00111 int usecs = timer->read_us(); 00112 if (usecs < 0) { 00113 usecs = 0; 00114 timer->stop(); 00115 timer->reset(); 00116 timer->start(); 00117 } 00118 int msecs = usecs % 1000000; 00119 00120 rprintf("%02d:%02d:%02d.%06d ", tm->tm_hour, tm->tm_min, tm->tm_sec, msecs); 00121 } 00122 00123 void dprintf(const char *format, ...) 00124 { 00125 std::va_list arg; 00126 00127 va_start(arg, format); 00128 VAprintf(true, true, _useDprintf, format, arg); 00129 va_end(arg); 00130 } 00131 00132 void rprintf(const char *format, ...) 00133 { 00134 std::va_list arg; 00135 00136 va_start(arg, format); 00137 VAprintf(false, false, _useDprintf, format, arg); 00138 va_end(arg); 00139 } 00140 00141 void VAprintf(bool timstamp, bool newline, bool printEnabled, const char *format, va_list arg) 00142 { 00143 if (!printEnabled) 00144 return; 00145 00146 if (timstamp) 00147 printTimeStamp(); 00148 #ifdef FEATURE_USBSERIAL 00149 if (usb) { 00150 usb->vprintf_irqsafe(format, arg); 00151 if (newline) 00152 usb->printf_irqsafe("\r\n"); 00153 } 00154 #endif 00155 if (ser) { 00156 // serial jas 00157 int r = 0; 00158 r = vsnprintf(NULL, 0, format, arg); 00159 if (r < 82) { 00160 char buffer[82+1]; 00161 00162 vsnprintf(buffer, sizeof(buffer), format, arg); 00163 r = ser->write(buffer, r); 00164 } else { 00165 char *buffer = new char[r+1]; 00166 if (buffer) { 00167 vsnprintf(buffer, r+1, format, arg); 00168 r = ser->write(buffer, r); 00169 delete[] buffer; 00170 } else { 00171 error("%s %d cannot alloc memory (%d bytes)!\r\n", __FILE__, __LINE__, r+1); 00172 r = 0; 00173 } 00174 } 00175 if (newline) 00176 ser->write("\r\n", 2); 00177 } 00178 } 00179 00180 char *ConsoleReadline(char *buf, int buflen, bool echo, int timeout_ms) 00181 { 00182 int count = 0; 00183 memset(buf, 0, buflen); 00184 00185 #ifdef FEATURE_USBSERIAL 00186 if (usb == NULL && ser == NULL) 00187 return NULL; 00188 #else 00189 if (ser == NULL) 00190 return NULL; 00191 #endif 00192 00193 Timer t; 00194 int start = 0; 00195 if (timeout_ms) { 00196 t.start(); 00197 start = t.read_ms(); 00198 } 00199 00200 #ifdef FEATURE_USBSERIAL 00201 if (usb) { 00202 usb->flush(); 00203 while(usb->readable()) 00204 usb->getc(); // flush old chars 00205 } 00206 #endif 00207 if (ser) { 00208 while(ser->readable()) 00209 ser->getc(); // flush old chars 00210 } 00211 00212 while(true) { 00213 if (timeout_ms && t.read_ms() - start > timeout_ms) 00214 return NULL; 00215 int c = -2; 00216 #ifdef FEATURE_USBSERIAL 00217 if (usb && usb->readable()) 00218 c = usb->getc(); 00219 #endif 00220 if (ser && ser->readable()) 00221 c = ser->getc(); 00222 if (c == -2) 00223 continue; 00224 00225 if (c == 0 || c == -1 || c == '\r' || c == '\n' || c == 3 || c == 4) 00226 break; 00227 if (c == '\b' || c == 0x7f) { // backspace 00228 if (count < 1) 00229 continue; 00230 buf[--count] = 0; 00231 if (echo) 00232 rprintf("\b \b"); 00233 #ifdef FEATURE_USBSERIAL 00234 if (usb) 00235 usb->flush(); 00236 #endif 00237 continue; 00238 } 00239 if (echo) { 00240 rprintf("%c", c); 00241 #ifdef FEATURE_USBSERIAL 00242 if (usb) 00243 usb->flush(); 00244 #endif 00245 } 00246 00247 start = t.read_ms(); 00248 buf[count] = c; 00249 if (count++ >= buflen-2) 00250 break; 00251 // dprintf("Got char: '%c'(%d)", c, c); 00252 } 00253 00254 if (echo) 00255 rprintf("\r\n"); 00256 if (count) 00257 return buf; 00258 return NULL; 00259 } 00260 00261 00262 void dump(const char *title, void *data, int len) 00263 { 00264 dump(title, data, len, false); 00265 } 00266 00267 void dump(const char *title, const void *data, int len, bool dwords) 00268 { 00269 dprintf("dump(\"%s\", 0x%x, %d bytes)", title, (unsigned int)data, len); 00270 00271 int i, j, cnt; 00272 unsigned char *u; 00273 const int width = 16; 00274 const int seppos = 7; 00275 00276 cnt = 0; 00277 u = (unsigned char *)data; 00278 while (len > 0) { 00279 rprintf("%08x: ", (unsigned int)data + cnt); 00280 if (dwords) { 00281 unsigned int *ip = ( unsigned int *)u; 00282 rprintf(" 0x%08x\r\n", *ip); 00283 u+= 4; 00284 len -= 4; 00285 cnt += 4; 00286 continue; 00287 } 00288 cnt += width; 00289 j = len < width ? len : width; 00290 for (i = 0; i < j; i++) { 00291 rprintf("%2.2x ", *(u + i)); 00292 if (i == seppos) 00293 rprintf(" "); 00294 } 00295 rprintf(" "); 00296 if (j < width) { 00297 i = width - j; 00298 if (i > seppos + 1) 00299 rprintf(" "); 00300 while (i--) { 00301 rprintf("%s", " "); 00302 } 00303 } 00304 for (i = 0; i < j; i++) { 00305 int c = *(u + i); 00306 if (c >= ' ' && c <= '~') 00307 rprintf("%c", c); 00308 else 00309 rprintf("."); 00310 if (i == seppos) 00311 rprintf(" "); 00312 } 00313 len -= width; 00314 u += width; 00315 rprintf("\r\n"); 00316 if (ser) 00317 wait_ms(5); // give the serial some time. 00318 } 00319 rprintf("--\r\n"); 00320 } 00321 00322 /* 00323 * Convert compile time to system time 00324 */ 00325 time_t 00326 cvt_date(char const *date, char const *time) 00327 { 00328 char s_month[5]; 00329 int year; 00330 struct tm t; 00331 static const char month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec"; 00332 sscanf(date, "%s %d %d", s_month, &t.tm_mday, &year); 00333 sscanf(time, "%2d %*c %2d %*c %2d", &t.tm_hour, &t.tm_min, &t.tm_sec); 00334 // Find where is s_month in month_names. Deduce month value. 00335 t.tm_mon = (strstr(month_names, s_month) - month_names) / 3; 00336 t.tm_year = year - 1900; 00337 return (int)mktime(&t); 00338 } 00339 00340 00341 00342 void InterruptMSG(enum InterruptDevice irqid) { 00343 help_atomic_or_relaxed(&PendingInterrupts, irqid); 00344 } 00345 00346 00347 uint32_t readclrPendingInterrupts() { 00348 return help_atomic_readclr_relaxed(&PendingInterrupts); 00349 } 00350 00351 uint32_t readPendingInterrupts() { 00352 return help_atomic_load_relaxed(&PendingInterrupts); 00353 } 00354 00355 const char * 00356 BatterySource(void) 00357 { 00358 const char *pwrSource = "Battery"; 00359 #ifdef BATPOWER_EN 00360 { 00361 DigitalIn pwr(BATPOWER_EN); 00362 if (pwr == BATPOWER_EXT) 00363 pwrSource = "USB"; 00364 } 00365 #endif 00366 return pwrSource; 00367 } 00368 00369 00370 float 00371 GetBrownOutVolt(void) 00372 { 00373 unsigned int *FlashOptionRegister = (unsigned int *)0x1FFF7800; 00374 00375 int val = *FlashOptionRegister >> 8 & 0x7; // masking out the BOR bits 9-11 00376 switch(val) { 00377 case 0: 00378 return 1.7; 00379 case 1: 00380 return 2.0; 00381 case 2: 00382 return 2.2; 00383 case 3: 00384 return 2.5; 00385 case 4: 00386 return 2.8; 00387 default: 00388 return 999; 00389 } 00390 } 00391 00392 void MCUReset(void) 00393 { 00394 #define AIRCR_VECTKEY_MASK 0x05FA0000 00395 SCB->AIRCR = AIRCR_VECTKEY_MASK | 0x04; // NVIC_GenerateSystemReset(); 00396 } 00397 00398 00399 #define FREEMEM_CELL 100 00400 00401 struct elem { /* Definition of a structure that is FREEMEM_CELL bytes in size.) */ 00402 struct elem *next; 00403 char dummy[FREEMEM_CELL-2]; 00404 }; 00405 00406 size_t 00407 MemoryAvailable(bool print) 00408 { 00409 size_t counter; 00410 #ifdef TOOLCHAIN_GCC 00411 struct mallinfo mi = mallinfo(); 00412 extern char end[]; 00413 extern char _estack[]; 00414 counter = (_estack - end) - mi.uordblks; 00415 if (print) 00416 dprintf("MemoryAvailable: %d kB (%d bytes)", counter/1024, counter); 00417 return counter; 00418 #else 00419 struct elem *head, *current, *nextone; 00420 current = head = (struct elem*) malloc(sizeof(struct elem)); 00421 if (head == NULL) 00422 return 0; /*No memory available.*/ 00423 counter = 0; 00424 // __disable_irq(); 00425 do { 00426 counter++; 00427 current->next = (struct elem*) malloc(sizeof(struct elem)); 00428 current = current->next; 00429 } while (current != NULL); 00430 /* Now counter holds the number of type elem 00431 structures we were able to allocate. We 00432 must free them all before returning. */ 00433 current = head; 00434 do { 00435 nextone = current->next; 00436 free(current); 00437 current = nextone; 00438 } while (nextone != NULL); 00439 // __enable_irq(); 00440 00441 if (print) 00442 dprintf("MemoryAvailable: %d kB (%d bytes)", (counter*FREEMEM_CELL)/1024, counter*FREEMEM_CELL); 00443 return counter*FREEMEM_CELL; 00444 #endif 00445 } 00446 00447 00448 static const char *cmds = \ 00449 "\r\nThe following commands are available:\r\n\r\n" \ 00450 " p -- Property Editor\r\n" \ 00451 " t -- LoRa PingPong Test\r\n" \ 00452 " x -- LoRa TX Continuous Wave Test\r\n" \ 00453 " d -- Hexdump of memory address [offset count]\r\n" 00454 " r -- Reset\r\n" \ 00455 " c -- Continue with RadioShuttle RadioTest\r\n" \ 00456 "\r\n" \ 00457 "waiting 10 secs ...\r\n" \ 00458 "\r\n"; 00459 00460 void RunCommands(int timeout_ms) { 00461 bool cmdLoop = true; 00462 while(cmdLoop) { 00463 char buf[32]; 00464 00465 rprintf(cmds); 00466 rprintf("Turtle$ "); 00467 if (ConsoleReadline(buf, sizeof(buf), true, timeout_ms) == NULL) { 00468 cmdLoop = false; 00469 break; 00470 } 00471 switch(buf[0]) { 00472 case 'p': 00473 case 'P': 00474 #ifdef FEATURE_NVPROPERTYEDITOR 00475 NVPropertyEditor(); 00476 #endif 00477 break; 00478 case 't': 00479 case 'T': 00480 #ifdef FEATURE_LORA_PING_PONG 00481 SX1276PingPong(); // basic LoRa raw ping/pong without RadioShuttle 00482 #endif 00483 break; 00484 #ifdef FEATURE_RADIOTESTSAMPLE 00485 case 'x': 00486 case 'X': 00487 RadioContinuesTX(); 00488 #endif 00489 break; 00490 case 'r': 00491 case 'R': 00492 MCUReset(); 00493 break; 00494 case 'd': 00495 case 'D': 00496 { 00497 char *addr = strchr(buf, ' '); 00498 if (addr) { 00499 *addr++ = 0; 00500 char *length = strchr(addr, ' '); 00501 if (length) { 00502 *length++ = 0; 00503 } 00504 unsigned long address = strtoll(addr, NULL, 0); 00505 unsigned long cnt = 32; 00506 if (length) 00507 cnt = strtoll(length, NULL, 0); 00508 dump("Hexdump", (void *)address, cnt); 00509 } 00510 } 00511 break; 00512 case 'c': 00513 case 'C': 00514 cmdLoop = false; 00515 break; 00516 default: 00517 break; 00518 } 00519 } 00520 rprintf("\r\n"); 00521 00522 }
Generated on Wed Jul 13 2022 12:02:31 by
1.7.2