示例#1
0
static int handle_rpc_call(struct msm_rpc_server *server,
			   struct rpc_request_hdr *req, unsigned len)
{
	struct timespec ts, tv;
	
	//20110813 [email protected] add period
	int64_t period = 0;

	switch (req->procedure) {
	case RPC_TIME_REMOTE_MTOA_NULL:
		return 0;

	case RPC_TIME_TOD_SET_APPS_BASES: {
		struct rpc_time_tod_set_apps_bases_args *args;
		args = (struct rpc_time_tod_set_apps_bases_args *)(req + 1);
		args->tick = be32_to_cpu(args->tick);
		args->stamp = be64_to_cpu(args->stamp);
		printk(KERN_INFO "RPC_TIME_TOD_SET_APPS_BASES:\n"
		       "\ttick = %d\n"
		       "\tstamp = %lld\n",
		       args->tick, args->stamp);

		getnstimeofday(&ts);
		if (msmrtc_is_suspended()) {
			//20110813 [email protected] add period [START]
			int64_t now, sleep, tick_at_suspend;

			// LGE_UPDATE_S
			//now = msm_timer_get_sclk_time(NULL);
			now = msm_timer_get_sclk_time(&period);
			// LGE_UPDATE_E
			tick_at_suspend = msmrtc_get_tickatsuspend();
			if (now && tick_at_suspend) {
				sleep = now - tick_at_suspend;
				// LGE_UPDATE_S
				if(sleep<0)
					sleep+=period;
				// LGE_UPDATE_E
				timespec_add_ns(&ts, sleep);
			} else
				pr_err("%s: Invalid ticks from SCLK"
					"now=%lld tick_at_suspend=%lld",
					__func__, now, tick_at_suspend);
			//20110813 [email protected] add period [END]

		}
		rtc_hctosys();
		getnstimeofday(&tv);
		/* Update the alarm information with the new time info. */
		alarm_update_timedelta(ts, tv);
		return 0;
	}

	case RPC_TIME_GET_APPS_USER_TIME:
		return read_rtc0_time(server, req, len);

	default:
		return -ENODEV;
	}
}
/**
 * read_persistent_clock -  Return time from a persistent clock.
 *
 * Reads the time from a source which isn't disabled during PM, the
 * 32k sync timer.  Convert the cycles elapsed since last read into
 * nsecs and adds to a monotonically increasing timespec.
 */
void read_persistent_clock(struct timespec *ts)
{
	struct omap_32k_sync_device     *omap = thecs;
	unsigned long long      nsecs;
	cycles_t                delta;
	struct timespec         *tsp;

	if (!omap) {
		ts->tv_sec = 0;
		ts->tv_nsec = 0;
		return;
	}

	tsp = &omap->persistent_ts;

	omap->last_cycles = omap->cycles;
	omap->cycles = omap->cs.read(&omap->cs);
	delta = omap->cycles - omap->last_cycles;

	nsecs = clocksource_cyc2ns(delta,
			omap->cs.mult, omap->cs.shift);

	timespec_add_ns(tsp, nsecs);
	*ts = *tsp;
}
示例#3
0
文件: util.c 项目: TUM-LIS/glip
/**
 * Blocking read from a cbuf
 *
 * This function is compatible to the glip_read_b() function and can be used in
 * backend implementations using a cbuf for storing incoming data.
 *
 * @param[in]  buf the buffer to read from
 * @param[in]  size how much data is supposed to be read
 * @param[out] data the read data
 * @param[out] size_read how much data has been read
 * @param[in]  timeout the maximum duration the read operation can take
 *
 * @return 0 if reading was successful
 * @return -ETIMEDOUT if the read timeout was hit
 * @return -ECANCELED if the blocking operation was cancelled
 * @return any other value indicates failure
 *
 * @see glip_read_b()
 */
int gb_util_cbuf_read_b(struct cbuf *buf, size_t size, uint8_t *data,
                        size_t *size_read, unsigned int timeout)
{
    int rv;
    int retval = 0;
    struct timespec ts;

    *size_read = 0;

    if (size > cbuf_size(buf)) {
        /*
         * This is not a problem for non-blocking reads, but blocking reads will
         * block forever in this case as the maximum amount of data ever
         * available is limited by the buffer size.
         * @todo: This can be solved by loop-reading until timeout
         */
        return -1;
    }

    /*
     * Wait until sufficient data is available to be read.
     */
    if (timeout != 0) {
        clock_gettime(CLOCK_REALTIME, &ts);
        timespec_add_ns(&ts, timeout * 1000 * 1000);
    }

    size_t level = cbuf_fill_level(buf);

    while (level < size) {
        if (timeout == 0) {
            rv = cbuf_wait_for_level_change(buf, level);
        } else {
            rv = cbuf_timedwait_for_level_change(buf, level, &ts);
        }

        retval = rv;
        if (rv == -ETIMEDOUT) {
            goto read_ret;
        } else if (rv != 0) {
            goto ret;
        }

        level = cbuf_fill_level(buf);
    }

    /*
     * We read whatever data is available, and assume a timeout if the available
     * amount of data does not match the requested amount.
     */
read_ret:
    rv = gb_util_cbuf_read(buf, size, data, size_read);
    if (rv == 0 && size != *size_read) {
        retval = -ETIMEDOUT;
    }

ret:
    return retval;
}
示例#4
0
static void process_cb_request(void *buffer)
{
	struct rtc_cb_recv *rtc_cb = buffer;
	struct timespec ts, tv;

	rtc_cb->client_cb_id = be32_to_cpu(rtc_cb->client_cb_id);
	rtc_cb->event = be32_to_cpu(rtc_cb->event);
	rtc_cb->cb_info_ptr = be32_to_cpu(rtc_cb->cb_info_ptr);

	if (rtc_cb->event == EVENT_TOD_CHANGE) {
		/* A TOD update has been received from the Modem */
		rtc_cb->cb_info_data.tod_update.tick =
			be32_to_cpu(rtc_cb->cb_info_data.tod_update.tick);
		rtc_cb->cb_info_data.tod_update.stamp =
			be64_to_cpu(rtc_cb->cb_info_data.tod_update.stamp);
		rtc_cb->cb_info_data.tod_update.freq =
			be32_to_cpu(rtc_cb->cb_info_data.tod_update.freq);
		pr_info("RPC CALL -- TOD TIME UPDATE: ttick = %d\n"
			"stamp=%lld, freq = %d\n",
			rtc_cb->cb_info_data.tod_update.tick,
			rtc_cb->cb_info_data.tod_update.stamp,
			rtc_cb->cb_info_data.tod_update.freq);

		getnstimeofday(&ts);
		if (atomic_read(&suspend_state.state)) {
			int64_t now, sleep, sclk_max;
			now = msm_timer_get_sclk_time(&sclk_max);

			if (now && suspend_state.tick_at_suspend) {
				if (now < suspend_state.tick_at_suspend) {
					sleep = sclk_max -
						suspend_state.tick_at_suspend
						+ now;
				} else {
					sleep = now -
						suspend_state.tick_at_suspend;
				}

				timespec_add_ns(&ts, sleep);
				suspend_state.tick_at_suspend = now;
			} else
				pr_err("%s: Invalid ticks from SCLK"
					"now=%lld tick_at_suspend=%lld",
					__func__, now,
					suspend_state.tick_at_suspend);
		}
		rtc_hctosys();
		getnstimeofday(&tv);
		/* Update the alarm information with the new time info. */
		alarm_update_timedelta(ts, tv);

	} else
		pr_err("%s: Unknown event EVENT=%x\n",
					__func__, rtc_cb->event);
}
/*
 * tegra_read_persistent_clock -  Return time from a persistent clock.
 *
 * Reads the time from a source which isn't disabled during PM, the
 * 32k sync timer.  Convert the cycles elapsed since last read into
 * nsecs and adds to a monotonically increasing timespec.
 * Care must be taken that this funciton is not called while the
 * tegra_rtc driver could be executing to avoid race conditions
 * on the RTC shadow register
 */
static void tegra_read_persistent_clock(struct timespec *ts)
{
	u64 delta;
	struct timespec *tsp = &persistent_ts;

	last_persistent_ms = persistent_ms;
	persistent_ms = tegra_rtc_read_ms();
	delta = persistent_ms - last_persistent_ms;

	timespec_add_ns(tsp, delta * NSEC_PER_MSEC);
	*ts = *tsp;
}
示例#6
0
static void sprd_read_persistent_clock(struct timespec *ts)
{
	u64 delta;
	struct timespec *tsp = &persistent_ts;

	last_persistent_ms = persistent_ms;
	persistent_ms = get_sys_cnt();
	delta = persistent_ms - last_persistent_ms;

	timespec_add_ns(tsp, delta * NSEC_PER_MSEC);
	*ts = *tsp;
}
示例#7
0
void read_persistent_clock(struct timespec *ts)
{
	unsigned long long nsecs;
	cycles_t delta;
	struct timespec *tsp = &persistent_ts;

	last_cycles = cycles;
	cycles = timer_32k_base ? __raw_readl(timer_32k_base) : 0;
	delta = cycles - last_cycles;

	nsecs = clocksource_cyc2ns(delta, persistent_mult, persistent_shift);

	timespec_add_ns(tsp, nsecs);
	*ts = *tsp;
}
示例#8
0
void msmrtc_updateatsuspend(struct timespec *ts)
{
	int64_t now, sleep;

	if (atomic_read(&suspend_state.state)) {
		now = msm_timer_get_sclk_time(NULL);
		if (now && suspend_state.tick_at_suspend) {
			sleep = now - suspend_state.tick_at_suspend;
			timespec_add_ns(ts, sleep);
		} else
			pr_err("%s: Invalid ticks from SCLK now=%lld"
				"tick_at_suspend=%lld", __func__, now,
				suspend_state.tick_at_suspend);
	}

}
void read_persistent_clock(struct timespec *ts)
{
	unsigned long long nsecs;
	cycles_t delta;
	struct timespec *tsp = &persistent_ts;

	last_cycles = cycles;
	cycles = clocksource_32k.read(&clocksource_32k);
	delta = cycles - last_cycles;

	nsecs = clocksource_cyc2ns(delta,
				   clocksource_32k.mult, clocksource_32k.shift);

	timespec_add_ns(tsp, nsecs);
	*ts = *tsp;
}
示例#10
0
/*
 * read_persistent_clock -  Return time from a persistent clock.
 *
 * Reads the time from a source which isn't disabled during PM, the
 * 32k sync timer.  Convert the cycles elapsed since last read into
 * nsecs and adds to a monotonically increasing timespec.
 * Care must be taken that this funciton is not called while the
 * tegra_rtc driver could be executing to avoid race conditions
 * on the RTC shadow register
 */
void read_persistent_clock(struct timespec *ts)
{
	u64 delta;
	struct timespec *tsp = &persistent_ts;
	unsigned long flags;

	spin_lock_irqsave(&read_persistent_clock_lock, flags);

	last_persistent_ms = persistent_ms;
	persistent_ms = tegra_rtc_read_ms();
	delta = persistent_ms - last_persistent_ms;

	timespec_add_ns(tsp, delta * NSEC_PER_MSEC);
	*ts = *tsp;

	spin_unlock_irqrestore(&read_persistent_clock_lock, flags);
}
void read_persistent_clock(struct timespec *ts)
{
	unsigned long long nsecs;
	cycles_t last_cycles;
	unsigned long flags;

	spin_lock_irqsave(&read_persistent_clock_lock, flags);

	last_cycles = cycles;
	cycles = timer_32k_base ? __raw_readl(timer_32k_base) : 0;

	nsecs = clocksource_cyc2ns(cycles - last_cycles,
					persistent_mult, persistent_shift);

	timespec_add_ns(&persistent_ts, nsecs);

	*ts = persistent_ts;

	spin_unlock_irqrestore(&read_persistent_clock_lock, flags);
}
示例#12
0
void read_persistent_clock(struct timespec *ts)
{
	unsigned long long nsecs;
	cycles_t delta;
	struct timespec *tsp = &persistent_ts;

	last_cycles = cycles;
	cycles = clocksource_32k.read(&clocksource_32k);
	delta = cycles - last_cycles;
	if (unlikely(cycles < last_cycles)) {
		pr_warning("%s: WRAP\n", __func__);
		delta = last_cycles - cycles;
	}

	nsecs = clocksource_cyc2ns(delta,
				   clocksource_32k.mult, clocksource_32k.shift);
		
	timespec_add_ns(tsp, nsecs);
	*ts = *tsp;
}
示例#13
0
文件: util.c 项目: TUM-LIS/glip
/**
 * Blocking write to a cbuf
 *
 * This function is compatible to the glip_write_b() function and can be used in
 * backend implementations using a cbuf for storing outgoing data.
 *
 * @param[in]  buf the buffer to read from
 * @param[in]  size how much data is supposed to be written
 * @param[in]  data that is supposed to be written
 * @param[out] size_written how much data has been written
 * @param[in]  timeout the maximum duration the write operation can take
 *
 * @return 0 if all data has been written
 * @return -ETIMEDOUT if the write timeout was hit
 * @return -ECANCELED if the blocking operation was cancelled
 * @return any other value indicates failure
 *
 * @see glip_write_b()
 */
int gb_util_cbuf_write_b(struct cbuf *buf, size_t size, uint8_t *data,
                         size_t *size_written, unsigned int timeout)
{
    struct timespec ts;
    int retval;
    int rv;

    if (timeout != 0) {
        clock_gettime(CLOCK_REALTIME, &ts);
        timespec_add_ns(&ts, timeout * 1000 * 1000);
    }

    size_t size_done = 0;
    while (1) {
        size_t size_done_tmp = 0;
        gb_util_cbuf_write(buf, size - size_done, &data[size_done],
                           &size_done_tmp);
        size_done += size_done_tmp;

        if (size_done == size) {
            retval = 0;
            goto ret;
        }

        if (cbuf_free_level(buf) == 0) {
            if (timeout == 0) {
                rv = cbuf_wait_for_level_change(buf, 0);
            } else {
                rv = cbuf_timedwait_for_level_change(buf, 0, &ts);
            }
            if (rv != 0) {
                retval = rv;
                goto ret;
            }
        }
    }

ret:
    *size_written = size_done;
    return retval;
}
示例#14
0
文件: uei_of.c 项目: BlastTNG/flight
void *uei_hwmon_loop(void *m_arg)
{
    struct timespec next;
    uint64_t periodns = NSEC_PER_SEC;
    int ret;
    uint32_t diag_channels[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14};

    ph_thread_set_name("UEI_HW");
    blast_startup("Starting UEI HWMon loop");

    clock_gettime(CLOCK_MONOTONIC, &next);

    while (!shutdown_mcp) {
        ret = DqAdvDnxpRead(hd_of, CPU_LAYER, sizeof(diag_channels) / sizeof(uint32_t), diag_channels,
                            raw_diag_data, diag_data);
        if (ret < 0) {
            blast_err("Could not read CPU Diagnostics: %s", DqTranslateError(ret));
        }
        timespec_add_ns(&next, periodns);
        clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &next, NULL);
    }

    return NULL;
}
示例#15
0
文件: uei_of.c 项目: BlastTNG/flight
void *uei_508_loop(void *m_arg)
{
    struct timespec next;
    uint64_t periodns = ((double)(NSEC_PER_SEC) / 10);
    int ret;
    int channel_list_508[8] = {0, 1, 2, 3, 4, 5, 6, 7};
    uint32_t channel_cfg_508[8] = {
        CFG_485(DQ_SL501_BAUD_9600),
        CFG_485(DQ_SL501_BAUD_9600),
        CFG_485(DQ_SL501_BAUD_9600),
        CFG_485(DQ_SL501_BAUD_9600),
        CFG_485(DQ_SL501_BAUD_9600),
        CFG_485(DQ_SL501_BAUD_9600),
        CFG_485(DQ_SL501_BAUD_9600),
        CFG_485(DQ_SL501_BAUD_9600)
    };
    int channel_flags_508[8] = { 0 };

    ph_library_init();
    ph_thread_set_name("UEI508");
    blast_startup("Starting UEI 508 loop");

    // set channel configuration
    for (int i = 0; i < 8; i++) {
        if ((ret = DqAdv501SetChannelCfg(hd_508, 4, i, channel_cfg_508[i])) < 0) {
            blast_err("Error in DqAdv501SetChannelCfg()");
        }
    }
    ret = DqRtVmapAddChannel(hd_508, vmapid_508, 4, DQ_SS0IN, channel_list_508, channel_flags_508, 8);
    ret = DqRtVmapAddChannel(hd_508, vmapid_508, 4, DQ_SS0OUT, channel_list_508, channel_flags_508, 8);
    ret = DqRtVmapStart(hd_508, vmapid_508);

    clock_gettime(CLOCK_MONOTONIC, &next);

    while (!shutdown_mcp) {
        for (int i = 0; i < 8; i++) {
            size_t num_bytes;
            ph_buf_t *outbuf = NULL;
            if ((num_bytes = ph_bufq_len(SL508_write_buffer[i]))) {
                outbuf = ph_bufq_consume_bytes(SL508_write_buffer[i], num_bytes);
                DqRtVmapWriteOutput(hd_508, vmapid_508, 4, i, num_bytes, ph_buf_mem(outbuf));
                ph_buf_delref(outbuf);
            }
            DqRtVmapRequestInput(hd_508, vmapid_508, 4, i, 128);
        }
        // Write output data to each TX port FIFO and Read each RX port FIFO
        ret = DqRtVmapRefresh(hd_508, vmapid_508, 0);

        // Read data received during the last refresh
        for (int i = 0; i < 8; i++) {
            uint8_t read_buffer[128];
            int read_len;
            DqRtVmapReadInput(hd_508, vmapid_508, 4, i, sizeof(read_buffer), &read_len, read_buffer);
            if (read_len > 0) {
                ph_bufq_append(SL508_read_buffer[i], read_buffer, read_len, NULL);
            }
        }

        timespec_add_ns(&next, periodns);
        clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &next, NULL);
    }

    DqRtVmapStop(hd_508, vmapid_508);
    DqRtVmapClose(hd_508, vmapid_508);
    return NULL;
}
示例#16
0
static void event_loop(struct server_state* ss)
{
  msg(1, "Starting event loop\n");

  struct timespec tx_ts, rx_ts, next_tx_ts, lost_tx_ts = { 0, 0 };
  ss->have_sent = ss->have_tx_ts = ss->have_rx_ts = false;
  int rc, rx_left = ss->rx_msg_size;
  unsigned send_i = 0;

  clock_gettime(CLOCK_REALTIME, &next_tx_ts);
  timespec_add_ns(&next_tx_ts, ss->inter_tx_gap_ns);

  while( 1 ) {
    struct epoll_event e;
    TRY( rc = epoll_wait(ss->epoll, &e, 1, 0) );

    if( rc == 0 ) {
      struct timespec now;
      clock_gettime(CLOCK_REALTIME, &now);
      if( ! timespec_le(next_tx_ts, now) )
        continue;
      timespec_add_ns(&next_tx_ts, ss->inter_tx_gap_ns);
      if( ++send_i >= cfg_measure_nth && ! ss->have_sent ) {
        msg(3, "Send message (timed)\n");
        TEST( send(ss->udp_sock_ts, ss->tx_buf_ts, ss->tx_msg_size, 0)
                == ss->tx_msg_size );
        if( ! cfg_hw_ts ) {
          ss->have_tx_ts = true;
          tx_ts = now;
        }
        send_i = 0;
        ss->have_sent = true;
      }
      else {
        msg(3, "Send message\n");
        TEST( send(ss->udp_sock, ss->tx_buf, ss->tx_msg_size, 0)
                == ss->tx_msg_size );
        if( send_i >= cfg_measure_nth ) {
          /* Not had a reply to last timed message.  Try to detect lost
           * messages.
           */
          if( send_i == cfg_measure_nth ) {
            lost_tx_ts = now;
          }
          else if( ss->have_tx_ts &&
                   timespec_diff_ns(now, lost_tx_ts) > 10000000 ) {
            msg(2, "WARNING: No response to timed message\n");
            if( ss->rtt_n > 0 )
              ++(ss->n_lost_msgs);
            ss->have_sent = false;
            ss->have_tx_ts = false;
            ss->have_rx_ts = false;
          }
        }
      }
    }

    else if( e.data.fd == ss->tcp_sock ) {
      TEST( e.events & EPOLLIN );
      if( cfg_hw_ts ) {
        rc = recv_ts(ss->tcp_sock, ss->rx_buf, rx_left, MSG_DONTWAIT, &rx_ts);
      }
      else {
        rc = recv(ss->tcp_sock, ss->rx_buf, rx_left, MSG_DONTWAIT);
        clock_gettime(CLOCK_REALTIME, &rx_ts);
      }
      if( rc > 0 ) {
        msg(3, "Received %d from client at %d.%09d\n", rc,
            (int) rx_ts.tv_sec, (int) rx_ts.tv_nsec);
        if( (rx_left -= rc) == 0 ) {
          send(ss->tcp_sock, ss->rx_buf, 1, MSG_NOSIGNAL);
          rx_left = ss->rx_msg_size;
          ss->have_rx_ts = true;
          if( ss->have_tx_ts )
            measured_rtt(ss, tx_ts, rx_ts);
        }
      }
      else if( rc == 0 || errno == ECONNRESET ) {
        break;
      }
      else if( errno == ETIME ) {
        fprintf(stderr, "ERROR: Did not get H/W timestamp on RX\n");
        exit(3);
      }
      else {
        TRY( rc );
      }
    }

    else if( e.data.fd == ss->udp_sock_ts ) {
      assert( cfg_hw_ts );
      assert( ! ss->have_tx_ts );
      TEST( recv_ts(ss->udp_sock_ts, ss->rx_buf, 1,
                    MSG_ERRQUEUE | MSG_DONTWAIT, &tx_ts) == 1 );
      msg(3, "TX timestamp %d.%09d\n", (int) tx_ts.tv_sec,
             (int) tx_ts.tv_nsec);
      ss->have_tx_ts = true;
      if( ss->have_rx_ts )
        measured_rtt(ss, tx_ts, rx_ts);
    }
  }

  msg(1, "Client disconnected\n");
  TRY( close(ss->tcp_sock) );
}
static void mm_fmwk_job_scheduler(struct work_struct *work)
{
	mm_job_status_e status = MM_JOB_STATUS_INVALID;
	bool is_hw_busy = false;
	struct dev_job_list *job_list_elem;

	struct mm_core *core_dev = container_of(work, \
					struct mm_core, \
					job_scheduler);
	MM_CORE_HW_IFC *hw_ifc = &core_dev->mm_device;

	if (plist_head_empty(&core_dev->job_list))
		return;

	job_list_elem = plist_first_entry(\
			&(core_dev->job_list), \
			struct dev_job_list, core_list);

	if (mm_core_enable_clock(core_dev))
		goto mm_fmwk_job_scheduler_done;

	is_hw_busy = hw_ifc->mm_get_status(hw_ifc->mm_device_id);
	if (!is_hw_busy) {
		if (job_list_elem->job.size) {

			if (job_list_elem->job.status == MM_JOB_STATUS_READY)
				clean_cnt++;

			if (job_list_elem->job.status == MM_JOB_STATUS_DIRTY) {
				mm_common_cache_clean();
				dirty_cnt++;
				if ((dirty_cnt % 1000) == 0)
					pr_debug("mm jobs dirty=%d, clean=%d\n",
					dirty_cnt, clean_cnt);
			}

			status	= hw_ifc->mm_start_job(\
					hw_ifc->mm_device_id, \
					&job_list_elem->job, 0);
			if (status < MM_JOB_STATUS_SUCCESS) {
				getnstimeofday(&core_dev->sched_time);
				timespec_add_ns(\
				&core_dev->sched_time, \
				hw_ifc->mm_timeout * NSEC_PER_MSEC);
				core_dev->mm_core_idle = false;

				is_hw_busy = true;
				pr_debug("job posted ");

				raw_notifier_call_chain(\
				&core_dev->mm_common->notifier_head, \
				MM_FMWK_NOTIFY_JOB_STARTED, NULL);

				}
			else {
				core_dev->mm_core_idle = true;
				job_list_elem->job.status \
				= MM_JOB_STATUS_SUCCESS;
				mm_common_job_completion(\
					job_list_elem, core_dev);
				SCHEDULER_WORK(core_dev, \
					&core_dev->job_scheduler);
				}
			}
		else {
			job_list_elem->job.status \
				= MM_JOB_STATUS_SUCCESS;
			mm_common_job_completion(\
				job_list_elem, core_dev);
			SCHEDULER_WORK(core_dev, \
				&core_dev->job_scheduler);
			}
		}
	else {
		struct timespec cur_time;
		getnstimeofday(&cur_time);
		if (timespec_compare(&cur_time, &core_dev->sched_time) > 0) {
			pr_err("abort hw ");
				hw_ifc->mm_abort(hw_ifc->mm_device_id, \
				&job_list_elem->job);
			core_dev->mm_core_idle = true;
			is_hw_busy = false;
			SCHEDULER_WORK(core_dev, &core_dev->job_scheduler);
			}
		}

	if (is_hw_busy) {
		mod_timer(&core_dev->dev_timer, \
			jiffies + msecs_to_jiffies(hw_ifc->mm_timer));
		pr_debug("mod_timer  %lx %lx", \
				jiffies, \
				msecs_to_jiffies(hw_ifc->mm_timer));
		return;
		}

mm_fmwk_job_scheduler_done:
	mm_core_disable_clock(core_dev);
}
示例#18
0
文件: uei_of.c 项目: BlastTNG/flight
void *uei_dmap_update_loop(void *m_arg) {
    int ret;
    uint32_t chentry;
    struct timespec next;
    uint64_t periodns = ((double)(NSEC_PER_SEC) / frequency);

    ph_thread_set_name("OF_DMP");
    blast_startup("Starting UEI OF DMap loop");

    /**
     * Add all channels except those read out through the diagnostic interface
     */
    for (channel_t *ch = channel_list; ch->field[0]; ch++) {
        /**
         * Only select out frame UEI channels and ignore any listing board numbers
         * larger than number of slots available on UEI
         */
        if ((ch->source != SRC_OF_UEI) || ch->board > 5) continue;

        if (ch->board == 2) {
            chentry = ch->chan | DQ_LNCL_GAIN(0) | DQ_LNCL_DIFF;
        } else {
            chentry = ch->chan | DQ_LNCL_GAIN(0);
        }
        uei_of_channels[ch->board][num_of_channels[ch->board]++] = ch;
        DqRtDmapAddChannel(hd_dmap, dmapid, ch->board, DQ_SS0IN, &chentry, 1);
    }

    /**
     * Add the Digital output channel to the DMAP.  WARNING! This is hard-coded
     * and will need to be changed if the physical order of the UEI boards
     * change!
     */
    DqRtDmapAddChannel(hd_dmap, dmapid, 3, DQ_SS0OUT, 0, 0);

    // Start the layers
    DqRtDmapStart(hd_dmap, dmapid);

    clock_gettime(CLOCK_MONOTONIC, &next);

    while (!shutdown_mcp) {
        DqRtDmapWriteRawData32(hd_dmap, dmapid, 3, &(CommandData.uei_command.uei_of_dio_432_out), 1);

        ret = DqRtDmapRefresh(hd_dmap, dmapid);
        if (ret < 0) {
            blast_err("DqRtDmapRefresh: error %d", ret);
        }

        for (int i = 0; i < 6; i++) {
            if (num_of_channels[i]) {
                if ((ret = DqRtDmapReadScaledData(hd_dmap, dmapid, i, raw_dmap_input[i], num_of_channels[i])) < 0) {
                    blast_err("Could not read scaled data from DMAP");
                    continue;
                }
            }
        }

        timespec_add_ns(&next, periodns);
        clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &next, NULL);
    }

    DqRtDmapStop(hd_dmap, dmapid);
    DqRtDmapClose(hd_dmap, dmapid);
    DqCloseIOM(hd_dmap);

    return NULL;
}
static void process_cb_request(void *buffer)
{
	struct rtc_cb_recv *rtc_cb = buffer;
	struct timespec ts, tv;

	rtc_cb->client_cb_id = be32_to_cpu(rtc_cb->client_cb_id);
	rtc_cb->event = be32_to_cpu(rtc_cb->event);
	rtc_cb->cb_info_ptr = be32_to_cpu(rtc_cb->cb_info_ptr);

	if (rtc_cb->event == EVENT_TOD_CHANGE) {
		/* A TOD update has been received from the Modem */
		rtc_cb->cb_info_data.tod_update.tick =
			be32_to_cpu(rtc_cb->cb_info_data.tod_update.tick);
		rtc_cb->cb_info_data.tod_update.stamp =
			be64_to_cpu(rtc_cb->cb_info_data.tod_update.stamp);
		rtc_cb->cb_info_data.tod_update.freq =
			be32_to_cpu(rtc_cb->cb_info_data.tod_update.freq);
		pr_info("RPC CALL -- TOD TIME UPDATE: ttick = %d\n"
			"stamp=%lld, freq = %d\n",
			rtc_cb->cb_info_data.tod_update.tick,
			rtc_cb->cb_info_data.tod_update.stamp,
			rtc_cb->cb_info_data.tod_update.freq);

		getnstimeofday(&ts);

/* CR 291540 - Function/Feature Failure (Partial)
 * system uptime gets corrupted with overflow in slow clock.
 * 
 * Problem description
 * During power collapse, APPS sleep time is calculated using slow clock
 * ticks. The calculation of sleep time does not considers slow clock
 * overflow and thus If slow clock overflows during suspend state then we
 * get wrong sleep time and thus system uptime values gets corrupted.
 * earlier sleep time was calculates as follows:
 * sleep = current_sclk_tick - suspend_state_sclk_tick
 * 
 * Failure frequency: Occasionally
 * Scenario frequency: Uncommon
 * Change description
 * Modified the sleep time calculation to include slow clock overflow as follows:
 * Now sleep time is calculated as:
 * sleep = Maximum_sclk_tick_val - suspend_state_sclk_tick + current_sclk_tick.
 * Files affected
 * kernel/drivers/rtc/rtc-msm.c
 * kernel/arch/arm/mach-msm/rpc_server_time_remote.c
*/	
		if (atomic_read(&suspend_state.state)) {
#if 1 //QCT SBA 404016
			int64_t now, sleep, sclk_max;
			now = msm_timer_get_sclk_time(&sclk_max);
#else
			int64_t now, sleep;
			now = msm_timer_get_sclk_time(NULL);
#endif
			if (now && suspend_state.tick_at_suspend) {
#if 1 //QCT SBA 404016
				if (now < suspend_state.tick_at_suspend) {
					sleep = sclk_max -
							suspend_state.tick_at_suspend
							+ now;
				} else {
					sleep = now -
							suspend_state.tick_at_suspend;
				}
#else
				sleep = now -
					suspend_state.tick_at_suspend;
#endif
				timespec_add_ns(&ts, sleep);
/* CR 293735 - Function/Feature Failure (Partial)
 * When system was in suspend, could make invalid "elapsed system time" at AP side.
 * 
 * Problem description
 * When system is in suspend mode and if more than one network time update
 * comes while system is in suspend mode then the uptime gets corrupted.
 * 
 * Failure frequency: Occasionally
 * Scenario frequency: Uncommon
 * Change description
 * Added change to modify tick_at_suspend (variable that stores time tick
 * while entering suspend) after each update to the current time tick.
 * Setting the suspend mode variable in case alarm time expires the current
 * RTC time as in thic case also system enters suspend mode.
 * to sdcc irq handlers returning IRQ_NONE without handling the interrupt.
 * When interrupt is disabled the communication between the SDIO client and
 * SDCC host controller is stopped while a pending command is in progress
 * and hence WLAN operation is stuck forever and LOGP recovery cannot be
 * processed.
 * Files affected
 * arch/arm/mach-msm/rpc_server_time_remote.c
 * drivers/rtc/rtc-msm.c
 * include/linux/rtc-msm.h
 */
#if 1 //QCT SBA 404017
				suspend_state.tick_at_suspend = now;
#endif
			} else
				pr_err("%s: Invalid ticks from SCLK"
					"now=%lld tick_at_suspend=%lld",
					__func__, now,
					suspend_state.tick_at_suspend);
		}
		rtc_hctosys();
		getnstimeofday(&tv);
		/* Update the alarm information with the new time info. */
		alarm_update_timedelta(ts, tv);

	} else
		pr_err("%s: Unknown event EVENT=%x\n",
					__func__, rtc_cb->event);
}
示例#20
0
int main(int argc, char* argv[]) {
    int i, count = 0;
    int ret;
    uint32_t status;
    int dmapid;
    uint32_t last_pps = UINT32_MAX;

    struct timeval tv1;
    struct timespec next;
    long long periodns;

    uint32_t input32[64];
    uint32_t evt_chan = CT650_EVENT_CH0;
    EV650_CFG event;

    double input_buffer[64];
    size_t num_channels[15] = { 0 };

    uint32 chentry;

    FILE *gps_fp;
    FILE *analog_fp;
    FILE *pps_fp;
    FILE *status_fp;

    pthread_t async_t;
    pthread_t gps_t;

    time_t last_secs = 0;

    gps_fp = fopen("/mnt/data/gps.dat", "a");
    analog_fp = fopen("/mnt/data/analog.dat", "a");
    pps_fp = fopen("/mnt/data/pps.dat", "a");
    status_fp = fopen("/mnt/data/layer_status.dat", "a");

    signal(SIGINT, sighandler);

    ret = DqInitDAQLib();
    if (ret < 0) {
        printf("Error %d in DqInitDAQLib\n", ret);
        return ret;
    }
    ret = DqOpenIOM("127.0.0.1", DQ_UDP_DAQ_PORT, 1000, &hd, &DQRdCfg);
    if (ret < 0) {
        printf("Error %d in DqOpenIOM\n", ret);
        return ret;
    }

    for (i = 0; i < 7; i++)
    {
        uint32_t devn;
        ret = DqGetDevnBySerial(hd, layers[i].serial, &devn, NULL, NULL, NULL);
        if (ret < 0) {
            printf("Error %d getting device number\n", ret);
            goto finish_up;
        }
        layers[i].devn = (int)devn;

        if (DQRdCfg->devmod[layers[i].devn])
        {
            printf("Model: %x Option: %x Dev: %d SN: %u\n",
                    DQRdCfg->devmod[layers[i].devn], DQRdCfg->option[layers[i].devn],layers[i].devn, layers[i].serial);
        }
    }

    /**
     * Set the initial watchdog timer to 25 seconds.  This should be enough time
     * for us to get into the main routine
     */
   // DqCmdSetWatchDog(hd, DQ_WD_CLEAR_ON_OSTASK, 25000, NULL, NULL);

    pthread_create(&async_t, NULL, async_thread, NULL);
    pthread_detach(async_t);

    pthread_create(&gps_t, NULL, read_GPS_serial_line, NULL);
    pthread_detach(gps_t);

    /**
     * Allow handling of GPS data by the 650 internal interrupts
     */

    ret = DqAdv650EnableGPSTracking(hd, IRIG650_SLOT, true, &status);
    if (ret < 0) {
        printf("Error %d in DqAdv650EnableGPSTracking\n", ret);
    } else {
//        while (!(status & CT650_GPS_ACC_GPSFIXV)) {
//            uint32_t status2 =0;
//            printf("Got GPS Status 0x%X, 0x%X\n", status, status2);
//            sleep(1);
//            ret = DqAdv650GetGPSStatus(hd, IRIG650_SLOT, 0, &status, &status2, NULL, NULL);
//        }
    }


    /**
     * Get the PPS source from the GPS module
     * Set the flags to automatically continue if source is lost
     */

    uint32 timekeeper_mode, timekeeper_flags;
    EV650_CFG event_cfg;

    timekeeper_mode = CT650_TKPPS_GPS;
    timekeeper_flags = CT650_TKFLG_AUTOFOLLOW | CT650_TKFLG_USENOMINAL;
    ret = DqAdv650ConfigTimekeeper(hd, IRIG650_SLOT, timekeeper_mode, timekeeper_flags);
    if (ret < 0) {
        printf("Error %d in DqAdv650ConfigTimekeeper\n", ret);
    }

    /**
     * Configure the IRIG PPS Clock event
     */
//    memset(&event_cfg, 0, sizeof(event_cfg));
//    event_cfg.event_cfg = CT650_EVT_CFG_EN|CT650_EVT_CFG_EV1IRQ|CT650_EVT_CFG_EV0IRQ|
//                          CT650_EVT_CFG_RPT|
//                          CT650_EVT_CFG_EDGE|
//                          CT650_EVT_PPS;
//
//    ret = DqAdv650SetEvents(hd, IRIG650_SLOT, CT650_EVENT_CH0, UINT32_MAX, &event_cfg, NULL);
//    if (ret < 0) {
//        printf("Error %d in DqAdv650ConfigEvents (PPS CLK): Errno: %d\n", ret, errno);
//    }

    /**
     * Single buffer mode
     * TTL0 outputs the GPS PPS
     * TTL1 outputs the IRIG PPS
     */
    ret = DqAdv650AssignTTLOutputs(hd, IRIG650_SLOT,
            CT650_OUT_TTLEN1|CT650_OUT_TTLEN0,         // mode = enable both TTL drivers/buffers for sharper edges
            0,                                         // when 0, use external TTL0..3 to debug
            CT650_OUT_CFG_SRC_1GPS,                    // pulse(s) from event2 when it happens (used for trigger)
            CT650_OUT_CFG_SRC_1PPS,
            CT650_OUT_CFG_EVENT0,                      // pulse(s) from event1 (used for timestamp)
            CT650_OUT_CFG_SRC_1PPS);
//                    DqAdv650AssignTTLOutputs(hd, IRIG650_SLOT, CT650_OUT_TTLEN0, 0,
//    CT650_OUT_CFG_SRC_1GPS, CT650_OUT_CFG_SRC_1PPS, CT650_OUT_CFG_SRC_0, CT650_OUT_CFG_SRC_0);
    if (ret < 0) {
        printf("Error %d in DqAdv650AssignTTLOutputs\n", ret);
    }

    // Configure PLL and event module to output 100kHz timetamp clock to
        event.event_cfg =       CT650_EVT_CFG_EN            // Enable
                                |CT650_EVT_CFG_RPT          // 1 - repeat
                                |CT650_EVT_CFG_EVTPL(0xd)   // pulse length 0xD ns
                                |00 << 18                   // Internal counter source selector: 00 - 66/100MHz
                                |(CT650_EVT_PPS<<12)        // IRSRC = 20<<12 = 1PPS
                                |CT650_EVT_CFG_EDGE         // 1 - rising edge, 0 - falling edge
                                |CT650_EVT_CFG_ESRC_DPLL    // Event sources and internal counter reset source (ESRC)
                                |0;
#define TS_CLOCKRATE  100000    // timestamp rate used to program IRIG-650 PLL
        event.event_prm = TS_CLOCKRATE; // TS clock frequenecy
        event.event_sub0_dly = 0;
        event.event_sub1_dly = 0;
        event.event_val = 0;

        DqAdv650SetEvents(hd, IRIG650_SLOT, evt_chan, 0, &event, NULL);

    /**
     * Enable the IRIG-650 card
     */
    ret = DqAdv650Enable(hd, IRIG650_SLOT, true);
    if (ret < 0) {
        printf("Error %d in DqAdv650Enable\n", ret);
    }

    // Use posix timer to tick at the desired frequency
    periodns = (long long) floor(1000000000.0 / frequency);
    DqRtDmapInit(hd, &dmapid, 2 * frequency);

    /**
     * Add the AI-201, using the first channel as a timestamp
     */
    chentry = DQ_LNCL_TIMESTAMP;
    DqRtDmapAddChannel(hd, dmapid, AI201_SLOT, DQ_SS0IN, &chentry, 1);
    num_channels[AI201_SLOT]++;

    for (i = 0; i < 24; i++) {
        chentry = i | DQ_AI201_GAIN_1;
        DqRtDmapAddChannel(hd, dmapid, AI201_SLOT, DQ_SS0IN, &chentry, 1);
        num_channels[AI201_SLOT]++;
    }

    /**
     * Add the DIO-448.  First two channels are for Digital Input but the
     * remaining channels are single-ended analog
     */
    uint32_t aiCl[DQ_DIO448_LINES];
    for (i=0; i<DQ_DIO448_LINES; i++) {
       aiCl[i] = i;
    }
    // Configure hysteresis on all 48 input lines
    DqAdv448SetLevels(hd, DI448_SLOT, DQ_DIO448_LINES, aiCl, 1.0, 3.0);

    // Set debouncer time interval for all channels
    // interval is set in 100usecs increment
    DqAdv448SetDebouncer(hd, DI448_SLOT, DQ_DIO448_LINES, aiCl, 10);

    chentry = DQ_LNCL_TIMESTAMP;
    DqRtDmapAddChannel(hd, dmapid, DI448_SLOT, DQ_SS0IN, &chentry, 1);
    num_channels[DI448_SLOT]++;

    // Get the first de-bounced channel
    chentry = 2;
    DqRtDmapAddChannel(hd, dmapid, DI448_SLOT, DQ_SS0IN, &chentry, 1);
    num_channels[DI448_SLOT]++;

    // Get the second de-bounced channel
    chentry = 3;
    DqRtDmapAddChannel(hd, dmapid, DI448_SLOT, DQ_SS0IN, &chentry, 1);
    num_channels[DI448_SLOT]++;

    chentry = DQL_CHAN448_STATUS;
    DqRtDmapAddChannel(hd, dmapid, DI448_SLOT, DQ_SS0IN, &chentry, 1);
    num_channels[DI448_SLOT]++;

    for (i = DQL_CHAN448_CHSE(0); i < DQL_CHAN448_CHSE(48); i++) {
        chentry = i;
        DqRtDmapAddChannel(hd, dmapid, DI448_SLOT, DQ_SS0IN, &chentry, 1);
        num_channels[DI448_SLOT]++;
    }

    /**
     * Add the DO-432 analog input channels (single ended)
     */
    chentry = DQ_LNCL_TIMESTAMP;
    DqRtDmapAddChannel(hd, dmapid, DO432_SLOT, DQ_SS0IN, &chentry, 1);
    num_channels[DO432_SLOT]++;

    for (i = 32; i < 64; i++) {
        chentry = i;
        DqRtDmapAddChannel(hd, dmapid, DO432_SLOT, DQ_SS0IN, &chentry, 1);
        num_channels[DO432_SLOT]++;
    }

    /**
     * Add the AI-225 analog input channels (single ended)
     */
    chentry = DQ_LNCL_TIMESTAMP;
    DqRtDmapAddChannel(hd, dmapid, AI225_SLOT, DQ_SS0IN, &chentry, 1);
    num_channels[AI225_SLOT]++;

    for (i = 0; i < 25; i++) {
        chentry = i;
        DqRtDmapAddChannel(hd, dmapid, AI225_SLOT, DQ_SS0IN, &chentry, 1);
        num_channels[AI225_SLOT]++;
    }

    // Start the layers
    DqRtDmapStart(hd, dmapid);

    gettimeofday(&tv1, NULL);
    clock_gettime(CLOCK_MONOTONIC, &next);

    fprintf(gps_fp, "%ld.%ld:\tRestart GPS Stream\n", (long) next.tv_sec, (long) next.tv_nsec);
    fprintf(analog_fp, "%ld.%ld:\tRestart Analog Stream\n", (long) next.tv_sec, (long) next.tv_nsec);

    printf("Starting loop\n");

    while (!stop) {

        DqRtDmapRefresh(hd, dmapid);

        DqRtDmapReadRawData32(hd, dmapid, DI448_SLOT, input32, num_channels[DI448_SLOT]);
//        printf("0x%0.8X, 0x%0.8X, 0x%0.8X, 0x%0.8X\n", input32[0], input32[1], input32[2], input32[3]);
        if ((input32[1] & 0x7) != last_pps) {
            last_pps = input32[1] & 0x7;
            fprintf(pps_fp, "%ld.%ld, 0x%02X\n", (long) next.tv_sec, (long) next.tv_nsec, last_pps);
        }

        /**
         * Reset the watchdog timer for 10 seconds
         */
        //DqCmdSetWatchDog(hd, DQ_WD_CLEAR_ON_OSTASK, 10000, NULL, NULL);

        // read inputs retrieved by the last refresh once every 10 seconds
        if ((last_secs != next.tv_sec) && ((next.tv_sec % 10) == 0)) {
            last_secs = next.tv_sec;
            for (i = 0; i < 15; i++) {
                if (num_channels[i] <= 0) continue;

                DqRtDmapReadScaledData(hd, dmapid, i, input_buffer, num_channels[i]);

                fprintf(analog_fp, "Board %x, %ld.%ld, ", DQRdCfg->devmod[i], (long) next.tv_sec, (long) next.tv_nsec);
                for (int j = 0; j < num_channels[i]; j++) {
                    fprintf(analog_fp, "%0.8f, ", input_buffer[j]);
                }
                fprintf(analog_fp, "\n");

            }

            {
                uint32_t diag_channels[13] = { 0, 1, 2, 4, 6, 7, 8, 9, 10, 12, 13, 14, 15 };
                uint32_t bdata[13];
                ret = DqAdvDnxpRead(hd, BASE_SLOT, 13, diag_channels, bdata, input_buffer);
                if (ret < 0) {
                    printf("Error %d in DqAdvDnxpRead\n", ret);
                }
                fprintf(analog_fp, "Diag Layer, %ld.%ld, %0.8f, %0.8f, %0.8f, %0.8f, %0.8f, %0.8f, %0.8f, %0.8f, %0.8f, %0.8f, %0.8f, %0.8f, %0.8f\n",
                        (long) next.tv_sec, (long) next.tv_nsec,
                        input_buffer[0], input_buffer[1], input_buffer[2], input_buffer[3],
                        input_buffer[4], input_buffer[5], input_buffer[6], input_buffer[7],
                        input_buffer[8], input_buffer[9], input_buffer[10], input_buffer[11], input_buffer[12]);
            }


            read_GPS_IRIG(gps_fp);

            get_status(status_fp);

        }
        count++;

        timespec_add_ns(&next, periodns);
        clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &next, NULL);
    }

    /**
     * Turn off the watchdog timer now that we have called the exit
     */
   // DqCmdSetWatchDog(hd, DQ_WD_CLEAR_DISABLED, 0, NULL, NULL);

    DqRtDmapStop(hd, dmapid);

    DqRtDmapClose(hd, dmapid);

    finish_up:
    DqCloseIOM(hd);
    DqCleanUpDAQLib();

    fclose(gps_fp);
    fclose(status_fp);
    fclose(analog_fp);
    fclose(pps_fp);

    return 0;
}
示例#21
0
void* read_GPS_serial_line(void *arg)
{
    int ret = DQ_SUCCESS;
    sigset_t set;
    char buffer[DQ_MAX_UDP_PAYLOAD_100];
    uint8_t term[2] = {0x0D, 0x0A};
    FILE *fp;
    char *filename = "/mnt/data/gps_serial.dat";

    struct timeval tv1;
    struct timespec next;
    long long periodns = 10LL * NSECS_PER_SEC;

    sigemptyset(&set);
    sigaddset(&set, SIGINT);
    pthread_sigmask(SIG_BLOCK, &set, NULL);

    fp = fopen(filename, "a");

    // Set channel configuration
    if ((ret = DqAdv501SetChannelCfg(hd, SL508_SLOT, 0,
                DQCFG_501(DQ_SL501_OPER_NORM,
                          DQ_SL501_MODE_232,
                          DQ_SL501_BAUD_4800,
                          DQ_SL501_WIDTH_8,
                          DQ_SL501_STOP_1,
                          DQ_SL501_PARITY_NONE))) < 0) {
        printf("error %d in DqAdv501SetChannelCfg()\n", ret);
    }

    // Specifies how long the SL-50x waits for the requested amount of bytes to be
    // received before only returning the bytes received so far
    if ((ret = DqAdv501SetTimeout(hd, SL508_SLOT, 0, 10000)) < 0) {
        printf("error %d in DqAdv501SetTimeout\n", ret);
    }

    // Specifies the maximum of bytes to keep in the FIFO before returning them to
    // the user
    if ((ret = DqAdv501SetTermLength(hd, SL508_SLOT, 0, 1)) < 0) {
        printf("error %d in DqAdv501SetTermLength\n", ret);
    }

    if ((ret = DqAdv501SetTermString(hd, SL508_SLOT, 0, 2, term)) < 0) {
        printf("error %d in DqAdv501SetTermString\n", ret);
    }

    if ((ret = DqAdv501Enable(hd, SL508_SLOT, TRUE)) < 0) {
        printf("Error %d in DqAdv501Enable()\n", ret);
    }

    gettimeofday(&tv1, NULL);
    clock_gettime(CLOCK_MONOTONIC, &next);

    while(!stop)
    {
        uint16_t buffer_length = DQ_MAX_UDP_PAYLOAD_100;
        uint16_t received = 0;
        int success;
        int has_more = 1;
        uint8_t error_code;
        uint8_t *bufp = (uint8_t*)buffer;

        while (received < MINMEA_MAX_LENGTH + 3) {
            buffer_length = DQ_MAX_UDP_PAYLOAD_100 - received;
            ret = DqAdv501RecvMessage(hd, SL508_SLOT, 0, bufp, &buffer_length, &success, &error_code, &has_more);
            received += buffer_length;

            /**
             * Check to ensure our line starts with a valid character for the GPS read
             */
            if (buffer[0] != '$') received = 0;

            bufp = (uint8_t*)buffer + received;
            if(ret < 0)
            {
                printf("Error %d receiving from serial port\n", ret);
                break;
            }
            if ((received > 4) &&
                    (*(bufp - 1) == 0x0A) &&
                    (*(bufp - 2) == 0x0D))
                break;
        }

        *bufp = '\0';

        if (success) decode_NMEA(buffer, fp);

        if (!has_more) {
            timespec_add_ns(&next, periodns);
            clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &next, NULL);
        }
    }

    fclose(fp);

    return NULL;
}