mirror of https://github.com/ARMmbed/mbed-os.git
292 lines
8.5 KiB
C++
292 lines
8.5 KiB
C++
/* Copyright (c) 2019 Unisoc Communications Inc.
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* 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 <stdlib.h>
|
|
#include "cmsis_os.h"
|
|
#include "mbed_interface.h"
|
|
#include "mbed_assert.h"
|
|
#include "events/mbed_shared_queues.h"
|
|
#include "netsocket/nsapi_types.h"
|
|
#include "lwip/arch.h"
|
|
#include "lwip/pbuf.h"
|
|
#include "rda5991h_wland.h"
|
|
#include "rda5981x_emac_config.h"
|
|
#include "rda5981x_emac.h"
|
|
#include "rda_sys_wrapper.h"
|
|
#include "maclib_task.h"
|
|
|
|
#define RDA_HWADDR_SIZE (6)
|
|
#define RDA_ETH_MTU_SIZE 1500
|
|
#define RDA_ETH_IF_NAME "st"
|
|
|
|
#define RX_PRIORITY (osPriorityNormal)
|
|
#define TX_PRIORITY (osPriorityNormal)
|
|
#define PHY_PRIORITY (osPriorityNormal)
|
|
|
|
extern void *packet_rx_queue;
|
|
|
|
RDA5981x_EMAC::RDA5981x_EMAC()
|
|
{
|
|
}
|
|
|
|
/**
|
|
* This function should do the actual transmission of the packet. The packet is
|
|
* contained in the memory buffer chain that is passed to the function.
|
|
*
|
|
* @param buf the MAC packet to send (e.g. IP packet including MAC addresses and type)
|
|
* @return true if the packet could be sent
|
|
* false value if the packet couldn't be sent
|
|
*
|
|
* @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to
|
|
* strange results. You might consider waiting for space in the DMA queue
|
|
* to become availale since the stack doesn't retry to send a packet
|
|
* dropped because of memory failure (except for the TCP timers).
|
|
*/
|
|
bool RDA5981x_EMAC::link_out(emac_mem_buf_t *buf)
|
|
{
|
|
emac_mem_buf_t *q, *p = buf;
|
|
|
|
u32_t actual_txlen = 0;
|
|
u8_t **data = NULL;
|
|
u16_t retry = 400;
|
|
|
|
LWIP_DEBUGF(NETIF_DEBUG, ("low_level_output enter, p:%08x\n", p));
|
|
|
|
while ((data == NULL) && (retry-- > 0)) {
|
|
data = (u8_t**)wland_get_databuf();
|
|
osThreadYield();
|
|
}
|
|
if (data == NULL) {
|
|
LWIP_DEBUGF(NETIF_DEBUG, ("rda91h_low_level_output, no PKT buf\r\n"));
|
|
memory_manager->free(buf);
|
|
return false;
|
|
}
|
|
|
|
for (q = p; q != NULL; q = memory_manager->get_next(q)) {
|
|
/* Send the data from the pbuf to the interface, one pbuf at a
|
|
time. The size of the data in each pbuf is kept in the ->len
|
|
variable. */
|
|
memcpy(&((*data)[actual_txlen+2]), memory_manager->get_ptr(q), memory_manager->get_len(q));//reserve wid header length
|
|
actual_txlen += memory_manager->get_len(q);
|
|
if (actual_txlen > 1514 || actual_txlen > memory_manager->get_total_len(p)) {
|
|
LWIP_DEBUGF(NETIF_DEBUG, ("low_level_output err, actual_txlen:%d, tot_len%d\n", actual_txlen, memory_manager->get_total_len(p)));
|
|
memory_manager->free(buf);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/* Signal rda5996 that packet should be sent */
|
|
if (actual_txlen == memory_manager->get_total_len(p)) {
|
|
wland_txip_data((void*)data, actual_txlen, 0);
|
|
memory_manager->free(buf);
|
|
return true;
|
|
}
|
|
|
|
LWIP_DEBUGF(NETIF_DEBUG, ("low_level_output pkt len mismatch, actual_txlen:%d, tot_len%d\n",
|
|
actual_txlen, memory_manager->get_total_len(p)));
|
|
|
|
memory_manager->free(buf);
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Should allocate a contiguous memory buffer and transfer the bytes of the incoming
|
|
* packet to the buffer.
|
|
*
|
|
* @param buf If a frame was received and the memory buffer allocation was successful, a memory
|
|
* buffer filled with the received packet (including MAC header)
|
|
* @return negative value when no more frames,
|
|
* zero when frame is received
|
|
*/
|
|
emac_mem_buf_t * RDA5981x_EMAC::low_level_input(u8_t *data, int len)
|
|
{
|
|
emac_mem_buf_t *p, *q;
|
|
u16_t index = 0;
|
|
|
|
LWIP_DEBUGF(NETIF_DEBUG, ("low_level_input enter, rxlen:%d\n", len));
|
|
|
|
/* Obtain the size of the packet and put it into the "len"
|
|
variable. */
|
|
if (!len) {
|
|
return NULL;
|
|
}
|
|
|
|
/* We allocate a pbuf chain of pbufs from the pool. */
|
|
p = memory_manager->alloc_pool(len, 0);
|
|
if (p != NULL) {
|
|
/* We iterate over the pbuf chain until we have read the entire
|
|
* packet into the pbuf. */
|
|
for (q = p; q != NULL; q = memory_manager->get_next(q)) {
|
|
/* Read enough bytes to fill this pbuf in the chain. The
|
|
* available data in the pbuf is given by the q->len
|
|
* variable.
|
|
* This does not necessarily have to be a memcpy, you can also preallocate
|
|
* pbufs for a DMA-enabled MAC and after receiving truncate it to the
|
|
* actually received size. In this case, ensure the tot_len member of the
|
|
* pbuf is the sum of the chained pbuf len members.
|
|
*/
|
|
/* load rx data from 96 to local mem_pool */
|
|
memcpy(memory_manager->get_ptr(q), &data[index], memory_manager->get_len(q));
|
|
index += memory_manager->get_len(q);
|
|
|
|
if (index >= len) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
/* Drop this packet */
|
|
LWIP_DEBUGF(NETIF_DEBUG, ("low_level_input pbuf_alloc fail, rxlen:%d\n", len));
|
|
|
|
return NULL;
|
|
}
|
|
return p;
|
|
}
|
|
|
|
|
|
/** \brief Attempt to read a packet from the EMAC interface.
|
|
*
|
|
*/
|
|
void RDA5981x_EMAC::packet_rx()
|
|
{
|
|
rda_msg msg;
|
|
packet_rx_queue = rda_mail_create(10, sizeof(unsigned int)*4);
|
|
/* move received packet into a new buf */
|
|
while (1) {
|
|
emac_mem_buf_t *p = NULL;
|
|
rda_mail_get(packet_rx_queue, (void*)&msg, osWaitForever);
|
|
switch(msg.type) {
|
|
case 0:
|
|
p = low_level_input((unsigned char*)msg.arg1, msg.arg2);
|
|
if (p == NULL) {
|
|
break;
|
|
}
|
|
if (p) {
|
|
emac_link_input_cb(p);
|
|
}
|
|
break;
|
|
case 1:
|
|
emac_link_state_cb(msg.arg1);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void RDA5981x_EMAC::thread_function(void *pvParameters)
|
|
{
|
|
static struct RDA5981x_EMAC *rda5981x_enet = static_cast<RDA5981x_EMAC *>(pvParameters);
|
|
rda5981x_enet->packet_rx();
|
|
}
|
|
|
|
bool RDA5981x_EMAC::power_up()
|
|
{
|
|
/* Initialize the hardware */
|
|
static int init_flag = 0;
|
|
if (init_flag == 0) {
|
|
wland_reg_func();
|
|
rda_thread_new("maclib_thread", maclib_task, NULL, DEFAULT_THREAD_STACKSIZE*8, PHY_PRIORITY);
|
|
rda_thread_new("wland_thread", wland_task, NULL, DEFAULT_THREAD_STACKSIZE*5, PHY_PRIORITY);
|
|
rda_thread_new("packet_rx", RDA5981x_EMAC::thread_function, this, DEFAULT_THREAD_STACKSIZE*5, PHY_PRIORITY);
|
|
/* Allow the PHY task to detect the initial link state and set up the proper flags */
|
|
osDelay(100);
|
|
wland_sta_init();
|
|
init_flag = 1;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
uint32_t RDA5981x_EMAC::get_mtu_size() const
|
|
{
|
|
return RDA_ETH_MTU_SIZE;
|
|
}
|
|
|
|
uint32_t RDA5981x_EMAC::get_align_preference() const
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
void RDA5981x_EMAC::get_ifname(char *name, uint8_t size) const
|
|
{
|
|
memcpy(name, RDA_ETH_IF_NAME, (size < sizeof(RDA_ETH_IF_NAME)) ? size : sizeof(RDA_ETH_IF_NAME));
|
|
}
|
|
|
|
uint8_t RDA5981x_EMAC::get_hwaddr_size() const
|
|
{
|
|
return RDA_HWADDR_SIZE;
|
|
}
|
|
|
|
bool RDA5981x_EMAC::get_hwaddr(uint8_t *addr) const
|
|
{
|
|
mbed_mac_address((char *)addr);
|
|
return true;
|
|
}
|
|
|
|
void RDA5981x_EMAC::set_hwaddr(const uint8_t *addr)
|
|
{
|
|
/* No-op at this stage */
|
|
}
|
|
|
|
void RDA5981x_EMAC::set_link_input_cb(emac_link_input_cb_t input_cb)
|
|
{
|
|
emac_link_input_cb = input_cb;
|
|
}
|
|
|
|
void RDA5981x_EMAC::set_link_state_cb(emac_link_state_change_cb_t state_cb)
|
|
{
|
|
emac_link_state_cb = state_cb;
|
|
}
|
|
|
|
void RDA5981x_EMAC::add_multicast_group(const uint8_t *addr)
|
|
{
|
|
/* No-op at this stage */
|
|
}
|
|
|
|
void RDA5981x_EMAC::remove_multicast_group(const uint8_t *addr)
|
|
{
|
|
/* No-op at this stage */
|
|
}
|
|
|
|
void RDA5981x_EMAC::set_all_multicast(bool all)
|
|
{
|
|
/* No-op at this stage */
|
|
}
|
|
|
|
void RDA5981x_EMAC::power_down()
|
|
{
|
|
/* No-op at this stage */
|
|
}
|
|
|
|
void RDA5981x_EMAC::set_memory_manager(EMACMemoryManager &mem_mngr)
|
|
{
|
|
memory_manager = &mem_mngr;
|
|
}
|
|
|
|
RDA5981x_EMAC &RDA5981x_EMAC::get_instance()
|
|
{
|
|
static RDA5981x_EMAC emac;
|
|
return emac;
|
|
}
|
|
|
|
// Weak so a module can override
|
|
MBED_WEAK EMAC &EMAC::get_default_instance()
|
|
{
|
|
return RDA5981x_EMAC::get_instance();
|
|
}
|
|
|