parent
fcff552626
commit
f7415e595e
|
@ -33,38 +33,67 @@
|
|||
/* thread phase init */
|
||||
void rt_init_thread_entry(void *parameter)
|
||||
{
|
||||
#ifdef RT_USING_LOGTRACE
|
||||
log_trace_init();
|
||||
log_trace_set_device(RT_CONSOLE_DEVICE_NAME);
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_FINSH
|
||||
/* initialize finsh */
|
||||
finsh_system_init();
|
||||
finsh_set_device(RT_CONSOLE_DEVICE_NAME);
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_VBUS
|
||||
rt_vbus_do_init();
|
||||
#endif
|
||||
}
|
||||
|
||||
/*the led thread*/
|
||||
ALIGN(RT_ALIGN_SIZE)
|
||||
static rt_uint8_t led_stack[ 512 ];
|
||||
static rt_uint8_t led_stack[1024];
|
||||
static struct rt_thread led_thread;
|
||||
static void led_thread_entry(void *parameter)
|
||||
{
|
||||
rt_uint8_t led_value = 0;
|
||||
rt_device_t led_dev;
|
||||
rt_device_t vbus_dev;
|
||||
rt_err_t err;
|
||||
|
||||
rt_led_hw_init();
|
||||
|
||||
led_dev = rt_device_find("led");
|
||||
if (led_dev == RT_NULL)
|
||||
{
|
||||
rt_kprintf("can not find the led device!\n");
|
||||
rt_kprintf("can not find the led device\n");
|
||||
return;
|
||||
}
|
||||
|
||||
vbus_dev = rt_device_find("vecho");
|
||||
if (vbus_dev == RT_NULL)
|
||||
{
|
||||
rt_kprintf("can not find the vbus device\n");
|
||||
return;
|
||||
}
|
||||
|
||||
err = rt_device_open(vbus_dev, RT_DEVICE_OFLAG_RDWR);
|
||||
if (err != RT_EOK)
|
||||
{
|
||||
rt_kprintf("open vbus failed: %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* led0 on */
|
||||
led_value = 1;
|
||||
led_dev->write(led_dev, 1, &led_value, 1);
|
||||
rt_thread_delay(RT_TICK_PER_SECOND / 2); /* sleep 0.5 second and switch to other thread */
|
||||
rt_uint8_t led_value;
|
||||
int len;
|
||||
|
||||
/* led0 off */
|
||||
led_value = 0;
|
||||
led_dev->write(led_dev, 1, &led_value, 1);
|
||||
rt_thread_delay(RT_TICK_PER_SECOND / 2);
|
||||
len = rt_device_read(vbus_dev, 0, &led_value, sizeof(led_value));
|
||||
if (len <= 0)
|
||||
{
|
||||
rt_kprintf("vbus read err: %d, %d\n", len, rt_get_errno());
|
||||
}
|
||||
|
||||
led_dev->write(led_dev, 1, &led_value, sizeof(led_value));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -74,17 +103,15 @@ int rt_application_init(void)
|
|||
rt_err_t result;
|
||||
tid = rt_thread_create("init",
|
||||
rt_init_thread_entry, RT_NULL,
|
||||
2048, RT_THREAD_PRIORITY_MAX / 3, 20);
|
||||
if (tid != RT_NULL) rt_thread_startup(tid);
|
||||
2048, 3, 20);
|
||||
if (tid != RT_NULL)
|
||||
rt_thread_startup(tid);
|
||||
|
||||
/* init led thread */
|
||||
result = rt_thread_init(&led_thread,
|
||||
"led",
|
||||
led_thread_entry,
|
||||
RT_NULL,
|
||||
(rt_uint8_t *)&led_stack[0],
|
||||
sizeof(led_stack),
|
||||
20,
|
||||
5);
|
||||
result = rt_thread_init(&led_thread, "led",
|
||||
led_thread_entry, RT_NULL,
|
||||
(rt_uint8_t *)&led_stack[0], sizeof(led_stack),
|
||||
20, 5);
|
||||
if (result == RT_EOK)
|
||||
{
|
||||
rt_thread_startup(&led_thread);
|
||||
|
|
|
@ -62,5 +62,7 @@ void rt_hw_board_init()
|
|||
|
||||
/* setup the console device */
|
||||
rt_console_set_device(RT_CONSOLE_DEVICE_NAME);
|
||||
|
||||
rt_kprintf("timer compval: %d\n", LPC_RITIMER->COMPVAL);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
#ifndef __VBUS_CONF_H__
|
||||
#define __VBUS_CONF_H__
|
||||
|
||||
/* Number of blocks in VBus. The total size of VBus is
|
||||
* RT_VMM_RB_BLK_NR * 64byte * 2. */
|
||||
#define RT_VMM_RB_BLK_NR 20
|
||||
|
||||
/* We don't use the IRQ number to trigger IRQ in this BSP. */
|
||||
#define RT_VBUS_GUEST_VIRQ 0
|
||||
#define RT_VBUS_HOST_VIRQ 0
|
||||
|
||||
#endif /* end of include guard: __VBUS_CONF_H__ */
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
#include <rtthread.h>
|
||||
|
||||
#ifdef RT_USING_VBUS
|
||||
#include <rtdevice.h>
|
||||
#include <vbus.h>
|
||||
#include <board.h>
|
||||
|
||||
struct rt_vbus_ring rt_vbus_rings[2] SECTION("vbus_ring");
|
||||
|
||||
int rt_vbus_do_init(void)
|
||||
{
|
||||
return rt_vbus_init(&rt_vbus_rings[1], &rt_vbus_rings[0]);
|
||||
}
|
||||
INIT_COMPONENT_EXPORT(rt_vbus_do_init);
|
||||
|
||||
int rt_vbus_hw_init(void)
|
||||
{
|
||||
NVIC_ClearPendingIRQ(M0_M4CORE_IRQn);
|
||||
NVIC_EnableIRQ(M0_M4CORE_IRQn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void M4CORE_IRQHandler(void)
|
||||
{
|
||||
LPC_CREG->M4TXEVENT = 0;
|
||||
rt_vbus_isr(M0_M4CORE_IRQn, RT_NULL);
|
||||
}
|
||||
|
||||
int rt_vbus_hw_eoi(int irqnr, void *param)
|
||||
{
|
||||
/* Nothing to do here as we cleared the interrupt in IRQHandler. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct rt_vbus_dev rt_vbus_chn_devx[] = {
|
||||
{
|
||||
.req =
|
||||
{
|
||||
.prio = 30,
|
||||
.name = "vecho",
|
||||
.is_server = 0,
|
||||
.recv_wm.low = RT_VMM_RB_BLK_NR / 3,
|
||||
.recv_wm.high = RT_VMM_RB_BLK_NR * 2 / 3,
|
||||
.post_wm.low = RT_VMM_RB_BLK_NR / 3,
|
||||
.post_wm.high = RT_VMM_RB_BLK_NR * 2 / 3,
|
||||
}
|
||||
},
|
||||
{
|
||||
.req =
|
||||
{
|
||||
.name = RT_NULL,
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
#endif /* RT_USING_VBUS */
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* VMM Bus
|
||||
*
|
||||
* COPYRIGHT (C) 2014, Shanghai Real-Thread Technology Co., Ltd
|
||||
*
|
||||
* This file is part of RT-Thread (http://www.rt-thread.org)
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2014-04-15 Grissiom init commit
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <board.h>
|
||||
|
||||
rt_inline void rt_vbus_tick(unsigned int target_cpu, unsigned int irqnr)
|
||||
{
|
||||
__SEV();
|
||||
}
|
||||
|
||||
/* Read memory barrier. */
|
||||
rt_inline void rt_vbus_smp_rmb(void)
|
||||
{
|
||||
__DMB();
|
||||
}
|
||||
|
||||
/* Write memory barrier. */
|
||||
rt_inline void rt_vbus_smp_wmb(void)
|
||||
{
|
||||
__DSB();
|
||||
}
|
||||
|
||||
/* General memory barrier. */
|
||||
rt_inline void rt_vbus_smp_mb(void)
|
||||
{
|
||||
__DSB();
|
||||
}
|
|
@ -224,7 +224,8 @@
|
|||
#define RT_LWIP_MSKADDR3 0
|
||||
// </section>
|
||||
|
||||
|
||||
#define RT_USING_VBUS
|
||||
#define RT_USING_LOGTRACE
|
||||
|
||||
// </RDTConfigurator>
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ MEMORY
|
|||
{
|
||||
CODE (rx) : ORIGIN = 0x1B000000, LENGTH = 0x00080000
|
||||
DATA (rw) : ORIGIN = 0x10080000, LENGTH = 0x00008000
|
||||
AHBRAM (rw) : ORIGIN = 0x20000000, LENGTH = 0x00010000
|
||||
}
|
||||
ENTRY(Reset_Handler)
|
||||
_system_stack_size = 0x200;
|
||||
|
@ -95,6 +96,11 @@ SECTIONS
|
|||
} > DATA
|
||||
__bss_end = .;
|
||||
|
||||
.vbus_ring (NOLOAD) :
|
||||
{
|
||||
*(vbus_ring)
|
||||
} > AHBRAM
|
||||
|
||||
_end = .;
|
||||
|
||||
/* Stabs debugging sections. */
|
||||
|
|
|
@ -11,5 +11,8 @@ LR_IROM2 0x1B000000 0x00080000 { ; load region size_region
|
|||
RW_IRAM2 0x10080000 0x00008000 { ; RW data
|
||||
.ANY (+RW +ZI)
|
||||
}
|
||||
RW_AHBRAM 0x20000000 0x00010000 { ; RW data
|
||||
* (vbus_ring)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef __VBUS_LOCAL_CONF_H__
|
||||
#define __VBUS_LOCAL_CONF_H__
|
||||
|
||||
#define RT_VBUS_USING_FLOW_CONTROL
|
||||
|
||||
#define RT_VBUS_USING_TESTS
|
||||
|
||||
#endif /* end of include guard: __VBUS_LOCAL_CONF_H__ */
|
|
@ -58,12 +58,26 @@ static void _boot_M0(void)
|
|||
/* thread phase init */
|
||||
void rt_init_thread_entry(void *parameter)
|
||||
{
|
||||
/*
|
||||
*register unsigned int _msp __asm("msp");
|
||||
*register unsigned int _psp __asm("psp");
|
||||
*rt_kprintf("msp@ %p, psp@ %p\n", _msp, _psp);
|
||||
*/
|
||||
#ifdef RT_USING_LOGTRACE
|
||||
log_trace_init();
|
||||
log_trace_set_device(RT_CONSOLE_DEVICE_NAME);
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_FINSH
|
||||
/* initialize finsh */
|
||||
finsh_system_init();
|
||||
finsh_set_device(RT_CONSOLE_DEVICE_NAME);
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_VBUS
|
||||
rt_vbus_do_init();
|
||||
#endif
|
||||
|
||||
_boot_M0();
|
||||
}
|
||||
|
||||
|
@ -73,26 +87,49 @@ static rt_uint8_t led_stack[ 512 ];
|
|||
static struct rt_thread led_thread;
|
||||
static void led_thread_entry(void *parameter)
|
||||
{
|
||||
rt_uint8_t led_value = 0;
|
||||
rt_uint8_t led_value;
|
||||
rt_device_t led_dev;
|
||||
rt_device_t vbus_dev;
|
||||
rt_err_t err;
|
||||
|
||||
rt_led_hw_init();
|
||||
|
||||
led_dev = rt_device_find("led");
|
||||
if (led_dev == RT_NULL)
|
||||
{
|
||||
rt_kprintf("can not find the led device!\n");
|
||||
rt_kprintf("can not find the led device\n");
|
||||
return;
|
||||
}
|
||||
|
||||
vbus_dev = rt_device_find("vecho");
|
||||
if (vbus_dev == RT_NULL)
|
||||
{
|
||||
rt_kprintf("can not find the vbus device\n");
|
||||
return;
|
||||
}
|
||||
|
||||
err = rt_device_open(vbus_dev, RT_DEVICE_OFLAG_RDWR);
|
||||
if (err != RT_EOK)
|
||||
{
|
||||
rt_kprintf("open vbus failed: %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
led_value = 0;
|
||||
while (1)
|
||||
{
|
||||
/* led0 on */
|
||||
led_value = 1;
|
||||
led_dev->write(led_dev, 0, &led_value, 1);
|
||||
rt_thread_delay(RT_TICK_PER_SECOND / 2); /* sleep 0.5 second and switch to other thread */
|
||||
int len;
|
||||
|
||||
/* led0 off */
|
||||
led_value = 0;
|
||||
led_dev->write(led_dev, 0, &led_value, 1);
|
||||
rt_thread_delay(RT_TICK_PER_SECOND / 2);
|
||||
led_dev->write(led_dev, 0, &led_value, sizeof(led_value));
|
||||
|
||||
led_value = !led_value;
|
||||
len = rt_device_write(vbus_dev, 0, &led_value, sizeof(led_value));
|
||||
if (len <= 0)
|
||||
{
|
||||
rt_kprintf("vbus write err: %d, %d\n", len, rt_get_errno());
|
||||
}
|
||||
|
||||
rt_thread_delay(1000);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -102,17 +139,15 @@ int rt_application_init(void)
|
|||
rt_err_t result;
|
||||
tid = rt_thread_create("init",
|
||||
rt_init_thread_entry, RT_NULL,
|
||||
2048, RT_THREAD_PRIORITY_MAX / 3, 20);
|
||||
if (tid != RT_NULL) rt_thread_startup(tid);
|
||||
2048, 3, 20);
|
||||
if (tid != RT_NULL)
|
||||
rt_thread_startup(tid);
|
||||
|
||||
/* init led thread */
|
||||
result = rt_thread_init(&led_thread,
|
||||
"led",
|
||||
led_thread_entry,
|
||||
RT_NULL,
|
||||
(rt_uint8_t *)&led_stack[0],
|
||||
sizeof(led_stack),
|
||||
20,
|
||||
5);
|
||||
result = rt_thread_init(&led_thread, "led",
|
||||
led_thread_entry, RT_NULL,
|
||||
(rt_uint8_t *)&led_stack[0], sizeof(led_stack),
|
||||
20, 5);
|
||||
if (result == RT_EOK)
|
||||
{
|
||||
rt_thread_startup(&led_thread);
|
||||
|
|
|
@ -65,6 +65,7 @@ void rt_hw_board_init()
|
|||
|
||||
/* setup the console device */
|
||||
rt_console_set_device(RT_CONSOLE_DEVICE_NAME);
|
||||
rt_kprintf("timer compval: %d\n", SystemCoreClock / RT_TICK_PER_SECOND - 1);
|
||||
|
||||
#if LPC_EXT_SDRAM == 1
|
||||
lpc_sdram_hw_init();
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
#ifndef __VBUS_CONF_H__
|
||||
#define __VBUS_CONF_H__
|
||||
|
||||
/* Number of blocks in VBus. The total size of VBus is
|
||||
* RT_VMM_RB_BLK_NR * 64byte * 2. */
|
||||
#define RT_VMM_RB_BLK_NR 20
|
||||
|
||||
/* We don't use the IRQ number to trigger IRQ in this BSP. */
|
||||
#define RT_VBUS_GUEST_VIRQ 0
|
||||
#define RT_VBUS_HOST_VIRQ 0
|
||||
|
||||
#endif /* end of include guard: __VBUS_CONF_H__ */
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
#include <rtthread.h>
|
||||
|
||||
#ifdef RT_USING_VBUS
|
||||
#include <rtdevice.h>
|
||||
#include <vbus.h>
|
||||
#include <board.h>
|
||||
|
||||
struct rt_vbus_ring rt_vbus_rings[2] SECTION("vbus_ring");
|
||||
|
||||
int rt_vbus_do_init(void)
|
||||
{
|
||||
return rt_vbus_init(&rt_vbus_rings[0], &rt_vbus_rings[1]);
|
||||
}
|
||||
INIT_COMPONENT_EXPORT(rt_vbus_do_init);
|
||||
|
||||
int rt_vbus_hw_init(void)
|
||||
{
|
||||
NVIC_ClearPendingIRQ(M0CORE_IRQn);
|
||||
NVIC_EnableIRQ(M0CORE_IRQn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void M0CORE_IRQHandler(void)
|
||||
{
|
||||
LPC_CREG->M0TXEVENT = 0;
|
||||
rt_vbus_isr(M0CORE_IRQn, RT_NULL);
|
||||
}
|
||||
|
||||
int rt_vbus_hw_eoi(int irqnr, void *param)
|
||||
{
|
||||
/* Nothing to do here as we cleared the interrupt in IRQHandler. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct rt_vbus_dev rt_vbus_chn_devx[] = {
|
||||
{
|
||||
.req =
|
||||
{
|
||||
.prio = 30,
|
||||
.name = "vecho",
|
||||
.is_server = 1,
|
||||
.recv_wm.low = RT_VMM_RB_BLK_NR / 3,
|
||||
.recv_wm.high = RT_VMM_RB_BLK_NR * 2 / 3,
|
||||
.post_wm.low = RT_VMM_RB_BLK_NR / 3,
|
||||
.post_wm.high = RT_VMM_RB_BLK_NR * 2 / 3,
|
||||
}
|
||||
},
|
||||
{
|
||||
.req =
|
||||
{
|
||||
.name = RT_NULL,
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
#endif /* RT_USING_VBUS */
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* VMM Bus
|
||||
*
|
||||
* COPYRIGHT (C) 2014, Shanghai Real-Thread Technology Co., Ltd
|
||||
*
|
||||
* This file is part of RT-Thread (http://www.rt-thread.org)
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2014-04-15 Grissiom init commit
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <board.h>
|
||||
|
||||
rt_inline void rt_vbus_tick(unsigned int target_cpu, unsigned int irqnr)
|
||||
{
|
||||
__SEV();
|
||||
}
|
||||
|
||||
/* Read memory barrier. */
|
||||
rt_inline void rt_vbus_smp_rmb(void)
|
||||
{
|
||||
__DMB();
|
||||
}
|
||||
|
||||
/* Write memory barrier. */
|
||||
rt_inline void rt_vbus_smp_wmb(void)
|
||||
{
|
||||
__DSB();
|
||||
}
|
||||
|
||||
/* General memory barrier. */
|
||||
rt_inline void rt_vbus_smp_mb(void)
|
||||
{
|
||||
__DSB();
|
||||
}
|
|
@ -223,7 +223,8 @@
|
|||
#define RT_LWIP_MSKADDR3 0
|
||||
// </section>
|
||||
|
||||
|
||||
#define RT_USING_VBUS
|
||||
#define RT_USING_LOGTRACE
|
||||
|
||||
// </RDTConfigurator>
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ MEMORY
|
|||
CODE (rx) : ORIGIN = 0x1A000000, LENGTH = 0x00080000
|
||||
M0CODE (rx) : ORIGIN = 0x1B000000, LENGTH = 0x00080000
|
||||
DATA (rw) : ORIGIN = 0x10000000, LENGTH = 0x00008000
|
||||
AHBRAM (rw) : ORIGIN = 0x20000000, LENGTH = 0x00010000
|
||||
}
|
||||
ENTRY(Reset_Handler)
|
||||
_system_stack_size = 0x200;
|
||||
|
@ -97,6 +98,12 @@ SECTIONS
|
|||
} > DATA
|
||||
__bss_end = .;
|
||||
|
||||
.vbus_ring (NOLOAD) :
|
||||
{
|
||||
*(vbus_ring)
|
||||
} > AHBRAM
|
||||
|
||||
|
||||
.text.M0CODE :
|
||||
{
|
||||
*(M0_CODE)
|
||||
|
|
|
@ -11,6 +11,9 @@ LR_IROM1 0x1A000000 0x00080000 { ; load region size_region
|
|||
RW_IRAM1 0x10000000 0x00008000 { ; RW data
|
||||
.ANY (+RW +ZI)
|
||||
}
|
||||
RW_AHBRAM 0x20000000 0x00010000 { ; RW data
|
||||
* (vbus_ring)
|
||||
}
|
||||
}
|
||||
|
||||
LR_IROM2 0x1B000000 0x00080000 {
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef __VBUS_LOCAL_CONF_H__
|
||||
#define __VBUS_LOCAL_CONF_H__
|
||||
|
||||
#define RT_VBUS_USING_FLOW_CONTROL
|
||||
|
||||
#define RT_VBUS_USING_TESTS
|
||||
|
||||
#endif /* end of include guard: __VBUS_LOCAL_CONF_H__ */
|
|
@ -0,0 +1,29 @@
|
|||
# RT-Thread building script for component
|
||||
|
||||
import SCons, os
|
||||
from building import *
|
||||
|
||||
group = []
|
||||
if not GetDepend(['RT_USING_VBUS']):
|
||||
Return('group')
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Glob('*.c')
|
||||
|
||||
for c, f in [['RT_USING_VBUS_RFS', 'utilities/rfs.c'],
|
||||
['RT_USING_VBUS_RSHELL', 'utilities/rshell.c'],
|
||||
]:
|
||||
if GetDepend(c):
|
||||
src += Glob(f)
|
||||
|
||||
with open(os.path.join(Dir('#').get_abspath(), 'vbus_local_conf.h'), 'r') as f:
|
||||
cpp = SCons.cpp.PreProcessor()
|
||||
cpp.process_contents(f.read())
|
||||
if 'RT_VBUS_USING_TESTS' in cpp.cpp_namespace:
|
||||
src += Glob('tests/*.c')
|
||||
|
||||
CPPPATH = [cwd, os.path.join(cwd, 'share_hdr')]
|
||||
|
||||
group = DefineGroup('VBus', src, depend = ['RT_USING_VBUS'], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
|
@ -0,0 +1,275 @@
|
|||
/*
|
||||
* Priority Queue
|
||||
*
|
||||
* COPYRIGHT (C) 2013, Shanghai Real-Thread Technology Co., Ltd
|
||||
*
|
||||
* This file is part of RT-Thread (http://www.rt-thread.org)
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2013-11-04 Grissiom add comment
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
|
||||
#include "prio_queue.h"
|
||||
|
||||
struct rt_prio_queue_item {
|
||||
struct rt_prio_queue_item *next;
|
||||
/* data follows */
|
||||
};
|
||||
|
||||
static void _do_push(struct rt_prio_queue *que,
|
||||
rt_uint8_t prio,
|
||||
struct rt_prio_queue_item *item)
|
||||
{
|
||||
if (que->head[prio] == RT_NULL)
|
||||
{
|
||||
que->head[prio] = item;
|
||||
que->bitmap |= 1 << prio;
|
||||
}
|
||||
else
|
||||
{
|
||||
RT_ASSERT(que->tail[prio]);
|
||||
que->tail[prio]->next = item;
|
||||
}
|
||||
que->tail[prio] = item;
|
||||
}
|
||||
|
||||
static struct rt_prio_queue_item* _do_pop(struct rt_prio_queue *que)
|
||||
{
|
||||
int ffs;
|
||||
struct rt_prio_queue_item *item;
|
||||
|
||||
ffs = __rt_ffs(que->bitmap);
|
||||
if (ffs == 0)
|
||||
return RT_NULL;
|
||||
ffs--;
|
||||
|
||||
item = que->head[ffs];
|
||||
RT_ASSERT(item);
|
||||
|
||||
que->head[ffs] = item->next;
|
||||
if (que->head[ffs] == RT_NULL)
|
||||
{
|
||||
que->bitmap &= ~(1 << ffs);
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
rt_err_t rt_prio_queue_init(struct rt_prio_queue *que,
|
||||
const char *name,
|
||||
void *buf,
|
||||
rt_size_t bufsz,
|
||||
rt_size_t itemsz)
|
||||
{
|
||||
RT_ASSERT(que);
|
||||
|
||||
rt_memset(que, 0, sizeof(*que));
|
||||
|
||||
rt_list_init(&(que->suspended_pop_list));
|
||||
|
||||
rt_mp_init(&que->pool, name, buf, bufsz,
|
||||
sizeof(struct rt_prio_queue_item) + itemsz);
|
||||
|
||||
que->item_sz = itemsz;
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
void rt_prio_queue_detach(struct rt_prio_queue *que)
|
||||
{
|
||||
/* wake up all suspended pop threads, push thread is suspended on mempool.
|
||||
*/
|
||||
while (!rt_list_isempty(&(que->suspended_pop_list)))
|
||||
{
|
||||
rt_thread_t thread;
|
||||
|
||||
/* disable interrupt */
|
||||
rt_ubase_t temp = rt_hw_interrupt_disable();
|
||||
|
||||
/* get next suspend thread */
|
||||
thread = rt_list_entry(que->suspended_pop_list.next, struct rt_thread, tlist);
|
||||
/* set error code to RT_ERROR */
|
||||
thread->error = -RT_ERROR;
|
||||
|
||||
rt_thread_resume(thread);
|
||||
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(temp);
|
||||
}
|
||||
rt_mp_detach(&que->pool);
|
||||
}
|
||||
|
||||
#ifdef RT_USING_HEAP
|
||||
struct rt_prio_queue* rt_prio_queue_create(const char *name,
|
||||
rt_size_t item_nr,
|
||||
rt_size_t item_sz)
|
||||
{
|
||||
struct rt_prio_queue *que;
|
||||
rt_size_t bufsz;
|
||||
|
||||
bufsz = item_nr * (sizeof(struct rt_prio_queue_item)
|
||||
+ item_sz
|
||||
+ sizeof(void*));
|
||||
|
||||
RT_ASSERT(item_nr);
|
||||
|
||||
que = rt_malloc(sizeof(*que) + bufsz);
|
||||
if (!que)
|
||||
return RT_NULL;
|
||||
|
||||
rt_prio_queue_init(que, name, que+1, bufsz, item_sz);
|
||||
|
||||
return que;
|
||||
}
|
||||
|
||||
void rt_prio_queue_delete(struct rt_prio_queue *que)
|
||||
{
|
||||
rt_prio_queue_detach(que);
|
||||
rt_free(que);
|
||||
}
|
||||
#endif
|
||||
|
||||
rt_err_t rt_prio_queue_push(struct rt_prio_queue *que,
|
||||
rt_uint8_t prio,
|
||||
void *data,
|
||||
rt_int32_t timeout)
|
||||
{
|
||||
rt_ubase_t level;
|
||||
struct rt_prio_queue_item *item;
|
||||
|
||||
RT_ASSERT(que);
|
||||
|
||||
if (prio >= RT_PRIO_QUEUE_PRIO_MAX)
|
||||
return -RT_ERROR;
|
||||
|
||||
item = rt_mp_alloc(&que->pool, timeout);
|
||||
if (item == RT_NULL)
|
||||
return -RT_ENOMEM;
|
||||
|
||||
rt_memcpy(item+1, data, que->item_sz);
|
||||
item->next = RT_NULL;
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
|
||||
_do_push(que, prio, item);
|
||||
|
||||
if (!rt_list_isempty(&(que->suspended_pop_list)))
|
||||
{
|
||||
rt_thread_t thread;
|
||||
|
||||
/* get thread entry */
|
||||
thread = rt_list_entry(que->suspended_pop_list.next,
|
||||
struct rt_thread,
|
||||
tlist);
|
||||
/* resume it */
|
||||
rt_thread_resume(thread);
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
/* perform a schedule */
|
||||
rt_schedule();
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
rt_err_t rt_prio_queue_pop(struct rt_prio_queue *que,
|
||||
void *data,
|
||||
rt_int32_t timeout)
|
||||
{
|
||||
rt_ubase_t level;
|
||||
struct rt_prio_queue_item *item;
|
||||
|
||||
RT_ASSERT(que);
|
||||
RT_ASSERT(data);
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
for (item = _do_pop(que);
|
||||
item == RT_NULL;
|
||||
item = _do_pop(que))
|
||||
{
|
||||
rt_thread_t thread;
|
||||
|
||||
if (timeout == 0)
|
||||
{
|
||||
rt_hw_interrupt_enable(level);
|
||||
return -RT_ETIMEOUT;
|
||||
}
|
||||
|
||||
RT_DEBUG_NOT_IN_INTERRUPT;
|
||||
|
||||
thread = rt_thread_self();
|
||||
thread->error = RT_EOK;
|
||||
rt_thread_suspend(thread);
|
||||
|
||||
rt_list_insert_before(&(que->suspended_pop_list), &(thread->tlist));
|
||||
|
||||
if (timeout > 0)
|
||||
{
|
||||
rt_timer_control(&(thread->thread_timer),
|
||||
RT_TIMER_CTRL_SET_TIME,
|
||||
&timeout);
|
||||
rt_timer_start(&(thread->thread_timer));
|
||||
}
|
||||
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
rt_schedule();
|
||||
|
||||
/* thread is waked up */
|
||||
if (thread->error != RT_EOK)
|
||||
return thread->error;
|
||||
level = rt_hw_interrupt_disable();
|
||||
}
|
||||
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
rt_memcpy(data, item+1, que->item_sz);
|
||||
rt_mp_free(item);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
void rt_prio_queue_dump(struct rt_prio_queue *que)
|
||||
{
|
||||
int level = 0;
|
||||
|
||||
rt_kprintf("bitmap: %08x\n", que->bitmap);
|
||||
for (level = 0; level < RT_PRIO_QUEUE_PRIO_MAX; level++)
|
||||
{
|
||||
struct rt_prio_queue_item *item;
|
||||
|
||||
rt_kprintf("%2d: ", level);
|
||||
for (item = que->head[level];
|
||||
item;
|
||||
item = item->next)
|
||||
{
|
||||
rt_kprintf("%p, ", item);
|
||||
}
|
||||
rt_kprintf("\n");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
#ifndef __PRIO_QUEUE_H__
|
||||
#define __PRIO_QUEUE_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#define RT_PRIO_QUEUE_PRIO_MAX 32
|
||||
|
||||
struct rt_prio_queue_item;
|
||||
|
||||
struct rt_prio_queue {
|
||||
rt_uint32_t bitmap;
|
||||
struct rt_prio_queue_item *head[RT_PRIO_QUEUE_PRIO_MAX];
|
||||
struct rt_prio_queue_item *tail[RT_PRIO_QUEUE_PRIO_MAX];
|
||||
/* push thread suspend on the mempool, not queue */
|
||||
rt_list_t suspended_pop_list;
|
||||
rt_size_t item_sz;
|
||||
|
||||
struct rt_mempool pool;
|
||||
};
|
||||
|
||||
rt_err_t rt_prio_queue_init(struct rt_prio_queue *que,
|
||||
const char *name,
|
||||
void *buf,
|
||||
rt_size_t bufsz,
|
||||
rt_size_t itemsz);
|
||||
void rt_prio_queue_detach(struct rt_prio_queue *que);
|
||||
|
||||
rt_err_t rt_prio_queue_push(struct rt_prio_queue *que,
|
||||
rt_uint8_t prio,
|
||||
void *data,
|
||||
rt_int32_t timeout);
|
||||
rt_err_t rt_prio_queue_pop(struct rt_prio_queue *que,
|
||||
void *data,
|
||||
rt_int32_t timeout);
|
||||
#ifdef RT_USING_HEAP
|
||||
struct rt_prio_queue* rt_prio_queue_create(const char *name,
|
||||
rt_size_t item_nr,
|
||||
rt_size_t item_sz);
|
||||
void rt_prio_queue_delete(struct rt_prio_queue *que);
|
||||
#endif
|
||||
|
||||
void rt_prio_queue_dump(struct rt_prio_queue *que);
|
||||
|
||||
#endif /* end of include guard: __PRIO_QUEUE_H__ */
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Water Gauge
|
||||
*
|
||||
* COPYRIGHT (C) 2014, Shanghai Real-Thread Technology Co., Ltd
|
||||
*
|
||||
* This file is part of RT-Thread (http://www.rt-thread.org)
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2014-04-16 Grissiom first version
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
|
||||
#include "rt_watermark_queue.h"
|
||||
|
||||
void rt_wm_que_set_mark(struct rt_watermark_queue *wg,
|
||||
unsigned int low, unsigned int high)
|
||||
{
|
||||
RT_ASSERT(low <= high);
|
||||
|
||||
wg->high_mark = high;
|
||||
wg->low_mark = low;
|
||||
}
|
||||
|
||||
void rt_wm_que_init(struct rt_watermark_queue *wg,
|
||||
unsigned int low, unsigned int high)
|
||||
{
|
||||
rt_wm_que_set_mark(wg, low, high);
|
||||
rt_list_init(&wg->suspended_threads);
|
||||
wg->level = 0;
|
||||
}
|
||||
|
||||
void rt_wm_que_dump(struct rt_watermark_queue *wg)
|
||||
{
|
||||
struct rt_list_node *node;
|
||||
|
||||
rt_kprintf("wg %p: low: %d, high: %d, cur: %d\n",
|
||||
wg, wg->low_mark, wg->high_mark, wg->level);
|
||||
rt_kprintf("thread suspend:");
|
||||
for (node = wg->suspended_threads.next;
|
||||
node != &wg->suspended_threads;
|
||||
node = node->next)
|
||||
{
|
||||
rt_thread_t thread;
|
||||
|
||||
thread = rt_list_entry(wg->suspended_threads.next,
|
||||
struct rt_thread,
|
||||
tlist);
|
||||
rt_kprintf(" %.*s", RT_NAME_MAX, thread->name);
|
||||
}
|
||||
rt_kprintf("\n");
|
||||
}
|
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* Thread queue with water mark
|
||||
*
|
||||
* COPYRIGHT (C) 2014, Shanghai Real-Thread Technology Co., Ltd
|
||||
*
|
||||
* This file is part of RT-Thread (http://www.rt-thread.org)
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2014-04-16 Grissiom first version
|
||||
*/
|
||||
|
||||
struct rt_watermark_queue
|
||||
{
|
||||
/* Current water level. */
|
||||
unsigned int level;
|
||||
unsigned int high_mark;
|
||||
unsigned int low_mark;
|
||||
rt_list_t suspended_threads;
|
||||
};
|
||||
|
||||
/** Init the struct rt_watermark_queue.
|
||||
*/
|
||||
void rt_wm_que_init(struct rt_watermark_queue *wg,
|
||||
unsigned int low, unsigned int high);
|
||||
void rt_wm_que_set_mark(struct rt_watermark_queue *wg,
|
||||
unsigned int low, unsigned int high);
|
||||
void rt_wm_que_dump(struct rt_watermark_queue *wg);
|
||||
|
||||
/* Water marks are often used in performance critical places. Benchmark shows
|
||||
* inlining functions will have 10% performance gain in some situation(for
|
||||
* example, VBus). So keep the inc/dec compact and inline. */
|
||||
|
||||
/** Increase the water level.
|
||||
*
|
||||
* It should be called in the thread that want to raise the water level. If the
|
||||
* current level is above the high mark, the thread will be suspended up to
|
||||
* @timeout ticks.
|
||||
*
|
||||
* @return RT_EOK if water level increased successfully. -RT_EFULL on @timeout
|
||||
* is zero and the level is above water mark. -RT_ETIMEOUT if timeout occurred.
|
||||
*/
|
||||
rt_inline rt_err_t rt_wm_que_inc(struct rt_watermark_queue *wg,
|
||||
int timeout)
|
||||
{
|
||||
rt_base_t ilvl;
|
||||
|
||||
/* Assert as early as possible. */
|
||||
if (timeout != 0)
|
||||
{
|
||||
RT_DEBUG_IN_THREAD_CONTEXT;
|
||||
}
|
||||
|
||||
ilvl = rt_hw_interrupt_disable();
|
||||
|
||||
while (wg->level > wg->high_mark)
|
||||
{
|
||||
rt_thread_t thread;
|
||||
|
||||
if (timeout == 0)
|
||||
{
|
||||
rt_hw_interrupt_enable(ilvl);
|
||||
return -RT_EFULL;
|
||||
}
|
||||
|
||||
thread = rt_thread_self();
|
||||
thread->error = RT_EOK;
|
||||
rt_thread_suspend(thread);
|
||||
rt_list_insert_after(&wg->suspended_threads, &thread->tlist);
|
||||
if (timeout > 0)
|
||||
{
|
||||
rt_timer_control(&(thread->thread_timer),
|
||||
RT_TIMER_CTRL_SET_TIME,
|
||||
&timeout);
|
||||
rt_timer_start(&(thread->thread_timer));
|
||||
}
|
||||
rt_hw_interrupt_enable(ilvl);
|
||||
rt_schedule();
|
||||
if (thread->error != RT_EOK)
|
||||
return thread->error;
|
||||
|
||||
ilvl = rt_hw_interrupt_disable();
|
||||
}
|
||||
|
||||
wg->level++;
|
||||
|
||||
if (wg->level == 0)
|
||||
{
|
||||
wg->level = ~0;
|
||||
}
|
||||
|
||||
rt_hw_interrupt_enable(ilvl);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
/** Decrease the water level.
|
||||
*
|
||||
* It should be called by the consumer that drain the water out. If the water
|
||||
* level reached low mark, all the thread suspended in this queue will be waken
|
||||
* up. It's safe to call this function in interrupt context.
|
||||
*/
|
||||
rt_inline void rt_wm_que_dec(struct rt_watermark_queue *wg)
|
||||
{
|
||||
int need_sched = 0;
|
||||
rt_base_t ilvl;
|
||||
|
||||
if (wg->level == 0)
|
||||
return;
|
||||
|
||||
ilvl = rt_hw_interrupt_disable();
|
||||
wg->level--;
|
||||
if (wg->level == wg->low_mark)
|
||||
{
|
||||
/* There should be spaces between the low mark and high mark, so it's
|
||||
* safe to resume all the threads. */
|
||||
while (!rt_list_isempty(&wg->suspended_threads))
|
||||
{
|
||||
rt_thread_t thread;
|
||||
|
||||
thread = rt_list_entry(wg->suspended_threads.next,
|
||||
struct rt_thread,
|
||||
tlist);
|
||||
rt_thread_resume(thread);
|
||||
need_sched = 1;
|
||||
}
|
||||
}
|
||||
rt_hw_interrupt_enable(ilvl);
|
||||
|
||||
if (need_sched)
|
||||
rt_schedule();
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
#ifndef __VBUS_API_H__
|
||||
#define __VBUS_API_H__
|
||||
|
||||
#include "vbus_conf.h"
|
||||
|
||||
#define RT_VBUS_CHANNEL_NR 32
|
||||
|
||||
#define RT_VBUS_BLK_HEAD_SZ 4
|
||||
#define RT_VBUS_MAX_PKT_SZ (256 - RT_VBUS_BLK_HEAD_SZ)
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
#include <stddef.h> /* For size_t */
|
||||
|
||||
struct rt_vbus_blk
|
||||
{
|
||||
unsigned char id;
|
||||
unsigned char qos;
|
||||
unsigned char len;
|
||||
unsigned char reserved;
|
||||
unsigned char data[60];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct rt_vbus_ring
|
||||
{
|
||||
volatile size_t put_idx;
|
||||
volatile size_t get_idx;
|
||||
/* whether the writer is blocked on this ring. For RTT, it means the
|
||||
* central writer thread is waiting. For Linux, it means there are some
|
||||
* threads waiting for space to write.
|
||||
*
|
||||
* Note that we don't record whether there are reading thread blocked. When
|
||||
* there is new data, the other side will always be waked up. */
|
||||
volatile unsigned int blocked;
|
||||
struct rt_vbus_blk blks[RT_VMM_RB_BLK_NR];
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
RT_VBUS_CHN0_CMD_ENABLE,
|
||||
RT_VBUS_CHN0_CMD_DISABLE,
|
||||
RT_VBUS_CHN0_CMD_SET,
|
||||
RT_VBUS_CHN0_CMD_ACK,
|
||||
RT_VBUS_CHN0_CMD_NAK,
|
||||
/* If the recieving side reached high water mark. It has the right to
|
||||
* suspend the channel. All the server/client should know about this
|
||||
* command but the one that does not implement flow control could ignore
|
||||
* this command. */
|
||||
RT_VBUS_CHN0_CMD_SUSPEND,
|
||||
RT_VBUS_CHN0_CMD_RESUME,
|
||||
RT_VBUS_CHN0_CMD_MAX,
|
||||
};
|
||||
|
||||
enum rt_vbus_chn_status
|
||||
{
|
||||
/* initial state, available for reuse */
|
||||
RT_VBUS_CHN_ST_AVAILABLE,
|
||||
/* ACK DISABLE send(CS) or received(CS), but not ready for reuse.(the
|
||||
* channel is not closed by this end) */
|
||||
RT_VBUS_CHN_ST_CLOSED,
|
||||
/* ENABLE send(client) or received(server) */
|
||||
RT_VBUS_CHN_ST_ESTABLISHING,
|
||||
/* ACK SET send(C) or received(S) */
|
||||
RT_VBUS_CHN_ST_ESTABLISHED,
|
||||
/* Channel suspended by flow control. */
|
||||
RT_VBUS_CHN_ST_SUSPEND,
|
||||
/* DISABLE received(CS) */
|
||||
RT_VBUS_CHN_ST_CLOSING,
|
||||
};
|
||||
#endif
|
||||
|
||||
#undef BUILD_ASSERT
|
||||
/* borrowed from http://lxr.linux.no/linux+v2.6.26.5/include/linux/kernel.h#L494 */
|
||||
#define BUILD_ASSERT(condition) ((void)sizeof(char[1 - 2*!(condition)]))
|
||||
|
||||
/* max length of a channel name, including the \0 */
|
||||
#define RT_VBUS_CHN_NAME_MAX 16
|
||||
|
||||
#endif /* end of include guard: __VBUS_API_H__ */
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,195 @@
|
|||
#ifndef __VBUS_H__
|
||||
#define __VBUS_H__
|
||||
/*
|
||||
* VBus
|
||||
*
|
||||
* COPYRIGHT (C) 2013-2014, Shanghai Real-Thread Technology Co., Ltd
|
||||
*
|
||||
* This file is part of RT-Thread (http://www.rt-thread.org)
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2014-06-09 Grissiom version 2.0.2; add comment
|
||||
*/
|
||||
|
||||
#include "vbus_local_conf.h"
|
||||
#include <vbus_api.h>
|
||||
|
||||
int rt_vbus_init(void *outr, void *inr);
|
||||
|
||||
void rt_vbus_resume_out_thread(void);
|
||||
|
||||
/** Post data on channel.
|
||||
*
|
||||
* @param chnr the channel number
|
||||
* @param prio the priority of the data
|
||||
* @param datap pointer to the actual data
|
||||
* @param size number of byte of the data
|
||||
* @param timeout the value used in the blocking API
|
||||
*
|
||||
* Note: rt_vbus_post is an asynchronous function that when it returns, the
|
||||
* @datap and @size is recorded in the post queue at least but there is no
|
||||
* guarantee that the data is copied into the ring buffer. To avoid data
|
||||
* corruption, you need to wait on the RT_VBUS_EVENT_ID_TX event.
|
||||
*
|
||||
* However, if you just post static data such as static string, there is no
|
||||
* need to wait.
|
||||
*
|
||||
* @sa rt_vbus_register_listener .
|
||||
*/
|
||||
rt_err_t rt_vbus_post(rt_uint8_t chnr,
|
||||
rt_uint8_t prio,
|
||||
const void *datap,
|
||||
rt_size_t size,
|
||||
rt_int32_t timeout);
|
||||
|
||||
struct rt_vbus_data {
|
||||
/* Number of bytes in current data package. */
|
||||
unsigned char size;
|
||||
/* Used internally in VBus. Don't modify this field as it may corrupt the
|
||||
* receive queue. */
|
||||
struct rt_vbus_data *next;
|
||||
/* Data follows the struct */
|
||||
};
|
||||
|
||||
struct rt_vbus_wm_cfg {
|
||||
unsigned int low, high;
|
||||
};
|
||||
|
||||
struct rt_vbus_request {
|
||||
unsigned char prio;
|
||||
const char *name;
|
||||
int is_server;
|
||||
struct rt_vbus_wm_cfg recv_wm, post_wm;
|
||||
};
|
||||
|
||||
/** Request a channel.
|
||||
*
|
||||
* @return channel number. Negative if error happened.
|
||||
*/
|
||||
int rt_vbus_request_chn(struct rt_vbus_request *req, int timeout);
|
||||
|
||||
/** Close channel @chnr */
|
||||
void rt_vbus_close_chn(unsigned char chnr);
|
||||
|
||||
/** Set the water mark level for posting into the channel @chnr. */
|
||||
void rt_vbus_set_post_wm(unsigned char chnr, unsigned int low, unsigned int high);
|
||||
/** Set the water mark level for receiving from the channel @chnr. */
|
||||
void rt_vbus_set_recv_wm(unsigned char chnr, unsigned int low, unsigned int high);
|
||||
|
||||
typedef void (*rt_vbus_event_listener)(void *ctx);
|
||||
|
||||
enum rt_vbus_event_id {
|
||||
/* On a packet received in channel. */
|
||||
RT_VBUS_EVENT_ID_RX,
|
||||
/* On the data of rt_vbus_post has been written to the ring buffer. */
|
||||
RT_VBUS_EVENT_ID_TX,
|
||||
/* On the channel has been closed. */
|
||||
RT_VBUS_EVENT_ID_DISCONN,
|
||||
RT_VBUS_EVENT_ID_MAX,
|
||||
};
|
||||
|
||||
/** Register callback @indi on the event @eve on the @chnr.
|
||||
*
|
||||
* @ctx will passed to @indi on calling the @indi.
|
||||
*/
|
||||
void rt_vbus_register_listener(unsigned char chnr,
|
||||
enum rt_vbus_event_id eve,
|
||||
rt_vbus_event_listener indi,
|
||||
void *ctx);
|
||||
|
||||
/** Listen on any events happen on the @chnr for @timeout ticks.
|
||||
*
|
||||
* This function blocks until events occur or timeout happened.
|
||||
*/
|
||||
rt_err_t rt_vbus_listen_on(rt_uint8_t chnr,
|
||||
rt_int32_t timeout);
|
||||
|
||||
/** Push a data package into the receive queue of the channel @chnr. */
|
||||
void rt_vbus_data_push(unsigned int chnr,
|
||||
struct rt_vbus_data *data);
|
||||
/** Pop a data package from the receive queue of the channel @chnr.
|
||||
*
|
||||
* The actual data is following the struct rt_vbus_data. After using it, it
|
||||
* should be freed by rt_free.
|
||||
*/
|
||||
struct rt_vbus_data* rt_vbus_data_pop(unsigned int chnr);
|
||||
|
||||
struct rt_vbus_dev
|
||||
{
|
||||
/* Runtime infomations. */
|
||||
rt_uint8_t chnr;
|
||||
struct rt_vbus_data *act;
|
||||
rt_size_t pos;
|
||||
|
||||
/* There will be a request for each channel. So no need to seperate them so
|
||||
* clearly. */
|
||||
struct rt_vbus_request req;
|
||||
};
|
||||
|
||||
rt_err_t rt_vbus_chnx_init(void);
|
||||
/** Get the corresponding channel number from the VBus device @dev. */
|
||||
rt_uint8_t rt_vbus_get_chnnr(rt_device_t dev);
|
||||
/** Register a call back on the other side disconnect the channel.
|
||||
*
|
||||
* @sa rt_vbus_register_listener .
|
||||
*/
|
||||
void rt_vbus_chnx_register_disconn(rt_device_t dev,
|
||||
rt_vbus_event_listener indi,
|
||||
void *ctx);
|
||||
|
||||
/* Commands for the device control interface. */
|
||||
#define VBUS_IOCRECV_WM 0xD1
|
||||
#define VBUS_IOCPOST_WM 0xD2
|
||||
/** Configure event listener */
|
||||
#define VBUS_IOC_LISCFG 0xD3
|
||||
|
||||
struct rt_vbus_dev_liscfg
|
||||
{
|
||||
enum rt_vbus_event_id event;
|
||||
rt_vbus_event_listener listener;
|
||||
void *ctx;
|
||||
};
|
||||
|
||||
int rt_vbus_shell_start(void);
|
||||
#ifdef RT_USING_VBUS_RFS
|
||||
int dfs_rfs_init(void);
|
||||
#endif
|
||||
|
||||
/** VBus hardware init function.
|
||||
*
|
||||
* BSP should implement this function to initialize the interrupts etc.
|
||||
*/
|
||||
int rt_vbus_hw_init(void);
|
||||
|
||||
/** VBus ISR function.
|
||||
*
|
||||
* BSP should call this function when the interrupt from other core is
|
||||
* triggered. @param is not used by VBus and will pass to rt_vbus_hw_eoi.
|
||||
*/
|
||||
void rt_vbus_isr(int irqnr, void *param);
|
||||
|
||||
/** VBus End Of Interrupt function.
|
||||
*
|
||||
* This function will be called when VBus finished the ISR handling. BSP should
|
||||
* define this function to clear the interrupt flag etc.
|
||||
*/
|
||||
int rt_vbus_hw_eoi(int irqnr, void *param);
|
||||
|
||||
#endif /* end of include guard: __VBUS_H__ */
|
|
@ -0,0 +1,286 @@
|
|||
/*
|
||||
* Channel on VMM Bus
|
||||
*
|
||||
* COPYRIGHT (C) 2013, Shanghai Real-Thread Technology Co., Ltd
|
||||
*
|
||||
* This file is part of RT-Thread (http://www.rt-thread.org)
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2013-11-04 Grissiom add comment
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
#include "vbus.h"
|
||||
|
||||
static void _rx_indicate(void *ctx)
|
||||
{
|
||||
rt_device_t dev = ctx;
|
||||
|
||||
if (dev->rx_indicate)
|
||||
dev->rx_indicate(dev, 0);
|
||||
}
|
||||
|
||||
static void _tx_complete(void *ctx)
|
||||
{
|
||||
rt_device_t dev = ctx;
|
||||
|
||||
if (dev->tx_complete)
|
||||
dev->tx_complete(dev, 0);
|
||||
}
|
||||
|
||||
static rt_err_t _open(rt_device_t dev, rt_uint16_t oflag)
|
||||
{
|
||||
int chnr;
|
||||
struct rt_vbus_dev *vdev = dev->user_data;
|
||||
|
||||
if (vdev->chnr)
|
||||
return RT_EOK;
|
||||
|
||||
/* FIXME: request the same name for twice will crash */
|
||||
chnr = rt_vbus_request_chn(&vdev->req, RT_WAITING_FOREVER);
|
||||
if (chnr < 0)
|
||||
return chnr;
|
||||
|
||||
vdev->chnr = chnr;
|
||||
rt_vbus_register_listener(chnr, RT_VBUS_EVENT_ID_RX, _rx_indicate, dev);
|
||||
rt_vbus_register_listener(chnr, RT_VBUS_EVENT_ID_TX, _tx_complete, dev);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t _close(rt_device_t dev)
|
||||
{
|
||||
struct rt_vbus_dev *vdev = dev->user_data;
|
||||
|
||||
RT_ASSERT(vdev->chnr != 0);
|
||||
|
||||
rt_vbus_close_chn(vdev->chnr);
|
||||
vdev->chnr = 0;
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_size_t _read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
|
||||
{
|
||||
rt_size_t outsz = 0;
|
||||
struct rt_vbus_dev *vdev = dev->user_data;
|
||||
|
||||
RT_ASSERT(vdev->chnr != 0);
|
||||
|
||||
if (vdev->act == RT_NULL)
|
||||
{
|
||||
vdev->act = rt_vbus_data_pop(vdev->chnr);
|
||||
vdev->pos = 0;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
rt_err_t err;
|
||||
|
||||
while (vdev->act)
|
||||
{
|
||||
rt_size_t cpysz;
|
||||
|
||||
if (size - outsz > vdev->act->size - vdev->pos)
|
||||
cpysz = vdev->act->size - vdev->pos;
|
||||
else
|
||||
cpysz = size - outsz;
|
||||
|
||||
rt_memcpy((char*)buffer + outsz, ((char*)(vdev->act+1)) + vdev->pos, cpysz);
|
||||
vdev->pos += cpysz;
|
||||
|
||||
outsz += cpysz;
|
||||
if (outsz == size)
|
||||
{
|
||||
return outsz;
|
||||
}
|
||||
else if (outsz > size)
|
||||
RT_ASSERT(0);
|
||||
|
||||
/* free old and get new */
|
||||
rt_free(vdev->act);
|
||||
vdev->act = rt_vbus_data_pop(vdev->chnr);
|
||||
vdev->pos = 0;
|
||||
}
|
||||
|
||||
/* TODO: We don't want to touch the rx_indicate here. But this lead to
|
||||
* some duplication. Maybe we should find a better way to handle this.
|
||||
*/
|
||||
if (rt_interrupt_get_nest() == 0)
|
||||
{
|
||||
err = rt_vbus_listen_on(vdev->chnr, RT_WAITING_FOREVER);
|
||||
}
|
||||
else
|
||||
{
|
||||
err = rt_vbus_listen_on(vdev->chnr, 0);
|
||||
}
|
||||
if (err != RT_EOK)
|
||||
{
|
||||
rt_set_errno(err);
|
||||
return outsz;
|
||||
}
|
||||
vdev->act = rt_vbus_data_pop(vdev->chnr);
|
||||
vdev->pos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static rt_size_t _write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
|
||||
{
|
||||
rt_err_t err;
|
||||
struct rt_vbus_dev *vdev = dev->user_data;
|
||||
|
||||
RT_ASSERT(vdev->chnr != 0);
|
||||
|
||||
if (rt_interrupt_get_nest() == 0)
|
||||
{
|
||||
/* Thread context. */
|
||||
err = rt_vbus_post(vdev->chnr, vdev->req.prio,
|
||||
buffer, size, RT_WAITING_FOREVER);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Interrupt context. */
|
||||
err = rt_vbus_post(vdev->chnr, vdev->req.prio,
|
||||
buffer, size, 0);
|
||||
}
|
||||
|
||||
if (err)
|
||||
{
|
||||
rt_set_errno(err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
rt_err_t _control(rt_device_t dev, rt_uint8_t cmd, void *args)
|
||||
{
|
||||
RT_ASSERT(dev);
|
||||
|
||||
switch (cmd) {
|
||||
case VBUS_IOC_LISCFG: {
|
||||
struct rt_vbus_dev *vdev = dev->user_data;
|
||||
struct rt_vbus_dev_liscfg *liscfg = args;
|
||||
|
||||
RT_ASSERT(vdev->chnr != 0);
|
||||
if (!liscfg)
|
||||
return -RT_ERROR;
|
||||
|
||||
rt_vbus_register_listener(vdev->chnr, liscfg->event,
|
||||
liscfg->listener, liscfg->ctx);
|
||||
return RT_EOK;
|
||||
}
|
||||
break;
|
||||
#ifdef RT_VBUS_USING_FLOW_CONTROL
|
||||
case VBUS_IOCRECV_WM: {
|
||||
struct rt_vbus_dev *vdev = dev->user_data;
|
||||
struct rt_vbus_wm_cfg *cfg;
|
||||
|
||||
RT_ASSERT(vdev->chnr != 0);
|
||||
|
||||
if (!args)
|
||||
return -RT_ERROR;
|
||||
|
||||
cfg = (struct rt_vbus_wm_cfg*)args;
|
||||
if (cfg->low > cfg->high)
|
||||
return -RT_ERROR;
|
||||
|
||||
rt_vbus_set_recv_wm(vdev->chnr, cfg->low, cfg->high);
|
||||
return RT_EOK;
|
||||
}
|
||||
break;
|
||||
case VBUS_IOCPOST_WM: {
|
||||
struct rt_vbus_dev *vdev = dev->user_data;
|
||||
struct rt_vbus_wm_cfg *cfg;
|
||||
|
||||
RT_ASSERT(vdev->chnr != 0);
|
||||
|
||||
if (!args)
|
||||
return -RT_ERROR;
|
||||
|
||||
cfg = (struct rt_vbus_wm_cfg*)args;
|
||||
if (cfg->low > cfg->high)
|
||||
return -RT_ERROR;
|
||||
|
||||
rt_vbus_set_post_wm(vdev->chnr, cfg->low, cfg->high);
|
||||
return RT_EOK;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
};
|
||||
|
||||
return -RT_ENOSYS;
|
||||
}
|
||||
|
||||
rt_uint8_t rt_vbus_get_chnnr(rt_device_t dev)
|
||||
{
|
||||
struct rt_vbus_dev *vdev;
|
||||
|
||||
RT_ASSERT(dev);
|
||||
|
||||
vdev = dev->user_data;
|
||||
|
||||
return vdev->chnr;
|
||||
}
|
||||
|
||||
void rt_vbus_chnx_register_disconn(rt_device_t dev,
|
||||
rt_vbus_event_listener indi,
|
||||
void *ctx)
|
||||
{
|
||||
struct rt_vbus_dev *vdev = dev->user_data;
|
||||
|
||||
RT_ASSERT(vdev->chnr != 0);
|
||||
|
||||
if (vdev)
|
||||
rt_vbus_register_listener(vdev->chnr, RT_VBUS_EVENT_ID_DISCONN,
|
||||
indi, ctx);
|
||||
}
|
||||
|
||||
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
|
||||
|
||||
extern struct rt_vbus_dev rt_vbus_chn_devx[];
|
||||
static struct rt_device _devx[32];
|
||||
|
||||
rt_err_t rt_vbus_chnx_init(void)
|
||||
{
|
||||
int i;
|
||||
struct rt_vbus_dev *p;
|
||||
|
||||
for (i = 0, p = rt_vbus_chn_devx;
|
||||
i < ARRAY_SIZE(_devx) && p->req.name;
|
||||
i++, p++)
|
||||
{
|
||||
_devx[i].type = RT_Device_Class_Char;
|
||||
_devx[i].open = _open;
|
||||
_devx[i].close = _close;
|
||||
_devx[i].read = _read;
|
||||
_devx[i].write = _write;
|
||||
_devx[i].control = _control;
|
||||
_devx[i].user_data = p;
|
||||
rt_device_register(&_devx[i], p->req.name, RT_DEVICE_FLAG_RDWR);
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
Loading…
Reference in New Issue