mirror of
https://github.com/im-tomu/foboot.git
synced 2024-09-20 02:40:09 +00:00
sw: fix line endings
Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
parent
482708d6fb
commit
9144b767a8
@ -1,124 +1,124 @@
|
||||
/*
|
||||
File: printf.h
|
||||
|
||||
Copyright (c) 2004,2012 Kustaa Nyholm / SpareTimeLabs
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
Neither the name of the Kustaa Nyholm or SpareTimeLabs nor the names of its
|
||||
contributors may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
||||
This library is realy just two files: 'printf.h' and 'printf.c'.
|
||||
|
||||
They provide a simple and small (+200 loc) printf functionality to
|
||||
be used in embedded systems.
|
||||
|
||||
I've found them so usefull in debugging that I do not bother with a
|
||||
debugger at all.
|
||||
|
||||
They are distributed in source form, so to use them, just compile them
|
||||
into your project.
|
||||
|
||||
Two printf variants are provided: printf and sprintf.
|
||||
|
||||
The formats supported by this implementation are: 'd' 'u' 'c' 's' 'x' 'X'.
|
||||
|
||||
Zero padding and field width are also supported.
|
||||
|
||||
If the library is compiled with 'PRINTF_SUPPORT_LONG' defined then the
|
||||
long specifier is also
|
||||
supported. Note that this will pull in some long math routines (pun intended!)
|
||||
and thus make your executable noticably longer.
|
||||
|
||||
The memory foot print of course depends on the target cpu, compiler and
|
||||
compiler options, but a rough guestimate (based on a H8S target) is about
|
||||
1.4 kB for code and some twenty 'int's and 'char's, say 60 bytes of stack space.
|
||||
Not too bad. Your milage may vary. By hacking the source code you can
|
||||
get rid of some hunred bytes, I'm sure, but personally I feel the balance of
|
||||
functionality and flexibility versus code size is close to optimal for
|
||||
many embedded systems.
|
||||
|
||||
To use the printf you need to supply your own character output function,
|
||||
something like :
|
||||
|
||||
void putc ( void* p, char c)
|
||||
{
|
||||
while (!SERIAL_PORT_EMPTY) ;
|
||||
SERIAL_PORT_TX_REGISTER = c;
|
||||
}
|
||||
|
||||
Before you can call printf you need to initialize it to use your
|
||||
character output function with something like:
|
||||
|
||||
init_printf(NULL,putc);
|
||||
|
||||
Notice the 'NULL' in 'init_printf' and the parameter 'void* p' in 'putc',
|
||||
the NULL (or any pointer) you pass into the 'init_printf' will eventually be
|
||||
passed to your 'putc' routine. This allows you to pass some storage space (or
|
||||
anything realy) to the character output function, if necessary.
|
||||
This is not often needed but it was implemented like that because it made
|
||||
implementing the sprintf function so neat (look at the source code).
|
||||
|
||||
The code is re-entrant, except for the 'init_printf' function, so it
|
||||
is safe to call it from interupts too, although this may result in mixed output.
|
||||
If you rely on re-entrancy, take care that your 'putc' function is re-entrant!
|
||||
|
||||
The printf and sprintf functions are actually macros that translate to
|
||||
'tfp_printf' and 'tfp_sprintf'. This makes it possible
|
||||
to use them along with 'stdio.h' printf's in a single source file.
|
||||
You just need to undef the names before you include the 'stdio.h'.
|
||||
Note that these are not function like macros, so if you have variables
|
||||
or struct members with these names, things will explode in your face.
|
||||
Without variadic macros this is the best we can do to wrap these
|
||||
fucnction. If it is a problem just give up the macros and use the
|
||||
functions directly or rename them.
|
||||
|
||||
For further details see source code.
|
||||
|
||||
regs Kusti, 23.10.2004
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __TFP_PRINTF__
|
||||
#define __TFP_PRINTF__
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
void init_printf(void* putp,void (*putf) (void*,char));
|
||||
|
||||
void tfp_printf(char *fmt, ...);
|
||||
void tfp_sprintf(char* s,char *fmt, ...);
|
||||
|
||||
void tfp_format(void* putp,void (*putf) (void*,char),char *fmt, va_list va);
|
||||
|
||||
#define printf tfp_printf
|
||||
#define sprintf tfp_sprintf
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*
|
||||
File: printf.h
|
||||
|
||||
Copyright (c) 2004,2012 Kustaa Nyholm / SpareTimeLabs
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
Neither the name of the Kustaa Nyholm or SpareTimeLabs nor the names of its
|
||||
contributors may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
||||
This library is realy just two files: 'printf.h' and 'printf.c'.
|
||||
|
||||
They provide a simple and small (+200 loc) printf functionality to
|
||||
be used in embedded systems.
|
||||
|
||||
I've found them so usefull in debugging that I do not bother with a
|
||||
debugger at all.
|
||||
|
||||
They are distributed in source form, so to use them, just compile them
|
||||
into your project.
|
||||
|
||||
Two printf variants are provided: printf and sprintf.
|
||||
|
||||
The formats supported by this implementation are: 'd' 'u' 'c' 's' 'x' 'X'.
|
||||
|
||||
Zero padding and field width are also supported.
|
||||
|
||||
If the library is compiled with 'PRINTF_SUPPORT_LONG' defined then the
|
||||
long specifier is also
|
||||
supported. Note that this will pull in some long math routines (pun intended!)
|
||||
and thus make your executable noticably longer.
|
||||
|
||||
The memory foot print of course depends on the target cpu, compiler and
|
||||
compiler options, but a rough guestimate (based on a H8S target) is about
|
||||
1.4 kB for code and some twenty 'int's and 'char's, say 60 bytes of stack space.
|
||||
Not too bad. Your milage may vary. By hacking the source code you can
|
||||
get rid of some hunred bytes, I'm sure, but personally I feel the balance of
|
||||
functionality and flexibility versus code size is close to optimal for
|
||||
many embedded systems.
|
||||
|
||||
To use the printf you need to supply your own character output function,
|
||||
something like :
|
||||
|
||||
void putc ( void* p, char c)
|
||||
{
|
||||
while (!SERIAL_PORT_EMPTY) ;
|
||||
SERIAL_PORT_TX_REGISTER = c;
|
||||
}
|
||||
|
||||
Before you can call printf you need to initialize it to use your
|
||||
character output function with something like:
|
||||
|
||||
init_printf(NULL,putc);
|
||||
|
||||
Notice the 'NULL' in 'init_printf' and the parameter 'void* p' in 'putc',
|
||||
the NULL (or any pointer) you pass into the 'init_printf' will eventually be
|
||||
passed to your 'putc' routine. This allows you to pass some storage space (or
|
||||
anything realy) to the character output function, if necessary.
|
||||
This is not often needed but it was implemented like that because it made
|
||||
implementing the sprintf function so neat (look at the source code).
|
||||
|
||||
The code is re-entrant, except for the 'init_printf' function, so it
|
||||
is safe to call it from interupts too, although this may result in mixed output.
|
||||
If you rely on re-entrancy, take care that your 'putc' function is re-entrant!
|
||||
|
||||
The printf and sprintf functions are actually macros that translate to
|
||||
'tfp_printf' and 'tfp_sprintf'. This makes it possible
|
||||
to use them along with 'stdio.h' printf's in a single source file.
|
||||
You just need to undef the names before you include the 'stdio.h'.
|
||||
Note that these are not function like macros, so if you have variables
|
||||
or struct members with these names, things will explode in your face.
|
||||
Without variadic macros this is the best we can do to wrap these
|
||||
fucnction. If it is a problem just give up the macros and use the
|
||||
functions directly or rename them.
|
||||
|
||||
For further details see source code.
|
||||
|
||||
regs Kusti, 23.10.2004
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __TFP_PRINTF__
|
||||
#define __TFP_PRINTF__
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
void init_printf(void* putp,void (*putf) (void*,char));
|
||||
|
||||
void tfp_printf(char *fmt, ...);
|
||||
void tfp_sprintf(char* s,char *fmt, ...);
|
||||
|
||||
void tfp_format(void* putp,void (*putf) (void*,char),char *fmt, va_list va);
|
||||
|
||||
#define printf tfp_printf
|
||||
#define sprintf tfp_sprintf
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
#ifndef _RGB_H_
|
||||
#define _RGB_H_
|
||||
|
||||
void rgb_init(void);
|
||||
void rgb_mode_idle(void);
|
||||
void rgb_mode_done(void);
|
||||
void rgb_mode_writing(void);
|
||||
void rgb_mode_error(void);
|
||||
|
||||
#ifndef _RGB_H_
|
||||
#define _RGB_H_
|
||||
|
||||
void rgb_init(void);
|
||||
void rgb_mode_idle(void);
|
||||
void rgb_mode_done(void);
|
||||
void rgb_mode_writing(void);
|
||||
void rgb_mode_error(void);
|
||||
|
||||
#endif /* _RGB_H_ */
|
@ -1,30 +1,30 @@
|
||||
#ifndef __USB_H
|
||||
#define __USB_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct usb_setup_request;
|
||||
|
||||
void usb_isr(void);
|
||||
void usb_init(void);
|
||||
void usb_connect(void);
|
||||
void usb_disconnect(void);
|
||||
|
||||
int usb_irq_happened(void);
|
||||
void usb_setup(const struct usb_setup_request *setup);
|
||||
int usb_send(const void *data, int total_count);
|
||||
void usb_ack_in(void);
|
||||
void usb_ack_out(void);
|
||||
void usb_err(void);
|
||||
int usb_recv(void *buffer, unsigned int buffer_len);
|
||||
void usb_poll(void);
|
||||
int usb_wait_for_send_done(void);
|
||||
void usb_recv_done(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef __USB_H
|
||||
#define __USB_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct usb_setup_request;
|
||||
|
||||
void usb_isr(void);
|
||||
void usb_init(void);
|
||||
void usb_connect(void);
|
||||
void usb_disconnect(void);
|
||||
|
||||
int usb_irq_happened(void);
|
||||
void usb_setup(const struct usb_setup_request *setup);
|
||||
int usb_send(const void *data, int total_count);
|
||||
void usb_ack_in(void);
|
||||
void usb_ack_out(void);
|
||||
void usb_err(void);
|
||||
int usb_recv(void *buffer, unsigned int buffer_len);
|
||||
void usb_poll(void);
|
||||
int usb_wait_for_send_done(void);
|
||||
void usb_recv_done(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
224
sw/src/rgb.c
224
sw/src/rgb.c
@ -1,113 +1,113 @@
|
||||
#include <rgb.h>
|
||||
#include <generated/csr.h>
|
||||
|
||||
enum led_registers {
|
||||
LEDDCR0 = 8,
|
||||
LEDDBR = 9,
|
||||
LEDDONR = 10,
|
||||
LEDDOFR = 11,
|
||||
LEDDBCRR = 5,
|
||||
LEDDBCFR = 6,
|
||||
LEDDPWRR = 1,
|
||||
LEDDPWRG = 2,
|
||||
LEDDPWRB = 3,
|
||||
};
|
||||
|
||||
#define BREATHE_ENABLE (1 << 7)
|
||||
#define BREATHE_EDGE_ON (0 << 6)
|
||||
#define BREATHE_EDGE_BOTH (1 << 6)
|
||||
#define BREATHE_MODE_MODULATE (1 << 5)
|
||||
#define BREATHE_RATE(x) ((x & 7) << 0)
|
||||
|
||||
#define RGB_SWITCH_MODE(x) do { \
|
||||
if (rgb_mode == x) \
|
||||
return; \
|
||||
rgb_mode = x; \
|
||||
/* Toggle LEDD_EXE to force the mode to switch */ \
|
||||
rgb_ctrl_write( (1 << 1) | (1 << 2)); \
|
||||
rgb_ctrl_write((1 << 0) | (1 << 1) | (1 << 2)); \
|
||||
} while(0)
|
||||
|
||||
static enum {
|
||||
INVALID = 0,
|
||||
IDLE,
|
||||
WRITING,
|
||||
ERROR,
|
||||
DONE,
|
||||
} rgb_mode;
|
||||
|
||||
static void rgb_write(uint8_t value, uint8_t addr) {
|
||||
rgb_addr_write(addr);
|
||||
rgb_dat_write(value);
|
||||
}
|
||||
|
||||
void rgb_init(void) {
|
||||
// Turn on the RGB block and current enable, as well as enabling led control
|
||||
rgb_ctrl_write((1 << 0) | (1 << 1) | (1 << 2));
|
||||
|
||||
// Enable the LED driver, and set 250 Hz mode.
|
||||
// Also set quick stop, which we'll use to switch patterns quickly.
|
||||
rgb_write((1 << 7) | (1 << 6) | (1 << 3), LEDDCR0);
|
||||
|
||||
// Set clock register to 12 MHz / 64 kHz - 1
|
||||
rgb_write((12000000/64000)-1, LEDDBR);
|
||||
|
||||
rgb_mode_idle();
|
||||
}
|
||||
|
||||
void rgb_mode_idle(void) {
|
||||
RGB_SWITCH_MODE(IDLE);
|
||||
// rgb_mode_writing(); return;
|
||||
rgb_write(12, LEDDONR);
|
||||
rgb_write(24, LEDDOFR);
|
||||
|
||||
rgb_write(BREATHE_ENABLE | BREATHE_EDGE_BOTH
|
||||
| BREATHE_MODE_MODULATE | BREATHE_RATE(2), LEDDBCRR);
|
||||
rgb_write(BREATHE_ENABLE | BREATHE_MODE_MODULATE | BREATHE_RATE(3), LEDDBCFR);
|
||||
|
||||
rgb_write(0x00/4, LEDDPWRG); // Red
|
||||
rgb_write(0x4a/4, LEDDPWRB); // Green
|
||||
rgb_write(0xe1/4, LEDDPWRR); // Blue
|
||||
}
|
||||
|
||||
void rgb_mode_writing(void) {
|
||||
RGB_SWITCH_MODE(WRITING);
|
||||
rgb_write(1, LEDDONR);
|
||||
rgb_write(2, LEDDOFR);
|
||||
|
||||
rgb_write(BREATHE_ENABLE | 0
|
||||
| BREATHE_MODE_MODULATE | BREATHE_RATE(1), LEDDBCRR);
|
||||
rgb_write(BREATHE_ENABLE | BREATHE_MODE_MODULATE | BREATHE_RATE(3), LEDDBCFR);
|
||||
|
||||
rgb_write(0x00/4, LEDDPWRG); // Red
|
||||
rgb_write(0x7a/4, LEDDPWRB); // Green
|
||||
rgb_write(0x51/4, LEDDPWRR); // Blue
|
||||
}
|
||||
|
||||
void rgb_mode_error(void) {
|
||||
RGB_SWITCH_MODE(ERROR);
|
||||
rgb_write(3, LEDDONR);
|
||||
rgb_write(3, LEDDOFR);
|
||||
|
||||
rgb_write(BREATHE_ENABLE | BREATHE_EDGE_BOTH
|
||||
| BREATHE_MODE_MODULATE | BREATHE_RATE(2), LEDDBCRR);
|
||||
rgb_write(BREATHE_ENABLE | BREATHE_MODE_MODULATE | BREATHE_RATE(3), LEDDBCFR);
|
||||
|
||||
rgb_write(0xf0/4, LEDDPWRG); // Red
|
||||
rgb_write(0x0a/4, LEDDPWRB); // Green
|
||||
rgb_write(0x01/4, LEDDPWRR); // Blue
|
||||
}
|
||||
|
||||
void rgb_mode_done(void) {
|
||||
RGB_SWITCH_MODE(DONE);
|
||||
rgb_write(8, LEDDONR);
|
||||
rgb_write(8, LEDDOFR);
|
||||
|
||||
rgb_write(BREATHE_ENABLE | BREATHE_EDGE_BOTH
|
||||
| BREATHE_MODE_MODULATE | BREATHE_RATE(2), LEDDBCRR);
|
||||
rgb_write(BREATHE_ENABLE | BREATHE_MODE_MODULATE | BREATHE_RATE(3), LEDDBCFR);
|
||||
|
||||
rgb_write(0x14/4, LEDDPWRG); // Red
|
||||
rgb_write(0xff/4, LEDDPWRB); // Green
|
||||
rgb_write(0x44/4, LEDDPWRR); // Blue
|
||||
#include <rgb.h>
|
||||
#include <generated/csr.h>
|
||||
|
||||
enum led_registers {
|
||||
LEDDCR0 = 8,
|
||||
LEDDBR = 9,
|
||||
LEDDONR = 10,
|
||||
LEDDOFR = 11,
|
||||
LEDDBCRR = 5,
|
||||
LEDDBCFR = 6,
|
||||
LEDDPWRR = 1,
|
||||
LEDDPWRG = 2,
|
||||
LEDDPWRB = 3,
|
||||
};
|
||||
|
||||
#define BREATHE_ENABLE (1 << 7)
|
||||
#define BREATHE_EDGE_ON (0 << 6)
|
||||
#define BREATHE_EDGE_BOTH (1 << 6)
|
||||
#define BREATHE_MODE_MODULATE (1 << 5)
|
||||
#define BREATHE_RATE(x) ((x & 7) << 0)
|
||||
|
||||
#define RGB_SWITCH_MODE(x) do { \
|
||||
if (rgb_mode == x) \
|
||||
return; \
|
||||
rgb_mode = x; \
|
||||
/* Toggle LEDD_EXE to force the mode to switch */ \
|
||||
rgb_ctrl_write( (1 << 1) | (1 << 2)); \
|
||||
rgb_ctrl_write((1 << 0) | (1 << 1) | (1 << 2)); \
|
||||
} while(0)
|
||||
|
||||
static enum {
|
||||
INVALID = 0,
|
||||
IDLE,
|
||||
WRITING,
|
||||
ERROR,
|
||||
DONE,
|
||||
} rgb_mode;
|
||||
|
||||
static void rgb_write(uint8_t value, uint8_t addr) {
|
||||
rgb_addr_write(addr);
|
||||
rgb_dat_write(value);
|
||||
}
|
||||
|
||||
void rgb_init(void) {
|
||||
// Turn on the RGB block and current enable, as well as enabling led control
|
||||
rgb_ctrl_write((1 << 0) | (1 << 1) | (1 << 2));
|
||||
|
||||
// Enable the LED driver, and set 250 Hz mode.
|
||||
// Also set quick stop, which we'll use to switch patterns quickly.
|
||||
rgb_write((1 << 7) | (1 << 6) | (1 << 3), LEDDCR0);
|
||||
|
||||
// Set clock register to 12 MHz / 64 kHz - 1
|
||||
rgb_write((12000000/64000)-1, LEDDBR);
|
||||
|
||||
rgb_mode_idle();
|
||||
}
|
||||
|
||||
void rgb_mode_idle(void) {
|
||||
RGB_SWITCH_MODE(IDLE);
|
||||
// rgb_mode_writing(); return;
|
||||
rgb_write(12, LEDDONR);
|
||||
rgb_write(24, LEDDOFR);
|
||||
|
||||
rgb_write(BREATHE_ENABLE | BREATHE_EDGE_BOTH
|
||||
| BREATHE_MODE_MODULATE | BREATHE_RATE(2), LEDDBCRR);
|
||||
rgb_write(BREATHE_ENABLE | BREATHE_MODE_MODULATE | BREATHE_RATE(3), LEDDBCFR);
|
||||
|
||||
rgb_write(0x00/4, LEDDPWRG); // Red
|
||||
rgb_write(0x4a/4, LEDDPWRB); // Green
|
||||
rgb_write(0xe1/4, LEDDPWRR); // Blue
|
||||
}
|
||||
|
||||
void rgb_mode_writing(void) {
|
||||
RGB_SWITCH_MODE(WRITING);
|
||||
rgb_write(1, LEDDONR);
|
||||
rgb_write(2, LEDDOFR);
|
||||
|
||||
rgb_write(BREATHE_ENABLE | 0
|
||||
| BREATHE_MODE_MODULATE | BREATHE_RATE(1), LEDDBCRR);
|
||||
rgb_write(BREATHE_ENABLE | BREATHE_MODE_MODULATE | BREATHE_RATE(3), LEDDBCFR);
|
||||
|
||||
rgb_write(0x00/4, LEDDPWRG); // Red
|
||||
rgb_write(0x7a/4, LEDDPWRB); // Green
|
||||
rgb_write(0x51/4, LEDDPWRR); // Blue
|
||||
}
|
||||
|
||||
void rgb_mode_error(void) {
|
||||
RGB_SWITCH_MODE(ERROR);
|
||||
rgb_write(3, LEDDONR);
|
||||
rgb_write(3, LEDDOFR);
|
||||
|
||||
rgb_write(BREATHE_ENABLE | BREATHE_EDGE_BOTH
|
||||
| BREATHE_MODE_MODULATE | BREATHE_RATE(2), LEDDBCRR);
|
||||
rgb_write(BREATHE_ENABLE | BREATHE_MODE_MODULATE | BREATHE_RATE(3), LEDDBCFR);
|
||||
|
||||
rgb_write(0xf0/4, LEDDPWRG); // Red
|
||||
rgb_write(0x0a/4, LEDDPWRB); // Green
|
||||
rgb_write(0x01/4, LEDDPWRR); // Blue
|
||||
}
|
||||
|
||||
void rgb_mode_done(void) {
|
||||
RGB_SWITCH_MODE(DONE);
|
||||
rgb_write(8, LEDDONR);
|
||||
rgb_write(8, LEDDOFR);
|
||||
|
||||
rgb_write(BREATHE_ENABLE | BREATHE_EDGE_BOTH
|
||||
| BREATHE_MODE_MODULATE | BREATHE_RATE(2), LEDDBCRR);
|
||||
rgb_write(BREATHE_ENABLE | BREATHE_MODE_MODULATE | BREATHE_RATE(3), LEDDBCFR);
|
||||
|
||||
rgb_write(0x14/4, LEDDPWRG); // Red
|
||||
rgb_write(0xff/4, LEDDPWRB); // Green
|
||||
rgb_write(0x44/4, LEDDPWRR); // Blue
|
||||
}
|
558
sw/src/usb-dev.c
558
sw/src/usb-dev.c
@ -1,279 +1,279 @@
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <usb.h>
|
||||
#include <dfu.h>
|
||||
#include <system.h>
|
||||
#include <printf.h>
|
||||
|
||||
#include <usb-desc.h>
|
||||
|
||||
static uint8_t reply_buffer[8];
|
||||
static uint8_t usb_configuration = 0;
|
||||
#define USB_MAX_PACKET_SIZE 64
|
||||
static uint32_t rx_buffer[USB_MAX_PACKET_SIZE/4];
|
||||
uint16_t last_request_and_type;
|
||||
|
||||
void usb_setup(const struct usb_setup_request *setup)
|
||||
{
|
||||
const uint8_t *data = NULL;
|
||||
uint32_t datalen = 0;
|
||||
const usb_descriptor_list_t *list;
|
||||
last_request_and_type = setup->wRequestAndType;
|
||||
|
||||
switch (setup->wRequestAndType)
|
||||
{
|
||||
case 0x0500: // SET_ADDRESS
|
||||
case 0x0b01: // SET_INTERFACE
|
||||
dfu_clrstatus();
|
||||
break;
|
||||
|
||||
case 0x0900: // SET_CONFIGURATION
|
||||
usb_configuration = setup->wValue;
|
||||
break;
|
||||
|
||||
case 0x0880: // GET_CONFIGURATION
|
||||
reply_buffer[0] = usb_configuration;
|
||||
datalen = 1;
|
||||
data = reply_buffer;
|
||||
break;
|
||||
|
||||
case 0x0080: // GET_STATUS (device)
|
||||
reply_buffer[0] = 0;
|
||||
reply_buffer[1] = 0;
|
||||
datalen = 2;
|
||||
data = reply_buffer;
|
||||
break;
|
||||
|
||||
case 0x0082: // GET_STATUS (endpoint)
|
||||
if (setup->wIndex > 0)
|
||||
{
|
||||
usb_err();
|
||||
return;
|
||||
}
|
||||
reply_buffer[0] = 0;
|
||||
reply_buffer[1] = 0;
|
||||
|
||||
// XXX handle endpoint stall here
|
||||
// if (USB->DIEP0CTL & USB_DIEP_CTL_STALL)
|
||||
// reply_buffer[0] = 1;
|
||||
data = reply_buffer;
|
||||
datalen = 2;
|
||||
break;
|
||||
|
||||
case 0x0102: // CLEAR_FEATURE (endpoint)
|
||||
if (setup->wIndex > 0 || setup->wValue != 0)
|
||||
{
|
||||
// TODO: do we need to handle IN vs OUT here?
|
||||
usb_err();
|
||||
return;
|
||||
}
|
||||
// XXX: Should we clear the stall bit?
|
||||
// USB->DIEP0CTL &= ~USB_DIEP_CTL_STALL;
|
||||
// TODO: do we need to clear the data toggle here?
|
||||
break;
|
||||
|
||||
case 0x0302: // SET_FEATURE (endpoint)
|
||||
if (setup->wIndex > 0 || setup->wValue != 0)
|
||||
{
|
||||
// TODO: do we need to handle IN vs OUT here?
|
||||
usb_err();
|
||||
return;
|
||||
}
|
||||
// XXX: Should we set the stall bit?
|
||||
// USB->DIEP0CTL |= USB_DIEP_CTL_STALL;
|
||||
// TODO: do we need to clear the data toggle here?
|
||||
break;
|
||||
|
||||
case 0x0680: // GET_DESCRIPTOR
|
||||
case 0x0681:
|
||||
for (list = usb_descriptor_list; 1; list++)
|
||||
{
|
||||
if (list->addr == NULL)
|
||||
break;
|
||||
if (setup->wValue == list->wValue)
|
||||
{
|
||||
data = list->addr;
|
||||
if ((setup->wValue >> 8) == 3)
|
||||
{
|
||||
// for string descriptors, use the descriptor's
|
||||
// length field, allowing runtime configured
|
||||
// length.
|
||||
datalen = *(list->addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
datalen = list->length;
|
||||
}
|
||||
goto send;
|
||||
}
|
||||
}
|
||||
usb_err();
|
||||
return;
|
||||
/*
|
||||
case (MSFT_VENDOR_CODE << 8) | 0xC0: // Get Microsoft descriptor
|
||||
case (MSFT_VENDOR_CODE << 8) | 0xC1:
|
||||
if (setup->wIndex == 0x0004)
|
||||
{
|
||||
// Return WCID descriptor
|
||||
data = usb_microsoft_wcid;
|
||||
datalen = MSFT_WCID_LEN;
|
||||
break;
|
||||
}
|
||||
usb_err();
|
||||
return;
|
||||
|
||||
case (WEBUSB_VENDOR_CODE << 8) | 0xC0: // Get WebUSB descriptor
|
||||
if (setup->wIndex == 0x0002)
|
||||
{
|
||||
if (setup->wValue == 0x0001)
|
||||
{
|
||||
// Return landing page URL descriptor
|
||||
data = (uint8_t*)&landing_url_descriptor;
|
||||
datalen = LANDING_PAGE_DESCRIPTOR_SIZE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// printf("%s:%d couldn't find webusb descriptor (%d / %d)\n", __FILE__, __LINE__, setup->wIndex, setup->wValue);
|
||||
usb_err();
|
||||
return;
|
||||
*/
|
||||
case 0x0121: // DFU_DNLOAD
|
||||
if (setup->wIndex > 0)
|
||||
{
|
||||
usb_err();
|
||||
return;
|
||||
}
|
||||
// Data comes in the OUT phase. But if it's a zero-length request, handle it now.
|
||||
if (setup->wLength == 0)
|
||||
{
|
||||
if (!dfu_download(setup->wValue, 0, 0, 0, NULL))
|
||||
{
|
||||
usb_err();
|
||||
return;
|
||||
}
|
||||
usb_ack_in();
|
||||
return;
|
||||
}
|
||||
|
||||
// ACK the setup packet
|
||||
// usb_ack_out();
|
||||
|
||||
int bytes_remaining = setup->wLength;
|
||||
int ep0_rx_offset = 0;
|
||||
// Fill the buffer, or if there is enough space transfer the whole packet.
|
||||
unsigned int blockLength = setup->wLength;
|
||||
unsigned int blockNum = setup->wValue;
|
||||
|
||||
while (bytes_remaining > 0) {
|
||||
unsigned int i;
|
||||
unsigned int len = blockLength;
|
||||
if (len > sizeof(rx_buffer))
|
||||
len = sizeof(rx_buffer);
|
||||
for (i = 0; i < sizeof(rx_buffer)/4; i++)
|
||||
rx_buffer[i] = 0xffffffff;
|
||||
|
||||
// Receive DATA packets (which are automatically ACKed)
|
||||
len = usb_recv((void *)rx_buffer, len);
|
||||
|
||||
// Append the data to the download buffer.
|
||||
dfu_download(blockNum, blockLength, ep0_rx_offset, len, (void *)rx_buffer);
|
||||
|
||||
bytes_remaining -= len;
|
||||
ep0_rx_offset += len;
|
||||
}
|
||||
|
||||
// ACK the final IN packet.
|
||||
usb_ack_in();
|
||||
|
||||
return;
|
||||
|
||||
case 0x0021: // DFU_DETACH
|
||||
// Send the "ACK" packet and wait for it
|
||||
// to be received.
|
||||
usb_ack_in();
|
||||
usb_wait_for_send_done();
|
||||
reboot_to(0x20040000);
|
||||
|
||||
// Issue a reboot
|
||||
reboot_to_image(0);
|
||||
while (1)
|
||||
;
|
||||
return;
|
||||
|
||||
case 0x03a1: // DFU_GETSTATUS
|
||||
if (setup->wIndex > 0)
|
||||
{
|
||||
usb_err();
|
||||
return;
|
||||
}
|
||||
if (dfu_getstatus(reply_buffer))
|
||||
{
|
||||
data = reply_buffer;
|
||||
datalen = 6;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
usb_err();
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x0421: // DFU_CLRSTATUS
|
||||
if (setup->wIndex > 0)
|
||||
{
|
||||
usb_err();
|
||||
return;
|
||||
}
|
||||
if (dfu_clrstatus())
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
usb_err();
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x05a1: // DFU_GETSTATE
|
||||
if (setup->wIndex > 0)
|
||||
{
|
||||
usb_err();
|
||||
return;
|
||||
}
|
||||
reply_buffer[0] = dfu_getstate();
|
||||
data = reply_buffer;
|
||||
datalen = 1;
|
||||
break;
|
||||
|
||||
case 0x0621: // DFU_ABORT
|
||||
if (setup->wIndex > 0)
|
||||
{
|
||||
usb_err();
|
||||
return;
|
||||
}
|
||||
if (dfu_abort())
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
usb_err();
|
||||
return;
|
||||
}
|
||||
|
||||
default:
|
||||
usb_err();
|
||||
return;
|
||||
}
|
||||
|
||||
send:
|
||||
if (data && datalen) {
|
||||
if (datalen > setup->wLength)
|
||||
datalen = setup->wLength;
|
||||
usb_send(data, datalen);
|
||||
}
|
||||
else
|
||||
usb_ack_in();
|
||||
return;
|
||||
}
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <usb.h>
|
||||
#include <dfu.h>
|
||||
#include <system.h>
|
||||
#include <printf.h>
|
||||
|
||||
#include <usb-desc.h>
|
||||
|
||||
static uint8_t reply_buffer[8];
|
||||
static uint8_t usb_configuration = 0;
|
||||
#define USB_MAX_PACKET_SIZE 64
|
||||
static uint32_t rx_buffer[USB_MAX_PACKET_SIZE/4];
|
||||
uint16_t last_request_and_type;
|
||||
|
||||
void usb_setup(const struct usb_setup_request *setup)
|
||||
{
|
||||
const uint8_t *data = NULL;
|
||||
uint32_t datalen = 0;
|
||||
const usb_descriptor_list_t *list;
|
||||
last_request_and_type = setup->wRequestAndType;
|
||||
|
||||
switch (setup->wRequestAndType)
|
||||
{
|
||||
case 0x0500: // SET_ADDRESS
|
||||
case 0x0b01: // SET_INTERFACE
|
||||
dfu_clrstatus();
|
||||
break;
|
||||
|
||||
case 0x0900: // SET_CONFIGURATION
|
||||
usb_configuration = setup->wValue;
|
||||
break;
|
||||
|
||||
case 0x0880: // GET_CONFIGURATION
|
||||
reply_buffer[0] = usb_configuration;
|
||||
datalen = 1;
|
||||
data = reply_buffer;
|
||||
break;
|
||||
|
||||
case 0x0080: // GET_STATUS (device)
|
||||
reply_buffer[0] = 0;
|
||||
reply_buffer[1] = 0;
|
||||
datalen = 2;
|
||||
data = reply_buffer;
|
||||
break;
|
||||
|
||||
case 0x0082: // GET_STATUS (endpoint)
|
||||
if (setup->wIndex > 0)
|
||||
{
|
||||
usb_err();
|
||||
return;
|
||||
}
|
||||
reply_buffer[0] = 0;
|
||||
reply_buffer[1] = 0;
|
||||
|
||||
// XXX handle endpoint stall here
|
||||
// if (USB->DIEP0CTL & USB_DIEP_CTL_STALL)
|
||||
// reply_buffer[0] = 1;
|
||||
data = reply_buffer;
|
||||
datalen = 2;
|
||||
break;
|
||||
|
||||
case 0x0102: // CLEAR_FEATURE (endpoint)
|
||||
if (setup->wIndex > 0 || setup->wValue != 0)
|
||||
{
|
||||
// TODO: do we need to handle IN vs OUT here?
|
||||
usb_err();
|
||||
return;
|
||||
}
|
||||
// XXX: Should we clear the stall bit?
|
||||
// USB->DIEP0CTL &= ~USB_DIEP_CTL_STALL;
|
||||
// TODO: do we need to clear the data toggle here?
|
||||
break;
|
||||
|
||||
case 0x0302: // SET_FEATURE (endpoint)
|
||||
if (setup->wIndex > 0 || setup->wValue != 0)
|
||||
{
|
||||
// TODO: do we need to handle IN vs OUT here?
|
||||
usb_err();
|
||||
return;
|
||||
}
|
||||
// XXX: Should we set the stall bit?
|
||||
// USB->DIEP0CTL |= USB_DIEP_CTL_STALL;
|
||||
// TODO: do we need to clear the data toggle here?
|
||||
break;
|
||||
|
||||
case 0x0680: // GET_DESCRIPTOR
|
||||
case 0x0681:
|
||||
for (list = usb_descriptor_list; 1; list++)
|
||||
{
|
||||
if (list->addr == NULL)
|
||||
break;
|
||||
if (setup->wValue == list->wValue)
|
||||
{
|
||||
data = list->addr;
|
||||
if ((setup->wValue >> 8) == 3)
|
||||
{
|
||||
// for string descriptors, use the descriptor's
|
||||
// length field, allowing runtime configured
|
||||
// length.
|
||||
datalen = *(list->addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
datalen = list->length;
|
||||
}
|
||||
goto send;
|
||||
}
|
||||
}
|
||||
usb_err();
|
||||
return;
|
||||
/*
|
||||
case (MSFT_VENDOR_CODE << 8) | 0xC0: // Get Microsoft descriptor
|
||||
case (MSFT_VENDOR_CODE << 8) | 0xC1:
|
||||
if (setup->wIndex == 0x0004)
|
||||
{
|
||||
// Return WCID descriptor
|
||||
data = usb_microsoft_wcid;
|
||||
datalen = MSFT_WCID_LEN;
|
||||
break;
|
||||
}
|
||||
usb_err();
|
||||
return;
|
||||
|
||||
case (WEBUSB_VENDOR_CODE << 8) | 0xC0: // Get WebUSB descriptor
|
||||
if (setup->wIndex == 0x0002)
|
||||
{
|
||||
if (setup->wValue == 0x0001)
|
||||
{
|
||||
// Return landing page URL descriptor
|
||||
data = (uint8_t*)&landing_url_descriptor;
|
||||
datalen = LANDING_PAGE_DESCRIPTOR_SIZE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// printf("%s:%d couldn't find webusb descriptor (%d / %d)\n", __FILE__, __LINE__, setup->wIndex, setup->wValue);
|
||||
usb_err();
|
||||
return;
|
||||
*/
|
||||
case 0x0121: // DFU_DNLOAD
|
||||
if (setup->wIndex > 0)
|
||||
{
|
||||
usb_err();
|
||||
return;
|
||||
}
|
||||
// Data comes in the OUT phase. But if it's a zero-length request, handle it now.
|
||||
if (setup->wLength == 0)
|
||||
{
|
||||
if (!dfu_download(setup->wValue, 0, 0, 0, NULL))
|
||||
{
|
||||
usb_err();
|
||||
return;
|
||||
}
|
||||
usb_ack_in();
|
||||
return;
|
||||
}
|
||||
|
||||
// ACK the setup packet
|
||||
// usb_ack_out();
|
||||
|
||||
int bytes_remaining = setup->wLength;
|
||||
int ep0_rx_offset = 0;
|
||||
// Fill the buffer, or if there is enough space transfer the whole packet.
|
||||
unsigned int blockLength = setup->wLength;
|
||||
unsigned int blockNum = setup->wValue;
|
||||
|
||||
while (bytes_remaining > 0) {
|
||||
unsigned int i;
|
||||
unsigned int len = blockLength;
|
||||
if (len > sizeof(rx_buffer))
|
||||
len = sizeof(rx_buffer);
|
||||
for (i = 0; i < sizeof(rx_buffer)/4; i++)
|
||||
rx_buffer[i] = 0xffffffff;
|
||||
|
||||
// Receive DATA packets (which are automatically ACKed)
|
||||
len = usb_recv((void *)rx_buffer, len);
|
||||
|
||||
// Append the data to the download buffer.
|
||||
dfu_download(blockNum, blockLength, ep0_rx_offset, len, (void *)rx_buffer);
|
||||
|
||||
bytes_remaining -= len;
|
||||
ep0_rx_offset += len;
|
||||
}
|
||||
|
||||
// ACK the final IN packet.
|
||||
usb_ack_in();
|
||||
|
||||
return;
|
||||
|
||||
case 0x0021: // DFU_DETACH
|
||||
// Send the "ACK" packet and wait for it
|
||||
// to be received.
|
||||
usb_ack_in();
|
||||
usb_wait_for_send_done();
|
||||
reboot_to(0x20040000);
|
||||
|
||||
// Issue a reboot
|
||||
reboot_to_image(0);
|
||||
while (1)
|
||||
;
|
||||
return;
|
||||
|
||||
case 0x03a1: // DFU_GETSTATUS
|
||||
if (setup->wIndex > 0)
|
||||
{
|
||||
usb_err();
|
||||
return;
|
||||
}
|
||||
if (dfu_getstatus(reply_buffer))
|
||||
{
|
||||
data = reply_buffer;
|
||||
datalen = 6;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
usb_err();
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x0421: // DFU_CLRSTATUS
|
||||
if (setup->wIndex > 0)
|
||||
{
|
||||
usb_err();
|
||||
return;
|
||||
}
|
||||
if (dfu_clrstatus())
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
usb_err();
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x05a1: // DFU_GETSTATE
|
||||
if (setup->wIndex > 0)
|
||||
{
|
||||
usb_err();
|
||||
return;
|
||||
}
|
||||
reply_buffer[0] = dfu_getstate();
|
||||
data = reply_buffer;
|
||||
datalen = 1;
|
||||
break;
|
||||
|
||||
case 0x0621: // DFU_ABORT
|
||||
if (setup->wIndex > 0)
|
||||
{
|
||||
usb_err();
|
||||
return;
|
||||
}
|
||||
if (dfu_abort())
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
usb_err();
|
||||
return;
|
||||
}
|
||||
|
||||
default:
|
||||
usb_err();
|
||||
return;
|
||||
}
|
||||
|
||||
send:
|
||||
if (data && datalen) {
|
||||
if (datalen > setup->wLength)
|
||||
datalen = setup->wLength;
|
||||
usb_send(data, datalen);
|
||||
}
|
||||
else
|
||||
usb_ack_in();
|
||||
return;
|
||||
}
|
||||
|
@ -1,267 +1,267 @@
|
||||
#include <usb.h>
|
||||
#include <irq.h>
|
||||
#include <generated/csr.h>
|
||||
#include <string.h>
|
||||
#include <printf.h>
|
||||
#include <uart.h>
|
||||
#include <usb.h>
|
||||
|
||||
#ifdef CSR_USB_EP_0_OUT_EV_PENDING_ADDR
|
||||
|
||||
/* The state machine states of a control pipe */
|
||||
enum CONTROL_STATE
|
||||
{
|
||||
WAIT_SETUP,
|
||||
IN_SETUP,
|
||||
IN_DATA,
|
||||
OUT_DATA,
|
||||
LAST_IN_DATA,
|
||||
WAIT_STATUS_IN,
|
||||
WAIT_STATUS_OUT,
|
||||
STALLED,
|
||||
} control_state;
|
||||
|
||||
// Note that our PIDs are only bits 2 and 3 of the token,
|
||||
// since all other bits are effectively redundant at this point.
|
||||
enum USB_PID {
|
||||
USB_PID_OUT = 0,
|
||||
USB_PID_SOF = 1,
|
||||
USB_PID_IN = 2,
|
||||
USB_PID_SETUP = 3,
|
||||
};
|
||||
|
||||
enum epfifo_response {
|
||||
EPF_ACK = 0,
|
||||
EPF_NAK = 1,
|
||||
EPF_NONE = 2,
|
||||
EPF_STALL = 3,
|
||||
};
|
||||
|
||||
#define USB_EV_ERROR 1
|
||||
#define USB_EV_PACKET 2
|
||||
|
||||
void usb_disconnect(void) {
|
||||
usb_ep_0_out_ev_enable_write(0);
|
||||
usb_ep_0_in_ev_enable_write(0);
|
||||
irq_setmask(irq_getmask() & ~(1 << USB_INTERRUPT));
|
||||
usb_pullup_out_write(0);
|
||||
}
|
||||
|
||||
void usb_connect(void) {
|
||||
|
||||
usb_ep_0_out_ev_pending_write(usb_ep_0_out_ev_enable_read());
|
||||
usb_ep_0_in_ev_pending_write(usb_ep_0_in_ev_pending_read());
|
||||
usb_ep_0_out_ev_enable_write(USB_EV_PACKET | USB_EV_ERROR);
|
||||
usb_ep_0_in_ev_enable_write(USB_EV_PACKET | USB_EV_ERROR);
|
||||
|
||||
// Accept incoming data by default.
|
||||
usb_ep_0_out_respond_write(EPF_ACK);
|
||||
|
||||
// Reject outgoing data, since we have none to give yet.
|
||||
usb_ep_0_in_respond_write(EPF_NAK);
|
||||
|
||||
usb_pullup_out_write(1);
|
||||
|
||||
irq_setmask(irq_getmask() | (1 << USB_INTERRUPT));
|
||||
}
|
||||
|
||||
void usb_init(void) {
|
||||
usb_pullup_out_write(0);
|
||||
return;
|
||||
}
|
||||
|
||||
#define EP0OUT_BUFFERS 4
|
||||
__attribute__((aligned(4)))
|
||||
static uint8_t volatile usb_ep0out_buffer[EP0OUT_BUFFERS][256];
|
||||
static uint8_t volatile usb_ep0out_buffer_len[EP0OUT_BUFFERS];
|
||||
static uint8_t volatile usb_ep0out_last_tok[EP0OUT_BUFFERS];
|
||||
static volatile uint8_t usb_ep0out_wr_ptr;
|
||||
static volatile uint8_t usb_ep0out_rd_ptr;
|
||||
static const int max_byte_length = 64;
|
||||
|
||||
static const uint8_t * volatile current_data;
|
||||
static volatile int current_length;
|
||||
static volatile int data_offset;
|
||||
static volatile int data_to_send;
|
||||
static int next_packet_is_empty;
|
||||
|
||||
static void process_tx(void) {
|
||||
|
||||
// Don't allow requeueing -- only queue more data if we're
|
||||
// currently set up to respond NAK.
|
||||
if (usb_ep_0_in_respond_read() != EPF_NAK) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Prevent us from double-filling the buffer.
|
||||
if (!usb_ep_0_in_ibuf_empty_read()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!current_data || !current_length) {
|
||||
return;
|
||||
}
|
||||
|
||||
data_offset += data_to_send;
|
||||
|
||||
data_to_send = current_length - data_offset;
|
||||
|
||||
// Clamp the data to the maximum packet length
|
||||
if (data_to_send > max_byte_length) {
|
||||
data_to_send = max_byte_length;
|
||||
next_packet_is_empty = 0;
|
||||
}
|
||||
else if (data_to_send == max_byte_length) {
|
||||
next_packet_is_empty = 1;
|
||||
}
|
||||
else if (next_packet_is_empty) {
|
||||
next_packet_is_empty = 0;
|
||||
data_to_send = 0;
|
||||
}
|
||||
else if (current_data == NULL || data_to_send <= 0) {
|
||||
next_packet_is_empty = 0;
|
||||
current_data = NULL;
|
||||
current_length = 0;
|
||||
data_offset = 0;
|
||||
data_to_send = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
int this_offset;
|
||||
for (this_offset = data_offset; this_offset < (data_offset + data_to_send); this_offset++) {
|
||||
usb_ep_0_in_ibuf_head_write(current_data[this_offset]);
|
||||
}
|
||||
usb_ep_0_in_respond_write(EPF_ACK);
|
||||
return;
|
||||
}
|
||||
|
||||
int usb_send(const void *data, int total_count) {
|
||||
|
||||
while ((current_length || current_data))// && usb_ep_0_in_respond_read() != EPF_NAK)
|
||||
;
|
||||
current_data = (uint8_t *)data;
|
||||
current_length = total_count;
|
||||
data_offset = 0;
|
||||
data_to_send = 0;
|
||||
control_state = IN_DATA;
|
||||
process_tx();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_wait_for_send_done(void) {
|
||||
while (current_data && current_length)
|
||||
usb_poll();
|
||||
while ((usb_ep_0_in_dtb_read() & 1) == 1)
|
||||
usb_poll();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void usb_isr(void) {
|
||||
uint8_t ep0o_pending = usb_ep_0_out_ev_pending_read();
|
||||
|
||||
// We got an OUT or a SETUP packet. Copy it to usb_ep0out_buffer
|
||||
// and clear the "pending" bit.
|
||||
if (ep0o_pending) {
|
||||
uint8_t last_tok = usb_ep_0_out_last_tok_read();
|
||||
|
||||
int byte_count = 0;
|
||||
usb_ep0out_last_tok[usb_ep0out_wr_ptr] = last_tok;
|
||||
volatile uint8_t * obuf = usb_ep0out_buffer[usb_ep0out_wr_ptr];
|
||||
while (!usb_ep_0_out_obuf_empty_read()) {
|
||||
obuf[byte_count++] = usb_ep_0_out_obuf_head_read();
|
||||
usb_ep_0_out_obuf_head_write(0);
|
||||
}
|
||||
usb_ep0out_buffer_len[usb_ep0out_wr_ptr] = byte_count - 2 /* Strip off CRC16 */;
|
||||
usb_ep0out_wr_ptr = (usb_ep0out_wr_ptr + 1) & (EP0OUT_BUFFERS-1);
|
||||
|
||||
if (last_tok == USB_PID_SETUP) {
|
||||
// usb_ep_0_out_dtb_write(1);
|
||||
usb_ep_0_in_dtb_write(1);
|
||||
data_offset = 0;
|
||||
current_length = 0;
|
||||
current_data = NULL;
|
||||
control_state = IN_SETUP;
|
||||
}
|
||||
usb_ep_0_out_ev_pending_write(ep0o_pending);
|
||||
usb_ep_0_out_respond_write(EPF_ACK);
|
||||
}
|
||||
|
||||
uint8_t ep0i_pending = usb_ep_0_in_ev_pending_read();
|
||||
// We just got an "IN" token. Send data if we have it.
|
||||
if (ep0i_pending) {
|
||||
usb_ep_0_in_respond_write(EPF_NAK);
|
||||
// current_offset += current_to_send;
|
||||
// process_tx();
|
||||
usb_ep_0_in_ev_pending_write(ep0i_pending);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void usb_ack_in(void) {
|
||||
// usb_ep_0_in_dtb_write(1);
|
||||
while (usb_ep_0_in_respond_read() == EPF_ACK)
|
||||
;
|
||||
usb_ep_0_in_respond_write(EPF_ACK);
|
||||
}
|
||||
|
||||
void usb_ack_out(void) {
|
||||
// usb_ep_0_out_dtb_write(1);
|
||||
while (usb_ep_0_out_respond_read() == EPF_ACK)
|
||||
;
|
||||
usb_ep_0_out_respond_write(EPF_ACK);
|
||||
}
|
||||
|
||||
void usb_err(void) {
|
||||
usb_ep_0_out_respond_write(EPF_STALL);
|
||||
usb_ep_0_in_respond_write(EPF_STALL);
|
||||
}
|
||||
|
||||
int usb_recv(void *buffer, unsigned int buffer_len) {
|
||||
|
||||
// Set the OUT response to ACK, since we are in a position to receive data now.
|
||||
usb_ep_0_out_respond_write(EPF_ACK);
|
||||
while (1) {
|
||||
if (usb_ep0out_rd_ptr != usb_ep0out_wr_ptr) {
|
||||
if (usb_ep0out_last_tok[usb_ep0out_rd_ptr] == USB_PID_OUT) {
|
||||
unsigned int ep0_buffer_len = usb_ep0out_buffer_len[usb_ep0out_rd_ptr];
|
||||
if (ep0_buffer_len < buffer_len)
|
||||
buffer_len = ep0_buffer_len;
|
||||
usb_ep0out_buffer_len[usb_ep0out_rd_ptr] = 0;
|
||||
memcpy(buffer, (void *)&usb_ep0out_buffer[usb_ep0out_rd_ptr], buffer_len);
|
||||
usb_ep0out_rd_ptr = (usb_ep0out_rd_ptr + 1) & (EP0OUT_BUFFERS-1);
|
||||
return buffer_len;
|
||||
}
|
||||
usb_ep0out_rd_ptr = (usb_ep0out_rd_ptr + 1) & (EP0OUT_BUFFERS-1);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// void usb_recv_done(void) {
|
||||
// usb_ep_0_in_respond_write(EPF_NAK);
|
||||
// }
|
||||
|
||||
void usb_poll(void) {
|
||||
// If some data was received, then process it.
|
||||
while (usb_ep0out_rd_ptr != usb_ep0out_wr_ptr) {
|
||||
const struct usb_setup_request *request = (const struct usb_setup_request *)(usb_ep0out_buffer[usb_ep0out_rd_ptr]);
|
||||
// unsigned int len = usb_ep0out_buffer_len[usb_ep0out_rd_ptr];
|
||||
uint8_t last_tok = usb_ep0out_last_tok[usb_ep0out_rd_ptr];
|
||||
|
||||
usb_ep0out_buffer_len[usb_ep0out_rd_ptr] = 0;
|
||||
usb_ep0out_rd_ptr = (usb_ep0out_rd_ptr + 1) & (EP0OUT_BUFFERS-1);
|
||||
|
||||
if (last_tok == USB_PID_SETUP) {
|
||||
usb_setup(request);
|
||||
}
|
||||
}
|
||||
|
||||
// If there's more data to send, queue some more data.
|
||||
// if ((usb_ep_0_in_respond_read() == EPF_NAK) && (current_data)) {
|
||||
process_tx();
|
||||
// }
|
||||
}
|
||||
|
||||
#include <usb.h>
|
||||
#include <irq.h>
|
||||
#include <generated/csr.h>
|
||||
#include <string.h>
|
||||
#include <printf.h>
|
||||
#include <uart.h>
|
||||
#include <usb.h>
|
||||
|
||||
#ifdef CSR_USB_EP_0_OUT_EV_PENDING_ADDR
|
||||
|
||||
/* The state machine states of a control pipe */
|
||||
enum CONTROL_STATE
|
||||
{
|
||||
WAIT_SETUP,
|
||||
IN_SETUP,
|
||||
IN_DATA,
|
||||
OUT_DATA,
|
||||
LAST_IN_DATA,
|
||||
WAIT_STATUS_IN,
|
||||
WAIT_STATUS_OUT,
|
||||
STALLED,
|
||||
} control_state;
|
||||
|
||||
// Note that our PIDs are only bits 2 and 3 of the token,
|
||||
// since all other bits are effectively redundant at this point.
|
||||
enum USB_PID {
|
||||
USB_PID_OUT = 0,
|
||||
USB_PID_SOF = 1,
|
||||
USB_PID_IN = 2,
|
||||
USB_PID_SETUP = 3,
|
||||
};
|
||||
|
||||
enum epfifo_response {
|
||||
EPF_ACK = 0,
|
||||
EPF_NAK = 1,
|
||||
EPF_NONE = 2,
|
||||
EPF_STALL = 3,
|
||||
};
|
||||
|
||||
#define USB_EV_ERROR 1
|
||||
#define USB_EV_PACKET 2
|
||||
|
||||
void usb_disconnect(void) {
|
||||
usb_ep_0_out_ev_enable_write(0);
|
||||
usb_ep_0_in_ev_enable_write(0);
|
||||
irq_setmask(irq_getmask() & ~(1 << USB_INTERRUPT));
|
||||
usb_pullup_out_write(0);
|
||||
}
|
||||
|
||||
void usb_connect(void) {
|
||||
|
||||
usb_ep_0_out_ev_pending_write(usb_ep_0_out_ev_enable_read());
|
||||
usb_ep_0_in_ev_pending_write(usb_ep_0_in_ev_pending_read());
|
||||
usb_ep_0_out_ev_enable_write(USB_EV_PACKET | USB_EV_ERROR);
|
||||
usb_ep_0_in_ev_enable_write(USB_EV_PACKET | USB_EV_ERROR);
|
||||
|
||||
// Accept incoming data by default.
|
||||
usb_ep_0_out_respond_write(EPF_ACK);
|
||||
|
||||
// Reject outgoing data, since we have none to give yet.
|
||||
usb_ep_0_in_respond_write(EPF_NAK);
|
||||
|
||||
usb_pullup_out_write(1);
|
||||
|
||||
irq_setmask(irq_getmask() | (1 << USB_INTERRUPT));
|
||||
}
|
||||
|
||||
void usb_init(void) {
|
||||
usb_pullup_out_write(0);
|
||||
return;
|
||||
}
|
||||
|
||||
#define EP0OUT_BUFFERS 4
|
||||
__attribute__((aligned(4)))
|
||||
static uint8_t volatile usb_ep0out_buffer[EP0OUT_BUFFERS][256];
|
||||
static uint8_t volatile usb_ep0out_buffer_len[EP0OUT_BUFFERS];
|
||||
static uint8_t volatile usb_ep0out_last_tok[EP0OUT_BUFFERS];
|
||||
static volatile uint8_t usb_ep0out_wr_ptr;
|
||||
static volatile uint8_t usb_ep0out_rd_ptr;
|
||||
static const int max_byte_length = 64;
|
||||
|
||||
static const uint8_t * volatile current_data;
|
||||
static volatile int current_length;
|
||||
static volatile int data_offset;
|
||||
static volatile int data_to_send;
|
||||
static int next_packet_is_empty;
|
||||
|
||||
static void process_tx(void) {
|
||||
|
||||
// Don't allow requeueing -- only queue more data if we're
|
||||
// currently set up to respond NAK.
|
||||
if (usb_ep_0_in_respond_read() != EPF_NAK) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Prevent us from double-filling the buffer.
|
||||
if (!usb_ep_0_in_ibuf_empty_read()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!current_data || !current_length) {
|
||||
return;
|
||||
}
|
||||
|
||||
data_offset += data_to_send;
|
||||
|
||||
data_to_send = current_length - data_offset;
|
||||
|
||||
// Clamp the data to the maximum packet length
|
||||
if (data_to_send > max_byte_length) {
|
||||
data_to_send = max_byte_length;
|
||||
next_packet_is_empty = 0;
|
||||
}
|
||||
else if (data_to_send == max_byte_length) {
|
||||
next_packet_is_empty = 1;
|
||||
}
|
||||
else if (next_packet_is_empty) {
|
||||
next_packet_is_empty = 0;
|
||||
data_to_send = 0;
|
||||
}
|
||||
else if (current_data == NULL || data_to_send <= 0) {
|
||||
next_packet_is_empty = 0;
|
||||
current_data = NULL;
|
||||
current_length = 0;
|
||||
data_offset = 0;
|
||||
data_to_send = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
int this_offset;
|
||||
for (this_offset = data_offset; this_offset < (data_offset + data_to_send); this_offset++) {
|
||||
usb_ep_0_in_ibuf_head_write(current_data[this_offset]);
|
||||
}
|
||||
usb_ep_0_in_respond_write(EPF_ACK);
|
||||
return;
|
||||
}
|
||||
|
||||
int usb_send(const void *data, int total_count) {
|
||||
|
||||
while ((current_length || current_data))// && usb_ep_0_in_respond_read() != EPF_NAK)
|
||||
;
|
||||
current_data = (uint8_t *)data;
|
||||
current_length = total_count;
|
||||
data_offset = 0;
|
||||
data_to_send = 0;
|
||||
control_state = IN_DATA;
|
||||
process_tx();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_wait_for_send_done(void) {
|
||||
while (current_data && current_length)
|
||||
usb_poll();
|
||||
while ((usb_ep_0_in_dtb_read() & 1) == 1)
|
||||
usb_poll();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void usb_isr(void) {
|
||||
uint8_t ep0o_pending = usb_ep_0_out_ev_pending_read();
|
||||
|
||||
// We got an OUT or a SETUP packet. Copy it to usb_ep0out_buffer
|
||||
// and clear the "pending" bit.
|
||||
if (ep0o_pending) {
|
||||
uint8_t last_tok = usb_ep_0_out_last_tok_read();
|
||||
|
||||
int byte_count = 0;
|
||||
usb_ep0out_last_tok[usb_ep0out_wr_ptr] = last_tok;
|
||||
volatile uint8_t * obuf = usb_ep0out_buffer[usb_ep0out_wr_ptr];
|
||||
while (!usb_ep_0_out_obuf_empty_read()) {
|
||||
obuf[byte_count++] = usb_ep_0_out_obuf_head_read();
|
||||
usb_ep_0_out_obuf_head_write(0);
|
||||
}
|
||||
usb_ep0out_buffer_len[usb_ep0out_wr_ptr] = byte_count - 2 /* Strip off CRC16 */;
|
||||
usb_ep0out_wr_ptr = (usb_ep0out_wr_ptr + 1) & (EP0OUT_BUFFERS-1);
|
||||
|
||||
if (last_tok == USB_PID_SETUP) {
|
||||
// usb_ep_0_out_dtb_write(1);
|
||||
usb_ep_0_in_dtb_write(1);
|
||||
data_offset = 0;
|
||||
current_length = 0;
|
||||
current_data = NULL;
|
||||
control_state = IN_SETUP;
|
||||
}
|
||||
usb_ep_0_out_ev_pending_write(ep0o_pending);
|
||||
usb_ep_0_out_respond_write(EPF_ACK);
|
||||
}
|
||||
|
||||
uint8_t ep0i_pending = usb_ep_0_in_ev_pending_read();
|
||||
// We just got an "IN" token. Send data if we have it.
|
||||
if (ep0i_pending) {
|
||||
usb_ep_0_in_respond_write(EPF_NAK);
|
||||
// current_offset += current_to_send;
|
||||
// process_tx();
|
||||
usb_ep_0_in_ev_pending_write(ep0i_pending);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void usb_ack_in(void) {
|
||||
// usb_ep_0_in_dtb_write(1);
|
||||
while (usb_ep_0_in_respond_read() == EPF_ACK)
|
||||
;
|
||||
usb_ep_0_in_respond_write(EPF_ACK);
|
||||
}
|
||||
|
||||
void usb_ack_out(void) {
|
||||
// usb_ep_0_out_dtb_write(1);
|
||||
while (usb_ep_0_out_respond_read() == EPF_ACK)
|
||||
;
|
||||
usb_ep_0_out_respond_write(EPF_ACK);
|
||||
}
|
||||
|
||||
void usb_err(void) {
|
||||
usb_ep_0_out_respond_write(EPF_STALL);
|
||||
usb_ep_0_in_respond_write(EPF_STALL);
|
||||
}
|
||||
|
||||
int usb_recv(void *buffer, unsigned int buffer_len) {
|
||||
|
||||
// Set the OUT response to ACK, since we are in a position to receive data now.
|
||||
usb_ep_0_out_respond_write(EPF_ACK);
|
||||
while (1) {
|
||||
if (usb_ep0out_rd_ptr != usb_ep0out_wr_ptr) {
|
||||
if (usb_ep0out_last_tok[usb_ep0out_rd_ptr] == USB_PID_OUT) {
|
||||
unsigned int ep0_buffer_len = usb_ep0out_buffer_len[usb_ep0out_rd_ptr];
|
||||
if (ep0_buffer_len < buffer_len)
|
||||
buffer_len = ep0_buffer_len;
|
||||
usb_ep0out_buffer_len[usb_ep0out_rd_ptr] = 0;
|
||||
memcpy(buffer, (void *)&usb_ep0out_buffer[usb_ep0out_rd_ptr], buffer_len);
|
||||
usb_ep0out_rd_ptr = (usb_ep0out_rd_ptr + 1) & (EP0OUT_BUFFERS-1);
|
||||
return buffer_len;
|
||||
}
|
||||
usb_ep0out_rd_ptr = (usb_ep0out_rd_ptr + 1) & (EP0OUT_BUFFERS-1);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// void usb_recv_done(void) {
|
||||
// usb_ep_0_in_respond_write(EPF_NAK);
|
||||
// }
|
||||
|
||||
void usb_poll(void) {
|
||||
// If some data was received, then process it.
|
||||
while (usb_ep0out_rd_ptr != usb_ep0out_wr_ptr) {
|
||||
const struct usb_setup_request *request = (const struct usb_setup_request *)(usb_ep0out_buffer[usb_ep0out_rd_ptr]);
|
||||
// unsigned int len = usb_ep0out_buffer_len[usb_ep0out_rd_ptr];
|
||||
uint8_t last_tok = usb_ep0out_last_tok[usb_ep0out_rd_ptr];
|
||||
|
||||
usb_ep0out_buffer_len[usb_ep0out_rd_ptr] = 0;
|
||||
usb_ep0out_rd_ptr = (usb_ep0out_rd_ptr + 1) & (EP0OUT_BUFFERS-1);
|
||||
|
||||
if (last_tok == USB_PID_SETUP) {
|
||||
usb_setup(request);
|
||||
}
|
||||
}
|
||||
|
||||
// If there's more data to send, queue some more data.
|
||||
// if ((usb_ep_0_in_respond_read() == EPF_NAK) && (current_data)) {
|
||||
process_tx();
|
||||
// }
|
||||
}
|
||||
|
||||
#endif /* CSR_USB_EP_0_OUT_EV_PENDING_ADDR */
|
@ -1,225 +1,225 @@
|
||||
#include <usb.h>
|
||||
#include <irq.h>
|
||||
#include <generated/csr.h>
|
||||
#include <string.h>
|
||||
#include <printf.h>
|
||||
#include <uart.h>
|
||||
|
||||
#ifdef CSR_USB_OBUF_EMPTY_ADDR
|
||||
|
||||
static const uint8_t crc5Table4[] =
|
||||
{
|
||||
0x00, 0x0E, 0x1C, 0x12, 0x11, 0x1F, 0x0D, 0x03,
|
||||
0x0B, 0x05, 0x17, 0x19, 0x1A, 0x14, 0x06, 0x08};
|
||||
static const uint8_t crc5Table0[] =
|
||||
{
|
||||
0x00, 0x16, 0x05, 0x13, 0x0A, 0x1C, 0x0F, 0x19,
|
||||
0x14, 0x02, 0x11, 0x07, 0x1E, 0x08, 0x1B, 0x0D};
|
||||
//---------------
|
||||
static int crc5Check(const uint8_t *data)
|
||||
//---------------
|
||||
{
|
||||
uint8_t b = data[0] ^ 0x1F;
|
||||
uint8_t crc = crc5Table4[b & 0x0F] ^ crc5Table0[(b >> 4) & 0x0F];
|
||||
b = data[1] ^ crc;
|
||||
return (crc5Table4[b & 0x0F] ^ crc5Table0[(b >> 4) & 0x0F]) == 0x06;
|
||||
}
|
||||
// crc5Check
|
||||
|
||||
static int do_check(uint16_t pkt) {
|
||||
uint8_t data[2] = {
|
||||
pkt >> 8,
|
||||
pkt,
|
||||
};
|
||||
return crc5Check(data);
|
||||
}
|
||||
|
||||
#define INT_SIZE 32
|
||||
static unsigned CRC5(unsigned dwInput, int iBitcnt)
|
||||
{
|
||||
const uint32_t poly5 = (0x05 << (INT_SIZE-5));
|
||||
uint32_t crc5 = (0x1f << (INT_SIZE-5));
|
||||
uint32_t udata = (dwInput << (INT_SIZE-iBitcnt));
|
||||
|
||||
if ( (iBitcnt<1) || (iBitcnt>INT_SIZE) ) // Validate iBitcnt
|
||||
return 0xffffffff;
|
||||
|
||||
while (iBitcnt--)
|
||||
{
|
||||
if ( (udata ^ crc5) & (0x1<<(INT_SIZE-1)) ) // bit4 != bit4?
|
||||
{
|
||||
crc5 <<= 1;
|
||||
crc5 ^= poly5;
|
||||
}
|
||||
else
|
||||
crc5 <<= 1;
|
||||
|
||||
udata <<= 1;
|
||||
}
|
||||
|
||||
// Shift back into position
|
||||
crc5 >>= (INT_SIZE-5);
|
||||
|
||||
// Invert contents to generate crc field
|
||||
crc5 ^= 0x1f;
|
||||
|
||||
return crc5;
|
||||
} //CRC5()
|
||||
|
||||
static uint32_t reverse_sof(uint32_t data) {
|
||||
int i;
|
||||
uint32_t data_flipped = 0;
|
||||
for (i = 0; i < 11; i++)
|
||||
if (data & (1 << i))
|
||||
data_flipped |= 1 << (10 - i);
|
||||
|
||||
return data_flipped;
|
||||
}
|
||||
|
||||
static uint8_t reverse_byte(uint8_t data) {
|
||||
int i;
|
||||
uint8_t data_flipped = 0;
|
||||
for (i = 0; i < 8; i++)
|
||||
if (data & (1 << i))
|
||||
data_flipped |= 1 << (7 - i);
|
||||
|
||||
return data_flipped;
|
||||
}
|
||||
|
||||
static uint8_t reverse_crc5(uint8_t data) {
|
||||
int i;
|
||||
uint8_t data_flipped = 0;
|
||||
for (i = 0; i < 5; i++)
|
||||
if (data & (1 << i))
|
||||
data_flipped |= 1 << (4 - i);
|
||||
|
||||
return data_flipped;
|
||||
}
|
||||
|
||||
static uint16_t make_token(uint16_t data) {
|
||||
uint16_t val = 0;
|
||||
|
||||
data = reverse_sof(data);
|
||||
val = data << 5;
|
||||
val |= CRC5(data, 11);
|
||||
|
||||
return (reverse_byte(val >> 8) << 8) | reverse_byte(val);
|
||||
}
|
||||
|
||||
int do_crc5(uint8_t bfr[2]) {
|
||||
uint8_t pkt_flipped[2] = {
|
||||
reverse_byte(bfr[0]),
|
||||
reverse_byte(bfr[1]),
|
||||
};
|
||||
uint32_t data = (pkt_flipped[1] >> 5) | (pkt_flipped[0] << 3);
|
||||
uint32_t data_flipped;
|
||||
uint8_t crc;
|
||||
uint16_t pkt;
|
||||
((uint8_t *)&pkt)[0] = bfr[1];
|
||||
((uint8_t *)&pkt)[1] = bfr[0];
|
||||
uint8_t found_crc = (pkt >> 3) & 0x1f;
|
||||
|
||||
data_flipped = reverse_sof(data);
|
||||
|
||||
crc = CRC5(data, 11);
|
||||
crc = reverse_crc5(crc);
|
||||
|
||||
uint16_t reconstructed = make_token(data_flipped);
|
||||
uint16_t wire = (reverse_byte(pkt >> 8) << 8) | reverse_byte(pkt);
|
||||
|
||||
printf("Packet: 0x%04x FCRC: %02x Data: 0x%04x "
|
||||
"Flipped: 0x%04x CRC5: 0x%02x Pass? %d Reconstructed: 0x%04x Wire: %04x\n",
|
||||
pkt, found_crc, data, data_flipped, crc, do_check(pkt),
|
||||
reconstructed,
|
||||
wire
|
||||
);
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
static const char hex[] = "0123456789abcdef";
|
||||
|
||||
uint8_t usb_ep0out_wr_ptr;
|
||||
uint8_t usb_ep0out_rd_ptr;
|
||||
#define EP0OUT_BUFFERS 64
|
||||
__attribute__((aligned(4)))
|
||||
static uint8_t usb_ep0out_buffer[EP0OUT_BUFFERS][128];
|
||||
static uint8_t usb_ep0out_buffer_len[EP0OUT_BUFFERS];
|
||||
void usb_poll(void)
|
||||
{
|
||||
// usb_isr();
|
||||
// printf("Start byte_count: %d\n", usb_byte_count_read());
|
||||
while (usb_ep0out_rd_ptr != usb_ep0out_wr_ptr) {
|
||||
uint8_t *obuf = usb_ep0out_buffer[usb_ep0out_rd_ptr];
|
||||
uint8_t cnt = usb_ep0out_buffer_len[usb_ep0out_rd_ptr];
|
||||
unsigned int i;
|
||||
if (cnt) {
|
||||
for (i = 0; i < cnt; i++) {
|
||||
uart_write(' ');
|
||||
uart_write(hex[(obuf[i] >> 4) & 0xf]);
|
||||
uart_write(hex[obuf[i] & (0xf)]);
|
||||
}
|
||||
uart_write('\r');
|
||||
uart_write('\n');
|
||||
}
|
||||
if (obuf[0] == 0xa5) {
|
||||
do_crc5(obuf + 1);
|
||||
}
|
||||
usb_ep0out_rd_ptr = (usb_ep0out_rd_ptr + 1) & (EP0OUT_BUFFERS-1);
|
||||
}
|
||||
}
|
||||
|
||||
int irq_happened;
|
||||
|
||||
void usb_init(void) {
|
||||
return;
|
||||
}
|
||||
|
||||
int usb_send(struct usb_device *dev, int epnum, const void *data, int total_count) {
|
||||
unsigned int i;
|
||||
const uint8_t *data_bfr = data;
|
||||
while (!usb_ibuf_empty_read())
|
||||
printf(".");
|
||||
usb_arm_write(0);
|
||||
for (i = 0; i < total_count; i++) {
|
||||
printf("Writing %02x ", data_bfr[i]);
|
||||
usb_ibuf_head_write(data_bfr[i]);
|
||||
}
|
||||
usb_arm_write(1);
|
||||
}
|
||||
|
||||
void usb_isr(void) {
|
||||
uint8_t pending = usb_ev_pending_read();
|
||||
unsigned int byte_count = 0;
|
||||
|
||||
// printf("Start pending: %d byte_count: %d empty: %d\n", pending, usb_byte_count_read(), usb_obuf_empty_read());
|
||||
// Advance the obuf head, which will reset the obuf_empty bit
|
||||
if (pending & 1) {
|
||||
uint8_t *obuf = usb_ep0out_buffer[usb_ep0out_wr_ptr];
|
||||
while (!usb_obuf_empty_read() && (byte_count < sizeof(usb_ep0out_buffer[usb_ep0out_wr_ptr]))) {
|
||||
obuf[byte_count++] = usb_obuf_head_read();
|
||||
usb_obuf_head_write(0);
|
||||
}
|
||||
usb_ep0out_buffer_len[usb_ep0out_wr_ptr] = byte_count;
|
||||
usb_ep0out_wr_ptr = (usb_ep0out_wr_ptr + 1) & (EP0OUT_BUFFERS-1);
|
||||
usb_ev_pending_write(pending);
|
||||
}
|
||||
// printf("Start pending: %d byte_count: %d empty: %d bytes_read: %d\n", pending, usb_byte_count_read(), usb_obuf_empty_read(), byte_count);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void usb_connect(void) {
|
||||
usb_pullup_out_write(1);
|
||||
|
||||
usb_ev_pending_write(usb_ev_pending_read());
|
||||
usb_ev_enable_write(1);
|
||||
|
||||
irq_setmask(irq_getmask() | (1 << USB_INTERRUPT));
|
||||
}
|
||||
|
||||
int usb_irq_happened(void) {
|
||||
return irq_happened;
|
||||
}
|
||||
|
||||
#include <usb.h>
|
||||
#include <irq.h>
|
||||
#include <generated/csr.h>
|
||||
#include <string.h>
|
||||
#include <printf.h>
|
||||
#include <uart.h>
|
||||
|
||||
#ifdef CSR_USB_OBUF_EMPTY_ADDR
|
||||
|
||||
static const uint8_t crc5Table4[] =
|
||||
{
|
||||
0x00, 0x0E, 0x1C, 0x12, 0x11, 0x1F, 0x0D, 0x03,
|
||||
0x0B, 0x05, 0x17, 0x19, 0x1A, 0x14, 0x06, 0x08};
|
||||
static const uint8_t crc5Table0[] =
|
||||
{
|
||||
0x00, 0x16, 0x05, 0x13, 0x0A, 0x1C, 0x0F, 0x19,
|
||||
0x14, 0x02, 0x11, 0x07, 0x1E, 0x08, 0x1B, 0x0D};
|
||||
//---------------
|
||||
static int crc5Check(const uint8_t *data)
|
||||
//---------------
|
||||
{
|
||||
uint8_t b = data[0] ^ 0x1F;
|
||||
uint8_t crc = crc5Table4[b & 0x0F] ^ crc5Table0[(b >> 4) & 0x0F];
|
||||
b = data[1] ^ crc;
|
||||
return (crc5Table4[b & 0x0F] ^ crc5Table0[(b >> 4) & 0x0F]) == 0x06;
|
||||
}
|
||||
// crc5Check
|
||||
|
||||
static int do_check(uint16_t pkt) {
|
||||
uint8_t data[2] = {
|
||||
pkt >> 8,
|
||||
pkt,
|
||||
};
|
||||
return crc5Check(data);
|
||||
}
|
||||
|
||||
#define INT_SIZE 32
|
||||
static unsigned CRC5(unsigned dwInput, int iBitcnt)
|
||||
{
|
||||
const uint32_t poly5 = (0x05 << (INT_SIZE-5));
|
||||
uint32_t crc5 = (0x1f << (INT_SIZE-5));
|
||||
uint32_t udata = (dwInput << (INT_SIZE-iBitcnt));
|
||||
|
||||
if ( (iBitcnt<1) || (iBitcnt>INT_SIZE) ) // Validate iBitcnt
|
||||
return 0xffffffff;
|
||||
|
||||
while (iBitcnt--)
|
||||
{
|
||||
if ( (udata ^ crc5) & (0x1<<(INT_SIZE-1)) ) // bit4 != bit4?
|
||||
{
|
||||
crc5 <<= 1;
|
||||
crc5 ^= poly5;
|
||||
}
|
||||
else
|
||||
crc5 <<= 1;
|
||||
|
||||
udata <<= 1;
|
||||
}
|
||||
|
||||
// Shift back into position
|
||||
crc5 >>= (INT_SIZE-5);
|
||||
|
||||
// Invert contents to generate crc field
|
||||
crc5 ^= 0x1f;
|
||||
|
||||
return crc5;
|
||||
} //CRC5()
|
||||
|
||||
static uint32_t reverse_sof(uint32_t data) {
|
||||
int i;
|
||||
uint32_t data_flipped = 0;
|
||||
for (i = 0; i < 11; i++)
|
||||
if (data & (1 << i))
|
||||
data_flipped |= 1 << (10 - i);
|
||||
|
||||
return data_flipped;
|
||||
}
|
||||
|
||||
static uint8_t reverse_byte(uint8_t data) {
|
||||
int i;
|
||||
uint8_t data_flipped = 0;
|
||||
for (i = 0; i < 8; i++)
|
||||
if (data & (1 << i))
|
||||
data_flipped |= 1 << (7 - i);
|
||||
|
||||
return data_flipped;
|
||||
}
|
||||
|
||||
static uint8_t reverse_crc5(uint8_t data) {
|
||||
int i;
|
||||
uint8_t data_flipped = 0;
|
||||
for (i = 0; i < 5; i++)
|
||||
if (data & (1 << i))
|
||||
data_flipped |= 1 << (4 - i);
|
||||
|
||||
return data_flipped;
|
||||
}
|
||||
|
||||
static uint16_t make_token(uint16_t data) {
|
||||
uint16_t val = 0;
|
||||
|
||||
data = reverse_sof(data);
|
||||
val = data << 5;
|
||||
val |= CRC5(data, 11);
|
||||
|
||||
return (reverse_byte(val >> 8) << 8) | reverse_byte(val);
|
||||
}
|
||||
|
||||
int do_crc5(uint8_t bfr[2]) {
|
||||
uint8_t pkt_flipped[2] = {
|
||||
reverse_byte(bfr[0]),
|
||||
reverse_byte(bfr[1]),
|
||||
};
|
||||
uint32_t data = (pkt_flipped[1] >> 5) | (pkt_flipped[0] << 3);
|
||||
uint32_t data_flipped;
|
||||
uint8_t crc;
|
||||
uint16_t pkt;
|
||||
((uint8_t *)&pkt)[0] = bfr[1];
|
||||
((uint8_t *)&pkt)[1] = bfr[0];
|
||||
uint8_t found_crc = (pkt >> 3) & 0x1f;
|
||||
|
||||
data_flipped = reverse_sof(data);
|
||||
|
||||
crc = CRC5(data, 11);
|
||||
crc = reverse_crc5(crc);
|
||||
|
||||
uint16_t reconstructed = make_token(data_flipped);
|
||||
uint16_t wire = (reverse_byte(pkt >> 8) << 8) | reverse_byte(pkt);
|
||||
|
||||
printf("Packet: 0x%04x FCRC: %02x Data: 0x%04x "
|
||||
"Flipped: 0x%04x CRC5: 0x%02x Pass? %d Reconstructed: 0x%04x Wire: %04x\n",
|
||||
pkt, found_crc, data, data_flipped, crc, do_check(pkt),
|
||||
reconstructed,
|
||||
wire
|
||||
);
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
static const char hex[] = "0123456789abcdef";
|
||||
|
||||
uint8_t usb_ep0out_wr_ptr;
|
||||
uint8_t usb_ep0out_rd_ptr;
|
||||
#define EP0OUT_BUFFERS 64
|
||||
__attribute__((aligned(4)))
|
||||
static uint8_t usb_ep0out_buffer[EP0OUT_BUFFERS][128];
|
||||
static uint8_t usb_ep0out_buffer_len[EP0OUT_BUFFERS];
|
||||
void usb_poll(void)
|
||||
{
|
||||
// usb_isr();
|
||||
// printf("Start byte_count: %d\n", usb_byte_count_read());
|
||||
while (usb_ep0out_rd_ptr != usb_ep0out_wr_ptr) {
|
||||
uint8_t *obuf = usb_ep0out_buffer[usb_ep0out_rd_ptr];
|
||||
uint8_t cnt = usb_ep0out_buffer_len[usb_ep0out_rd_ptr];
|
||||
unsigned int i;
|
||||
if (cnt) {
|
||||
for (i = 0; i < cnt; i++) {
|
||||
uart_write(' ');
|
||||
uart_write(hex[(obuf[i] >> 4) & 0xf]);
|
||||
uart_write(hex[obuf[i] & (0xf)]);
|
||||
}
|
||||
uart_write('\r');
|
||||
uart_write('\n');
|
||||
}
|
||||
if (obuf[0] == 0xa5) {
|
||||
do_crc5(obuf + 1);
|
||||
}
|
||||
usb_ep0out_rd_ptr = (usb_ep0out_rd_ptr + 1) & (EP0OUT_BUFFERS-1);
|
||||
}
|
||||
}
|
||||
|
||||
int irq_happened;
|
||||
|
||||
void usb_init(void) {
|
||||
return;
|
||||
}
|
||||
|
||||
int usb_send(struct usb_device *dev, int epnum, const void *data, int total_count) {
|
||||
unsigned int i;
|
||||
const uint8_t *data_bfr = data;
|
||||
while (!usb_ibuf_empty_read())
|
||||
printf(".");
|
||||
usb_arm_write(0);
|
||||
for (i = 0; i < total_count; i++) {
|
||||
printf("Writing %02x ", data_bfr[i]);
|
||||
usb_ibuf_head_write(data_bfr[i]);
|
||||
}
|
||||
usb_arm_write(1);
|
||||
}
|
||||
|
||||
void usb_isr(void) {
|
||||
uint8_t pending = usb_ev_pending_read();
|
||||
unsigned int byte_count = 0;
|
||||
|
||||
// printf("Start pending: %d byte_count: %d empty: %d\n", pending, usb_byte_count_read(), usb_obuf_empty_read());
|
||||
// Advance the obuf head, which will reset the obuf_empty bit
|
||||
if (pending & 1) {
|
||||
uint8_t *obuf = usb_ep0out_buffer[usb_ep0out_wr_ptr];
|
||||
while (!usb_obuf_empty_read() && (byte_count < sizeof(usb_ep0out_buffer[usb_ep0out_wr_ptr]))) {
|
||||
obuf[byte_count++] = usb_obuf_head_read();
|
||||
usb_obuf_head_write(0);
|
||||
}
|
||||
usb_ep0out_buffer_len[usb_ep0out_wr_ptr] = byte_count;
|
||||
usb_ep0out_wr_ptr = (usb_ep0out_wr_ptr + 1) & (EP0OUT_BUFFERS-1);
|
||||
usb_ev_pending_write(pending);
|
||||
}
|
||||
// printf("Start pending: %d byte_count: %d empty: %d bytes_read: %d\n", pending, usb_byte_count_read(), usb_obuf_empty_read(), byte_count);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void usb_connect(void) {
|
||||
usb_pullup_out_write(1);
|
||||
|
||||
usb_ev_pending_write(usb_ev_pending_read());
|
||||
usb_ev_enable_write(1);
|
||||
|
||||
irq_setmask(irq_getmask() | (1 << USB_INTERRUPT));
|
||||
}
|
||||
|
||||
int usb_irq_happened(void) {
|
||||
return irq_happened;
|
||||
}
|
||||
|
||||
#endif /* CSR_USB_OBUF_EMPTY_ADDR */
|
Loading…
Reference in New Issue
Block a user