Helmut Tschemernjak / Mbed 2 deprecated Turtle_RadioShuttle

Dependencies:   mbed BufferedSerial SX1276GenericLib OLED_SSD1306 HELIOS_Si7021 NVProperty RadioShuttle-STM32L4 USBDeviceHT

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers utils.cpp Source File

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 }