Esempio n. 1
0
// The task to process Console events
static void btn_task(iptr_t timer) {
	ticks_t start = timer_clock();
	ticks_t elapsed;
	(void)timer;

	DB2(LOG_INFO("Button timer...\r\n"));

	// LightUp all LEDS to notify calibration/reset pending
	LED_NOTIFY_ON();

	// Wait for button release or reset timeout
	while (!signal_status(SIGNAL_PLAT_BUTTON)) {
		elapsed = timer_clock() - start;
		if ( ms_to_ticks(BTN_RESET_SEC*1000) <= elapsed ) {
			// Button pressed fot t > BTN_CHECK_SEC+BTN_RESET_SEC
			reset_board();
		}
		DELAY(100);
	}

	// Button pressed BTN_CHECK_SEC < t < BTN_CHECK_SEC+BTN_RESET_SEC
	LED_NOTIFY_OFF();
	ERR_OFF();

	controlCalibration();

}
Esempio n. 2
0
static bool flash_wait(struct KBlock *blk)
{
	Flash *fls = FLASH_CAST(blk);
	ticks_t start = timer_clock();
	while (true)
	{
		if (!(EMB_FLASH->SR & FLASH_FLAG_BSY))
			break;

		if (EMB_FLASH->SR & FLASH_FLAG_PGERR)
		{
			fls->hw->status |= FLASH_NOT_ERASED;
			LOG_ERR("flash not erased..\n");
			return false;
		}

		if (EMB_FLASH->SR & FLASH_FLAG_WRPRTERR)
		{
			fls->hw->status |= FLASH_WR_PROTECT;
			LOG_ERR("wr protect..\n");
			return false;
		}

		if (timer_clock() - start > ms_to_ticks(CONFIG_FLASH_WR_TIMEOUT))
		{
			fls->hw->status |= FLASH_WR_TIMEOUT;
			LOG_ERR("Timeout..\n");
			return false;
		}

		cpu_relax();
	}

	return true;
}
Esempio n. 3
0
static void synctimer_test(void)
{
	size_t i;

	LIST_INIT(&synctimer_list);
	for (i = 0; i < countof(synctimer_timers); ++i)
	{
		Timer *timer = &synctimer_timers[i];
		timer_setDelay(timer, ms_to_ticks(test_delays[i]));
		timer_setSoftint(timer, synctimer_test_hook, (iptr_t)timer);
		synctimer_add(timer, &synctimer_list);
	}

	int secs = 0;
	mtime_t start_time = ticks_to_ms(timer_clock());
	mtime_t now;

	while (secs <= 10)
	{
		now = ticks_to_ms(timer_clock());
		synctimer_poll(&synctimer_list);
		if (now - start_time >= 1000)
		{
			++secs;
			start_time += 1000;
			kprintf("seconds = %d, ticks=%lu\n", secs, (unsigned long)now);
		}
		wdt_reset();
	}

	for (i = 0; i < countof(synctimer_timers); ++i)
	{
		synctimer_abort(&synctimer_timers[i]);
	}
}
Esempio n. 4
0
int main(void)
{
	init();
	ticks_t start = timer_clock();
	unsigned char x = 0;

	// FIXME
	memcpy(path[1].call, MYCALL, 6);
	path[1].ssid = MYCALL_SSID;

	while (1)
	{
		/* As long as CONFIG_AFSK_RXTIMEOUT is set to 0, this function won't block and return immediately. */
		ax25_poll(&ax25);

#if 1
		/* Send out message every 15sec */
		if (timer_clock() - start > ms_to_ticks(APRS_BEACON_TIME * 1000L))
		{
			kfile_printf(&ser.fd, "Beep %d\n", x++);
			start = timer_clock();
			ax25_sendVia(&ax25, path, countof(path), APRS_BEACON_MSG, sizeof(APRS_BEACON_MSG));
		}
#endif

	}
	return 0;
}
Esempio n. 5
0
static bool flash_wait(struct KBlock *blk, uint32_t event)
{
	Flash *fls = FLASH_CAST(blk);
	ticks_t start = timer_clock();
	while (true)
	{
		if (!(FLASH_FMC_R & event))
			break;

		if (FLASH_FCRIS_R & FLASH_FCRIS_ARIS)
		{
			fls->hw->status |= FLASH_WR_PROTECT;
			LOG_ERR("wr protect..\n");
			return false;
		}

		if (timer_clock() - start > ms_to_ticks(CONFIG_FLASH_WR_TIMEOUT))
		{
			fls->hw->status |= FLASH_WR_TIMEOUT;
			LOG_ERR("Timeout..\n");
			return false;
		}

		cpu_relax();
	}

	return true;
}
Esempio n. 6
0
/**
 * Chip erase function.
 *
 * Erase all sector of serial flash memory.
 *
 * \note This operation could take a while.
 */
void flash25_chipErase(Flash25 *fd)
{
	/*
	 * Erase all chip could take a while,
	 * for debug we measure that time
	 * see datasheet to compare this time.
	 */
	DB(ticks_t start_time = timer_clock());

	/*
	 * To erase serial flash memory we must first
	 * enable write with a WREN opcode command, before
	 * the CHIP_ERASE opcode.
	 */
	flash25_sendCmd(fd, FLASH25_WREN);
	flash25_sendCmd(fd, FLASH25_CHIP_ERASE);

	/*
	 * We check serial flash memory state, and wait until ready-flag
	 * is high.
	 */
	flash25_waitReady(fd);

	DB(kprintf("Erased all memory in %ld ms\n", ticks_to_ms(timer_clock() - start_time)));

}
Esempio n. 7
0
void timer_wait(int ms)
{
	clock_t timestamp = timer_clock();

	while (timer_clock() < timestamp + ms) {
		//watchdog_clear();
	}
}
Esempio n. 8
0
int main (void) {
    init();

    #if SERIAL_PROTOCOL == PROTOCOL_KISS
        while (true) {
            ax25_poll(&AX25);
            
            if (serial_available(0)) {
                char sbyte = uart0_getchar_nowait();
                kiss_serialCallback(sbyte);
            }
        }
    #endif

    #if SERIAL_PROTOCOL == PROTOCOL_SIMPLE_SERIAL
        ticks_t start = timer_clock();
        while (1) {    
            ax25_poll(&AX25);

            if (!sertx && serial_available(0)) {
                sbyte = uart0_getchar_nowait();

                #if SERIAL_DEBUG
                    if ((serialLen < AX25_MAX_FRAME_LEN) && (sbyte != 10)) {
                        serialBuffer[serialLen] = sbyte;
                        serialLen++;
                    } else {
                        sertx = true;
                    }
                #else
                    if (serialLen < AX25_MAX_FRAME_LEN-1) {
                        serialBuffer[serialLen] = sbyte;
                        serialLen++;
                    } else {
                        serialBuffer[serialLen] = sbyte;
                        serialLen++;
                        sertx = true;
                    }

                    start = timer_clock();
                #endif
            } else {
                if (!SERIAL_DEBUG && serialLen > 0 && timer_clock() - start > ms_to_ticks(TX_MAXWAIT)) {
                    sertx = true;
                }
            }

            if (sertx) {
                ss_serialCallback(serialBuffer, serialLen, &AX25);
                sertx = false;
                serialLen = 0;
            }

        }
    #endif

    return(0);
}
Esempio n. 9
0
bool timer_periodic(clock_t * tcks, uint32_t period)
{
	if (timer_clock() >= *tcks + period) {
		*tcks = timer_clock();
		return true;
	}

	return false;
}
Esempio n. 10
0
File: kbd.c Progetto: mtarek/BeRTOS
/**
 * Wait up to \c timeout ms for a keypress
 * and return the mask of depressed keys, or K_TIMEOUT
 * if the timeout was reacked.
 */
keymask_t kbd_get_timeout(mtime_t timeout)
{
    keymask_t key;

    ticks_t start = timer_clock();
    ticks_t stop  = ms_to_ticks(timeout);
    do
    {
        if ((key = kbd_peek()))
            return key;
    }
    while (timer_clock() - start < stop);

    return K_TIMEOUT;
}
Esempio n. 11
0
/**
 * Add \param entropy bits from \param data buffer to the entropy \param pool
 */
void randpool_add(EntropyPool *pool, void *data, size_t entropy)
{
	uint8_t sep[] = "\xaa\xaa\xaa\xaa";  // ??
	size_t data_len = ROUND_UP(entropy, 8) / 8; //Number of entropy byte in input.

	randpool_push(pool, data, data_len); //Insert data to entropy pool.

#if CONFIG_RANDPOOL_TIMER

	ticks_t event = timer_clock();
	ticks_t delta;

	/*Difference of time between a two accese to entropy pool.*/
	delta = event - pool->last_counter;

	randpool_push(pool, &event, sizeof(ticks_t));
	randpool_push(pool, sep, sizeof(sep) - 1); // ??
	randpool_push(pool, &delta, sizeof(delta));

	/*
	 * Count of number entropy bit add with delta.
	 */
	delta = delta & 0xff;
	while(delta)
	{
		delta >>= 1;
		entropy++;
	}

	pool->last_counter = event;

#endif

	pool->entropy += entropy;      //Update a entropy of the pool.
}
Esempio n. 12
0
static int __init timer_source_init(int ch)
{
	struct clocksource *cs = &tm_source_clk;
	struct timer_info *info = tm_source_info();

	info->channel = ch;
	info->irqno = -1;
	timer_clock_select(info, TIMER_CLOCK_SOURCE_HZ);

	/*
	 * register timer source
	 */
	clocksource_register_hz(cs, info->rate);

	pr_debug("timer.%d: source shift =%u  \n", ch, cs->shift);
	pr_debug("timer.%d: source mult  =%u  \n", ch, cs->mult);

	/*
	 * source timer run
	 */
	info->tcount = -1UL;
	timer_reset(ch);
	timer_stop (ch, 0);
	timer_clock(ch, info->tmmux, info->prescale);
	timer_count(ch, info->tcount + 1);
	timer_start(ch, 0);

	__timer_sys_mux_val = info->tmmux;
	__timer_sys_scl_val = info->prescale;
	__timer_sys_clk_clr = readl(TIMER_SYS_CLKGEN + CLKGEN_CLR);
	printk("timer.%d: source, %9lu(HZ:%d), mult:%u\n", ch, info->rate, HZ, cs->mult);
 	return 0;
}
Esempio n. 13
0
/**
 * Randpool function initialization.
 * The entropy pool can be initialize also with
 * a previous entropy pool.
 */
void randpool_init(EntropyPool *pool, void *_data, size_t len)
{
	uint8_t *data;

	data = (uint8_t *)_data;

	memset(pool, 0, sizeof(EntropyPool));
	pool->pos_get = MD2_DIGEST_LEN;

#if CONFIG_RANDPOOL_TIMER
	pool->last_counter = timer_clock();
#endif

	if(data)
	{
		/*
		 * Initialize a entropy pool with a
		 * previous pool, and assume all pool as
		 * entropy.
		 */
		len = MIN(len,(size_t)CONFIG_SIZE_ENTROPY_POOL);
		memcpy(pool->pool_entropy, data, len);
		pool->entropy = len;
	}

}
Esempio n. 14
0
static void x917_next(X917Context *ctx, BlockCipher *cipher, uint8_t *out)
{
	const size_t blen = cipher_block_len(cipher);

	struct
	{
		time_t t0;
		hptime_t t1;
		uint8_t padding[blen - sizeof(time_t) - sizeof(hptime_t)];
	} DT;

	ASSERT(sizeof(DT) == blen);

	memset(&DT, 0, sizeof(DT));
	DT.t0 = timer_clock();
	DT.t1 = timer_hw_hpread();

	cipher_ecb_encrypt(cipher, &DT);

	xor_block(out, (uint8_t*)&DT, ctx->state, blen);
	cipher_ecb_encrypt(cipher, out);

	xor_block(ctx->state, (uint8_t*)&DT, out, blen);
	cipher_ecb_encrypt(cipher, ctx->state);

	PURGE(DT);
}
Esempio n. 15
0
/**
 * Discard input to resynchronize with remote end.
 *
 * Discard incoming data until the kfile_getc stops receiving
 * characters for at least \a delay milliseconds.
 *
 * \note If the timeout occur, we reset the error before to
 * quit.
 */
void kfile_resync(KFile *fd, mtime_t delay)
{
	ticks_t start_time = timer_clock();
	for(;;)
	{
		if(kfile_getc(fd) != EOF)
			start_time = timer_clock();

		if ((timer_clock() - start_time) > ms_to_ticks(delay))
		{
			kfile_clearerr(fd);
			break;
		}

	}
}
Esempio n. 16
0
File: kbd.c Progetto: mtarek/BeRTOS
/**
 * Handle keyboard debounce
 */
static keymask_t kbd_debHandlerFunc(keymask_t key)
{
    /** Buffer for debounce */
    static keymask_t debounce_key;

    /** Timer for keyboard debounce */
    static ticks_t debounce_time;

    /** Key aquired after debounce */
    static keymask_t new_key;


    ticks_t now = timer_clock();

    if (key != debounce_key)
    {
        /* Reset debounce timer */
        debounce_key = key;
        debounce_time = now;
    }
    else if ((new_key != debounce_key)
             && (now - debounce_time > ms_to_ticks(KBD_DEBOUNCE_TIME)))
    {
        new_key = debounce_key;
        debounce_time = now;
    }

    return new_key;
}
Esempio n. 17
0
bool cutoff_check(ticks_t now, int32_t curr_alt, udegree_t lat, udegree_t lon)
{
	bool cutoff =(!cutoff_checkTime(now) ||
		!cutoff_checkDist(lat, lon, now) ||
		!cutoff_checkAltitude(curr_alt, now) ||
		!cutoff_checkMaxalt(curr_alt, now));

	static bool logged = false;
	if (cutoff)
	{
		if (cutoff_pause_time && timer_clock() - cutoff_pause_time < ms_to_ticks(PAUSE_TIME))
		{
			if (!logged)
			{
				radio_printf("CUTOFF pending!\n");
				logged = true;
			}
		}
		else
		{
			cutoff_pause_time = 0;
			logged = false;
			cutoff_cut();
		}
	}
	else
	{
		if (logged)
			radio_printf("Pending CUTOFF cancelled\n");
		logged = false;
	}

	return cutoff;
}
Esempio n. 18
0
static void timer_test_poll(void)
{
	int secs = 0;
	mtime_t start_time = ticks_to_ms(timer_clock());
	mtime_t now;

	while (secs <= 10)
	{
		now = ticks_to_ms(timer_clock());
		if (now - start_time >= 1000)
		{
			++secs;
			start_time += 1000;
			kprintf("seconds = %d, ticks=%lu\n", secs, (unsigned long)now);
		}
		wdt_reset();
	}
}
Esempio n. 19
0
File: clock.c Progetto: sgh/aos
static void clock_isr(UNUSED void* arg) {
	system_ticks++;

	timer_clock();
	sched_clock();

	AOS_HOOK(timer_event,ticks2ms(system_ticks));

	T0_IR = BIT0;    // Clear interrupt
}
Esempio n. 20
0
/*
 * Timer clock event
 */
static inline void timer_event_resume(struct timer_info *info)
{
	int ch = info->channel;
	if (info->in_tclk) {
		clk_set_rate(info->clk, info->rate);
		clk_enable(info->clk);
	}
	timer_stop(ch, 1);
	timer_clock(ch, info->tmmux, info->prescale);
}
Esempio n. 21
0
File: sb.c Progetto: fantasea/APRS
bool sb_send(bool beacon_now)
{
	if (beacon_now || (SEC_SINCE_BEACON > sb_rate)) { 
		LOG_INFO("since %ld sb_rate %d\n", SEC_SINCE_BEACON, sb_rate);
		sb_last_send = timer_clock();
		return true;
	}

	return false;
}
Esempio n. 22
0
static void pit_load(PIT *pit, int t)
{
        int l = pit->l[t] ? pit->l[t] : 0x10000;
        timer_clock();
        pit->newcount[t] = 0;
        pit->disabled[t] = 0;
        switch (pit->m[t])
        {
                case 0: /*Interrupt on terminal count*/
                pit->count[t] = l;
                pit->c[t] = (int64_t)((((int64_t) l) << TIMER_SHIFT) * PITCONST);
                pit_set_out(pit, t, 0);
                pit->thit[t] = 0;
                pit->enabled[t] = pit->gate[t];
                break;
                case 1: /*Hardware retriggerable one-shot*/
                pit->enabled[t] = 1;
                break;
                case 2: /*Rate generator*/
                if (pit->initial[t])
                {
                        pit->count[t] = l - 1;
                        pit->c[t] = (int64_t)(((((int64_t) l) - 1LL) << TIMER_SHIFT) * PITCONST);
                        pit_set_out(pit, t, 1);
                        pit->thit[t] = 0;
                }
                pit->enabled[t] = pit->gate[t];
                break;
                case 3: /*Square wave mode*/
                if (pit->initial[t])
                {
                        pit->count[t] = l;
                        pit->c[t] = (int64_t)((((((int64_t) l) + 1LL) >> 1) << TIMER_SHIFT) * PITCONST);
                        pit_set_out(pit, t, 1);
                        pit->thit[t] = 0;
                }
                pit->enabled[t] = pit->gate[t];
                break;
                case 4: /*Software triggered stobe*/
                if (!pit->thit[t] && !pit->initial[t])
                        pit->newcount[t] = 1;
                else
                {
                        pit->count[t] = l;
                        pit->c[t] = (int64_t)((l << TIMER_SHIFT) * PITCONST);
                        pit_set_out(pit, t, 0);
                        pit->thit[t] = 0;
                }
                pit->enabled[t] = pit->gate[t];
                break;
                case 5: /*Hardware triggered stobe*/
                pit->enabled[t] = 1;
                break;
        }
Esempio n. 23
0
/*
 * Check link speed and duplex as negotiated by the PHY
 * and configure CPU EMAC accordingly.
 * Requires active PHY maintenance mode.
 */
static void emac_autoNegotiation(void)
{
	uint16_t reg;
	time_t start;

	// Wait for auto-negotation to complete
	start = timer_clock();
	do {
		reg = phy_hw_read(NIC_PHY_ADDR, NIC_PHY_BMSR);
		if (timer_clock() - start > 2000)
		{
			kprintf("eth error: auto-negotiation timeout\n");
			return;
		}
	}
	while (!(reg & NIC_PHY_BMSR_ANCOMPL));

	reg = phy_hw_read(NIC_PHY_ADDR, NIC_PHY_ANLPAR);

	if ((reg & NIC_PHY_ANLPAR_TX_FDX) || (reg & NIC_PHY_ANLPAR_TX_HDX))
	{
		LOG_INFO("eth: 100BASE-TX\n");
		EMAC_NCFGR |= BV(EMAC_SPD);
	}
	else
	{
		LOG_INFO("eth: 10BASE-T\n");
		EMAC_NCFGR &= ~BV(EMAC_SPD);
	}

	if ((reg & NIC_PHY_ANLPAR_TX_FDX) || (reg & NIC_PHY_ANLPAR_10_FDX))
	{
		LOG_INFO("eth: full duplex\n");
		EMAC_NCFGR |= BV(EMAC_FD);
	}
	else
	{
		LOG_INFO("eth: half duplex\n");
		EMAC_NCFGR &= ~BV(EMAC_FD);
	}
}
Esempio n. 24
0
static void NORETURN acc_process(void)
{
	ticks_t start = timer_clock();
	mtime_t delay = 0;
	while (1)
	{
		sem_obtain(&i2c_sem);
		bool r = mma845x_rawAcc(&i2c_bus, 0, acc_buf[acc_idx].acc);
		sem_release(&i2c_sem);
		if (!r)
			kprintf("ACC error!\n");
		if (++acc_idx >= countof(acc_buf))
		{
			acc_idx = 0;
			logging_acc(acc_buf, sizeof(acc_buf));
		}

		/* Wait for the next sample adjusting for time spent above */
		delay += (1000 / ACC_SAMPLE_RATE);
		timer_delay(delay - ticks_to_ms(timer_clock() - start));
	}
}
Esempio n. 25
0
static void NORETURN cutoff_process(void)
{
	while (1)
	{
		timer_delay(1000);

		ticks_t now = timer_clock();
		int32_t curr_alt = gps_info()->altitude;
		udegree_t lat = gps_info()->latitude;
		udegree_t lon = gps_info()->longitude;

		cutoff_check(now, curr_alt, lat, lon);
	}
}
Esempio n. 26
0
File: kbd.c Progetto: mtarek/BeRTOS
/**
 * Handle long pression keys.
 */
static keymask_t kbd_lngHandlerFunc(keymask_t key)
{
    static ticks_t start;
    ticks_t now = timer_clock();

    if (key & K_LNG_MASK)
    {
        if (now - start > ms_to_ticks(KBD_LNG_DELAY))
            key |= K_LONG;
    }
    else
        start = now;
    return key;
}
Esempio n. 27
0
/**
 * Insert \a c in tx FIFO buffer.
 * \note This function will switch out the calling process
 * if the tx buffer is full. If the buffer is full
 * and \a port->txtimeout is 0 return EOF immediatly.
 *
 * \return EOF on error or timeout, \a c otherwise.
 */
static int ser_putchar(int c, struct Serial *port)
{
	if (fifo_isfull_locked(&port->txfifo))
	{
#if CONFIG_SER_TXTIMEOUT != -1
		/* If timeout == 0 we don't want to wait */
		if (port->txtimeout == 0)
			return EOF;

		ticks_t start_time = timer_clock();
#endif

		/* Wait while buffer is full... */
		do
		{
			cpu_relax();

#if CONFIG_SER_TXTIMEOUT != -1
			if (timer_clock() - start_time >= port->txtimeout)
			{
				ATOMIC(port->status |= SERRF_TXTIMEOUT);
				return EOF;
			}
#endif /* CONFIG_SER_TXTIMEOUT */
		}
		while (fifo_isfull_locked(&port->txfifo));
	}

	fifo_push_locked(&port->txfifo, (unsigned char)c);

	/* (re)trigger tx interrupt */
	port->hw->table->txStart(port->hw);

	/* Avoid returning signed extended char */
	return (int)((unsigned char)c);
}
Esempio n. 28
0
/**
 * Fetch a character from the rx FIFO buffer.
 * \note This function will switch out the calling process
 * if the rx buffer is empty. If the buffer is empty
 * and \a port->rxtimeout is 0 return EOF immediatly.
 *
 * \return EOF on error or timeout, \a c otherwise.
 */
static int ser_getchar(struct Serial *port)
{
	if (fifo_isempty_locked(&port->rxfifo))
	{
#if CONFIG_SER_RXTIMEOUT != -1
		/* If timeout == 0 we don't want to wait for chars */
		if (port->rxtimeout == 0)
			return EOF;

		ticks_t start_time = timer_clock();
#endif

		/* Wait while buffer is empty */
		do
		{
			cpu_relax();

#if CONFIG_SER_RXTIMEOUT != -1
			if (timer_clock() - start_time >= port->rxtimeout)
			{
				ATOMIC(port->status |= SERRF_RXTIMEOUT);
				return EOF;
			}
#endif /* CONFIG_SER_RXTIMEOUT */
		}
		while (fifo_isempty_locked(&port->rxfifo) && (ser_getstatus(port) & SERRF_RX) == 0);
	}

	/*
	 * Get a byte from the FIFO (avoiding sign-extension),
	 * re-enable RTS, then return result.
	 */
	if (ser_getstatus(port) & SERRF_RX)
		return EOF;
	return (int)(unsigned char)fifo_pop_locked(&port->rxfifo);
}
Esempio n. 29
0
void kiss_csma(AX25Ctx *ctx, uint8_t *buf, size_t len) {
    bool sent = false;
    while (!sent) {
        //puts("Waiting in CSMA");
        if(!channel->hdlc.receiving) {
            uint8_t tp = rand() & 0xFF;
            if (tp < p) {
                ax25_sendRaw(ctx, buf, len);
                sent = true;
            } else {
                ticks_t start = timer_clock();
                long slot_ticks = ms_to_ticks(slotTime);
                while (timer_clock() - start < slot_ticks) {
                    cpu_relax();
                }
            }
        } else {
            while (!sent && channel->hdlc.receiving) {
                // Continously poll the modem for data
                // while waiting, so we don't overrun
                // receive buffers
                ax25_poll(ax25ctx);

                if (channel->status != 0) {
                    // If an overflow or other error
                    // occurs, we'll back off and drop
                    // this packet silently.
                    channel->status = 0;
                    sent = true;
                }
            }
        }

    }
    
}
Esempio n. 30
0
File: main.c Progetto: DINKIN/bertos
int main(void)
{
	init();
	ticks_t start = timer_clock();

	while (1)
	{
		/*
		 * This function will look for new messages from the AFSK channel.
		 * It will call the message_callback() function when a new message is received.
		 * If there's nothing to do, this function will call cpu_relax()
		 */
		ax25_poll(&ax25);


		/* Send out message every 15sec */
		if (timer_clock() - start > ms_to_ticks(15000L))
		{
			start = timer_clock();
			ax25_sendVia(&ax25, path, countof(path), APRS_MSG, sizeof(APRS_MSG));
		}
	}
	return 0;
}