Using firmware libraries in user code

I understand that the Photon firmware build is modular, and that only those parts of the HAL and API that have been explicitly exposed are available to application developers.

Still I think there should be some way of circumventing this restriction.

The Photon uses some excellent libraries, including lwip, FreeRTOS, tropicssl, WICED and CMSIS. Not having access to low level functionality will make the device much less attractive to product developers.

There should be at least three possibilities:

  1. copy library into user space
  • wasteful, but should work for simpler, self-contained libraries such as tropicssl
  • probably useless for most networking and tasks, which will be state dependent
  1. user modification of exported functions
  • flexible, but seems like a nightmare to maintain
  1. non-modular build
  • building into a single firmware image (though with bootloader and settings sectors intact) allows library and user code to be linked freely

I’m aware that the build has a MODULAR=n option, though this doesn’t seem to work quite as required. Correct me if I’m wrong, but I’m getting undefined references if I try. Also you’d want the #include search paths to include the available libraries, which is not currently the case.

The Photon is a great device with huge potential - thanks for all the hard work everyone!

Hi @mars

I appreciate your thoughtful take on this and I think a lot of advanced users also want what you want.

We should get @mdma and @BDub to put some thoughts in here, but my feeling is that non-modular builds are going to be required by “product developers” (but maybe not by “makers”). There are a lot advantages to modular building, especially early on. And the disadvantages are mostly around performance and code size.

Right now, I think the firmware team is focused on getting everybody working (i2c, DNS, TCP/IP) for prototyping with modular builds. This helps the most people since there are a lot makers, but I am sure they have not forgotten the product developers who need more.

So the work-around is cut-and-paste code into user space. It’s not ideal but it can work for prototyping and it is a work-around, not a solution.

And I personally think that non-modular build is important and will get some love from the team when they are caught up on the current set of problems.

It’s possible to add a dynalib interface to expose the libraries to user code. We welcome PRs for this.

1 Like

thanks @bko, @mdma, I’ll try it out.
Though it sounds like I’ll have to revert to the WICED SDK for what I need.

What functionality do you need? On the one hand we want to provide an abstraction of common functionality so that it’s available via the same code on different platforms. But equally I’d like to open up the possibility of using the unique functionality on each device.

FreeRTOS would be a good candidate for a new dynalib since it will also be supported on the Electron. (And many parts of WICED are just a wrapper around FreeRTOS - queues, semaphores, timers etc…)

The show stopper for me right now is that I can’t configure the device as an AP without entering listening mode. Very soon I will also need to configure my own tasks and have fairly low level MCU access.

I haven’t looked at your implementation in detail but I can see that your dynalibs are implemented as jump tables, so I imagine there will be some overheads. At the end of the day, you wouldn’t want a jump table entry for every function in every library, or you might as well link it all statically.

I’ve tried a few different ways to build the firmware as a single image, with MODULAR_FIRMWARE=n. Am I barking up the wrong tree?

I also tried adding my own WiFi.configureAccessPoint(), but get link errors - presumably it’s the division between system part1 and part2 that trips me up.

It’s a complex build - I counted 390 subdirectories! - but then I guess WICED SDK is about twice that.

Right - jump tables are used when the 10 or so instructions represent an insignificant overhead. The CMSIS STM32 library is available for static linking. However, please profile first before being concerned about avoiding dynamic linking from performance concerns.

We will be building AP mode into the photon in the coming months. You’re welcome to of course have a go at implementing it yourself - either by adding new dynalib functions or using MODULAR=n.

cool - any docs on building with MODULAR=n?

I’ve implemented functions to start and stop access point, and to select the network interface (client or access point).

I can now switch between local wifi and soft ap, and run HTTP and UDP services on either. But not both at the same time!

The Photon hardware supports having both interfaces active simultaneously, as evidenced in the WICED apsta example, but implementing that would require much deeper changes to the firmware.

My top-level changes (additions to WiFi):

  /**
   * Select which network interface to use.
   * 0 for STA (client interface, default), 1 for AP (soft ap)
   * @return previous interface or -1 if change could not be actuated
   */
  int selectNetworkInterface(int iface);

  /**
   * Start an access point
   */
  bool startAccessPoint(const char* ssid, const char* passwd, int channel);

  /**
   * Stop a running access point
   */
  bool stopAccessPoint();

startAccessPoint() is not yet fully functional: it starts an AP with the default stored details and ignores the parameters.

1 Like