1
\$\begingroup\$

I'm writing my first large-ish C++ embedded program on a STM32F413. I've become a reasonably firm believer in object oriented coding but am not particularly knowledgeable. The STM32F413 has one RTC but almost all my classes need to time stamp events. I have a class for each of my sensors like GPS, pressure, pH, humidity and so on. Every time a new piece of data comes in from any sensor, it needs to get time stamped. I'd like to write a RTC class and give many other classes access to the RTC date and time through a single public "getDateTime" method. The only way I know how to do this is with a singleton. Is there a better way?

Thanks in advance

\$\endgroup\$
5
  • \$\begingroup\$ You can write a class with static functions that wrap the RTC, if you want. In that case, you don't actually need to instance a class object. (We also don't know if you are running multi-threaded or not. It may be helpful to know that.) \$\endgroup\$
    – jonk
    Oct 14, 2020 at 4:03
  • \$\begingroup\$ I'm not running any OS so not multi-threaded. I do use a pretty classic GOF state machine pattern and try to keep all my methods non-blocking. Communication between classes is through FIFO queues. I do use a unit testing framework so that might make a difference. I've read a lot of threads on the benefits and the evils of singletons and static classes (mostly evils for static classes). I just don't know how to sort through what is really evil and what is just theoretically "bad" programming. \$\endgroup\$
    – Gene
    Oct 14, 2020 at 4:10
  • \$\begingroup\$ It's probably better than that you disclose your coding. It's hard to say what's good or bad without seeing the situation. Static methods aren't at all evil. Can you reference a site discussing them? Perhaps I can help you interpret what they are saying. (I've been writing at least some C++ since about 1983 -- well before it was standardized -- as I worked with with the Unix kernel and AT&T since 1978 and was exposed to Stroustrup from the early days.) \$\endgroup\$
    – jonk
    Oct 14, 2020 at 4:12
  • \$\begingroup\$ Jonk - thanks for you generous offer. I'm going to try the extern "c" approach that Chris suggested below. I know how to do the singleton and static approaches and I'll be able to compare all 3. I may still take you up on your offer after that. \$\endgroup\$
    – Gene
    Oct 14, 2020 at 4:38
  • \$\begingroup\$ Okay. Just let me know by using @jonk in your writing. That will get my attention. \$\endgroup\$
    – jonk
    Oct 14, 2020 at 6:14

1 Answer 1

2
\$\begingroup\$

If you decide to use a class paradigm, then your choice is really between having a member (or instance) function of a singleton, vs. having a static (or class) method.

If you feel it makes sense to simply read the RTC hardware each time, and you don't need to track any useful RTC related state in software, then you can simply go with simplicity of a static or class method. Call it from anywhere, it grabs some kind of hardware lock (probably buried in a C-language HAL library), reads the hardware, releases the lock, and returns the value.

But maybe you conclude you do need to track state in an object instance. Or maybe you'd like that mutex to be owned by an instance - in this case, you can legitimately say "hey, there's a single instance of the RTC hardware, there should be a single instance of the class as well" and go with a singleton pattern.

Of course there's a third choice, too... you don't have to use an OOP paradigm for the RTC. Either in C++, or by calling an extern "C" method defined in a C source file it's perfectly legitimate to just have code which interacts with the hardware - if you use a vendor HAL, you're likely to end up with that under the covers, even if you put an OOP wrapper on top.

I believe you'll find that on larger systems, system time is usually either something that breaks the OOP model, or else in a language that is fundamentally object oriented, it tends to be a static or class method. I can't off the top of my head recall a singleton case; though there are examples of IPC based system services (in Android for example) where you access certain resources by first getting a unique instance of a class to do the local end of the IPC.

\$\endgroup\$
4
  • \$\begingroup\$ Great answer, thanks. I've seen extern "C" used in a few places but didn't really understand what it did. I've just done a little bit of reading and it sounds like a reasonable solution. I'll give it a try. Thanks again. \$\endgroup\$
    – Gene
    Oct 14, 2020 at 4:22
  • \$\begingroup\$ @Gene You should know you need extern C for interrupt handlers anyways since C++ does name mangling and the it wont match the designated interrupt function name. WIthout it, it will compile without errors but your ISR never runs. \$\endgroup\$
    – DKNguyen
    Oct 14, 2020 at 5:32
  • \$\begingroup\$ Just when I thought everything was going so well. As I said, I'm not a very experienced C++ programmer but I have written a bunch of small test programs. One of them is a UART driver for a GPS receiver. The driver uses the STM32 HAL library DMA and IRQ drivers for TX and RX. TX is easy since I know how many bytes I want to transmit. Since I don't know how many bytes I'll be receiving, I use the Idle Line Detect IRQ to end the DMA RX. That little driver seems to work without extern C call at least on my part. Is the STM32HAL using them under the hood and I just haven't looked deep enough? \$\endgroup\$
    – Gene
    Oct 14, 2020 at 6:54
  • \$\begingroup\$ The headers for the HAL libraries probably frame the prototypes in one if they detect a C++ complier \$\endgroup\$ Oct 14, 2020 at 11:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.