tests: gadget0: test for unaligned buffer read/writes.
This currently fails on stm32F072, which is expected but not normal. See GH issues #401 , #461
This commit is contained in:
parent
c585336766
commit
c3512f4de5
@ -318,3 +318,54 @@ class TestControlTransfer_Reads(unittest.TestCase):
|
|||||||
self.assertEqual(len(q), 10, "In this case, should have gotten wLen back")
|
self.assertEqual(len(q), 10, "In this case, should have gotten wLen back")
|
||||||
|
|
||||||
|
|
||||||
|
class TestUnaligned(unittest.TestCase):
|
||||||
|
"""
|
||||||
|
M0 and M0+ cores don't support unaligned memory accesses. These test
|
||||||
|
how the stack behaves with aligned vs unaligned buffers.
|
||||||
|
https://github.com/libopencm3/libopencm3/issues/401
|
||||||
|
https://github.com/libopencm3/libopencm3/issues/461
|
||||||
|
"""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.dev = usb.core.find(idVendor=0xcafe, idProduct=0xcafe, custom_match=find_by_serial(DUT_SERIAL))
|
||||||
|
self.assertIsNotNone(self.dev, "Couldn't find locm3 gadget0 device")
|
||||||
|
|
||||||
|
self.cfg = uu.find_descriptor(self.dev, bConfigurationValue=2)
|
||||||
|
self.assertIsNotNone(self.cfg, "Config 2 should exist")
|
||||||
|
self.dev.set_configuration(self.cfg);
|
||||||
|
self.req = uu.CTRL_OUT | uu.CTRL_TYPE_VENDOR | uu.CTRL_RECIPIENT_INTERFACE
|
||||||
|
self.intf = self.cfg[(0, 0)]
|
||||||
|
# heh, kinda gross...
|
||||||
|
self.ep_out = [ep for ep in self.intf if uu.endpoint_direction(ep.bEndpointAddress) == uu.ENDPOINT_OUT][0]
|
||||||
|
self.ep_in = [ep for ep in self.intf if uu.endpoint_direction(ep.bEndpointAddress) == uu.ENDPOINT_IN][0]
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
uu.dispose_resources(self.dev)
|
||||||
|
|
||||||
|
def set_unaligned(self):
|
||||||
|
# GZ_REQ_SET_UNALIGNED
|
||||||
|
x = self.dev.ctrl_transfer(self.req, 4, 0, 0)
|
||||||
|
|
||||||
|
def set_aligned(self):
|
||||||
|
# GZ_REQ_SET_ALIGNED
|
||||||
|
x = self.dev.ctrl_transfer(self.req, 3, 0, 0)
|
||||||
|
|
||||||
|
def do_readwrite(self):
|
||||||
|
"""
|
||||||
|
transfer garbage data to/from bulk EP; alignment issues will hardfault the target
|
||||||
|
"""
|
||||||
|
data = [x for x in range(int(self.ep_out.wMaxPacketSize / 2))]
|
||||||
|
written = self.dev.write(self.ep_out, data)
|
||||||
|
self.assertEqual(written, len(data), "Should have written all bytes plz")
|
||||||
|
|
||||||
|
read_size = self.ep_in.wMaxPacketSize * 10
|
||||||
|
data = self.dev.read(self.ep_in, read_size)
|
||||||
|
self.assertEqual(len(data), read_size, "Should have read as much as we asked for")
|
||||||
|
|
||||||
|
def test_aligned(self):
|
||||||
|
self.set_aligned()
|
||||||
|
self.do_readwrite()
|
||||||
|
|
||||||
|
def test_unaligned(self):
|
||||||
|
self.set_unaligned()
|
||||||
|
self.do_readwrite()
|
||||||
|
@ -45,6 +45,8 @@
|
|||||||
*/
|
*/
|
||||||
#define GZ_REQ_SET_PATTERN 1
|
#define GZ_REQ_SET_PATTERN 1
|
||||||
#define GZ_REQ_PRODUCE 2
|
#define GZ_REQ_PRODUCE 2
|
||||||
|
#define GZ_REQ_SET_ALIGNED 3
|
||||||
|
#define GZ_REQ_SET_UNALIGNED 4
|
||||||
#define INTEL_COMPLIANCE_WRITE 0x5b
|
#define INTEL_COMPLIANCE_WRITE 0x5b
|
||||||
#define INTEL_COMPLIANCE_READ 0x5c
|
#define INTEL_COMPLIANCE_READ 0x5c
|
||||||
|
|
||||||
@ -177,42 +179,60 @@ static usbd_device *our_dev;
|
|||||||
static struct {
|
static struct {
|
||||||
uint8_t pattern;
|
uint8_t pattern;
|
||||||
int pattern_counter;
|
int pattern_counter;
|
||||||
|
int test_unaligned; /* If 0 (default), use 16-bit aligned buffers. This should not be declared as bool */
|
||||||
} state = {
|
} state = {
|
||||||
.pattern = 0,
|
.pattern = 0,
|
||||||
.pattern_counter = 0,
|
.pattern_counter = 0,
|
||||||
|
.test_unaligned = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void gadget0_ss_out_cb(usbd_device *usbd_dev, uint8_t ep)
|
static void gadget0_ss_out_cb(usbd_device *usbd_dev, uint8_t ep)
|
||||||
{
|
{
|
||||||
(void) ep;
|
(void) ep;
|
||||||
|
uint16_t x;
|
||||||
/* TODO - if you're really keen, perf test this. tiva implies it matters */
|
/* TODO - if you're really keen, perf test this. tiva implies it matters */
|
||||||
/* char buf[64] __attribute__ ((aligned(4))); */
|
/* char buf[64] __attribute__ ((aligned(4))); */
|
||||||
char buf[BULK_EP_MAXPACKET];
|
uint8_t buf[BULK_EP_MAXPACKET + 1] __attribute__ ((aligned(2)));
|
||||||
|
uint8_t *dest;
|
||||||
|
|
||||||
trace_send_blocking8(0, 'O');
|
trace_send_blocking8(0, 'O');
|
||||||
uint16_t x = usbd_ep_read_packet(usbd_dev, ep, buf, sizeof(buf));
|
if (state.test_unaligned) {
|
||||||
|
dest = buf + 1;
|
||||||
|
} else {
|
||||||
|
dest = buf;
|
||||||
|
}
|
||||||
|
x = usbd_ep_read_packet(usbd_dev, ep, dest, BULK_EP_MAXPACKET);
|
||||||
trace_send_blocking8(1, x);
|
trace_send_blocking8(1, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gadget0_ss_in_cb(usbd_device *usbd_dev, uint8_t ep)
|
static void gadget0_ss_in_cb(usbd_device *usbd_dev, uint8_t ep)
|
||||||
{
|
{
|
||||||
(void) usbd_dev;
|
(void) usbd_dev;
|
||||||
|
uint8_t buf[BULK_EP_MAXPACKET + 1] __attribute__ ((aligned(2)));
|
||||||
|
uint8_t *src;
|
||||||
|
|
||||||
trace_send_blocking8(0, 'I');
|
trace_send_blocking8(0, 'I');
|
||||||
uint8_t buf[BULK_EP_MAXPACKET];
|
if (state.test_unaligned) {
|
||||||
|
src = buf + 1;
|
||||||
|
} else {
|
||||||
|
src = buf;
|
||||||
|
}
|
||||||
|
|
||||||
switch (state.pattern) {
|
switch (state.pattern) {
|
||||||
case 0:
|
case 0:
|
||||||
memset(buf, 0, sizeof(buf));
|
memset(src, 0, BULK_EP_MAXPACKET);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
for (unsigned i = 0; i < sizeof(buf); i++) {
|
for (unsigned i = 0; i < BULK_EP_MAXPACKET; i++) {
|
||||||
buf[i] = state.pattern_counter++ % 63;
|
src[i] = state.pattern_counter++ % 63;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t x = usbd_ep_write_packet(usbd_dev, ep, buf, sizeof(buf));
|
uint16_t x = usbd_ep_write_packet(usbd_dev, ep, src, BULK_EP_MAXPACKET);
|
||||||
/* As we are calling write in the callback, this should never fail */
|
/* As we are calling write in the callback, this should never fail */
|
||||||
trace_send_blocking8(2, x);
|
trace_send_blocking8(2, x);
|
||||||
if (x != sizeof(buf)) {
|
if (x != BULK_EP_MAXPACKET) {
|
||||||
ER_DPRINTF("failed to write?: %d\n", x);
|
ER_DPRINTF("failed to write?: %d\n", x);
|
||||||
}
|
}
|
||||||
/*assert(x == sizeof(buf));*/
|
/*assert(x == sizeof(buf));*/
|
||||||
@ -256,6 +276,12 @@ static int gadget0_control_request(usbd_device *usbd_dev,
|
|||||||
case INTEL_COMPLIANCE_READ:
|
case INTEL_COMPLIANCE_READ:
|
||||||
ER_DPRINTF("unimplemented!");
|
ER_DPRINTF("unimplemented!");
|
||||||
return USBD_REQ_NOTSUPP;
|
return USBD_REQ_NOTSUPP;
|
||||||
|
case GZ_REQ_SET_UNALIGNED:
|
||||||
|
state.test_unaligned = 1;
|
||||||
|
return USBD_REQ_HANDLED;
|
||||||
|
case GZ_REQ_SET_ALIGNED:
|
||||||
|
state.test_unaligned = 0;
|
||||||
|
return USBD_REQ_HANDLED;
|
||||||
case GZ_REQ_PRODUCE:
|
case GZ_REQ_PRODUCE:
|
||||||
ER_DPRINTF("fake loopback of %d\n", req->wValue);
|
ER_DPRINTF("fake loopback of %d\n", req->wValue);
|
||||||
if (req->wValue > sizeof(usbd_control_buffer)) {
|
if (req->wValue > sizeof(usbd_control_buffer)) {
|
||||||
@ -280,6 +306,7 @@ static void gadget0_set_config(usbd_device *usbd_dev, uint16_t wValue)
|
|||||||
ER_DPRINTF("set cfg %d\n", wValue);
|
ER_DPRINTF("set cfg %d\n", wValue);
|
||||||
switch (wValue) {
|
switch (wValue) {
|
||||||
case GZ_CFG_SOURCESINK:
|
case GZ_CFG_SOURCESINK:
|
||||||
|
state.test_unaligned = 0;
|
||||||
usbd_ep_setup(usbd_dev, 0x01, USB_ENDPOINT_ATTR_BULK, BULK_EP_MAXPACKET,
|
usbd_ep_setup(usbd_dev, 0x01, USB_ENDPOINT_ATTR_BULK, BULK_EP_MAXPACKET,
|
||||||
gadget0_ss_out_cb);
|
gadget0_ss_out_cb);
|
||||||
usbd_ep_setup(usbd_dev, 0x82, USB_ENDPOINT_ATTR_BULK, BULK_EP_MAXPACKET,
|
usbd_ep_setup(usbd_dev, 0x82, USB_ENDPOINT_ATTR_BULK, BULK_EP_MAXPACKET,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user