/**
 * @brief Initializes the buffer module.
 *
 * This function initializes the buffer module.
 * This function should be called before using any other functionality
 * of buffer module.
 */
void bmm_buffer_init(void)
{
	uint8_t index;

	/* Initialize free buffer queue for large buffers */
#if (TOTAL_NUMBER_OF_LARGE_BUFS > 0)
    #ifdef ENABLE_QUEUE_CAPACITY
	qmm_queue_init(&free_large_buffer_q, TOTAL_NUMBER_OF_LARGE_BUFS);
    #else
	qmm_queue_init(&free_large_buffer_q);
    #endif  /* ENABLE_QUEUE_CAPACITY */
#endif

	/* Initialize free buffer queue for small buffers */
#if (TOTAL_NUMBER_OF_SMALL_BUFS > 0)
    #ifdef ENABLE_QUEUE_CAPACITY
	qmm_queue_init(&free_small_buffer_q, TOTAL_NUMBER_OF_SMALL_BUFS);
    #else
	qmm_queue_init(&free_small_buffer_q);
    #endif  /* ENABLE_QUEUE_CAPACITY */
#endif

#if (TOTAL_NUMBER_OF_LARGE_BUFS > 0)
	for (index = 0; index < TOTAL_NUMBER_OF_LARGE_BUFS; index++) {
		/*
		 * Initialize the buffer body pointer with address of the
		 * buffer body
		 */
		buf_header[index].body = buf_pool + (index * LARGE_BUFFER_SIZE);

		/* Append the buffer to free large buffer queue */
		qmm_queue_append(&free_large_buffer_q, &buf_header[index]);
	}
#endif

#if (TOTAL_NUMBER_OF_SMALL_BUFS > 0)
	for (index = 0; index < TOTAL_NUMBER_OF_SMALL_BUFS; index++) {
		/*
		 * Initialize the buffer body pointer with address of the
		 * buffer body
		 */
		buf_header[index + TOTAL_NUMBER_OF_LARGE_BUFS].body \
			= buf_pool +
				(TOTAL_NUMBER_OF_LARGE_BUFS *
				LARGE_BUFFER_SIZE) + \
				(index * SMALL_BUFFER_SIZE);

		/* Append the buffer to free small buffer queue */
		qmm_queue_append(&free_small_buffer_q, &buf_header[index + \
				TOTAL_NUMBER_OF_LARGE_BUFS]);
	}
#endif
}
Beispiel #2
0
retval_t wpan_init(void)
{
    /* Init queue used for MAC to next higher layer communication */
#ifdef ENABLE_QUEUE_CAPACITY
    qmm_queue_init(&mac_nhle_q, MAC_NHLE_QUEUE_CAPACITY);
#else
    qmm_queue_init(&mac_nhle_q);
#endif  /* ENABLE_QUEUE_CAPACITY */

    /*
     * Initialize MAC.
     */
    return mac_init();
}
Beispiel #3
0
/**
 * @brief Initializes the TAL
 *
 * This function is called to initialize the TAL. The transceiver is
 * initialized, the TAL PIBs are set to their default values, and the TAL state
 * machine is set to TAL_IDLE state.
 *
 * @return MAC_SUCCESS  if the transceiver state is changed to TRX_OFF and the
 *                 current device part number and version number are correct;
 *         FAILURE otherwise
 */
retval_t tal_init(void)
{
    /* Init the PAL and by this means also the transceiver interface */
    if (pal_init() != MAC_SUCCESS)
    {
        return FAILURE;
    }

    if (trx_init() != MAC_SUCCESS)
    {
        return FAILURE;
    }

#if (EXTERN_EEPROM_AVAILABLE == 1)
    pal_ps_get(EXTERN_EEPROM, EE_IEEE_ADDR, 8, &tal_pib.IeeeAddress);
#else
    pal_ps_get(INTERN_EEPROM, EE_IEEE_ADDR, 8, &tal_pib.IeeeAddress);
#endif

    /*
     * Do the reset stuff.
     * Set the default PIBs.
     * Generate random seed.
     */
    if (internal_tal_reset(true) != MAC_SUCCESS)
    {
        return FAILURE;
    }

#ifndef DISABLE_IEEE_ADDR_CHECK
    /* Check if a valid IEEE address is available. */
    /*
     * This while loop is on purpose, since just in the
     * rare case that such an address is randomly
     * generated again, we must repeat this.
     */
    while ((tal_pib.IeeeAddress == 0x0000000000000000) ||
            (tal_pib.IeeeAddress == 0xFFFFFFFFFFFFFFFF)
          )
    {
        /*
         * In case no valid IEEE address is available, a random
         * IEEE address will be generated to be able to run the
         * applications for demonstration purposes.
         * In production code this can be omitted.
         */
        /*
         * The proper seed for function rand() has already been generated
         * in function tal_generate_rand_seed().
         */
        uint8_t *ptr_pib = (uint8_t *)&tal_pib.IeeeAddress;

        for (uint8_t i = 0; i < 8; i++)
        {
            *ptr_pib++ = (uint8_t)rand();
            /*
             * Note:
             * Even if casting the 16 bit rand value back to 8 bit,
             * and running the loop 8 timers (instead of only 4 times)
             * may look cumbersome, it turns out that the code gets
             * smaller using 8-bit here.
             * And timing is not an issue at this place...
             */
        }
    }
#endif  /* #ifndef DISABLE_IEEE_ADDR_CHECK */

    /*
     * Configure interrupt handling.
     * Install handlers for the transceiver interrupts.
     */
    pal_trx_irq_init_rx_end((FUNC_PTR)trx_rx_end_handler_cb);
    pal_trx_irq_init_tx_end((FUNC_PTR)trx_tx_end_handler_cb);
    pal_trx_irq_init_awake((FUNC_PTR)trx_awake_handler_cb);

#if (defined BEACON_SUPPORT) || (defined ENABLE_TSTAMP)
    /* Configure time stamp interrupt. */
    pal_trx_irq_init_tstamp((FUNC_PTR)trx_irq_timestamp_handler_cb);
#endif /* (defined BEACON_SUPPORT) || (defined ENABLE_TSTAMP) */

    /* Initialize the buffer management module and get a buffer to store reveived frames. */
    bmm_buffer_init();
    tal_rx_buffer = bmm_buffer_alloc(LARGE_BUFFER_SIZE);

    /* Init incoming frame queue */
#ifdef ENABLE_QUEUE_CAPACITY
    qmm_queue_init(&tal_incoming_frame_queue, TAL_INCOMING_FRAME_QUEUE_CAPACITY);
#else
    qmm_queue_init(&tal_incoming_frame_queue);
#endif  /* ENABLE_QUEUE_CAPACITY */

#ifdef ENABLE_TFA
    tfa_init();
#endif

    return MAC_SUCCESS;
} /* tal_init() */
/**
 * @brief Initializes the TAL
 *
 * This function is called to initialize the TAL. The transceiver is
 * initialized, the TAL PIBs are set to their default values, and the TAL state
 * machine is set to TAL_IDLE state.
 *
 * @return MAC_SUCCESS  if the transceiver state is changed to TRX_OFF and the
 *                 current device part number and version number are correct;
 *         FAILURE otherwise
 */
retval_t tal_init(void)
{
    /* Init the PAL and by this means also the transceiver interface */
#ifdef ENABLE_RP
    /*
     * The ranging processor (RP) only performs a minimalistic
     * initialization here.
     */
    pal_basic_init();
#else  /* !ENABLE_RP */
    if (pal_init() != MAC_SUCCESS)
    {
        return FAILURE;
    }

    if (trx_init() != MAC_SUCCESS)
    {
        return FAILURE;
    }

#if (EXTERN_EEPROM_AVAILABLE == 1)
    pal_ps_get(EXTERN_EEPROM, EE_IEEE_ADDR, 8, &tal_pib.IeeeAddress);
#else
    #if (USER_SIGN_AVAILABLE == 1)
        pal_ps_get(USER_SIGNATURE, USER_SIGNATURES_START + 2, 8, &tal_pib.IeeeAddress);
        //http://www.atmel.com/Images/Atmel-42172-Wireless-ZigBit-ATZB-X0-256-3-0-C_Datasheet.pdf
    #else
        pal_ps_get(INTERN_EEPROM, EE_IEEE_ADDR, 8, &tal_pib.IeeeAddress);
    #endif
#endif

    /*
     * Do the reset stuff.
     * Set the default PIBs.
     * Generate random seed.
     */
    if (internal_tal_reset(true) != MAC_SUCCESS)
    {
        return FAILURE;
    }

#ifndef DISABLE_IEEE_ADDR_CHECK
    /* Check if a valid IEEE address is available. */
    /*
     * This while loop is on purpose, since just in the
     * rare case that such an address is randomly
     * generated again, we must repeat this.
     */
    while ((tal_pib.IeeeAddress == 0x0000000000000000) ||
           (tal_pib.IeeeAddress == 0xFFFFFFFFFFFFFFFF))
    {
        /*
         * In case no valid IEEE address is available, a random
         * IEEE address will be generated to be able to run the
         * applications for demonstration purposes.
         * In production code this can be omitted.
         */
        /*
         * The proper seed for function rand() has already been generated
         * in function tal_generate_rand_seed().
         */
        uint8_t *ptr_pib = (uint8_t *)&tal_pib.IeeeAddress;

        for (uint8_t i = 0; i < 8; i++)
        {
            *ptr_pib++ = (uint8_t)rand();
            /*
             * Note:
             * Even if casting the 16 bit rand value back to 8 bit,
             * and running the loop 8 timers (instead of only 4 times)
             * may look cumbersome, it turns out that the code gets
             * smaller using 8-bit here.
             * And timing is not an issue at this place...
             */
        }
    }
#endif  /* #ifndef DISABLE_IEEE_ADDR_CHECK */
#endif  /* ENABLE_RP */

    /*
     * Configure interrupt handling.
     * Install a handler for the transceiver interrupt.
     */
    pal_trx_irq_init(trx_irq_handler_cb);
#ifndef ENABLE_RP
    pal_trx_irq_en();   /* Enable transceiver main interrupt. */
#endif

#if ((defined BEACON_SUPPORT) || (defined ENABLE_TSTAMP)) && (DISABLE_TSTAMP_IRQ == 0)
    /* Configure time stamp interrupt. */
    pal_trx_irq_init_tstamp(trx_irq_timestamp_handler_cb);
#ifndef ENABLE_RP
    pal_trx_irq_en_tstamp();    /* Enable timestamp interrupt. */
#endif
#endif

    /* Initialize the buffer management module and get a buffer to store received frames. */
    bmm_buffer_init();
    tal_rx_buffer = bmm_buffer_alloc(LARGE_BUFFER_SIZE);
#if DEBUG > 0
    if (tal_rx_buffer == NULL)
    {
        return FAILURE;
    }
#endif

    /* Init incoming frame queue */
#ifdef ENABLE_QUEUE_CAPACITY
    qmm_queue_init(&tal_incoming_frame_queue, TAL_INCOMING_FRAME_QUEUE_CAPACITY);
#else
    qmm_queue_init(&tal_incoming_frame_queue);
#endif  /* ENABLE_QUEUE_CAPACITY */

#ifdef ENABLE_TFA
    tfa_init();
#endif

    return MAC_SUCCESS;
} /* tal_init() */
Beispiel #5
0
/*
 * \brief Initializes the TAL
 *
 * This function is called to initialize the TAL. The transceiver is
 * initialized, the TAL PIBs are set to their default values, and the TAL state
 * machine is set to TAL_IDLE state.
 *
 * \return MAC_SUCCESS  if the transceiver state is changed to TRX_OFF and the
 *                 current device part number and version number are correct;
 *         FAILURE otherwise
 */
retval_t tal_init(void)
{
    /* Init the PAL and by this means also the transceiver interface */
    if (pal_init() != MAC_SUCCESS) {
        return FAILURE;
    }

    if (trx_init() != MAC_SUCCESS) {
        return FAILURE;
    }

    if (tal_timer_init() != MAC_SUCCESS) {
        return FAILURE;
    }

#ifdef ENABLE_STACK_NVM
    pal_ps_get(INTERN_EEPROM, EE_IEEE_ADDR, 8, &tal_pib.IeeeAddress);
#endif

    /*
     * For systems including the AT86RF230B the random seed generation
     * cannot be done using a dedicated hardware feature.
     * Therefore all random seed generation needs to be done by special
     * means (e.g. utilization of ADC) that generate a random value only
     * within a certain range.
     *
     * In case the node already has a valid IEEE address (i.e. an IEEE
     * address which is different from 0x0000000000000000 or
     * 0xFFFFFFFFFFFFFFFF), this IEEE address (the lower 16 bit)
     * shall be used as seed for srand(), since each node should have a
     *unique
     * IEEE address.
     * In this case srand() is called directly and function
     *tal_generate_rand_seed()
     * is not called.
     *
     * Note: This behaviour is different in all other TALs, since in these
     * cases the seed for srand() is always generated based on transceiver
     * hardware support.
     */

#ifndef DISABLE_IEEE_ADDR_CHECK
    if ((tal_pib.IeeeAddress == 0x0000000000000000) ||
            (tal_pib.IeeeAddress == 0xFFFFFFFFFFFFFFFF)
       ) {
        /*
         * Generate a seed for the random number generator in function
         *rand().
         * This is required (for example) as seed for the CSMA-CA
         *algorithm.
         */
        tal_generate_rand_seed();

        /*
         * Now that we have generated a random seed, we can generate a
         *random
         * IEEE address for this node.
         */
        do {
            /*
             * In case no valid IEEE address is available, a random
             * IEEE address will be generated to be able to run the
             * applications for demonstration purposes.
             * In production code this can be omitted.
             */

            /*
             * The proper seed for function rand() has already been
             *generated
             * in function tal_generate_rand_seed().
             */
            uint8_t *ptr_pib = (uint8_t *)&tal_pib.IeeeAddress;

            for (uint8_t i = 0; i < 8; i++) {
                *ptr_pib++ = (uint8_t)rand();

                /*
                 * Note:
                 * Even if casting the 16 bit rand value back to
                 *8 bit,
                 * and running the loop 8 timers (instead of
                 *only 4 times)
                 * may look cumbersome, it turns out that the
                 *code gets
                 * smaller using 8-bit here.
                 * And timing is not an issue at this place...
                 */
            }
        }
        /* Check if a valid IEEE address is available. */
        while ((tal_pib.IeeeAddress == 0x0000000000000000) ||
                (tal_pib.IeeeAddress == 0xFFFFFFFFFFFFFFFF)
              );
    } else {
        /* Valid IEEE address, so no need to generate a new random seed.
         **/
        uint16_t cur_rand_seed = (uint16_t)tal_pib.IeeeAddress;
        srand(cur_rand_seed);
    }

#else

    /*
     * No check for a valid IEEE address done, so directly create a seed
     * for srand().
     */
    tal_generate_rand_seed();
#endif

    /*
     * Do the reset stuff.
     * Set the default PIBs.
     */
    if (internal_tal_reset(true) != MAC_SUCCESS) {
        return FAILURE;
    }

    pal_trx_reg_read(RG_IRQ_STATUS); /* clear pending irqs, dummy read */

    /*
     * Configure interrupt handling.
     * Install a handler for the transceiver interrupt.
     */
    pal_trx_irq_init((FUNC_PTR)trx_irq_handler_cb);
    pal_trx_irq_en(); /* Enable transceiver main interrupt. */

    /* Initialize the buffer management module and get a buffer to store
     *reveived frames. */
    bmm_buffer_init();
    tal_rx_buffer = bmm_buffer_alloc(LARGE_BUFFER_SIZE);

    /* Init incoming frame queue */
#ifdef ENABLE_QUEUE_CAPACITY
    qmm_queue_init(&tal_incoming_frame_queue,
                   TAL_INCOMING_FRAME_QUEUE_CAPACITY);
#else
    qmm_queue_init(&tal_incoming_frame_queue);
#endif  /* ENABLE_QUEUE_CAPACITY */

    return MAC_SUCCESS;
} /* tal_init() */
Beispiel #6
0
/**
 * @brief Initializes the MAC sublayer
 *
 * @return MAC_SUCCESS  if TAL is intialized successfully else FAILURE
 */
retval_t mac_init(void)
{
	#ifdef GTS_DEBUG
	struct port_config config_port_pin;
	config_port_pin.direction = PORT_PIN_DIR_OUTPUT;
	port_pin_set_config(DEBUG_PIN1, &config_port_pin);
	port_pin_set_config(DEBUG_PIN2, &config_port_pin);
	port_pin_set_config(DEBUG_PIN3, &config_port_pin);
	port_pin_set_config(DEBUG_PIN4, &config_port_pin);
	port_pin_set_config(DEBUG_PIN5, &config_port_pin);
	port_pin_set_config(DEBUG_PIN6, &config_port_pin);
	port_pin_set_config(DEBUG_PIN7, &config_port_pin);
	port_pin_set_config(DEBUG_PIN8, &config_port_pin);
	port_pin_set_config(DEBUG_PIN9, &config_port_pin);
	port_pin_set_config(DEBUG_PIN10, &config_port_pin);
	port_pin_set_config(DEBUG_PIN11, &config_port_pin);
	port_pin_set_config(DEBUG_PIN12, &config_port_pin);
	port_pin_set_config(DEBUG_PIN13, &config_port_pin);
	port_pin_set_config(DEBUG_PIN14, &config_port_pin);
	port_pin_set_config(DEBUG_PIN15, &config_port_pin);

	/*ioport_configure_pin(DEBUG_PIN1, IOPORT_DIR_OUTPUT |
	 *  IOPORT_INIT_LOW);
	 *  ioport_configure_pin(DEBUG_PIN2, IOPORT_DIR_OUTPUT |
	 *  IOPORT_INIT_LOW);
	 *  ioport_configure_pin(DEBUG_PIN3, IOPORT_DIR_OUTPUT |
	 *  IOPORT_INIT_LOW);
	 *  ioport_configure_pin(DEBUG_PIN4, IOPORT_DIR_OUTPUT |
	 *  IOPORT_INIT_LOW);*/
	#endif

	/* Initialize TAL */
	if (tal_init() != MAC_SUCCESS) {
		return FAILURE;
	}

#ifdef STB_ON_SAL
	stb_init();
#endif

#ifdef ENABLE_RTB
	/* Initialize RTB */
	if (rtb_init() != RTB_SUCCESS) {
		return FAILURE;
	}

#endif  /* ENABLE_RTB */

	/* Calibrate MCU's RC oscillator */
	if (!pal_calibrate_rc_osc()) {
		return FAILURE;
	}

	if (MAC_SUCCESS != mac_timers_init()) {
		return FAILURE;
	}

	mac_soft_reset(true);

	/* Set radio to sleep if allowed */
	mac_sleep_trans();

	/* Initialize the queues */
#ifdef ENABLE_QUEUE_CAPACITY
	qmm_queue_init(&nhle_mac_q, NHLE_MAC_QUEUE_CAPACITY);
	qmm_queue_init(&tal_mac_q, TAL_MAC_QUEUE_CAPACITY);
    #if (MAC_INDIRECT_DATA_FFD == 1)
	qmm_queue_init(&indirect_data_q, INDIRECT_DATA_QUEUE_CAPACITY);
    #endif /* (MAC_INDIRECT_DATA_FFD == 1) */
    #if (MAC_START_REQUEST_CONFIRM == 1)
    #ifdef BEACON_SUPPORT
	qmm_queue_init(&broadcast_q, BROADCAST_QUEUE_CAPACITY);
    #endif  /* BEACON_SUPPORT */
    #endif /* (MAC_START_REQUEST_CONFIRM == 1) */
#else
	qmm_queue_init(&nhle_mac_q);
	qmm_queue_init(&tal_mac_q);
    #if (MAC_INDIRECT_DATA_FFD == 1)
	qmm_queue_init(&indirect_data_q);
    #endif /* (MAC_INDIRECT_DATA_FFD == 1) */
    #if (MAC_START_REQUEST_CONFIRM == 1)
    #ifdef BEACON_SUPPORT
	qmm_queue_init(&broadcast_q);
    #endif  /* BEACON_SUPPORT */
    #endif /* (MAC_START_REQUEST_CONFIRM == 1) */
#endif  /* ENABLE_QUEUE_CAPACITY */

	return MAC_SUCCESS;
}
Beispiel #7
0
/**
 * @brief Initializes the TAL
 *
 * This function is called to initialize the TAL. The transceiver is
 * initialized, the TAL PIBs are set to their default values, and the TAL state
 * machine is set to TAL_IDLE state.
 *
 * @return MAC_SUCCESS  if the transceiver state is changed to TRX_OFF and the
 *                 current device part number and version number are correct;
 *         FAILURE otherwise
 */
retval_t tal_init(void)
{
	/* Init the PAL and by this means also the transceiver interface */
	if (pal_init() != MAC_SUCCESS) {
		return FAILURE;
	}

	/* Reset trx */
	if (trx_reset(RFBOTH) != MAC_SUCCESS) {
		return FAILURE;
	}

	/* Check if RF215 is connected */
	if ((trx_reg_read( RG_RF_PN) != 0x34) ||
			(trx_reg_read( RG_RF_VN) != 0x01)) {
		return FAILURE;
	}

	/* Initialize trx */
	trx_init();

	if (tal_timer_init() != MAC_SUCCESS) {
		return FAILURE;
	}

	/* Initialize the buffer management */
	bmm_buffer_init();

	/* Configure both trx and set default PIB values */
	for (uint8_t trx_id = 0; trx_id < NUM_TRX; trx_id++) {
		/* Configure transceiver */
		trx_config((trx_id_t)trx_id);
#ifdef RF215V1
		/* Calibrate LO */
		calibrate_LO((trx_id_t)trx_id);
#endif

		/* Set the default PIB values */
		init_tal_pib((trx_id_t)trx_id); /* see 'tal_pib.c' */
		calculate_pib_values((trx_id_t)trx_id);

		/*
		 * Write all PIB values to the transceiver
		 * that are needed by the transceiver itself.
		 */
		write_all_tal_pib_to_trx((trx_id_t)trx_id); /* see 'tal_pib.c'
		                                             **/
		config_phy((trx_id_t)trx_id);

		tal_rx_buffer[trx_id] = bmm_buffer_alloc(LARGE_BUFFER_SIZE);
		if (tal_rx_buffer[trx_id] == NULL) {
			return FAILURE;
		}

		/* Init incoming frame queue */
		qmm_queue_init(&tal_incoming_frame_queue[trx_id]);

		tal_state[trx_id] = TAL_IDLE;
		tx_state[trx_id] = TX_IDLE;
	}

	/* Init seed of rand() */
	tal_generate_rand_seed();

#ifndef DISABLE_IEEE_ADDR_CHECK
	for (uint8_t trx_id = 0; trx_id < 2; trx_id++) {
		/* Check if a valid IEEE address is available. */

		/*
		 * This while loop is on purpose, since just in the
		 * rare case that such an address is randomly
		 * generated again, we must repeat this.
		 */
		while ((tal_pib[trx_id].IeeeAddress == 0x0000000000000000) ||
				(tal_pib[trx_id].IeeeAddress ==
				((uint64_t)-1))) {
			/*
			 * In case no valid IEEE address is available, a random
			 * IEEE address will be generated to be able to run the
			 * applications for demonstration purposes.
			 * In production code this can be omitted.
			 */

			/*
			 * The proper seed for function rand() has already been
			 *generated
			 * in function tal_generate_rand_seed().
			 */
			uint8_t *ptr_pib
				= (uint8_t *)&tal_pib[trx_id].IeeeAddress;

			for (uint8_t i = 0; i < 8; i++) {
				*ptr_pib++ = (uint8_t)rand();

				/*
				 * Note:
				 * Even if casting the 16 bit rand value back to
				 *8 bit,
				 * and running the loop 8 timers (instead of
				 *only 4 times)
				 * may look cumbersome, it turns out that the
				 *code gets
				 * smaller using 8-bit here.
				 * And timing is not an issue at this place...
				 */
			}
		}
	}
#endif

#ifdef IQ_RADIO
	/* Init BB IRQ handler */
	pal_trx_irq_flag_clr(RF215_BB);
	trx_irq_init(RF215_BB, bb_irq_handler_cb);
	pal_trx_irq_en(RF215_BB);

	/* Init RF IRQ handler */
	pal_trx_irq_flag_clr(RF215_RF);
	trx_irq_init(RF215_RF, rf_irq_handler_cb);
	pal_trx_irq_en(RF215_RF);
#else

	/*
	 * Configure interrupt handling.
	 * Install a handler for the radio and the baseband interrupt.
	 */
	pal_trx_irq_flag_clr();
	trx_irq_init((FUNC_PTR)trx_irq_handler_cb);
	pal_trx_irq_en(); /* Enable transceiver main interrupt. */
#endif

#if ((defined SUPPORT_FSK) && (defined SUPPORT_MODE_SWITCH))
	init_mode_switch();
#endif

	return MAC_SUCCESS;
} /* tal_init() */