Update example-lcd.

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
This commit is contained in:
NIIBE Yutaka
2019-12-27 09:49:35 +09:00
parent 76f962fbdd
commit 99023a1126
13 changed files with 2576 additions and 132 deletions

View File

@@ -16,13 +16,15 @@ LDSCRIPT= sample.ld.gd32vf103
### LDSCRIPT= sample.ld.m4 ### LDSCRIPT= sample.ld.m4
### LDSCRIPT= sample.ld ### LDSCRIPT= sample.ld
### LDSCRIPT= sample.ld.m3 ### LDSCRIPT= sample.ld.m3
CSRC = sample.c CSRC = sample.c usb-vendor-specific.c
# CSRC += debug.c
ARCH=riscv32 ARCH=riscv32
CHIP=gd32vf103 CHIP=gd32vf103
### CHIP=stm32l4 ### CHIP=stm32l4
### USE_SYS = yes ### USE_SYS = yes
USE_USART = yes USE_USART = yes
USE_USB = yes
################################### ###################################
### CROSS = arm-none-eabi- ### CROSS = arm-none-eabi-
@@ -40,6 +42,7 @@ DEFS = -DFREE_STANDING -DMHZ=96
### DEFS = -DFREE_STANDING -DUSE_SYS3 -DBUSY_LOOP -DCHX_FLAGS_MAIN=CHOPSTX_SCHED_RR ### DEFS = -DFREE_STANDING -DUSE_SYS3 -DBUSY_LOOP -DCHX_FLAGS_MAIN=CHOPSTX_SCHED_RR
OPT = -O3 -Os -g OPT = -O3 -Os -g
LIBS = LIBS =
#LIBS = -lgcc
CSRC += $(CHOPSTX)/contrib/spi-st.c CSRC += $(CHOPSTX)/contrib/spi-st.c

View File

@@ -0,0 +1,34 @@
from load_image_to_screen import Longan_LCD
from gnupg_logo_16bit_160x80 import gnupg_logo_16bit_160x80
image = gnupg_logo_16bit_160x80
pos = [ 1, 2, 2, 2, 3, 3, 4, 5, 6, 7, 8, 9, 12, 14, 17, 20, 23, 28, 33, 40, 47, 56 ]
background0 = [ 0x5d, 0xdf ]
background1 = [ 0x7e, 0xdf ]
def fill(i, bg0, bg1):
if (i % 2) == 0:
return bg0
else:
return bg1
def move_right(x, bg0, bg1, img):
result = []
for i in range(80):
for j in range(x):
result = result + fill(j, bg0, bg1)
result = result + (img[i*160*2:(i+1)*160*2])[0:160*2-x*2]
return result
images = [ bytes(move_right(x, background0, background1, image)) for x in pos ]
lcd = Longan_LCD()
for loop in range(10):
for i in range(len(pos)):
lcd.load_image_to_screen(images[len(pos)-1-i])
for i in range(len(pos)):
lcd.load_image_to_screen(images[i])

26
example-lcd/debug.c Normal file
View File

@@ -0,0 +1,26 @@
#include <stdint.h>
#include <stdlib.h>
#include <chopstx.h>
#include <contrib/usart.h>
#include <stdarg.h>
extern int vsnprintf(char *str, size_t size, const char *format, va_list ap);
#define USART_NO 0
/* Intentionally only adding LF */
void
debug (const char *fmt, ...)
{
char buf[256];
va_list ap;
size_t len;
va_start(ap, fmt);
len = vsnprintf (buf, sizeof buf - 1, fmt, ap);
va_end(ap);
if (len >= sizeof buf - 1)
len = sizeof buf - 2;
buf[len++] = '\n';
usart_write (USART_NO, buf, len);
}

1
example-lcd/debug.h Normal file
View File

@@ -0,0 +1 @@
void debug (const char *fmt, ...);

File diff suppressed because it is too large Load Diff

96
example-lcd/l.py Normal file
View File

@@ -0,0 +1,96 @@
#! /usr/bin/python3
# pos = [
# 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
# 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3,
# 3, 4, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 9, 9, 10, 11,
# 12, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 28, 30, 31, 33, 35,
# 37, 40, 42, 44, 47, 50, 53, 56, 59, 63, 66, 70, 75, 79, 84, 89, 94,100,105,112,
# 118,125,133,141,149,158
# ]
pos = [
0, 1, 1, 1,
1, 2, 2, 3,
4, 6, 8, 11,
15, 20, 26, 35,
47, 63, 84, 112,
149
]
import usb.core
import usb.util
dev = usb.core.find(idVendor=0xffff, idProduct=0x0001)
if dev is None:
raise ValueError('Device not found')
# dev.set_configuration()
# get an endpoint instance
cfg = dev.get_active_configuration()
intf = cfg[(0,0)]
ep_out = usb.util.find_descriptor(
intf,
# match the first OUT endpoint
custom_match = \
lambda e: \
usb.util.endpoint_direction(e.bEndpointAddress) == \
usb.util.ENDPOINT_OUT)
ep_in = usb.util.find_descriptor(
intf,
# match the first IN endpoint
custom_match = \
lambda e: \
usb.util.endpoint_direction(e.bEndpointAddress) == \
usb.util.ENDPOINT_IN)
if ep_out is None:
raise ValueError('Endpoint to send data not found')
if ep_in is None:
raise ValueError('Endpoint to receive data not found')
color_black = [ 0, 0 ]
color0 = [ 0xff, 0x03 ]
color1 = [ 0xef, 0x7f ]
color2 = [ 0x00, 0x78 ]
color3 = [ 0xff, 0xff ]
def gen_image(x):
image = []
for i in range(80):
image = image + (color_black * x) + (color0 * (160-x))
return image
images = [ gen_image(p) for p in pos ]
# images = [ gen_image(p) for p in range(160) ]
import time
import sys
def prepare_send():
w=ep_in.read(64)
# print(w)
def finish_send():
dev.ctrl_transfer(0x41, 0x00, 0x00, 0x00, "")
# print(".", end='', flush=True)
for i in range(len(images)*8):
i0 = i % (len(images)*2)
if i0 < len(images):
x = (i % len(images))
else:
x = len(images)- 1 - (i % len(images))
# print("%d %d: %d" % (i, x, len(images[x])))
if True:
prepare_send()
ep_out.write(images[x])
finish_send()
prepare_send()
dev.ctrl_transfer(0x41, 0x00, 0x01, 0x00, "")

View File

@@ -0,0 +1,51 @@
#! /usr/bin/python3
import usb.core
import usb.util
import time
import sys
class Longan_LCD(object):
def __init__(self):
self.dev = usb.core.find(idVendor=0xffff, idProduct=0x0001)
if self.dev is None:
raise ValueError('Device not found')
cfg = self.dev.get_active_configuration()
intf = cfg[(0,0)]
self.ep_out = usb.util.find_descriptor(
intf,
# match the first OUT endpoint
custom_match = \
lambda e: \
usb.util.endpoint_direction(e.bEndpointAddress) == \
usb.util.ENDPOINT_OUT)
self.ep_in = usb.util.find_descriptor(
intf,
# match the first IN endpoint
custom_match = \
lambda e: \
usb.util.endpoint_direction(e.bEndpointAddress) == \
usb.util.ENDPOINT_IN)
if self.ep_out is None:
raise ValueError('Endpoint to send data not found')
if self.ep_in is None:
raise ValueError('Endpoint to receive data not found')
def prepare_send(self):
w=self.ep_in.read(64)
# print(w)
def finish_send(self):
self.dev.ctrl_transfer(0x41, 0x00, 0x00, 0x00, "")
# print(".", end='', flush=True)
def load_image_to_screen(self, image):
self.prepare_send()
self.ep_out.write(image)
self.finish_send()

View File

@@ -0,0 +1,93 @@
#! /usr/bin/python3
import usb.core
import usb.util
dev = usb.core.find(idVendor=0xffff, idProduct=0x0001)
if dev is None:
raise ValueError('Device not found')
# dev.set_configuration()
# get an endpoint instance
cfg = dev.get_active_configuration()
intf = cfg[(0,0)]
ep_out = usb.util.find_descriptor(
intf,
# match the first OUT endpoint
custom_match = \
lambda e: \
usb.util.endpoint_direction(e.bEndpointAddress) == \
usb.util.ENDPOINT_OUT)
ep_in = usb.util.find_descriptor(
intf,
# match the first IN endpoint
custom_match = \
lambda e: \
usb.util.endpoint_direction(e.bEndpointAddress) == \
usb.util.ENDPOINT_IN)
if ep_out is None:
raise ValueError('Endpoint to send data not found')
if ep_in is None:
raise ValueError('Endpoint to receive data not found')
def prepare_send():
w=ep_in.read(64)
# print(w)
def finish_send():
dev.ctrl_transfer(0x41, 0x00, 0x00, 0x00, "")
# print(".", end='', flush=True)
color0 = [ 0xff, 0x03 ]
color1 = [ 0xef, 0x7f ]
color2 = [ 0x00, 0x78 ]
color3 = [ 0xff, 0xff ]
image = color0*160*80
# + color1*160*40
image64 = color0*32
image = color1*160*80
point1600a=(color0*40+color1*40)*20
point1600b=(color1*40+color0*40)*20
point1600c=(color2*20+color3*20)*40
point1600d=(color3*20+color2*20)*40
import time
import sys
for i in range(10):
prepare_send()
ep_out.write(point1600a)
print(".", end='', flush=True)
ep_out.write(point1600b)
print(".", end='', flush=True)
ep_out.write(point1600a)
print(".", end='', flush=True)
ep_out.write(point1600b)
print(".", end='', flush=True)
ep_out.write(point1600a)
print(".", end='', flush=True)
ep_out.write(point1600b)
print(".", end='', flush=True)
ep_out.write(point1600a)
print(".", end='', flush=True)
ep_out.write(point1600b)
print(".")
finish_send()
prepare_send()
ep_out.write(point1600c*2+point1600d*2+point1600c*2+point1600d*2)
print(".")
finish_send()
prepare_send()
dev.ctrl_transfer(0x41, 0x00, 0x01, 0x00, "")

View File

@@ -8,6 +8,8 @@
#include <mcu/gd32vf103.h> #include <mcu/gd32vf103.h>
#include "vrsp.h"
void void
set_led_b (void) set_led_b (void)
{ {
@@ -33,91 +35,13 @@ set_led (int on)
GPIOC->ODR |= (1 << 13); GPIOC->ODR |= (1 << 13);
} }
static chopstx_mutex_t mtx;
static chopstx_cond_t cnd0;
static chopstx_cond_t cnd1;
static uint8_t u, v;
static uint8_t m; /* 0..100 */
static void
wait_for (uint32_t usec)
{
#if defined(BUSY_LOOP)
uint32_t count = usec * 6;
uint32_t i;
for (i = 0; i < count; i++)
asm volatile ("" : : "r" (i) : "memory");
#else
chopstx_usec_wait (usec);
#endif
}
static void *
pwm (void *arg)
{
(void)arg;
chopstx_mutex_lock (&mtx);
chopstx_cond_wait (&cnd0, &mtx);
chopstx_mutex_unlock (&mtx);
while (1)
{
set_led (u&v);
wait_for (m);
set_led (0);
wait_for (100-m);
}
return NULL;
}
static void *
blk (void *arg)
{
(void)arg;
chopstx_mutex_lock (&mtx);
chopstx_cond_wait (&cnd1, &mtx);
chopstx_mutex_unlock (&mtx);
while (1)
{
v = 0;
wait_for (200*1000);
v = 1;
wait_for (200*1000);
}
return NULL;
}
#if defined(BUSY_LOOP)
#define PRIO_PWM (CHOPSTX_SCHED_RR|1)
#define PRIO_BLK (CHOPSTX_SCHED_RR|1)
#else
#define PRIO_PWM 3
#define PRIO_BLK 2
#endif
#define STACK_MAIN #define STACK_MAIN
#define STACK_PROCESS_1 #define STACK_PROCESS_1
#define STACK_PROCESS_2
#define STACK_PROCESS_3
#include "stack-def.h" #include "stack-def.h"
#define PRIO_USART 3
#define STACK_ADDR_PWM ((uint32_t)process1_base) #define STACK_ADDR_USART ((uint32_t)process1_base)
#define STACK_SIZE_PWM (sizeof process1_base) #define STACK_SIZE_USART (sizeof process1_base)
#define STACK_ADDR_BLK ((uint32_t)process2_base)
#define STACK_SIZE_BLK (sizeof process2_base)
#define PRIO_USART 4
#define STACK_ADDR_USART ((uint32_t)process3_base)
#define STACK_SIZE_USART (sizeof process3_base)
#define LCD_WIDTH 160 #define LCD_WIDTH 160
#define LCD_HEIGHT 80 #define LCD_HEIGHT 80
@@ -168,10 +92,8 @@ lcd_control (int control)
static void static void
lcd_send (uint8_t data) lcd_send (uint8_t data)
{ {
lcd_chip_select (1);
spi_send (data); spi_send (data);
spi_recv (); spi_recv ();
lcd_chip_select (0);
} }
static void static void
@@ -206,13 +128,14 @@ lcd_init (void)
lcd_reset (1); lcd_reset (1);
chopstx_usec_wait (500*1000); chopstx_usec_wait (500*1000);
lcd_reset (0); lcd_reset (0);
chopstx_usec_wait (50*1000); lcd_chip_select (1);
chopstx_usec_wait (100*1000);
lcd_command (0x11); /* SLPOUT: Sleep out */ lcd_command (0x11); /* SLPOUT: Sleep out */
chopstx_usec_wait (100*1000); chopstx_usec_wait (100*1000);
lcd_command (0x21); /* INVON: display inversion on */ lcd_command (0x21); /* INVON: display inversion on */
/* INVOFF: display inversion off: 0x20 */ /* INVOFF: display inversion off: 0x20 */
lcd_command (0x3a); /* COLMOD: Pixel data format */ lcd_command (0x3a); /* COLMOD: Pixel data format */
lcd_data8 (0x05); /* 16-bit/pixel */ lcd_data8 (0x05); /* 16-bit/pixel */
@@ -356,72 +279,93 @@ ss_notify (uint8_t dev_no, uint16_t state_bits)
return 0; return 0;
} }
#include "fsij-logo.c" uint16_t screen_image[12800];
int int
main (int argc, const char *argv[]) main (int argc, const char *argv[])
{ {
chopstx_poll_cond_t poll_desc; chopstx_poll_cond_t usart_poll_desc;
struct chx_poll_head *ph[1]; chopstx_poll_cond_t usb_poll_desc;
struct chx_poll_head *ph[2];
uint32_t timeout; uint32_t timeout;
int cl = 0; int cl = 0;
int play_mode = 0;
struct vrsp *v;
uint32_t u = 0;
(void)argc; (void)argc;
(void)argv; (void)argv;
set_led (1);
chopstx_mutex_init (&mtx);
chopstx_cond_init (&cnd0);
chopstx_cond_init (&cnd1);
m = 10;
chopstx_create (PRIO_PWM, STACK_ADDR_PWM, STACK_SIZE_PWM, pwm, NULL);
chopstx_create (PRIO_BLK, STACK_ADDR_BLK, STACK_SIZE_BLK, blk, NULL);
chopstx_usec_wait (200*1000);
chopstx_mutex_lock (&mtx);
chopstx_cond_signal (&cnd0);
chopstx_cond_signal (&cnd1);
chopstx_mutex_unlock (&mtx);
lcd_init ();
usart_init (PRIO_USART, STACK_ADDR_USART, STACK_SIZE_USART, ss_notify); usart_init (PRIO_USART, STACK_ADDR_USART, STACK_SIZE_USART, ss_notify);
usart_config (0, B115200 | CS8 | STOP1B); usart_config (0, B115200 | CS8 | STOP1B);
usart_read_prepare_poll (0, &poll_desc); v = vrsp_open ();
ph[0] = (struct chx_poll_head *)&poll_desc;
chopstx_usec_wait (500*1000);
set_led (1);
lcd_init ();
lcd_clear (colors[26]);
chopstx_usec_wait (500*1000);
vrsp_prepare_poll (v, &usb_poll_desc);
ph[0] = (struct chx_poll_head *)&usb_poll_desc;
usart_read_prepare_poll (0, &usart_poll_desc);
ph[1] = (struct chx_poll_head *)&usart_poll_desc;
timeout = 200*1000*6; timeout = 200*1000*6;
while (1) while (1)
{ {
chopstx_poll (&timeout, 1, ph); chopstx_poll (&timeout, 2, ph);
if (usart_poll_desc.ready)
{
char buf[16];
int r;
r = usart_read (0, buf, 16);
if (r)
usart_write (0, buf, r);
}
if (usb_poll_desc.ready)
{
int r;
r = vrsp_screen_acquire (v);
if (r < 0)
/* It's busy. */
;
else if (r == 0)
{
play_mode = 1;
lcd_load_image (screen_image);
vrsp_screen_release (v);
}
else
{
play_mode = 0;
vrsp_screen_release (v);
}
}
if (timeout == 0) if (timeout == 0)
{ {
usart_write (0, "Hello\r\n", 7); usart_write (0, "Hello\r\n", 7);
u ^= 1;
timeout = 200*1000*6; timeout = 200*1000*6;
lcd_clear (colors[cl]); u ^= 1;
set_led (u);
chopstx_usec_wait (1000*1000); if (play_mode == 0)
lcd_load_image (fsij_logo); {
chopstx_usec_wait (1000*1000); lcd_clear (colors[cl]);
cl++; cl++;
if (cl >= 27) if (cl >= 27)
cl = 0; cl = 0;
} }
else
{
char buf[256];
int r;
r = usart_read (0, buf, 256);
if (r)
usart_write (0, buf, r);
} }
} }

View File

@@ -41,6 +41,7 @@ SECTIONS
*(.process_stack.1) *(.process_stack.1)
*(.process_stack.2) *(.process_stack.2)
*(.process_stack.3) *(.process_stack.3)
*(.process_stack.4)
. = ALIGN(8); . = ALIGN(8);
} > ram } > ram

View File

@@ -1,8 +1,9 @@
#define MAIN_SIZE 0x0100 /* Idle+Exception handlers */ #define MAIN_SIZE 0x0100 /* Idle+Exception handlers */
#define SIZE_0 0x0400 /* Main program */ #define SIZE_0 0x0600 /* Main program */
#define SIZE_1 0x0200 /* first thread program */ #define SIZE_1 0x0c00 /* first thread program */
#define SIZE_2 0x0200 /* second thread program */ #define SIZE_2 0x0600 /* second thread program */
#define SIZE_3 0x0600 /* second thread program */ #define SIZE_3 0x0000 /* third thread program */
#define SIZE_4 0x0000 /* fourth thread program */
#if defined(STACK_MAIN) #if defined(STACK_MAIN)
/* /*

View File

@@ -0,0 +1,585 @@
#include <stdint.h>
#include <stdlib.h>
#include <chopstx.h>
#include <string.h>
#include "board.h"
#include "usb_lld.h"
#include "vrsp.h"
extern uint16_t screen_image[12800];
static chopstx_intr_t usb_intr;
struct vrsp {
struct usb_dev dev;
chopstx_mutex_t mtx;
chopstx_cond_t cnd;
uint32_t device_state : 3; /* USB device status */
uint32_t screen_mem_owner : 1; /* 0: driver, 1: app */
uint32_t mode : 8;
uint16_t *screen_ptr;
};
static struct vrsp vrsp0;
/*
* Locate VRSP structure from interface number or endpoint number.
* Currently, it always returns vrsp0, because we only have the one.
*/
static struct vrsp *
vrsp_get (int interface, uint8_t ep_num)
{
struct vrsp *v = &vrsp0;
(void)interface;
(void)ep_num;
return v;
}
static void vrsp_update_finish (struct vrsp *v, int value);
/* USB Device Descriptor */
static const uint8_t vrsp_device_desc[18] = {
18, /* bLength */
DEVICE_DESCRIPTOR, /* bDescriptorType */
0x10, 0x01, /* bcdUSB = 1.1 */
0x00, /* bDeviceClass. */
0x00, /* bDeviceSubClass. */
0x00, /* bDeviceProtocol. */
0x40, /* bMaxPacketSize. */
0xFF, 0xFF, /* idVendor */
0x01, 0x00, /* idProduct */
0x00, 0x01, /* bcdDevice */
1, /* iManufacturer. */
2, /* iProduct. */
3, /* iSerialNumber. */
1 /* bNumConfigurations. */
};
#define FEATURE_BUS_POWERED 0x80
/* Configuration Descriptor */
static const uint8_t vrsp_config_desc[32] = {
9,
CONFIG_DESCRIPTOR, /* bDescriptorType: Configuration */
/* Configuration Descriptor.*/
32, 0x00, /* wTotalLength. */
0x01, /* bNumInterfaces. */
0x01, /* bConfigurationValue. */
0, /* iConfiguration. */
FEATURE_BUS_POWERED, /* bmAttributes. */
50, /* bMaxPower (100mA). */
/* Interface Descriptor.*/
9,
INTERFACE_DESCRIPTOR,
0x00, /* bInterfaceNumber. */
0x00, /* bAlternateSetting. */
0x02, /* bNumEndpoints. */
0xFF, /* bInterfaceClass (Vendor specific). */
0x00, /* bInterfaceSubClass. */
0x00, /* bInterfaceProtocol. */
0, /* iInterface. */
/* Endpoint 1-OUT Descriptor.*/
7,
ENDPOINT_DESCRIPTOR,
ENDP1, /* bEndpointAddress. */
0x02, /* bmAttributes (Bulk). */
0x40, 0x00, /* wMaxPacketSize. */
0x00, /* bInterval. */
/* Endpoint 1-IN Descriptor.*/
7,
ENDPOINT_DESCRIPTOR,
ENDP1|0x80, /* bEndpointAddress. */
0x02, /* bmAttributes (Bulk). */
0x40, 0x00, /* wMaxPacketSize. */
0x00, /* bInterval. */
};
/*
* U.S. English language identifier.
*/
static const uint8_t vrsp_string0[4] = {
4, /* bLength */
STRING_DESCRIPTOR,
0x09, 0x04 /* LangID = 0x0409: US-English */
};
static const uint8_t vrsp_string1[] = {
23*2+2, /* bLength */
STRING_DESCRIPTOR, /* bDescriptorType */
/* Manufacturer: "Flying Stone Technology" */
'F', 0, 'l', 0, 'y', 0, 'i', 0, 'n', 0, 'g', 0, ' ', 0, 'S', 0,
't', 0, 'o', 0, 'n', 0, 'e', 0, ' ', 0, 'T', 0, 'e', 0, 'c', 0,
'h', 0, 'n', 0, 'o', 0, 'l', 0, 'o', 0, 'g', 0, 'y', 0,
};
static const uint8_t vrsp_string2[] = {
14*2+2, /* bLength */
STRING_DESCRIPTOR, /* bDescriptorType */
/* Product name: "Chopstx Sample" */
'C', 0, 'h', 0, 'o', 0, 'p', 0, 's', 0, 't', 0, 'x', 0, ' ', 0,
'S', 0, 'a', 0, 'm', 0, 'p', 0, 'l', 0, 'e', 0,
};
/*
* Serial Number string.
*/
static const uint8_t vrsp_string3[10] = {
10, /* bLength */
STRING_DESCRIPTOR, /* bDescriptorType */
'0', 0, '.', 0, '0', 0, '0', 0, /* Version number */
};
#define NUM_INTERFACES 1
static void
usb_device_reset (struct usb_dev *dev)
{
usb_lld_reset (dev, FEATURE_BUS_POWERED);
chopstx_mutex_lock (&vrsp0.mtx);
vrsp0.device_state = USB_DEVICE_STATE_ATTACHED;
vrsp0.screen_mem_owner = 0;
vrsp0.screen_ptr = screen_image;
vrsp0.mode = 2;
chopstx_cond_signal (&vrsp0.cnd);
chopstx_mutex_unlock (&vrsp0.mtx);
}
static void
usb_ctrl_write_finish (struct usb_dev *dev)
{
(void)dev;
}
static int
usb_setup (struct usb_dev *dev)
{
struct device_req *arg = &dev->dev_req;
uint8_t type_rcp = arg->type & (REQUEST_TYPE|RECIPIENT);
if (USB_SETUP_SET (arg->type))
{
if (type_rcp == (VENDOR_REQUEST | INTERFACE_RECIPIENT)
&& arg->request == 0x00
&& arg->index == 0 /* interface 0 */)
{
struct vrsp *v = vrsp_get (arg->index, 0);
/* Finish the screen update. */
vrsp_update_finish (v, arg->value);
return usb_lld_ctrl_ack (dev);
}
}
return -1;
}
static int
usb_get_descriptor (struct usb_dev *dev)
{
struct device_req *arg = &dev->dev_req;
uint8_t rcp = arg->type & RECIPIENT;
uint8_t desc_type = (arg->value >> 8);
uint8_t desc_index = (arg->value & 0xff);
if (rcp != DEVICE_RECIPIENT)
return -1;
if (desc_type == DEVICE_DESCRIPTOR)
return usb_lld_ctrl_send (dev,
vrsp_device_desc, sizeof (vrsp_device_desc));
else if (desc_type == CONFIG_DESCRIPTOR)
return usb_lld_ctrl_send (dev,
vrsp_config_desc, sizeof (vrsp_config_desc));
else if (desc_type == STRING_DESCRIPTOR)
{
const uint8_t *str;
int size;
switch (desc_index)
{
case 0:
str = vrsp_string0;
size = sizeof (vrsp_string0);
break;
case 1:
str = vrsp_string1;
size = sizeof (vrsp_string1);
break;
case 2:
str = vrsp_string2;
size = sizeof (vrsp_string2);
break;
case 3:
str = vrsp_string3;
size = sizeof (vrsp_string3);
break;
default:
return -1;
}
return usb_lld_ctrl_send (dev, str, size);
}
return -1;
}
static const uint8_t status_zero;
static void
vrsp_setup_endpoints_for_interface (struct usb_dev *dev,
uint16_t interface, int stop)
{
if (interface == 0)
{
if (!stop)
{
struct vrsp *v = vrsp_get (interface, 0);
usb_lld_setup_endp (dev, ENDP1, EP_BULK, 1, 1);
if (v->screen_mem_owner == 0)
usb_lld_tx_enable_buf (&v->dev, ENDP1, &status_zero, 1);
}
else
{
usb_lld_stall_rx (dev, ENDP1);
usb_lld_stall_tx (dev, ENDP1);
}
}
}
static int
usb_set_configuration (struct usb_dev *dev)
{
uint8_t current_conf;
current_conf = usb_lld_current_configuration (dev);
if (current_conf == 0)
{
if (dev->dev_req.value != 1)
return -1;
usb_lld_set_configuration (dev, 1);
vrsp_setup_endpoints_for_interface (dev, 0, 0);
}
else if (current_conf != dev->dev_req.value)
{
if (dev->dev_req.value != 0)
return -1;
usb_lld_set_configuration (dev, 0);
vrsp_setup_endpoints_for_interface (dev, 0, 1);
}
return usb_lld_ctrl_ack (dev);
}
static int
usb_set_interface (struct usb_dev *dev)
{
uint16_t interface = dev->dev_req.index;
uint16_t alt = dev->dev_req.value;
if (interface >= NUM_INTERFACES)
return -1;
if (alt != 0)
return -1;
else
{
vrsp_setup_endpoints_for_interface (dev, interface, 0);
return usb_lld_ctrl_ack (dev);
}
}
static int
usb_get_interface (struct usb_dev *dev)
{
const uint8_t zero = 0;
uint16_t interface = dev->dev_req.index;
if (interface >= NUM_INTERFACES)
return -1;
/* We don't have alternate interface, so, always return 0. */
return usb_lld_ctrl_send (dev, &zero, 1);
}
static int
usb_get_status_interface (struct usb_dev *dev)
{
const uint16_t status_info = 0;
uint16_t interface = dev->dev_req.index;
if (interface >= NUM_INTERFACES)
return -1;
return usb_lld_ctrl_send (dev, &status_info, 2);
}
static void
vrsp_update_receive (struct vrsp *v, int len)
{
chopstx_mutex_lock (&v->mtx);
if (v->screen_mem_owner == 0 && v->screen_ptr)
{
v->screen_ptr += len / 2;
if (v->screen_ptr < screen_image + 12800)
usb_lld_rx_enable_buf (&v->dev, ENDP1, v->screen_ptr, 64);
}
chopstx_mutex_unlock (&v->mtx);
}
static void
vrsp_update_finish (struct vrsp *v, int value)
{
chopstx_mutex_lock (&v->mtx);
if (v->screen_mem_owner == 0 && v->screen_ptr)
{
v->screen_ptr = NULL;
v->mode = value;
chopstx_cond_signal (&v->cnd);
}
chopstx_mutex_unlock (&v->mtx);
}
static void
usb_tx_done (uint8_t ep_num, uint16_t len)
{
struct vrsp *v = vrsp_get (-1, ep_num);
(void)len;
/*
* Coming here means that notification ("it's ready to accept screen
* data") is retrieved by host. Enable the receive endpoint to
* accept data.
*/
/* EP_NUM should be ENDP1 in this implementation. */
usb_lld_rx_enable_buf (&v->dev, ENDP1, v->screen_ptr, 64);
}
static void
usb_rx_ready (uint8_t ep_num, uint16_t len)
{
struct vrsp *v = vrsp_get (-1, ep_num);
if (ep_num == ENDP1)
vrsp_update_receive (v, len);
}
#define PRIO_VRSP 4
#define STACK_PROCESS_2
#include "stack-def.h"
#define STACK_ADDR_VRSP ((uint32_t)process2_base)
#define STACK_SIZE_VRSP (sizeof process2_base)
static void *
vrsp_main (void *arg)
{
struct vrsp *v = arg;
struct usb_dev *dev = &v->dev;
int e;
chopstx_claim_irq (&usb_intr, INTR_REQ_USB);
usb_lld_init (dev, FEATURE_BUS_POWERED);
while (1)
{
chopstx_intr_wait (&usb_intr);
if (usb_intr.ready)
{
uint8_t ep_num;
/*
* When interrupt is detected, call usb_lld_event_handler.
* The event may be one of following:
* (1) Transfer to endpoint (bulk or interrupt)
* In this case EP_NUM is encoded in the variable E.
* (2) "NONE" event: some trasfer was done, but all was
* done by lower layer, no other work is needed in
* upper layer.
* (3) Device events: Reset or Suspend
* (4) Device requests to the endpoint zero.
*
*/
e = usb_lld_event_handler (dev);
chopstx_intr_done (&usb_intr);
ep_num = USB_EVENT_ENDP (e);
if (ep_num != 0)
{
if (USB_EVENT_TXRX (e))
usb_tx_done (ep_num, USB_EVENT_LEN (e));
else
usb_rx_ready (ep_num, USB_EVENT_LEN (e));
}
else
switch (USB_EVENT_ID (e))
{
case USB_EVENT_DEVICE_RESET:
usb_device_reset (dev);
continue;
case USB_EVENT_DEVICE_ADDRESSED:
/* The addres is assigned to the device. We don't
* need to do anything for this actually, but in this
* application, we maintain the USB status of the
* device. Usually, just "continue" as EVENT_OK is
* OK.
*/
chopstx_mutex_lock (&v->mtx);
v->device_state = USB_DEVICE_STATE_ADDRESSED;
chopstx_cond_signal (&v->cnd);
chopstx_mutex_unlock (&v->mtx);
continue;
case USB_EVENT_GET_DESCRIPTOR:
if (usb_get_descriptor (dev) < 0)
usb_lld_ctrl_error (dev);
continue;
case USB_EVENT_SET_CONFIGURATION:
if (usb_set_configuration (dev) < 0)
usb_lld_ctrl_error (dev);
continue;
case USB_EVENT_SET_INTERFACE:
if (usb_set_interface (dev) < 0)
usb_lld_ctrl_error (dev);
continue;
case USB_EVENT_CTRL_REQUEST:
/* Device specific device request. */
if (usb_setup (dev) < 0)
usb_lld_ctrl_error (dev);
continue;
case USB_EVENT_GET_STATUS_INTERFACE:
if (usb_get_status_interface (dev) < 0)
usb_lld_ctrl_error (dev);
continue;
case USB_EVENT_GET_INTERFACE:
if (usb_get_interface (dev) < 0)
usb_lld_ctrl_error (dev);
continue;
case USB_EVENT_SET_FEATURE_DEVICE:
case USB_EVENT_SET_FEATURE_ENDPOINT:
case USB_EVENT_CLEAR_FEATURE_DEVICE:
case USB_EVENT_CLEAR_FEATURE_ENDPOINT:
usb_lld_ctrl_ack (dev);
continue;
case USB_EVENT_CTRL_WRITE_FINISH:
/* Control WRITE transfer finished. */
usb_ctrl_write_finish (dev);
continue;
case USB_EVENT_OK:
case USB_EVENT_DEVICE_SUSPEND:
default:
continue;
}
}
}
return NULL;
}
static int
vrsp_ready_check (void *arg)
{
struct vrsp *v = arg;
return v->screen_mem_owner == 0 && v->screen_ptr == NULL;
}
/* API exposed to application. */
struct vrsp *
vrsp_open (void)
{
struct vrsp *v = &vrsp0; /* Now, we only have a single VRSP. */
chopstx_mutex_init (&v->mtx);
chopstx_cond_init (&v->cnd);
v->device_state = USB_DEVICE_STATE_UNCONNECTED;
v->screen_mem_owner = 0;
v->screen_ptr = screen_image;
v->mode = 1;
chopstx_create (PRIO_VRSP, STACK_ADDR_VRSP, STACK_SIZE_VRSP, vrsp_main, v);
return v;
}
void
vrsp_prepare_poll (struct vrsp *v, chopstx_poll_cond_t *poll_desc)
{
poll_desc->type = CHOPSTX_POLL_COND;
poll_desc->ready = 0;
poll_desc->cond = &v->cnd;
poll_desc->mutex = &v->mtx;
poll_desc->check = vrsp_ready_check;
poll_desc->arg = v;
}
/*
* vrsp_screen_acquire: Acquire the screen memory by the application to
* update the LCD.
*
* Returns < 0 on error
* >= 0 on success
*/
int
vrsp_screen_acquire (struct vrsp *v)
{
int r = 0;
chopstx_mutex_lock (&v->mtx);
while (1)
if (v->screen_mem_owner != 0)
{
/* something goes wrong, it's your turn already. */
r = -1;
break;
}
else if (v->screen_ptr)
/* The use of screen has not been finished yet. */
chopstx_cond_wait (&v->cnd, &v->mtx);
else
{
v->screen_mem_owner = 1;
r = v->mode;
break;
}
chopstx_mutex_unlock (&v->mtx);
return r;
}
/*
* vrsp_screen_release: release the screen memory by the application
*/
void
vrsp_screen_release (struct vrsp *v)
{
chopstx_mutex_lock (&v->mtx);
v->screen_mem_owner = 0;
v->screen_ptr = screen_image;
chopstx_mutex_unlock (&v->mtx);
/* Put the notification to host. */
usb_lld_tx_enable_buf (&v->dev, ENDP1, &status_zero, 1);
}

7
example-lcd/vrsp.h Normal file
View File

@@ -0,0 +1,7 @@
struct vrsp;
struct vrsp *vrsp_open (void);
void vrsp_prepare_poll (struct vrsp *v, chopstx_poll_cond_t *poll_desc);
int vrsp_screen_acquire (struct vrsp *v);
void vrsp_screen_release (struct vrsp *v);