An example project for the Heltec Turtle LoRa board (STM32L4 and SX1276 chips). The projects is only supported for the Nucleo-L432KC board platform in the mbed online and offline compiler environment. Visit www.radioshuttle.de (choose Turtle board) for instructions. Note that most source files and libraries are open source, however some files especially the RadioShuttle core protocol is copyrighted work. Check header for details.

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 }