What all is happening in the main() function of my Programmable XBee Application?
After you have selected your first example application from the Programmable XBee Tutorial, you will notice a few functions already populated in the main() procedure call of your application, followed by the typical "run forever" for-loop found in most processor/MCU based code.
If you have started your tutorial with an example from the XBee samples, then you will notice that your main() function will look something like the following:
While at the top-most level, there are only a few lines of code present in the main function itself (besides the for-loop), there is quite a bit of code being executed within these few statements. That being said, it's always good to know exactly what is happening underneath these function calls in order to give you a better idea as to how and when structures are set up and interfaces initialized on the Freescale side of the equation, as well as when and how the various XBee radio parameters are initialized and how they work together with the Freescale CPU to provide you with an interface to create a programmable XBee application.
For your first sample application, it's not necessary that you understand all of the details and inner-workings of these functions, but it is a good idea to know what is already being set up for you in these functions so that you have a better idea of what your options are should you decide to add additional functionality to the main() function itself.
Let's start with the first line in the main function, which is where the majority of the functionality and setup for your Programmable XBee application takes place.
(Step 1): sys_hw_init()
This function is by far the "busiest" function, when it comes to setting up your application, primarily because it is initializing the hardware and software features of the onboard Freescale CPU, in addition to setting up some of the core requirements for the communciation between the CPU and XBee radio itself.
The first function call which is invoked from sys_hw_init() is sys_init(). This function first calls sys_gpio_init(), which primarily initializes basic system GPIOs, one of those being the XBee RESET pin.
The next function call which is made is sys_clocks_init(), which is used to initialize the Freescale system clock.
Finally, sys_init() makes a call to sys_radio_reset(), which sets the XBee's RESET pin low for 250ns and at the end of initializing is released, so that it can be raised and lowered later on as needed.
This is the last configuration step that is made by sys_init(). From here, sys_hw_init() continues by configuring the real time clock in the Freescale CPU by calling rtc_config(). This function serves to enable the RTC by enabling the interrupt and setting the frequency of each clock tick to 4ms. The RTC can be used later in your programmable XBee application in different ways including watchdog operations as well as making calls to functions such as delay_ticks() for adding delays in your application.
The next call which is made by sys_init() is sys_irqs_enable(), enabling the CPU's IRQs in preperation for more upcoming CPU/radio configuration. Note: if the "ENABLE_SLEEP_RQ" option is set, sys_init() will at this time set the "sleep_rq" pin to low.
The next function which is called takes different steps beyond the scope of this Wiki article, depending on whether it is configuring an S2B or S2C module. In short, a call is made to radio_switch_to_api_mode_and_autorate() which uses a baud rate array structure and various calls in "uart.c" to determine the XBee radio's baud rate.
After this function returns, the sys_init() function then starts a process to initialize the XBee radio by first calling xbee_dev_init(). This function is responsible for setting up the structure needed to hold the various configuration options for the radio, but contrary to the name of the function, does not yet start communication to the XBee radio itself.
When xbee_dev_init() returns, program flow then continues on by calling xbee_cmd_init_device(), which starts the XBee initialization process. Based on the results of built-in macros and checking a configuration bit, this function determines whether or not the XBee device needs to be queried to fill in a special structure called "xbee_dev_t", containing certain XBee specific parameters, such as: HV, VR, SH, SL, GT, CT, CC, EO, AI, NP, MY and others, described in the XBee Firmware Library reference documenation. If this structure needs to be filled in with values, xbee_cmd_query_device() is then called. A callback routine is set in order to handle setting up the radio specific parameters, as they are returned from the results of calling commands to get radio configuration.
After this structure has been set up for the XBee device, sys_hw_init() then continues to call radio_gpio_init(), which is responsible for initializing radio functionality pins, such as enabling the association LED pin, commissioning pin, Sleep_RQ, and the Sleep pin, set up as an input to allow for waking up the XBee while sleeping (if configured for certain types of power management), and finally the RSSI_PWM pin. It then disables certain pins which are user configurable and can be controlled by the Freescale CPU. These pins are different, depending on whether the XBee is an S2B or S2C device (see "hwinit.c" for more information and details).
After the radio's GPIO pins have been initialized, a call is made to sys_irqs_disable() so that the configuration of system GPIO can begin. A call to gpio_init() is then made, which in turn calls gpio_config() for each pin. The number and range of pins configured will depend on whether the XBee is an S2B or S2C device. In addition, gpio_config_irq() is called to configure IRQ driven pins, port_config() is called to configure ports 0-4, and the ADC mechanism (Analog to Digital Converter) is also configured, thereby enabling all appropriate ADC channels for the radio.
From here, sys_hw_init() finishes up by enabling the UART, FLASH memory, Analog to Digital Converter, and any other hardware functionality and interfaces which the programmer has specified to use, such as the i2c and 1-wire interfaces, etc. At the end, sys_hw_init() finishes up by re-enabling the system IRQs which were disabled previously by making a call to sys_irqs_enable().
(Step 2): sys_xbee_init()
After the long initialization phase of the sys_hw_init() function, the XBee radio should now be in a state to be initialized further. This happens first by a call to xbee_params_init(), which initializes parameters for the XBee, including ID, NI, NT, SC, SD, SM, SN, SP, ST, SO, WH, PO, DD and A0. A final call is made to xbee_wpan_init(), which performs the ultimate initilization and start of the WPAN layer of the XBee device. This is the layer which is responsible for enabling things such as endpoints and clusters, and other implementation needed by the ZigBee layers, including the ability to transmit basic data frames.
After this step, the driver attempts to query the XBee device by calling xbee_device_tick(), sys_watchdog_reset(), and finally xbee_cmd_query_status(), to verify the proper initialization previously performed in earlier steps (init functions).
(Step 3): sys_app_banner()
After sys_xbee_init() is finished, a final call is made to sys_app_banner(), which prints out information primarily for debugging purposes such as the radio's 64-bit address, the application version string, and other XBee version information. In addition, hardware address and hardware version is also reported, as well as the PAN ID.
(Step 4): The "for-loop"
From here, the Freescale CPU enters the typical "for-loop" which runs "forever" until power to the programmable XBee is turned off. This type of loop is typical for CPU/MCU devices, so that it runs in a continuous loop, while servicing the needs of the device (the XBee radio in the case of the programmable XBee).