Пример #1
0
/*
 * Motion Sense Task
 * Requirement: motion_sensors[] are defined in board.c file.
 * Two (minimium) Accelerometers:
 *    1 in the A/B(lid, display) and 1 in the C/D(base, keyboard)
 * Gyro Sensor (optional)
 */
void motion_sense_task(void)
{
	int i, ret, wait_us, fifo_flush_needed = 0;
	timestamp_t ts_begin_task, ts_end_task;
	uint32_t event = 0;
	uint16_t ready_status;
	struct motion_sensor_t *sensor;
#ifdef CONFIG_LID_ANGLE
	const uint16_t lid_angle_sensors = ((1 << CONFIG_LID_ANGLE_SENSOR_BASE)|
					    (1 << CONFIG_LID_ANGLE_SENSOR_LID));
#endif
#ifdef CONFIG_ACCEL_FIFO
	timestamp_t ts_last_int;
#endif
#ifdef CONFIG_LPC
	int sample_id = 0;
	uint8_t *lpc_status;
	uint16_t *lpc_data;

	lpc_status = host_get_memmap(EC_MEMMAP_ACC_STATUS);
	lpc_data = (uint16_t *)host_get_memmap(EC_MEMMAP_ACC_DATA);
	set_present(lpc_status);
#endif

#ifdef CONFIG_ACCEL_FIFO
	ts_last_int = get_time();
#endif
	do {
		ts_begin_task = get_time();
		ready_status = 0;
		for (i = 0; i < motion_sensor_count; ++i) {

			sensor = &motion_sensors[i];

			/* if the sensor is active in the current power state */
			if (SENSOR_ACTIVE(sensor)) {
				if (sensor->state != SENSOR_INITIALIZED) {
					continue;
				}

				ts_begin_task = get_time();
				ret = motion_sense_process(sensor, event,
						&ts_begin_task,
						&fifo_flush_needed);
				if (ret != EC_SUCCESS)
					continue;
				ready_status |= (1 << i);
			}
		}

#ifdef CONFIG_GESTURE_DETECTION
		/* Run gesture recognition engine */
		gesture_calc();
#endif
#ifdef CONFIG_LID_ANGLE
		/*
		 * Check to see that the sensors required for lid angle
		 * calculation are ready.
		 */
		ready_status &= lid_angle_sensors;
		if (ready_status == lid_angle_sensors)
			motion_lid_calc();
#endif
#ifdef CONFIG_CMD_ACCEL_INFO
		if (accel_disp) {
			CPRINTF("[%T event 0x%08x ", event);
			for (i = 0; i < motion_sensor_count; ++i) {
				sensor = &motion_sensors[i];
				CPRINTF("%s=%-5d, %-5d, %-5d ", sensor->name,
					sensor->xyz[X],
					sensor->xyz[Y],
					sensor->xyz[Z]);
			}
#ifdef CONFIG_LID_ANGLE
			CPRINTF("a=%-4d", motion_lid_get_angle());
#endif
			CPRINTF("]\n");
		}
#endif
#ifdef CONFIG_LPC
		update_sense_data(lpc_status, lpc_data, &sample_id);
#endif

		ts_end_task = get_time();
#ifdef CONFIG_ACCEL_FIFO
		/*
		 * Ask the host to flush the queue if
		 * - a flush event has been queued.
		 * - the queue is almost full,
		 * - we haven't done it for a while.
		 */
		if (fifo_flush_needed ||
		    event & TASK_EVENT_MOTION_ODR_CHANGE ||
		    queue_space(&motion_sense_fifo) < CONFIG_ACCEL_FIFO_THRES ||
		    (accel_interval > 0 &&
		     (ts_end_task.val - ts_last_int.val) > accel_interval)) {
			if (!fifo_flush_needed)
				motion_sense_insert_timestamp();
			fifo_flush_needed = 0;
			ts_last_int = ts_end_task;
#ifdef CONFIG_MKBP_EVENT
			/*
			 * We don't currently support wake up sensor.
			 * When we do, add per sensor test to know
			 * when sending the event.
			 */
			if (sensor_active == SENSOR_ACTIVE_S0)
				mkbp_send_event(EC_MKBP_EVENT_SENSOR_FIFO);
#endif
		}
#endif
		if (accel_interval > 0) {
			/*
			 * Delay appropriately to keep sampling time
			 * consistent.
			 */
			wait_us = accel_interval -
				(ts_end_task.val - ts_begin_task.val);

			/*
			 * Guarantee some minimum delay to allow other lower
			 * priority tasks to run.
			 */
			if (wait_us < MIN_MOTION_SENSE_WAIT_TIME)
				wait_us = MIN_MOTION_SENSE_WAIT_TIME;
		} else {
			wait_us = -1;
		}

	} while ((event = task_wait_event(wait_us)));
}
Пример #2
0
int pd_custom_vdm(int port, int cnt, uint32_t *payload,
		  uint32_t **rpayload)
{
	int cmd = PD_VDO_CMD(payload[0]);
	uint16_t dev_id = 0;
	int is_rw, is_latest;

	/* make sure we have some payload */
	if (cnt == 0)
		return 0;

	switch (cmd) {
	case VDO_CMD_VERSION:
		/* guarantee last byte of payload is null character */
		*(payload + cnt - 1) = 0;
		CPRINTF("version: %s\n", (char *)(payload+1));
		break;
	case VDO_CMD_READ_INFO:
	case VDO_CMD_SEND_INFO:
		/* copy hash */
		if (cnt == 7) {
			dev_id = VDO_INFO_HW_DEV_ID(payload[6]);
			is_rw = VDO_INFO_IS_RW(payload[6]);
			is_latest = pd_dev_store_rw_hash(port,
							 dev_id,
							 payload + 1,
							 is_rw ?
							 SYSTEM_IMAGE_RW :
							 SYSTEM_IMAGE_RO);

			/*
			 * Send update host event unless our RW hash is
			 * already known to be the latest update RW.
			 */
			if (!is_rw || !is_latest)
				pd_send_host_event(PD_EVENT_UPDATE_DEVICE);

			CPRINTF("DevId:%d.%d SW:%d RW:%d\n",
				HW_DEV_ID_MAJ(dev_id),
				HW_DEV_ID_MIN(dev_id),
				VDO_INFO_SW_DBG_VER(payload[6]),
				is_rw);
		} else if (cnt == 6) {
			/* really old devices don't have last byte */
			pd_dev_store_rw_hash(port, dev_id, payload + 1,
					     SYSTEM_IMAGE_UNKNOWN);
		}
		break;
	case VDO_CMD_CURRENT:
		CPRINTF("Current: %dmA\n", payload[1]);
		break;
	case VDO_CMD_FLIP:
		usb_mux_flip(port);
		break;
#ifdef CONFIG_USB_PD_LOGGING
	case VDO_CMD_GET_LOG:
		pd_log_recv_vdm(port, cnt, payload);
		break;
#endif /* CONFIG_USB_PD_LOGGING */
#ifdef CONFIG_CASE_CLOSED_DEBUG
	case VDO_CMD_CCD_EN:
		ccd_set_mode(system_is_locked() ? CCD_MODE_PARTIAL
						: CCD_MODE_ENABLED);
		break;
#endif
	}

	return 0;
}
Пример #3
0
static void siglog_deferred(void)
{
	const struct gpio_info *g = gpio_list;
	unsigned int i;
	timestamp_t tdiff = {.val = 0};

	/* Disable interrupts for input signals while we print stuff.*/
	for (i = 0; i < POWER_SIGNAL_COUNT; i++)
		gpio_disable_interrupt(power_signal_list[i].gpio);

	CPRINTF("%d signal changes:\n", siglog_entries);
	for (i = 0; i < siglog_entries; i++) {
		if (i)
			tdiff.val = siglog[i].time.val - siglog[i-1].time.val;
		CPRINTF("  %.6ld  +%.6ld  %s => %d\n",
			siglog[i].time.val, tdiff.val,
			g[siglog[i].signal].name,
			siglog[i].level);
	}
	if (siglog_truncated)
		CPRINTF("  SIGNAL LOG TRUNCATED...\n");
	siglog_entries = siglog_truncated = 0;

	/* Okay, turn 'em on again. */
	for (i = 0; i < POWER_SIGNAL_COUNT; i++)
		gpio_enable_interrupt(power_signal_list[i].gpio);
}
DECLARE_DEFERRED(siglog_deferred);

static void siglog_add(enum gpio_signal signal)
{
	if (siglog_entries >= MAX_SIGLOG_ENTRIES) {
		siglog_truncated = 1;
		return;
	}

	siglog[siglog_entries].time = get_time();
	siglog[siglog_entries].signal = signal;
	siglog[siglog_entries].level = gpio_get_level(signal);
	siglog_entries++;

	hook_call_deferred(siglog_deferred, SECOND);
}

#define SIGLOG(S) siglog_add(S)

#else
#define SIGLOG(S)
#endif	/* CONFIG_BRINGUP */


void power_signal_interrupt(enum gpio_signal signal)
{
	SIGLOG(signal);

	/* Shadow signals and compare with our desired signal state. */
	power_update_signals();

	/* Wake up the task */
	task_wake(TASK_ID_CHIPSET);
}
Пример #4
0
test_mockable __keep int main(void)
{
#ifdef CONFIG_REPLACE_LOADER_WITH_BSS_SLOW
	/*
	 * Now that we have started execution, we no longer need the loader.
	 * Instead, variables placed in the .bss.slow section will use this
	 * space.  Therefore, clear out this region now.
	 */
	memset((void *)(CONFIG_PROGRAM_MEMORY_BASE + CONFIG_LOADER_MEM_OFF), 0,
	       CONFIG_LOADER_SIZE);
#endif /* defined(CONFIG_REPLACE_LOADER_WITH_BSS_SLOW) */
	/*
	 * Pre-initialization (pre-verified boot) stage.  Initialization at
	 * this level should do as little as possible, because verified boot
	 * may need to jump to another image, which will repeat this
	 * initialization.  In particular, modules should NOT enable
	 * interrupts.
	 */
#ifdef CONFIG_BOARD_PRE_INIT
	board_config_pre_init();
#endif

#ifdef CONFIG_MPU
	mpu_pre_init();
#endif

	/* Configure the pin multiplexers and GPIOs */
	jtag_pre_init();
	gpio_pre_init();

#ifdef CONFIG_BOARD_POST_GPIO_INIT
	board_config_post_gpio_init();
#endif
	/*
	 * Initialize interrupts, but don't enable any of them.  Note that
	 * task scheduling is not enabled until task_start() below.
	 */
	task_pre_init();

	/*
	 * Initialize the system module.  This enables the hibernate clock
	 * source we need to calibrate the internal oscillator.
	 */
	system_pre_init();
	system_common_pre_init();

#ifdef CONFIG_FLASH
	/*
	 * Initialize flash and apply write protect if necessary.  Requires
	 * the reset flags calculated by system initialization.
	 */
	flash_pre_init();
#endif

#if defined(CONFIG_CASE_CLOSED_DEBUG)
	/*
	 * If the device is locked we assert PD_NO_DEBUG, preventing the EC
	 * from interfering with the AP's access to the SPI flash.
	 * The PD_NO_DEBUG signal is latched in hardware, so changing this
	 * GPIO later has no effect.
	 */
	gpio_set_level(GPIO_PD_DISABLE_DEBUG, system_is_locked());
#endif

	/* Set the CPU clocks / PLLs.  System is now running at full speed. */
	clock_init();

	/*
	 * Initialize timer.  Everything after this can be benchmarked.
	 * get_time() and udelay() may now be used.  usleep() requires task
	 * scheduling, so cannot be used yet.  Note that interrupts declared
	 * via DECLARE_IRQ() call timer routines when profiling is enabled, so
	 * timer init() must be before uart_init().
	 */
	timer_init();

	/* Main initialization stage.  Modules may enable interrupts here. */
	cpu_init();

#ifdef CONFIG_DMA
	/* Initialize DMA.  Must be before UART. */
	dma_init();
#endif

	/* Initialize UART.  Console output functions may now be used. */
	uart_init();

	if (system_jumped_to_this_image()) {
		CPRINTS("UART initialized after sysjump");
	} else {
		CPUTS("\n\n--- UART initialized after reboot ---\n");
		CPUTS("[Reset cause: ");
		system_print_reset_flags();
		CPUTS("]\n");
	}
	CPRINTF("[Image: %s, %s]\n",
		 system_get_image_copy_string(), system_get_build_info());

#ifdef CONFIG_BRINGUP
	ccprintf("\n\nWARNING: BRINGUP BUILD\n\n\n");
#endif

#ifdef CONFIG_WATCHDOG
	/*
	 * Intialize watchdog timer.  All lengthy operations between now and
	 * task_start() must periodically call watchdog_reload() to avoid
	 * triggering a watchdog reboot.  (This pretty much applies only to
	 * verified boot, because all *other* lengthy operations should be done
	 * by tasks.)
	 */
	watchdog_init();
#endif

	/*
	 * Verified boot needs to read the initial keyboard state and EEPROM
	 * contents.  EEPROM must be up first, so keyboard_scan can toggle
	 * debugging settings via keys held at boot.
	 */
#ifdef CONFIG_EEPROM
	eeprom_init();
#endif
#ifdef HAS_TASK_KEYSCAN
	keyboard_scan_init();
#endif

#ifdef CONFIG_RWSIG
	/*
	 * Check the RW firmware signature
	 * and eventually jump to it if it is good.
	 */
	check_rw_signature();
#endif

	/*
	 * Print the init time.  Not completely accurate because it can't take
	 * into account the time before timer_init(), but it'll at least catch
	 * the majority of the time.
	 */
	CPRINTS("Inits done");

	/* Launch task scheduling (never returns) */
	return task_start();
}
Пример #5
0
Файл: spi.c Проект: longsleep/ec
/**
 * Handle an event on the NSS pin
 *
 * A falling edge of NSS indicates that the master is starting a new
 * transaction. A rising edge indicates that we have finsihed
 *
 * @param signal	GPIO signal for the NSS pin
 */
void spi_event(enum gpio_signal signal)
{
	stm32_dma_chan_t *rxdma;
	uint16_t *nss_reg;
	uint32_t nss_mask;
	uint16_t i;

	/* If not enabled, ignore glitches on NSS */
	if (!enabled)
		return;

	/* Check chip select.  If it's high, the AP ended a transaction. */
	nss_reg = gpio_get_level_reg(GPIO_SPI1_NSS, &nss_mask);
	if (REG16(nss_reg) & nss_mask) {
		enable_sleep(SLEEP_MASK_SPI);

		/*
		 * If the buffer is still used by the host command, postpone
		 * the DMA rx setup.
		 */
		if (state == SPI_STATE_PROCESSING) {
			setup_transaction_later = 1;
			return;
		}

		/* Set up for the next transaction */
		spi_init(); /* Fix for bug chrome-os-partner:31390 */
		return;
	}
	disable_sleep(SLEEP_MASK_SPI);

	/* Chip select is low = asserted */
	if (state != SPI_STATE_READY_TO_RX) {
		/*
		 * AP started a transaction but we weren't ready for it.
		 * Tell AP we weren't ready, and ignore the received data.
		 */
		CPRINTS("SPI not ready");
		tx_status(EC_SPI_NOT_READY);
		state = SPI_STATE_RX_BAD;
		return;
	}

	/* We're now inside a transaction */
	state = SPI_STATE_RECEIVING;
	tx_status(EC_SPI_RECEIVING);
	rxdma = dma_get_channel(STM32_DMAC_SPI1_RX);

	/* Wait for version, command, length bytes */
	if (wait_for_bytes(rxdma, 3, nss_reg, nss_mask))
		goto spi_event_error;

	if (in_msg[0] == EC_HOST_REQUEST_VERSION) {
		/* Protocol version 3 */
		struct ec_host_request *r = (struct ec_host_request *)in_msg;
		int pkt_size;

		/* Wait for the rest of the command header */
		if (wait_for_bytes(rxdma, sizeof(*r), nss_reg, nss_mask))
			goto spi_event_error;

		/*
		 * Check how big the packet should be.  We can't just wait to
		 * see how much data the host sends, because it will keep
		 * sending dummy data until we respond.
		 */
		pkt_size = host_request_expected_size(r);
		if (pkt_size == 0 || pkt_size > sizeof(in_msg))
			goto spi_event_error;

		/* Wait for the packet data */
		if (wait_for_bytes(rxdma, pkt_size, nss_reg, nss_mask))
			goto spi_event_error;

		spi_packet.send_response = spi_send_response_packet;

		spi_packet.request = in_msg;
		spi_packet.request_temp = NULL;
		spi_packet.request_max = sizeof(in_msg);
		spi_packet.request_size = pkt_size;

		/* Response must start with the preamble */
		memcpy(out_msg, out_preamble, sizeof(out_preamble));
		spi_packet.response = out_msg + sizeof(out_preamble);
		/* Reserve space for the preamble and trailing past-end byte */
		spi_packet.response_max = sizeof(out_msg)
			- sizeof(out_preamble) - EC_SPI_PAST_END_LENGTH;
		spi_packet.response_size = 0;

		spi_packet.driver_result = EC_RES_SUCCESS;

		/* Move to processing state */
		state = SPI_STATE_PROCESSING;
		tx_status(EC_SPI_PROCESSING);

		host_packet_receive(&spi_packet);
		return;

	} else if (in_msg[0] >= EC_CMD_VERSION0) {
		/*
		 * Protocol version 2
		 *
		 * TODO(crosbug.com/p/20257): Remove once kernel supports
		 * version 3.
		 */

#ifdef CHIP_FAMILY_STM32F0
		CPRINTS("WARNING: Protocol version 2 is not supported on the F0"
			" line due to crbug.com/31390");
#endif

		args.version = in_msg[0] - EC_CMD_VERSION0;
		args.command = in_msg[1];
		args.params_size = in_msg[2];

		/* Wait for parameters */
		if (wait_for_bytes(rxdma, 3 + args.params_size,
				   nss_reg, nss_mask))
			goto spi_event_error;

		/*
		 * Params are not 32-bit aligned in protocol version 2.  As a
		 * workaround, move them to the beginning of the input buffer
		 * so they are aligned.
		 */
		if (args.params_size)
			memmove(in_msg, in_msg + 3, args.params_size);

		args.params = in_msg;
		args.send_response = spi_send_response;

		/* Allow room for the header bytes */
		args.response = out_msg + SPI_PROTO2_OFFSET;
		args.response_max = sizeof(out_msg) - SPI_PROTO2_OVERHEAD;
		args.response_size = 0;
		args.result = EC_RES_SUCCESS;

		/* Move to processing state */
		state = SPI_STATE_PROCESSING;
		tx_status(EC_SPI_PROCESSING);

		host_command_received(&args);
		return;
	}

 spi_event_error:
	/* Error, timeout, or protocol we can't handle.  Ignore data. */
	tx_status(EC_SPI_RX_BAD_DATA);
	state = SPI_STATE_RX_BAD;
	CPRINTS("SPI rx bad data");

	CPRINTF("in_msg=[");
	for (i = 0; i < dma_bytes_done(rxdma, sizeof(in_msg)); i++)
		CPRINTF("%02x ", in_msg[i]);
	CPRINTF("]\n");
}
Пример #6
0
/*---------------------------------------------------------------------------*/
static int
read_packet(void)
{
  struct xmac_hdr *hdr;
  uint8_t len;

  rimebuf_clear();

  len = radio->read(rimebuf_dataptr(), RIMEBUF_SIZE);

  if(len > 0) {
    rimebuf_set_datalen(len);
    hdr = rimebuf_dataptr();

    rimebuf_hdrreduce(sizeof(struct xmac_hdr));

    if(rimebuf_totlen() == 0) {
      CPRINTF(".");
      /* There is no data in the packet so it has to be a strobe. */
      someone_is_sending = 2;
      
      if(rimeaddr_cmp(&hdr->receiver, &rimeaddr_node_addr)) {
	/* This is a strobe packet for us. */

	if(rimeaddr_cmp(&hdr->sender, &rimeaddr_node_addr)) {
	  /* If the sender address is our node address, the strobe is
	     a stray strobe ACK to us, which we ignore unless we are
	     currently sending a packet.  */
	  CPRINTF("&");
	  someone_is_sending = 0;
	} else {
	  struct xmac_hdr msg;
	  /* If the sender address is someone else, we should
	     acknowledge the strobe and wait for the packet. By using
	     the same address as both sender and receiver, we flag the
	     message is a strobe ack. */
#if WITH_TIMETABLE
	  TIMETABLE_TIMESTAMP(xmac_timetable, "read send ack");
#endif
	  rimeaddr_copy(&msg.receiver, &hdr->sender);
	  rimeaddr_copy(&msg.sender, &hdr->sender);
	  CPRINTF("!");
	  /* We turn on the radio in anticipation of the incoming
	     packet. */
	  someone_is_sending = 1;
	  waiting_for_packet = 1;
	  on();
	  radio->send((const uint8_t *)&msg, sizeof(struct xmac_hdr));
	}
      } else if(rimeaddr_cmp(&hdr->receiver, &rimeaddr_null)) {
	/* If the receiver address is null, the strobe is sent to
	   prepare for an incoming broadcast packet. If this is the
	   case, we turn on the radio and wait for the incoming
	   broadcast packet. */
	waiting_for_packet = 1;
	on();
      }
      /* We are done processing the strobe and we therefore return
	 to the caller. */
      return RIME_OK;
    } else {
      CPRINTF("-");
      someone_is_sending = 0;
      if(rimeaddr_cmp(&hdr->receiver, &rimeaddr_node_addr) ||
	 rimeaddr_cmp(&hdr->receiver, &rimeaddr_null)) {
#if WITH_TIMETABLE
	TIMETABLE_TIMESTAMP(xmac_timetable, "read got packet");
#endif
	/* This is a regular packet that is destined to us or to the
	   broadcast address. */
	
	/* We have received the final packet, so we can go back to being
	   asleep. */
	off();
	waiting_for_packet = 0;
	
	/* XXX should set timer to send queued packet later. */
	if(queued_packet != NULL) {
	  queuebuf_free(queued_packet);
	  queued_packet = NULL;
	}
	
	return rimebuf_totlen();
      }
    }
  }
  return 0;
}
Пример #7
0
/*---------------------------------------------------------------------------*/
static int
send_packet(void)
{
  rtimer_clock_t t0;
  rtimer_clock_t t;
  int strobes;
  struct xmac_hdr *hdr;
  int got_ack = 0;
  struct xmac_hdr msg;
  int len;
  int is_broadcast = 0;

#if WITH_TIMETABLE
  TIMETABLE_TIMESTAMP(xmac_timetable, "send");
#endif
  
#if WITH_CHANNEL_CHECK
  /* Check if there are other strobes in the air. */
  waiting_for_packet = 1;
  on();
  t0 = RTIMER_NOW();
  while(RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + xmac_config.strobe_wait_time * 2)) {
    len = radio->read(&msg, sizeof(msg));
    if(len > 0) {
      someone_is_sending = 1;
    }
  }
  waiting_for_packet = 0;
  
  while(someone_is_sending); /* {printf("z");}*/

#if WITH_TIMETABLE
  TIMETABLE_TIMESTAMP(xmac_timetable, "send 2");
#endif /* WITH_TIMETABLE */
  
#endif /* WITH_CHANNEL_CHECK */
  
  /* By setting we_are_sending to one, we ensure that the rtimer
     powercycle interrupt do not interfere with us sending the packet. */
  we_are_sending = 1;

  off();

  
  rimebuf_hdralloc(sizeof(struct xmac_hdr));
  hdr = rimebuf_hdrptr();
  rimeaddr_copy(&hdr->sender, &rimeaddr_node_addr);
  rimeaddr_copy(&hdr->receiver, rimebuf_addr(RIMEBUF_ADDR_RECEIVER));
  if(rimeaddr_cmp(&hdr->receiver, &rimeaddr_null)) {
    is_broadcast = 1;
  }
  rimebuf_compact();

  t0 = RTIMER_NOW();
  strobes = 0;

  BB_SET(XMAC_RECEIVER, hdr->receiver.u16[0]);
  
  LEDS_ON(LEDS_BLUE);

  /* Send a train of strobes until the receiver answers with an ACK. */

  /* Turn on the radio to listen for the strobe ACK. */
  if(!is_broadcast) {
    on();
  }

  watchdog_stop();
  got_ack = 0;
  for(strobes = 0;
      got_ack == 0 &&
	RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + xmac_config.strobe_time);
      strobes++) {

    t = RTIMER_NOW();

    rimeaddr_copy(&msg.sender, &rimeaddr_node_addr);
    rimeaddr_copy(&msg.receiver, rimebuf_addr(RIMEBUF_ADDR_RECEIVER));

#if WITH_TIMETABLE
    if(rimeaddr_cmp(&msg.receiver, &rimeaddr_null)) {
      TIMETABLE_TIMESTAMP(xmac_timetable, "send broadcast strobe");
    } else {
      TIMETABLE_TIMESTAMP(xmac_timetable, "send strobe");
    }
#endif
    if(is_broadcast) {
      /* If we are sending a broadcast, we don't send strobes, we
	 simply send the data packet repetedly */
      radio->send(rimebuf_hdrptr(), rimebuf_totlen());
    } else {
      /* Send the strobe packet. */
      radio->send((const uint8_t *)&msg, sizeof(struct xmac_hdr));
    }
    CPRINTF("+");

    while(got_ack == 0 &&
	  RTIMER_CLOCK_LT(RTIMER_NOW(), t + xmac_config.strobe_wait_time)) {
      /* See if we got an ACK */
      len = radio->read((uint8_t *)&msg, sizeof(struct xmac_hdr));
      if(len > 0) {
	CPRINTF("_");
	if(rimeaddr_cmp(&msg.sender, &rimeaddr_node_addr) &&
	   rimeaddr_cmp(&msg.receiver, &rimeaddr_node_addr)) {
#if WITH_TIMETABLE
	  TIMETABLE_TIMESTAMP(xmac_timetable, "send ack received");
#endif
	  CPRINTF("@");
	  /* We got an ACK from the receiver, so we can immediately send
	     the packet. */
	  got_ack = 1;
	}
      }
    }

    /* XXX: turn off radio if we haven't heard an ACK within a
       specified time interval. */

    /*    if(got_ack == 0) {
      off();
      while(RTIMER_CLOCK_LT(RTIMER_NOW(), t + xmac_config.strobe_wait_time));
      on();
      }*/
  }

  if(got_ack /* XXX && needs_ack */) {
#if WITH_TIMETABLE
    TIMETABLE_TIMESTAMP(xmac_timetable, "send got ack");
#endif
    on(); /* Wait for possible ACK packet */
  } else if(!is_broadcast) {
#if WITH_TIMETABLE
    TIMETABLE_TIMESTAMP(xmac_timetable, "send no ack received");
#endif
    on(); /* shell ping don't seem to work with off() here, so we'll
	     keep it on() for a while. */
  }

  /* Send the data packet. */
  if(is_broadcast || got_ack) {
#if WITH_TIMETABLE
    TIMETABLE_TIMESTAMP(xmac_timetable, "send packet");
#endif
    radio->send(rimebuf_hdrptr(), rimebuf_totlen());
    CPRINTF("#");
  }
  watchdog_start();

  PRINTF("xmac: send (strobes=%u,len=%u,%s), done\n", strobes,
	 rimebuf_totlen(), got_ack ? "ack" : "no ack");

  BB_SET(XMAC_STROBES, strobes);
  if(got_ack) {
    BB_INC(XMAC_SEND_WITH_ACK, 1);
  } else {
    BB_INC(XMAC_SEND_WITH_NOACK, 1);
  }

  /*  printf("Strobe %d got_ack %d\n", strobes, got_ack);*/

  we_are_sending = 0;
#if WITH_TIMETABLE
  TIMETABLE_TIMESTAMP(xmac_timetable, "send we_are_sending = 0");
#endif
  LEDS_OFF(LEDS_BLUE);
  return 1;

}
Пример #8
0
/*---------------------------------------------------------------------------*/
static char 
powercycle(struct rtimer *t, void *ptr)
{
  int r;
#if WITH_TIMESYNCH
  rtimer_clock_t should_be, adjust;
#endif /* WITH_TIMESYNCH */

  CPRINTF("*");
  
  PT_BEGIN(&pt);

  while(1) {
    /* Only wait for some cycles to pass for someone to start sending */
    if(someone_is_sending > 0) {
      someone_is_sending--;
    }

    if(xmac_config.off_time > 0) {
      if(waiting_for_packet == 0) {
	if(we_are_sending == 0) {
	  off();
	}
      } else {
	waiting_for_packet++;
	if(waiting_for_packet > 2) {
	  /* We should not be awake for more than two consecutive
	     power cycles without having heard a packet, so we turn off
	     the radio. */
	  waiting_for_packet = 0;
#if WITH_TIMETABLE
	  TIMETABLE_TIMESTAMP(xmac_timetable, "off waiting");
#endif
	  off();
	}
      }

#if WITH_TIMESYNCH
#define NUM_SLOTS 8
      should_be = ((timesynch_rtimer_to_time(RTIMER_TIME(t)) +
		    xmac_config.off_time) &
		   ~(xmac_config.off_time + xmac_config.on_time - 1)) +
	(rimeaddr_node_addr.u8[0] % NUM_SLOTS *
	 ((xmac_config.off_time + xmac_config.on_time) / NUM_SLOTS));

      should_be = timesynch_time_to_rtimer(should_be);

      if(should_be - RTIMER_TIME(t) > xmac_config.off_time) {
	adjust = xmac_config.off_time / 2;
      } else {
	adjust = should_be - RTIMER_TIME(t);
      }
      r = rtimer_set(t, RTIMER_TIME(t) + adjust, 1,
		     (void (*)(struct rtimer *, void *))powercycle, ptr);
#else /* WITH_TIMESYNCH */
      r = rtimer_set(t, RTIMER_TIME(t) + xmac_config.off_time, 1,
		     TC(powercycle), ptr);
#endif /* WITH_TIMESYNCH */
      if(r) {
	PRINTF("xmac: 1 could not set rtimer %d\n", r);
      }
      PT_YIELD(&pt);
    }

    if(we_are_sending == 0 &&
       waiting_for_packet == 0) {
      on();
    }
    r = rtimer_set(t, RTIMER_TIME(t) + xmac_config.on_time, 1,
		   TC(powercycle), ptr);
    if(r) {
      PRINTF("xmac: 3 could not set rtimer %d\n", r);
    }

    PT_YIELD(&pt);
  }

  PT_END(&pt);
}
Пример #9
0
static int do_flash_op(enum flash_op op, int is_info_bank,
		       int byte_offset, int words)
{
	volatile uint32_t *fsh_pe_control;
	uint32_t opcode, tmp, errors;
	int retry_count, max_attempts, extra_prog_pulse, i;
	int timedelay_us = 100;
	uint32_t prev_error = 0;

	/* Make sure the smart program/erase algorithms are enabled. */
	if (!GREAD(FLASH, FSH_TIMING_PROG_SMART_ALGO_ON) ||
	    !GREAD(FLASH, FSH_TIMING_ERASE_SMART_ALGO_ON)) {
		CPRINTF("%s:%d\n", __func__, __LINE__);
		return EC_ERROR_UNIMPLEMENTED;
	}

	/* Error status is self-clearing. Read it until it does (we hope). */
	for (i = 0; i < 50; i++) {
		tmp = GREAD(FLASH, FSH_ERROR);
		if (!tmp)
			break;
		usleep(timedelay_us);
	}
	/* If we can't clear the error status register then something is wrong.
	 */
	if (tmp) {
		CPRINTF("%s:%d\n", __func__, __LINE__);
		return EC_ERROR_UNKNOWN;
	}

	/* We have two flash banks. Adjust offset and registers accordingly. */
	if (is_info_bank) {
		/* Only INFO bank operations are supported. */
		fsh_pe_control = GREG32_ADDR(FLASH, FSH_PE_CONTROL1);
	} else if (byte_offset >= CONFIG_FLASH_SIZE / 2) {
		byte_offset -= CONFIG_FLASH_SIZE / 2;
		fsh_pe_control = GREG32_ADDR(FLASH, FSH_PE_CONTROL1);
	} else {
		fsh_pe_control = GREG32_ADDR(FLASH, FSH_PE_CONTROL0);
	}

	/* What are we doing? */
	switch (op) {
	case OP_ERASE_BLOCK:
		if (is_info_bank)
			/* Erasing the INFO bank from the RW section is
			 * unsupported. */
			return EC_ERROR_INVAL;
		opcode = 0x31415927;
		words = 0;			/* don't care, really */
		/* This number is based on the TSMC spec Nme=Terase/Tsme */
		max_attempts = 45;
		break;
	case OP_WRITE_BLOCK:
		opcode = 0x27182818;
		words--;		     /* count register is zero-based */
		/* This number is based on the TSMC spec Nmp=Tprog/Tsmp */
		max_attempts = 9;
		break;
	}

	/*
	 * Set the parameters. For writes, we assume the write buffer is
	 * already filled before we call this function.
	 */
	GWRITE_FIELD(FLASH, FSH_TRANS, OFFSET,
		     byte_offset / 4);		  /* word offset */
	GWRITE_FIELD(FLASH, FSH_TRANS, MAINB, is_info_bank ? 1 : 0);
	GWRITE_FIELD(FLASH, FSH_TRANS, SIZE, words);

	/* TODO: Make sure this function isn't getting called "too often" in
	 * between erases.
	 */
	extra_prog_pulse = 0;
	for (retry_count = 0; retry_count < max_attempts; retry_count++) {
		/* Kick it off */
		GWRITE(FLASH, FSH_PE_EN, 0xb11924e1);
		*fsh_pe_control = opcode;

		/* Wait for completion. 150ms should be enough
		 * (crosbug.com/p/45366).
		 */
		for (i = 0; i < 1500; i++) {
			tmp = *fsh_pe_control;
			if (!tmp)
				break;
			usleep(timedelay_us);
		}

		/* Timed out waiting for control register to clear */
		if (tmp) {
			CPRINTF("%s:%d\n", __func__, __LINE__);
			return EC_ERROR_UNKNOWN;
		}
		/* Check error status */
		errors = GREAD(FLASH, FSH_ERROR);

		if (errors && (errors != prev_error)) {
			prev_error = errors;
			CPRINTF("%s:%d errors %x fsh_pe_control %p\n",
				__func__, __LINE__, errors, fsh_pe_control);
		}
		/* Error status is self-clearing. Read it until it does
		 * (we hope).
		 */
		for (i = 0; i < 50; i++) {
			tmp = GREAD(FLASH, FSH_ERROR);
			if (!tmp)
				break;
			usleep(timedelay_us);
		}
		/* If we can't clear the error status register then something
		 * is wrong.
		 */
		if (tmp) {
			CPRINTF("%s:%d\n", __func__, __LINE__);
			return EC_ERROR_UNKNOWN;
		}
		/* The operation was successful. */
		if (!errors) {
			/* From the spec:
			 * "In addition, one more program pulse is needed after
			 * program verification is passed."
			 */
			if (op == OP_WRITE_BLOCK && !extra_prog_pulse) {
				extra_prog_pulse = 1;
				max_attempts++;
				continue;
			}
			return EC_SUCCESS;
		}
		/* If there were errors after completion retry. */
		watchdog_reload();
	}
	CPRINTF("%s:%d, retry count %d\n", __func__, __LINE__, retry_count);
	return EC_ERROR_UNKNOWN;
}