Linux Audio

Check our new training course

Embedded Linux Audio

Check our new training course
with Creative Commons CC-BY-SA
lecture materials

Bootlin logo

Elixir Cross Referencer

Loading...
/* dummy_15_4_radio.c - 802.15.4 radio driver loopbacks Tx frames back to us */

/*
 * Copyright (c) 2015 Intel Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "contiki.h"

#include <net/l2_buf.h>
#include <console/uart_pipe.h>

#include "contiki/packetbuf.h"
#include "contiki/netstack.h"
#include "dummy_15_4_radio.h"
#include "net_driver_15_4.h"

#include <string.h>

#if UIP_CONF_LOGGING
#define DEBUG DEBUG_FULL
#else
#define DEBUG DEBUG_NONE
#endif
#include "contiki/ip/uip-debug.h"

#if UIP_LOGGING
#include <stdio.h>
void uip_log(char *msg);
#define UIP_LOG(m) uip_log(m)
#else
#define UIP_LOG(m)
#endif

#define FOOTER_LEN 2
#define NETWORK_TEST_MAX_PACKET_LEN      PACKETBUF_SIZE

static volatile uint16_t last_packet_timestamp;

/* Data sending and receiving is done in TLV way. */
#if defined CONFIG_NETWORKING_WITH_15_4_LOOPBACK_UART
#define DUMMY_RADIO_15_4_FRAME_TYPE	0xF0
static uint8_t input[NETWORK_TEST_MAX_PACKET_LEN];
static uint8_t input_len, input_offset, input_type;
static bool starting = true;
#define PRINT_DATA 1
#undef PRINT_DATA /* comment this to print transferred bytes */
#else
static uint8_t loopback[NETWORK_TEST_MAX_PACKET_LEN];
#endif

/*---------------------------------------------------------------------------*/
#if defined CONFIG_NETWORKING_WITH_15_4_LOOPBACK_UART
static uint8_t *recv_cb(uint8_t *buf, size_t *off)
{
#if PRINT_DATA
  PRINTF("dummy154radio: %s(): input[] %d data 0x%x uart offset %d\n",
	 __FUNCTION__, input_offset, buf[0], *off);
#endif

  if (starting) {
    if (buf[0] == 0) {
       goto done;
    } else {
       starting = false;
    }
  }
  if (input_len == 0 && input_offset == 0 &&
       buf[0] == DUMMY_RADIO_15_4_FRAME_TYPE) {
    input_type = buf[0];
    goto done;
  }

  if (input_len == 0 && input_offset == 0 &&
       input_type == DUMMY_RADIO_15_4_FRAME_TYPE) {
    input_len = buf[0];

    if (input_len >= NETWORK_TEST_MAX_PACKET_LEN) {
        PRINTF("dummy154radio: too long message %d max is %d, "
	       "discarding packet\n", input_len, NETWORK_TEST_MAX_PACKET_LEN);
    } else {
       PRINTF("dummy154radio: will receive %d bytes\n", input_len);
    }
    goto done;
  }

  if (input_len) {
    static bool printed;
    if (input_offset >= NETWORK_TEST_MAX_PACKET_LEN) {
      if (!printed) {
        PRINTF("dummy154radio: too long message (offset %d), "
	       "discarding packet\n", input_offset);
	printed = true;
      }
      goto fail;
    } else {
      printed = false;
      input[input_offset++] = buf[0];
    }
  }

  if (input_len && input_len == input_offset) {
     if (input_len < NETWORK_TEST_MAX_PACKET_LEN) {
       struct net_buf *mbuf;

       mbuf = l2_buf_get_reserve(0);
       if (mbuf) {
         packetbuf_copyfrom(mbuf, input, input_len);
	 packetbuf_set_datalen(mbuf, input_len);
	 packetbuf_set_attr(mbuf, PACKETBUF_ATTR_TIMESTAMP,
			    last_packet_timestamp);
	 PRINTF("dummy154radio: received %d bytes\n", input_len);

	 if (net_driver_15_4_recv_from_hw(mbuf) < 0) {
           PRINTF("dummy154radio: rdc input failed, packet discarded\n");
	   l2_buf_unref(mbuf);
	 }
       }
     }

  fail:
     input_len = input_offset = input_type = 0;
     memset(input, 0, sizeof(input));
  }

done:
  *off = 0;
  return buf;
}
#endif

#if defined CONFIG_NETWORKING_WITH_15_4_LOOPBACK_UART
static void uart_send(unsigned char c)
{
  uint8_t buf[1] = { c };

#if PRINT_DATA
  PRINTF("dummy154radio: %s(): writing 0x%x\n",
	 __FUNCTION__, buf[0]);
#endif

  uart_pipe_send(&buf[0], 1);
}
#endif

/*---------------------------------------------------------------------------*/
static int
init(void)
{
#if defined CONFIG_NETWORKING_WITH_15_4_LOOPBACK_UART
  /* Use small temp buffer for receiving data */
  static uint8_t buf[1];

  uart_pipe_register(buf, sizeof(buf), recv_cb);

  /* It seems that some of the start bytes are lost so
   * send some null bytes in the start in order to sync
   * the link.
   */
  uart_send(0);
  uart_send(0);
  uart_send(0);
  uart_send(0);
  uart_send(0);
#endif

  return 0;
}
/*---------------------------------------------------------------------------*/
static int
prepare(const void *payload, unsigned short payload_len)
{
  return 1;
}
/*---------------------------------------------------------------------------*/
static int
transmit(struct net_buf *buf, unsigned short transmit_len)
{
  return RADIO_TX_OK;
}

#ifndef CONFIG_NETWORKING_WITH_15_4_LOOPBACK_UART
static void route_buf(struct net_buf *buf)
{
	int len;
	struct net_buf *mbuf;

	len = packetbuf_copyto(buf, loopback);
	/* Receiver buffer that is passed to 15.4 Rx fiber */
	PRINTF("dummy154radio: got %d bytes\n", len);

	mbuf = l2_buf_get_reserve(0);
	if (mbuf) {
		packetbuf_copyfrom(mbuf, loopback, len);
		packetbuf_set_datalen(mbuf, len);
		packetbuf_set_attr(mbuf, PACKETBUF_ATTR_TIMESTAMP,
						last_packet_timestamp);
		PRINTF("dummy154radio: 15.4 Rx input %d bytes\n", len);

		if (net_driver_15_4_recv_from_hw(mbuf) < 0) {
			PRINTF("dummy154radio: rdc input failed, "
							"packet discarded\n");
			l2_buf_unref(mbuf);
		}

		NET_BUF_CHECK_IF_NOT_IN_USE(mbuf);
	}
}
#endif

/*---------------------------------------------------------------------------*/
static int
send(struct net_buf *buf, const void *payload, unsigned short payload_len)
{
#if defined CONFIG_NETWORKING_WITH_15_4_LOOPBACK_UART
  static uint8_t output[NETWORK_TEST_MAX_PACKET_LEN];
  uint8_t len, i;

  len = packetbuf_copyto(buf, output);
  if (len != payload_len) {
    PRINTF("dummy154radio: sending %d bytes, payload %d bytes\n",
	   len, payload_len);
  } else {
    PRINTF("dummy154radio: sending %d bytes\n", len);
  }

  uart_send(DUMMY_RADIO_15_4_FRAME_TYPE); /* Type */
  uart_send(len); /* Length */

  for (i = 0; i < len; i++) {
    uart_send(output[i]);
  }

  return RADIO_TX_OK;
#else
  route_buf(buf);
  return transmit(buf, payload_len);
#endif
}
/*---------------------------------------------------------------------------*/
static int
radio_read(void *buf, unsigned short buf_len)
{
  return 0;
}
/*---------------------------------------------------------------------------*/
static int
channel_clear(void)
{
  return 1;
}
/*---------------------------------------------------------------------------*/
static int
receiving_packet(void)
{
  return 0;
}
/*---------------------------------------------------------------------------*/
static int
pending_packet(void)
{
  return 0;
}
/*---------------------------------------------------------------------------*/
static int
on(void)
{
  return 0;
}
/*---------------------------------------------------------------------------*/
static int
off(void)
{
  return 0;
}
/*---------------------------------------------------------------------------*/
static radio_result_t
get_value(radio_param_t param, radio_value_t *value)
{
  return RADIO_RESULT_NOT_SUPPORTED;
}
/*---------------------------------------------------------------------------*/
static radio_result_t
set_value(radio_param_t param, radio_value_t value)
{
  return RADIO_RESULT_NOT_SUPPORTED;
}
/*---------------------------------------------------------------------------*/
static radio_result_t
get_object(radio_param_t param, void *dest, size_t size)
{
  return RADIO_RESULT_NOT_SUPPORTED;
}
/*---------------------------------------------------------------------------*/
static radio_result_t
set_object(radio_param_t param, const void *src, size_t size)
{
  return RADIO_RESULT_NOT_SUPPORTED;
}
/*---------------------------------------------------------------------------*/
const struct radio_driver dummy154radio_driver =
  {
    .init = init,
    .prepare = prepare,
    .transmit = transmit,
    .send = send,
    .read = radio_read,
    .channel_clear = channel_clear,
    .receiving_packet = receiving_packet,
    .pending_packet = pending_packet,
    .on = on,
    .off = off,
    .get_value = get_value,
    .set_value = set_value,
    .get_object = get_object,
    .set_object = set_object
  };
/*---------------------------------------------------------------------------*/