Photon Listening mode

@HardWater, because of the HAL and the separation of the system and user firmware, access to low level resources has to be done via a HAL API. The API is necessary for accessing the ISR vector table. Only the develop branch has that right now. Can you wait till 0.4.2 is released in a couple of weeks? Develop is still beta in a lot of areas. :smile:

@peekay123 thanks for the quick answer.

We are trying so hard to get the Photon code in shape to continue the successful design we had on the Core. From the sounds oh it. There is little chance to directly set the timer registers and vector table without use of the HAL interface, which sounds like a major roadblock for us. We were planning on shipping in 2-3 weeks. How sure are you the 0.4.2 will come out in 2 weeks?

Yeah I was interested in playing with it with the develop branch but was not interested in shipping product using the develop branch as that would be way too risky.

I am thinking maybe a better approach to breaking out of listening mode might be to find out where in the low level code the photon loops while in listening mode and test against a timeout limit there. Upon tripping the timeout the code either returns or calls another function. Obviously this would have to be a local compilation of a modification to the master branch. This sounds like the most fruitful path. Any thoughts or comments would be helpful?

Anyone know where in the code this listening loop might be?

Hey @HardWater, here's the spot you want to target for a timeout. You can easily use millis() and you may have to do more than just break out of the loop and fall through the remaining function calls.
https://github.com/spark/firmware/blob/develop/system/src/system_network.cpp#L91

Also something to note: WiFi.listen(); just sets a flag, that gets checked when the loop() exits or when Spark.process() is called, or when a delay() is called.

1 Like

Thanks @BDub,

Unfortunately I spent the full day working on this and beat you to the punch by about an hour, but anyways I appreciate the help.

I have started a new thread to discuss the implications of system modification and hope that you will follow me there Implications of customized system firmware - Photon

Hi @BDub .

I can neither find this particular path in your this post in the github repository nor system_network.cpp.

I did a clone of spark/firmware and did a find on the top level for this file with no luck.

Am I missing something?

@armystic, did you clone the “develop” branch of the firmware repo? Cloning the main branch will not get you the code you need. :smile:

Hi @armystic

There are two sets of branches right now in the spark/firmware repo that are in use, the older set of branches for the core and a new set used for Photon. Eventually these will merge.

The new branches have a very different set of files from the old branches so it makes a big difference which branch you pull! The branch “develop” is where all the new stuff for Photon (and eventually for Core) is going.

Thank you Legends, @peekay123 and @bko for your lightening fast replies. Indeed when I cloned the develop branch a whole new world opened up!

While we are at it, I have been trying to figure out how to put the firmware on a shiny P1 fresh from the fab (assuming I do my own fab with no pre-loaded f/w). I notice on the P1 datasheet it mentions FreeRTOS.

I presume I would need to toolchain cross-compile the FreeRTOS, load the P1-specific firmware onto it and make an image which the bootloader then loads and hopefully gets the P1 up and running. Is this procedure documented in detail? In specific I am wonderfing about the freeRTOS bits.

@armystic, FreeRTOS is used as part of the Broadcom WICED code and is entirely managed (compiled, linked, etc) by the make facility in the develop branch. You will most likely need a JTAG adaptor to get the initial image on the P1, including the bootloader. Perhaps @BDub can give you pointers on getting a blank P1 up and running. :smile:

Thanks @peekay123 for the hints. @BDub any pointers. In specific, is this process documented?

Hi @peekay123, have you released the new timer library for Photons?

I am interested in using an interrupt to switch WiFi.listen() off after a period time so that I can run code “offline” (i.e. without connecting to WiFi) if the device doesn’t receive credentials after a set amount of time.

@LeoW if you are building locally, let me know. There are now system events that are published during listen (kind of like a callback) so your application can take action during listening mode, such as implementing a timeout.

Hi @mdma! We're building locally on the develop branch with firmware 0.4.3. However, the new "latest" branch breaks on compile with a bunch of errors.

Here's the last paragraph in "make" error

Building target: ../../../build/target/user-part/platform-6-m/APP_NAME.elf
Invoking: ARM GCC C++ Linker
mkdir -p ../../../build/target/user-part/platform-6-m/
arm-none-eabi-g++ -DSTM32_DEVICE -DSTM32F2XX -DPLATFORM_THREADING=1 -DPLATFORM_ID=6 -DPLATFORM_NAME=photon -DUSBD_VID_SPARK=0x2B04 -DUSBD_PID_DFU=0xD006 -DUSBD_PID_CDC=0xC006 -DINCLUDE_PLATFORM=1 -fno-builtin -DUSE_STDPERIPH_DRIVER -DDFU_BUILD_ENABLE -fno-builtin-malloc -fno-builtin-free -fno-builtin-realloc -DUSER_FIRMWARE_IMAGE_SIZE=0x20000 -DUSER_FIRMWARE_IMAGE_LOCATION=0x80A0000 -DMODULAR_FIRMWARE=1 -DMODULE_VERSION=2 -DMODULE_FUNCTION=5 -DMODULE_INDEX=1 -DMODULE_DEPENDENCY=4,2,3 -DRELEASE_BUILD -Werror -I./inc -I../../../user/inc -I../../../dynalib/inc -I../../../services/inc -I../../../hal/inc -I../../../hal/shared -I../../../hal/src/photon -I../../../hal/src/stm32f2xx -I../../../hal/src/photon/api -I../../../system/inc -I../../../rt-dynalib/inc -I../../../wiring/inc -I../../../modules/photon/system-part1/inc -I../../../platform/shared -I../../../platform/MCU/STM32F2xx/CMSIS/Include -I../../../platform/MCU/STM32F2xx/CMSIS/Device/ST/Include -I../../../platform/MCU/STM32F2xx/SPARK_Firmware_Driver/inc -I../../../platform/MCU/STM32F2xx/STM32_StdPeriph_Driver/inc -I../../../platform/MCU/STM32F2xx/STM32_USB_Device_Driver/inc -I../../../platform/MCU/STM32F2xx/STM32_USB_Host_Driver/inc -I../../../platform/MCU/STM32F2xx/STM32_USB_OTG_Driver/inc -I. -MD -MP -MF ../../../build/target/user-part/platform-6-m/APP_NAME.d -ffunction-sections -fdata-sections -Wall -Wno-switch -Wno-error=deprecated-declarations -fmessage-length=0 -fno-strict-aliasing -DSPARK=1 -DSTART_DFU_FLASHER_SERIAL_SPEED=14400 -DSTART_YMODEM_FLASHER_SERIAL_SPEED=28800 -g3 -gdwarf-2 -Os -mcpu=cortex-m3 -mthumb ../../../build/target/user-part/platform-6-m/src/module_info.o ../../../build/target/user-part/platform-6-m/src/user_export.o ../../../build/target/user-part/platform-6-m/src/user_module.o ../../../build/target/user-part/platform-6-m/src/newlib_stubs.o --output ../../../build/target/user-part/platform-6-m/APP_NAME.elf -Wl,--whole-archive ../../../hal/src/photon/lib/STM32F2xx_Peripheral_Libraries.a -Wl,--no-whole-archive --specs=nano.specs -lnosys -L../../../modules/photon/system-part2 -L../../../modules/photon/system-part1 -L. -T./linker.ld -Wl,--defsym,USER_FIRMWARE_IMAGE_SIZE=0x20000 -Wl,--defsym,USER_FIRMWARE_IMAGE_LOCATION=0x80A0000 -Wl,-Map,../../../build/target/user-part/platform-6-m/APP_NAME.map -L../../../build/target/user/platform-6-m/applications/APP_NAME -L../../../build/target/services-dynalib/arm/ -L../../../build/target/hal-dynalib/platform-6-m/ -L../../../build/target/system-dynalib/platform-6-m/ -L../../../build/target/rt-dynalib/platform-6-m/ -L../../../build/target/wiring/platform-6-m/ -L../../../build/target/communication-dynalib/platform-6-m/ -L../../../build/target/platform/platform-6-m/ -L../../../hal/src/photon/lib/ -Wl,--whole-archive -luser -lhal-dynalib -lservices-dynalib -lsystem-dynalib -lrt-dynalib -lwiring -lcommunication-dynalib -lplatform -Wl,--no-whole-archive -L../../../build/arm/linker -nostartfiles -Xlinker --gc-sections
/usr/local/Cellar/gcc-arm-none-eabi-49/20150609/bin/../lib/gcc/arm-none-eabi/4.9.3/../../../../arm-none-eabi/lib/armv7-m/libg_nano.a(lib_a-sbrkr.o): In function _sbrk_r':
sbrkr.c:(.text._sbrk_r+0xc): undefined reference to_sbrk'
collect2: error: ld returned 1 exit status
make[1]: *** [../../../build/target/user-part/platform-6-m/APP_NAME.elf] Error 1
make: *** [modules/photon/user-part] Error 2

Here's the error when make is silenced "make APP=APP_NAME PLATFORM=photon -s":

/usr/local/Cellar/gcc-arm-none-eabi-49/20150609/bin/../lib/gcc/arm-none-eabi/4.9.3/../../../../arm-none-eabi/lib/armv7-m/libg_nano.a(lib_a-sbrkr.o): In function _sbrk_r': sbrkr.c:(.text._sbrk_r+0xc): undefined reference to _sbrk'
collect2: error: ld returned 1 exit status
make[1]: *** [../../../build/target/user-part/platform-6-m/APP_NAME.elf] Error 1
make: *** [modules/photon/user-part] Error 2

1 Like

When _sbrk is not found this means that there is some function (most likely a C-library function) that is trying to allocate memory, but isn’t using malloc.

Here’s how to find out which function is causing the problem:

  • add a function extern "C" void* _sbrk() { return NULL; } to your program. This is only temporary and will fill in the missing function so the code links.
  • open the user-part.lst file that is produced alongside your compiled application code
  • search for _sbrk to find which function is calling that. (It’s usually _malloc_r)
  • then search for _malloc_r and see which function is calling that. That will tell you which function is trying to allocate memory directly via _malloc_r rather than via malloc()

Another approach, a little less direct, is to systematically remove pieces of your code until the program compiles, including/excluding pieces until you narrow down the exact line of code.

Once you find out which function is causing the linker error, please let me know and I’ll investigate how we can fix things.

Thanks :slight_smile:

4 Likes

You were right! Thanks @mdma! We were using the function below to check the amount of free memory we had available which we commented out so it can compile on the latest branch:

extern "C" char *sbrk(int i);
uint32_t freeMemoryAvailable(void)
{
register char * current_stack_pointer asm ("sp");
char *heapend = sbrk(0);
return (current_stack_pointer - heapend);
}

With that settled, could you tell us what the system events are (what they are, how to use them, etc.)? We really want to implement a timeout so we can implement an offline mode after staying in listening mode for a set amount of time.

Thanks! :smile:

1 Like

Hi @LeoW! The system events hasn’t made it into a formal release (so it’s undocumented at present) - it was something I squeezed in for another customer. You’ll find an example app here - Implications of customized system firmware - Photon. That should help get you started! :smile:

Hey @mdma and anyone interested/involved!

Just wanted to update you guys on my use of both the system event during listening mode and various other wifi functions :smile: There have been many issues with the system events and with the wifi functions in general that other people have probably noticed. I have confirmed that these issues appear with several other people working with similar build environments and will describe my findings below so that we can confirm whether or not the observed behaviors are intended or if they need fixing. I hope these will observations will be helpful for you guys and hope these observations can be confirmed as bugs (or not) as soon as possible :smile:

Here’s the situation:

Build environment

  1. I am compiling the code on photons
  2. I use the “develop” branch of the system firmware
  3. I have the photons flashed with the 0.4.3 update

Observations:

WiFi.connect()

  • If the Photon has credentials, it will enter connecting mode (blinking green) and attempt to connect to WiFi and block user code. If the Photon doesn’t connect, it will attempt to connect for approximately 30 to 40 seconds (duration varies each time) and then exits to user code.
  • Sometimes, the Photon will attempt to connect but immediately exit out of connecting mode (blinking green) and start running user code.
  • After exiting out of connecting mode (blinking green), the photon will continue blinking green while running user code until a different wifi function is called.

WiFi.listen()

  • Blocks user code indefinitely (already noted feature)
  • When called, will sometimes immediately enter listening mode (blinking blue) and may sometimes take up to 20 seconds to enter listening mode i.e. if in connecting mode (blinking green), will take up to 20 seconds before the photon begins blinking blue and broadcasting its wifi signal.

Photon General Behavior Bugs

  • Serial1 connection is blocked while in listening mode (i.e. calling serial1.begin() doesn’t actually start serial1 channel)
  • This is a very important feature for us because we have a device that talks to the serial1 channel!

Thanks!

5 Likes

I did a little debugging on this today and found that the following functions in the Time class call localtime, a C-library function, which calls malloc_r (via localtime_r, _tzset_unlocked, _tzset_unlocked_r).

  • hour
  • hourFormat12
  • minute
  • second
  • day
  • weekday
  • month
  • year
  • timeStr

I’ve added it to our backlog with high priority. Not sure of the best way to fix and may need to wait until Mat gets back from vacation.

6 Likes

Hi @leow regarding the blocking nature of connecting I have found of using manual mode is the a way to avoid these difficulties.

Using the system events to solve the listening mode blocking problem has also worked well for me.

Thanks for the tip @HardWater!

Update:
I did some extensive testing yesterday and today and was able to resolve the “Photon’s General Behavior Bugs” on two of the photons I’ve been using! I have yet to try it on the other photon units we have, but I fixed the odd behavior with these steps (fixed as in the photon immediately starts blinking blue and enters listening mode when I hold setup for 3 seconds):

  1. In the “develop” branch of your firmware local repo,
    “cd modules” Put the photon in DFU-mode (blinking yellow)
  2. Run “make PLATFORM=photon clean all program-dfu PARTICLE_DEVELOP=1”
  3. In firmware/main, clean and remake all user code “make PLATFORM=photon APP=YOUR_APP_NAME_HERE clean all PARTICLE_DEVELOP=1”
  4. Flash the code onto your photon (either through cloud or dfu-util).
  5. Photon should not have weird listening mode behavior now!

edit: Need to also re-flash user application code to remove solid green light bug. Also don’t need to download 0.4.3 release.

If done correctly, the photon should accept the flash and should not have odd behavior anymore! You can try this most easily by putting the photon into safe mode and trying listening mode then (i.e. in safe mode, press setup for 3 seconds until photon goes into listening mode).

I was also able to begin connection to serial1 again inside the listening system event mdma implemented. When WiFi.listen() is called, it seems to close the serial connections so you need to call Serial1.begin() again inside the system event. I confirmed this by trying to turn on a light through serial1 inside the system event with and without serial1.begin() called inside the system event. If called outside, the lights won’t turn on.