REKLAMA

RadKIT-V2.61.rar

Detektor promieniowania gamma oraz beta do projektu Radioactive@Home

https://obrazki.elektroda.pl/3771254900_1508259880_thumb.jpg Witam szanownych Kolegów Chcę zaprezentować modyfikację czujnika do projektu Radioactive@Home Oryginalny czujnik w wersji 2.61 stanowi monolityczne urządzenie uniemożliwiając jego zastosowanie na zewnątrz. Stąd powstał pomysł aby wykorzystując częściowo zmodyfikować oryginalny projekt i rozbić go na 2 części: Część 1 - okrojony oryginalny sterownik w wersji 2.61 - pozostał właściwie mikrokontroler, wyświetlacz, LED, przycisk sterowania podświetleniem wyświetlacza. - zdjęcie na początku postu. Część 2 - przetwornica 12V/400V, tuba Geigera, stopień formujący impuls dla mikrokontrolera. https://obrazki.elektroda.pl/4347175600_1508260032_thumb.jpg Zdecydowałem się na zastosowanie zasilania czujnika zewnętrznego dwoma napięciami - 5V i 12V z uwagi na wykorzystanie w tym projekcie tego co miałem w zapasach. Jedyny mosfet logic level miał za niskie napięcie pracy. Pozostałe mosfet'y wymagały wyższego napięcia otwarcia - stąd 12V Zachęcam wszystkich do odwiedzenie strony RADIOACTIVE@HOME gdzie można prawie że on line (niewielkie ok 30 min opóźnienie) śledzić poziom promieniowania nie tylko w Polsce :) W załącznikach oryginalny projekt kolegi Szopler'a zmodyfikowane schematy do wersji jaką wykonałem ja, wsad ten sam - zmiana sposobu formowania impulsu nie spowodowała konieczności zmiany softu. Zachęcam do wykonywania i podłączania czujek do projektu - w obliczu zagrożeń ze strony militarnej jak i cywilnej - lepiej wiedzieć wcześniej i ze źródła nie powiązanego z żadnym rządem :) Zdjęcia wykonane po montażu - na dowód że działa - moja czujka ma nr. 28211


Pobierz plik - link do postu
  • RadKIT-V2.61.rar
    • main.h
    • MJS_usart
      • usart.c
      • usart.h
    • FUSE BITS VALUES.txt
    • makefile_bootloader.txt
    • usbdrv
      • asmcommon.inc
      • usbdrvasm18-crc.inc
      • usbdrvasm.S
      • usbdrvasm15.inc
      • usbdrvasm16.inc
      • oddebug.h
      • usbdrv.h
      • usbdrvasm12.inc
      • usbdrv.c
      • usbdrvasm165.inc
      • usbdrvasm128.inc
      • usbdrvasm.asm
      • usbportability.h
      • oddebug.c
      • usbdrvasm20.inc
    • delay_nonblock.c
    • Radioactive_V2.61_FW1.0_OFFICIAL.hex
    • usbconfig.h
    • delay_noblock.h
    • Bootloader.hex
    • MJS_i2c_lcd
      • i2c_lcd_universal.h
      • i2c_lcd_universal.c
    • MJS_i2c
      • i2c_lib.c
      • i2c_lib.h
    • main.c


RadKIT-V2.61.rar > usart.h

/* Name: usart.h
* Project: Radioactive@Home KIT Firmware
* Author: Michal 'Szopler' Szoplik
* Creation Date: 04-2014
* License: GNU GPL v3
*/


#ifndef USART_H_
#define USART_H_

#define BAUDRATE 9600UL
#define __UBRR ( F_CPU + BAUDRATE * 8UL ) / (16UL * BAUDRATE) -1


void uart_init(uint16_t baud);
void uart_putc(char chr);
void uart_putstr(char *str);
void uart_putnum(int number, uint8_t base);

#endif /* USART_H_ */


RadKIT-V2.61.rar > FUSE BITS VALUES.txt

Low: 0xDF
High: 0xD4
Ext: 0xFC

Above with bootloader.
If you want not to use bootloader, just change Ext. Fuse to 0xFD


RadKIT-V2.61.rar > makefile_bootloader.txt

#----------------------------------------------------------------------------
# make all = Make software.
# make clean = Clean out built project files.
# make size = Display sizes of object files.
# make doc = Start doxygen to prepare documentation.
# make filename.s = Just compile filename.c into the assembler code only.
# make filename.i = Create a preprocessed source file.
# make program = Download the hex file to the device.
# make fuse = Download configuration bits to the device.
# make lock = Download lock bits to the device.
#----------------------------------------------------------------------------

# MCU name
MCU = ATMega88PA

# MCU frequency (without UL suffix)
F_CPU = 20000000

# Bootloader options
# m128, m1284p = 0x1FC00
# m32, m328 = 0x7E00
# m16, m168 = 0x3E00
# m8, m88 = 0x1E00
BLS_START = 0x1E00

# dla po³¹czeñ Bluetooth czas oczekiwania min 3 s
BOOT_WAIT = 1

BAUD_RATE = 19200

# MCU configuration fuse and lockbits (leave empty if not to be programmed or
# to be programmed according to .fuse and .lock sections in ELF file)
LFUSE =
HFUSE =
EFUSE =
LOCK =

# Target file name (without extension)
TARGET = Bootloader

# Optimization level (can be 0, 1, 2, 3 or s)
OPT = s

# List C source files here (C dependencies are automatically generated)
SRC = main.c

# List Assembler source files here (make them always end in a capital .S!)
ASRC =

# List any extra directories to look for include files here
EXTRAINCDIRS =

# Doxygen configuration file (leave empty if not available)
DOXYFILE =

# C Standard level (can be c89, gnu89, c99 or gnu99)
CSTANDARD = -std=gnu99

# Output format (can be srec, ihex or binary)
FORMAT = ihex

# Debugging format
DEBUG = dwarf-2

# Programming hardware
AVRDUDE_PROGRAMMER = usbasp
AVRDUDE_PORT = lpt1

# Object files directory (don't leave it empty, put . instead!)
OBJDIR = .

# Place -D or -U options here for all sources
COMDEFS = -DBLS_START=$(BLS_START)
COMDEFS += -DBOOT_WAIT=$(BOOT_WAIT)
COMDEFS += -DBAUD=$(BAUD_RATE)
COMDEFS += -DMCU=$(MCU)
COMDEFS += -DXTAL=$(F_CPU)

# Place -D or -U options here for C sources
CDEFS =

# Place -D or -U options here for ASM sources
ADEFS =


#---------------- Compiler Options C ----------------
# -g*: generate debugging information
# -O*: optimization level
# -f...: tuning, see GCC manual and avr-libc documentation
# -Wall...: warning level
# -Wa,...: tell GCC to pass this to the assembler.
# -adhlns...: create assembler listing
CFLAGS = -g$(DEBUG)
CFLAGS += -DF_CPU=$(F_CPU)UL
CFLAGS += $(COMDEFS)
CFLAGS += $(CDEFS)
CFLAGS += -O$(OPT)
CFLAGS += -fgnu89-inline
CFLAGS += -funsigned-char
CFLAGS += -funsigned-bitfields
CFLAGS += -fpack-struct
CFLAGS += -fshort-enums
CFLAGS += -fno-tree-scev-cprop
CFLAGS += -fno-inline-small-functions
CFLAGS += -fno-split-wide-types
CFLAGS += -ffreestanding
CFLAGS += -mno-interrupts
#CFLAGS += -mshort-calls
CFLAGS += -pedantic
CFLAGS += -Wextra
CFLAGS += -Wno-sign-compare
CFLAGS += -Wstrict-prototypes
CFLAGS += -Wundef
#CFLAGS += -Wunreachable-code
CFLAGS += -Wa,-adhlns=$( & lt; :%.c=$(OBJDIR)/%.lst)
CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS))
CFLAGS += $(CSTANDARD)


#---------------- Assembler Options ----------------
# -Wa,...: tell GCC to pass this to the assembler.
# -adhlns: create listing
# -gstabs: have the assembler create line number information; note that
# for use in COFF files, additional information about filenames
# and function names needs to be present in the assembler source
# files -- see avr-libc docs [FIXME: not yet described there]
# -listing-cont-lines: Sets the maximum number of continuation lines of hex
# dump that will be displayed for a given single line of source input.
ASFLAGS = -gstabs
ASFLAGS += -DF_CPU=$(F_CPU)
ASFLAGS += $(COMDEFS)
ASFLAGS += $(ADEFS)
ASFLAGS += -Wa,-adhlns=$( & lt; :%.S=$(OBJDIR)/%.lst)
ASFLAGS += -listing-cont-lines=100


#---------------- Library Options ----------------
# List any extra directories to look for libraries here.
# Each directory must be seperated by a space.
# Use forward slashes for directory separators.
# For a directory that has spaces, enclose it in quotes.
EXTRALIBDIRS =


#---------------- Linker Options ----------------
# -Wl,...: tell GCC to pass this to linker.
# -Map: create map file
# --cref: add cross reference to map file
LDFLAGS = -Wl,-Map=$(TARGET).map,--cref
#LDFLAGS += -Wl,--relax
LDFLAGS += -nostartfiles
LDFLAGS += -Wl,--section-start=.text=$(BLS_START)
LDFLAGS += $(patsubst %,-L%,$(EXTRALIBDIRS))
#LDFLAGS += -T linker_script.x


#---------------- Programming Options (avrdude) ----------------
AVRDUDE_FLAGS = -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER)


#============================================================================


# Define programs and commands.
SHELL = sh
CC = avr-gcc
OBJCOPY = avr-objcopy
OBJDUMP = avr-objdump
SIZE = avr-size
AR = avr-ar rcs
NM = avr-nm
AVRDUDE = avrdude
REMOVE = rm -f
REMOVEDIR = rm -rf
COPY = cp
WINSHELL = cmd
DOXYGEN = doxygen


# Define all object files.
OBJ = $(SRC:%.c=$(OBJDIR)/%.o) $(ASRC:%.S=$(OBJDIR)/%.o)

# Define all listing files.
LST = $(SRC:%.c=$(OBJDIR)/%.lst) $(ASRC:%.S=$(OBJDIR)/%.lst)


# Compiler flags to generate dependency files.
GENDEPFLAGS = -MMD -MP -MF .dep/$(@F).d


# Combine all necessary flags and optional flags.
# Add target processor to flags.
ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) $(GENDEPFLAGS)
ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS)


#============================================================================


# Default target.
all: begin sizebefore build sizeafter end

# Change the build target to build a HEX file or a library.
build: elf hex lss sym
#build: lib


burn: fuse program lock

elf: $(TARGET).elf
hex: $(TARGET).hex
lss: $(TARGET).lss
sym: $(TARGET).sym
LIBNAME=lib$(TARGET).a
lib: $(LIBNAME)


# Eye candy.
begin:
@echo
@echo -------- begin --------

end:
@echo -------- end --------
@echo


# Display size of file.
HEXSIZE = $(SIZE) --target=$(FORMAT) $(TARGET).hex
ELFSIZE = $(SIZE) --mcu=$(MCU) --format=avr $(TARGET).elf

sizebefore:
@if test -f $(TARGET).elf; then echo; echo Size before:; $(ELFSIZE); \
2 & gt; /dev/null; fi

sizeafter:
@if test -f $(TARGET).elf; then echo; echo Size after:; $(ELFSIZE); \
2 & gt; /dev/null; fi


# Program the device.
program: $(TARGET).hex
@echo
@echo Programming Flash memory:
$(AVRDUDE) $(AVRDUDE_FLAGS) -U flash:w:$(TARGET).hex


# Program fusebits.
fuse: $(TARGET).elf
@echo
ifdef LFUSE
@echo Programming low fusebits:
$(AVRDUDE) $(AVRDUDE_FLAGS) -U lfuse:w:$(LFUSE):m
else
@echo Creating load file for low fusebits:
-$(OBJCOPY) -j .fuse --change-section-lma .fuse=0 --no-change-warnings \
-i 3 -b 0 -O $(FORMAT) $ & lt; $(TARGET).lfuse || exit 0
@echo
@echo Programming low fusebits:
$(AVRDUDE) $(AVRDUDE_FLAGS) -U lfuse:w:$(TARGET).lfuse
endif
@echo
ifdef HFUSE
@echo Programming high fusebits:
$(AVRDUDE) $(AVRDUDE_FLAGS) -U hfuse:w:$(HFUSE):m
else
@echo Creating load file for high fusebits:
-$(OBJCOPY) -j .fuse --change-section-lma .fuse=0 --no-change-warnings \
-i 3 -b 1 -O $(FORMAT) $ & lt; $(TARGET).hfuse || exit 0
@echo
@echo Programming high fusebits:
$(AVRDUDE) $(AVRDUDE_FLAGS) -U hfuse:w:$(TARGET).hfuse
endif
@echo
ifdef EFUSE
@echo Programming extended fusebits:
$(AVRDUDE) $(AVRDUDE_FLAGS) -U efuse:w:$(EFUSE):m
else
@echo Creating load file for extended fusebits:
-$(OBJCOPY) -j .fuse --change-section-lma .fuse=0 --no-change-warnings \
-i 3 -b 2 -O $(FORMAT) $ & lt; $(TARGET).efuse || exit 0
@echo
@echo Programming extended fusebits:
$(AVRDUDE) $(AVRDUDE_FLAGS) -U efuse:w:$(TARGET).efuse
endif


# Program lockbits.
lock: $(TARGET).elf
@echo
ifdef LOCK
@echo Programming lockbits:
$(AVRDUDE) $(AVRDUDE_FLAGS) -U lock:w:$(LOCK):m
else
@echo Creating load file for lockbits:
-$(OBJCOPY) -j .lock --change-section-lma .lock=0 --no-change-warnings \
-O $(FORMAT) $ & lt; $(TARGET).lock || exit 0
@echo
@echo Programming lockbits:
$(AVRDUDE) $(AVRDUDE_FLAGS) -U lock:w:$(TARGET).lock
endif


# Generate documentation with Doxygen.
doc:
@if test -f $(DOXYFILE); echo; then $(DOXYGEN) $(DOXYFILE); fi


# Display sizes of the object files.
size: $(OBJ)
@echo
@echo Sizes of the object files " (Flash = .text + .data, RAM = .data + .bss) " :
$(SIZE) -B -d -t --common $(OBJ)


# Create final output file (.hex) from ELF output file.
%.hex: %.elf
@echo
@echo Creating load file for Flash: $@
$(OBJCOPY) -O $(FORMAT) -R .eeprom -R .fuse -R .lock $ & lt; $@

# Create extended listing file from ELF output file.
%.lss: %.elf
@echo
@echo Creating Extended Listing: $@
$(OBJDUMP) -h -S -z $ & lt; & gt; $@

# Create a symbol table from ELF output file.
%.sym: %.elf
@echo
@echo Creating Symbol Table: $@
$(NM) -n $ & lt; & gt; $@


# Create library from object files.
.SECONDARY : $(TARGET).a
.PRECIOUS : $(OBJ)
%.a: $(OBJ)
@echo
@echo Creating library: $@
$(AR) $@ $(OBJ)


# Link: create ELF output file from object files.
.SECONDARY : $(TARGET).elf
.PRECIOUS : $(OBJ)
%.elf: $(OBJ)
@echo
@echo Linking: $@
$(CC) $(ALL_CFLAGS) $^ --output $@ $(LDFLAGS)


# Compile: create object files from C source files.
$(OBJDIR)/%.o : %.c
@echo
@echo Compiling C: $ & lt;
$(CC) -c $(ALL_CFLAGS) $ & lt; -o $@


# Compile: create assembler files from C source files.
%.s : %.c
$(CC) -S $(ALL_CFLAGS) $ & lt; -o $@


# Assemble: create object files from assembler source files.
$(OBJDIR)/%.o : %.S
@echo
@echo Assembling: $ & lt;
$(CC) -c $(ALL_ASFLAGS) $ & lt; -o $@


# Create preprocessed source for use in sending a bug report.
%.i : %.c
$(CC) -E -mmcu=$(MCU) -I. $(CFLAGS) $ & lt; -o $@


# Target: clean project.
clean: begin clean_list end

clean_list :
@echo
@echo Cleaning project:
$(REMOVE) $(TARGET).hex
$(REMOVE) $(TARGET).lfuse
$(REMOVE) $(TARGET).hfuse
$(REMOVE) $(TARGET).efuse
$(REMOVE) $(TARGET).lock
$(REMOVE) $(TARGET).elf
$(REMOVE) $(TARGET).map
$(REMOVE) $(TARGET).sym
$(REMOVE) $(TARGET).lss
$(REMOVE) $(SRC:%.c=$(OBJDIR)/%.o)
$(REMOVE) $(SRC:%.c=$(OBJDIR)/%.lst)
$(REMOVE) $(ASRC:%.S=$(OBJDIR)/%.o)
$(REMOVE) $(ASRC:%.S=$(OBJDIR)/%.lst)
$(REMOVE) $(SRC:.c=.s)
$(REMOVE) $(SRC:.c=.d)
$(REMOVE) $(SRC:.c=.i)
$(REMOVEDIR) .dep


# Create object files directory
$(shell mkdir $(OBJDIR) 2 & gt; /dev/null)


# Include the dependency files.
-include $(shell mkdir .dep 2 & gt; /dev/null) $(wildcard .dep/*)


# Listing of phony targets.
.PHONY : all begin finish end sizebefore sizeafter \
build elf hex lss sym \
clean clean_list program fuse lock doc


RadKIT-V2.61.rar > main.h

/* Name: main.h
* Project: Radioactive@Home KIT Firmware
* Author: Michal 'Szopler' Szoplik
* Creation Date: 04-2014
* License: GNU GPL v3
*/

#ifndef MAIN_H_
#define MAIN_H_

#include & lt; avr/io.h & gt;
#include & lt; avr/wdt.h & gt;
#include & lt; avr/interrupt.h & gt;
#include & lt; avr/pgmspace.h & gt;
#include & lt; util/delay.h & gt;
//#include & lt; avr/eeprom.h & gt;

#include & lt; stdlib.h & gt;
#include & lt; stdio.h & gt;
#include & lt; string.h & gt;

#include " usbdrv/usbdrv.h "
#include " MJS_i2c_lcd/i2c_lcd_universal.h "
#include " MJS_i2c/i2c_lib.h "
#include " MJS_usart/usart.h "

#include " ./delay_noblock.h "


/* Macros */
#define sbi(byte,bit) byte|=(1 & lt; & lt; bit)
#define cbi(byte,bit) byte & =~(1 & lt; & lt; bit)
#define bit(byte,n) (byte & gt; & gt; n) & 1

#define _Set 1
#define _Rst 0

#define _On 1
#define _Off 0

#define buz_port PORTD
#define buz_pin PD7
#define led_port PORTD
#define led_pin PD6


#endif /* MAIN_H_ */


RadKIT-V2.61.rar > oddebug.h

/* Name: oddebug.h
* Project: AVR library
* Author: Christian Starkjohann
* Creation Date: 2005-01-16
* Tabsize: 4
* Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH
* License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
* This Revision: $Id: oddebug.h 692 2008-11-07 15:07:40Z cs $
*/

#ifndef __oddebug_h_included__
#define __oddebug_h_included__

/*
General Description:
This module implements a function for debug logs on the serial line of the
AVR microcontroller. Debugging can be configured with the define
'DEBUG_LEVEL'. If this macro is not defined or defined to 0, all debugging
calls are no-ops. If it is 1, DBG1 logs will appear, but not DBG2. If it is
2, DBG1 and DBG2 logs will be printed.

A debug log consists of a label ('prefix') to indicate which debug log created
the output and a memory block to dump in hex ('data' and 'len').
*/


#ifndef F_CPU
#define F_CPU 20000000 /* 20 MHz */
#endif

/* make sure we have the UART defines: */
#include " usbportability.h "

#ifndef uchar
# define uchar unsigned char
#endif

#if DEBUG_LEVEL & gt; 0 & & !(defined TXEN || defined TXEN0) /* no UART in device */
# warning " Debugging disabled because device has no UART "
# undef DEBUG_LEVEL
#endif

#ifndef DEBUG_LEVEL
# define DEBUG_LEVEL 0
#endif

/* ------------------------------------------------------------------------- */

#if DEBUG_LEVEL & gt; 0
# define DBG1(prefix, data, len) odDebug(prefix, data, len)
#else
# define DBG1(prefix, data, len)
#endif

#if DEBUG_LEVEL & gt; 1
# define DBG2(prefix, data, len) odDebug(prefix, data, len)
#else
# define DBG2(prefix, data, len)
#endif

/* ------------------------------------------------------------------------- */

#if DEBUG_LEVEL & gt; 0
extern void odDebug(uchar prefix, uchar *data, uchar len);

/* Try to find our control registers; ATMEL likes to rename these */

#if defined UBRR
# define ODDBG_UBRR UBRR
#elif defined UBRRL
# define ODDBG_UBRR UBRRL
#elif defined UBRR0
# define ODDBG_UBRR UBRR0
#elif defined UBRR0L
# define ODDBG_UBRR UBRR0L
#endif

#if defined UCR
# define ODDBG_UCR UCR
#elif defined UCSRB
# define ODDBG_UCR UCSRB
#elif defined UCSR0B
# define ODDBG_UCR UCSR0B
#endif

#if defined TXEN
# define ODDBG_TXEN TXEN
#else
# define ODDBG_TXEN TXEN0
#endif

#if defined USR
# define ODDBG_USR USR
#elif defined UCSRA
# define ODDBG_USR UCSRA
#elif defined UCSR0A
# define ODDBG_USR UCSR0A
#endif

#if defined UDRE
# define ODDBG_UDRE UDRE
#else
# define ODDBG_UDRE UDRE0
#endif

#if defined UDR
# define ODDBG_UDR UDR
#elif defined UDR0
# define ODDBG_UDR UDR0
#endif

static inline void odDebugInit(void)
{
ODDBG_UCR |= (1 & lt; & lt; ODDBG_TXEN);
ODDBG_UBRR = F_CPU / (19200 * 16L) - 1;
}
#else
# define odDebugInit()
#endif

/* ------------------------------------------------------------------------- */

#endif /* __oddebug_h_included__ */


RadKIT-V2.61.rar > usbdrv.h

/* Name: usbdrv.h
* Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers
* Author: Christian Starkjohann
* Creation Date: 2004-12-29
* Tabsize: 4
* Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH
* License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
* This Revision: $Id: usbdrv.h 793 2010-07-15 15:58:11Z cs $
*/

#ifndef __usbdrv_h_included__
#define __usbdrv_h_included__
#include " ../usbconfig.h "
#include " usbportability.h "

/*
Hardware Prerequisites:
=======================
USB lines D+ and D- MUST be wired to the same I/O port.
We recommend that D+ triggers the interrupt (best achieved by using INT0 for D+),
but it is also possible to trigger the interrupt from D-.
If D- is used, interrupts are also triggered by SOF packets.
D- requires a pull-up of 1.5k to +3.5V (and the device must be powered at 3.5V)
to identify as low-speed USB device.
A pull-down or pull-up of 1M SHOULD be connected from D+ to +3.5V to prevent
interference when no USB master is connected. If you use Zener diodes to limit
the voltage on D+ and D-, you MUST use a pull-down resistor, not a pull-up.
We use D+ as interrupt source and not D- because it does not trigger on
keep-alive and RESET states. If you want to count keep-alive events with
USB_COUNT_SOF, you MUST use D- as an interrupt source.

As a compile time option, the 1.5k pull-up resistor on D- can be made
switchable to allow the device to disconnect at will. See the definition of
usbDeviceConnect() and usbDeviceDisconnect() further down in this file.

Please adapt the values in usbconfig.h according to your hardware!

The device MUST be clocked at exactly 12 MHz, 15 MHz, 16 MHz or 20 MHz
or at 12.8 MHz resp. 16.5 MHz +/- 1%. See usbconfig-prototype.h for details.


Limitations:
============
Robustness with respect to communication errors:
The driver assumes error-free communication. It DOES check for errors in
the PID, but does NOT check bit stuffing errors, SE0 in middle of a byte,
token CRC (5 bit) and data CRC (16 bit). CRC checks can not be performed due
to timing constraints: We must start sending a reply within 7 bit times.
Bit stuffing and misplaced SE0 would have to be checked in real-time, but CPU
performance does not permit that. The driver does not check Data0/Data1
toggling, but application software can implement the check.

Input characteristics:
Since no differential receiver circuit is used, electrical interference
robustness may suffer. The driver samples only one of the data lines with
an ordinary I/O pin's input characteristics. However, since this is only a
low speed USB implementation and the specification allows for 8 times the
bit rate over the same hardware, we should be on the safe side. Even the spec
requires detection of asymmetric states at high bit rate for SE0 detection.

Number of endpoints:
The driver supports the following endpoints:

- Endpoint 0, the default control endpoint.
- Any number of interrupt- or bulk-out endpoints. The data is sent to
usbFunctionWriteOut() and USB_CFG_IMPLEMENT_FN_WRITEOUT must be defined
to 1 to activate this feature. The endpoint number can be found in the
global variable 'usbRxToken'.
- One default interrupt- or bulk-in endpoint. This endpoint is used for
interrupt- or bulk-in transfers which are not handled by any other endpoint.
You must define USB_CFG_HAVE_INTRIN_ENDPOINT in order to activate this
feature and call usbSetInterrupt() to send interrupt/bulk data.
- One additional interrupt- or bulk-in endpoint. This was endpoint 3 in
previous versions of this driver but can now be configured to any endpoint
number. You must define USB_CFG_HAVE_INTRIN_ENDPOINT3 in order to activate
this feature and call usbSetInterrupt3() to send interrupt/bulk data. The
endpoint number can be set with USB_CFG_EP3_NUMBER.

Please note that the USB standard forbids bulk endpoints for low speed devices!
Most operating systems allow them anyway, but the AVR will spend 90% of the CPU
time in the USB interrupt polling for bulk data.

Maximum data payload:
Data payload of control in and out transfers may be up to 254 bytes. In order
to accept payload data of out transfers, you need to implement
'usbFunctionWrite()'.

USB Suspend Mode supply current:
The USB standard limits power consumption to 500uA when the bus is in suspend
mode. This is not a problem for self-powered devices since they don't need
bus power anyway. Bus-powered devices can achieve this only by putting the
CPU in sleep mode. The driver does not implement suspend handling by itself.
However, the application may implement activity monitoring and wakeup from
sleep. The host sends regular SE0 states on the bus to keep it active. These
SE0 states can be detected by using D- as the interrupt source. Define
USB_COUNT_SOF to 1 and use the global variable usbSofCount to check for bus
activity.

Operation without an USB master:
The driver behaves neutral without connection to an USB master if D- reads
as 1. To avoid spurious interrupts, we recommend a high impedance (e.g. 1M)
pull-down or pull-up resistor on D+ (interrupt). If Zener diodes are used,
use a pull-down. If D- becomes statically 0, the driver may block in the
interrupt routine.

Interrupt latency:
The application must ensure that the USB interrupt is not disabled for more
than 25 cycles (this is for 12 MHz, faster clocks allow longer latency).
This implies that all interrupt routines must either have the " ISR_NOBLOCK "
attribute set (see " avr/interrupt.h " ) or be written in assembler with " sei "
as the first instruction.

Maximum interrupt duration / CPU cycle consumption:
The driver handles all USB communication during the interrupt service
routine. The routine will not return before an entire USB message is received
and the reply is sent. This may be up to ca. 1200 cycles @ 12 MHz (= 100us) if
the host conforms to the standard. The driver will consume CPU cycles for all
USB messages, even if they address another (low-speed) device on the same bus.

*/

/* ------------------------------------------------------------------------- */
/* --------------------------- Module Interface ---------------------------- */
/* ------------------------------------------------------------------------- */

#define USBDRV_VERSION 20100715
/* This define uniquely identifies a driver version. It is a decimal number
* constructed from the driver's release date in the form YYYYMMDD. If the
* driver's behavior or interface changes, you can use this constant to
* distinguish versions. If it is not defined, the driver's release date is
* older than 2006-01-25.
*/


#ifndef USB_PUBLIC
#define USB_PUBLIC
#endif
/* USB_PUBLIC is used as declaration attribute for all functions exported by
* the USB driver. The default is no attribute (see above). You may define it
* to static either in usbconfig.h or from the command line if you include
* usbdrv.c instead of linking against it. Including the C module of the driver
* directly in your code saves a couple of bytes in flash memory.
*/

#ifndef __ASSEMBLER__
#ifndef uchar
#define uchar unsigned char
#endif
#ifndef schar
#define schar signed char
#endif
/* shortcuts for well defined 8 bit integer types */

#if USB_CFG_LONG_TRANSFERS /* if more than 254 bytes transfer size required */
# define usbMsgLen_t unsigned
#else
# define usbMsgLen_t uchar
#endif
/* usbMsgLen_t is the data type used for transfer lengths. By default, it is
* defined to uchar, allowing a maximum of 254 bytes (255 is reserved for
* USB_NO_MSG below). If the usbconfig.h defines USB_CFG_LONG_TRANSFERS to 1,
* a 16 bit data type is used, allowing up to 16384 bytes (the rest is used
* for flags in the descriptor configuration).
*/
#define USB_NO_MSG ((usbMsgLen_t)-1) /* constant meaning " no message " */

struct usbRequest; /* forward declaration */

USB_PUBLIC void usbInit(void);
/* This function must be called before interrupts are enabled and the main
* loop is entered. We exepct that the PORT and DDR bits for D+ and D- have
* not been changed from their default status (which is 0). If you have changed
* them, set both back to 0 (configure them as input with no internal pull-up).
*/
USB_PUBLIC void usbPoll(void);
/* This function must be called at regular intervals from the main loop.
* Maximum delay between calls is somewhat less than 50ms (USB timeout for
* accepting a Setup message). Otherwise the device will not be recognized.
* Please note that debug outputs through the UART take ~ 0.5ms per byte
* at 19200 bps.
*/
extern uchar *usbMsgPtr;
/* This variable may be used to pass transmit data to the driver from the
* implementation of usbFunctionWrite(). It is also used internally by the
* driver for standard control requests.
*/
USB_PUBLIC usbMsgLen_t usbFunctionSetup(uchar data[8]);
/* This function is called when the driver receives a SETUP transaction from
* the host which is not answered by the driver itself (in practice: class and
* vendor requests). All control transfers start with a SETUP transaction where
* the host communicates the parameters of the following (optional) data
* transfer. The SETUP data is available in the 'data' parameter which can
* (and should) be casted to 'usbRequest_t *' for a more user-friendly access
* to parameters.
*
* If the SETUP indicates a control-in transfer, you should provide the
* requested data to the driver. There are two ways to transfer this data:
* (1) Set the global pointer 'usbMsgPtr' to the base of the static RAM data
* block and return the length of the data in 'usbFunctionSetup()'. The driver
* will handle the rest. Or (2) return USB_NO_MSG in 'usbFunctionSetup()'. The
* driver will then call 'usbFunctionRead()' when data is needed. See the
* documentation for usbFunctionRead() for details.
*
* If the SETUP indicates a control-out transfer, the only way to receive the
* data from the host is through the 'usbFunctionWrite()' call. If you
* implement this function, you must return USB_NO_MSG in 'usbFunctionSetup()'
* to indicate that 'usbFunctionWrite()' should be used. See the documentation
* of this function for more information. If you just want to ignore the data
* sent by the host, return 0 in 'usbFunctionSetup()'.
*
* Note that calls to the functions usbFunctionRead() and usbFunctionWrite()
* are only done if enabled by the configuration in usbconfig.h.
*/
USB_PUBLIC usbMsgLen_t usbFunctionDescriptor(struct usbRequest *rq);
/* You need to implement this function ONLY if you provide USB descriptors at
* runtime (which is an expert feature). It is very similar to
* usbFunctionSetup() above, but it is called only to request USB descriptor
* data. See the documentation of usbFunctionSetup() above for more info.
*/
#if USB_CFG_HAVE_INTRIN_ENDPOINT
USB_PUBLIC void usbSetInterrupt(uchar *data, uchar len);
/* This function sets the message which will be sent during the next interrupt
* IN transfer. The message is copied to an internal buffer and must not exceed
* a length of 8 bytes. The message may be 0 bytes long just to indicate the
* interrupt status to the host.
* If you need to transfer more bytes, use a control read after the interrupt.
*/
#define usbInterruptIsReady() (usbTxLen1 & 0x10)
/* This macro indicates whether the last interrupt message has already been
* sent. If you set a new interrupt message before the old was sent, the
* message already buffered will be lost.
*/
#if USB_CFG_HAVE_INTRIN_ENDPOINT3
USB_PUBLIC void usbSetInterrupt3(uchar *data, uchar len);
#define usbInterruptIsReady3() (usbTxLen3 & 0x10)
/* Same as above for endpoint 3 */
#endif
#endif /* USB_CFG_HAVE_INTRIN_ENDPOINT */
#if USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH /* simplified interface for backward compatibility */
#define usbHidReportDescriptor usbDescriptorHidReport
/* should be declared as: PROGMEM char usbHidReportDescriptor[]; */
/* If you implement an HID device, you need to provide a report descriptor.
* The HID report descriptor syntax is a bit complex. If you understand how
* report descriptors are constructed, we recommend that you use the HID
* Descriptor Tool from usb.org, see http://www.usb.org/developers/hidpage/.
* Otherwise you should probably start with a working example.
*/
#endif /* USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH */
#if USB_CFG_IMPLEMENT_FN_WRITE
USB_PUBLIC uchar usbFunctionWrite(uchar *data, uchar len);
/* This function is called by the driver to provide a control transfer's
* payload data (control-out). It is called in chunks of up to 8 bytes. The
* total count provided in the current control transfer can be obtained from
* the 'length' property in the setup data. If an error occurred during
* processing, return 0xff (== -1). The driver will answer the entire transfer
* with a STALL token in this case. If you have received the entire payload
* successfully, return 1. If you expect more data, return 0. If you don't
* know whether the host will send more data (you should know, the total is
* provided in the usbFunctionSetup() call!), return 1.
* NOTE: If you return 0xff for STALL, 'usbFunctionWrite()' may still be called
* for the remaining data. You must continue to return 0xff for STALL in these
* calls.
* In order to get usbFunctionWrite() called, define USB_CFG_IMPLEMENT_FN_WRITE
* to 1 in usbconfig.h and return 0xff in usbFunctionSetup()..
*/
#endif /* USB_CFG_IMPLEMENT_FN_WRITE */
#if USB_CFG_IMPLEMENT_FN_READ
USB_PUBLIC uchar usbFunctionRead(uchar *data, uchar len);
/* This function is called by the driver to ask the application for a control
* transfer's payload data (control-in). It is called in chunks of up to 8
* bytes each. You should copy the data to the location given by 'data' and
* return the actual number of bytes copied. If you return less than requested,
* the control-in transfer is terminated. If you return 0xff, the driver aborts
* the transfer with a STALL token.
* In order to get usbFunctionRead() called, define USB_CFG_IMPLEMENT_FN_READ
* to 1 in usbconfig.h and return 0xff in usbFunctionSetup()..
*/
#endif /* USB_CFG_IMPLEMENT_FN_READ */

extern uchar usbRxToken; /* may be used in usbFunctionWriteOut() below */
#if USB_CFG_IMPLEMENT_FN_WRITEOUT
USB_PUBLIC void usbFunctionWriteOut(uchar *data, uchar len);
/* This function is called by the driver when data is received on an interrupt-
* or bulk-out endpoint. The endpoint number can be found in the global
* variable usbRxToken. You must define USB_CFG_IMPLEMENT_FN_WRITEOUT to 1 in
* usbconfig.h to get this function called.
*/
#endif /* USB_CFG_IMPLEMENT_FN_WRITEOUT */
#ifdef USB_CFG_PULLUP_IOPORTNAME
#define usbDeviceConnect() ((USB_PULLUP_DDR |= (1 & lt; & lt; USB_CFG_PULLUP_BIT)), \
(USB_PULLUP_OUT |= (1 & lt; & lt; USB_CFG_PULLUP_BIT)))
#define usbDeviceDisconnect() ((USB_PULLUP_DDR & = ~(1 & lt; & lt; USB_CFG_PULLUP_BIT)), \
(USB_PULLUP_OUT & = ~(1 & lt; & lt; USB_CFG_PULLUP_BIT)))
#else /* USB_CFG_PULLUP_IOPORTNAME */
#define usbDeviceConnect() (USBDDR & = ~(1 & lt; & lt; USBMINUS))
#define usbDeviceDisconnect() (USBDDR |= (1 & lt; & lt; USBMINUS))
#endif /* USB_CFG_PULLUP_IOPORTNAME */
/* The macros usbDeviceConnect() and usbDeviceDisconnect() (intended to look
* like a function) connect resp. disconnect the device from the host's USB.
* If the constants USB_CFG_PULLUP_IOPORT and USB_CFG_PULLUP_BIT are defined
* in usbconfig.h, a disconnect consists of removing the pull-up resisitor
* from D-, otherwise the disconnect is done by brute-force pulling D- to GND.
* This does not conform to the spec, but it works.
* Please note that the USB interrupt must be disabled while the device is
* in disconnected state, or the interrupt handler will hang! You can either
* turn off the USB interrupt selectively with
* USB_INTR_ENABLE & = ~(1 & lt; & lt; USB_INTR_ENABLE_BIT)
* or use cli() to disable interrupts globally.
*/
extern unsigned usbCrc16(unsigned data, uchar len);
#define usbCrc16(data, len) usbCrc16((unsigned)(data), len)
/* This function calculates the binary complement of the data CRC used in
* USB data packets. The value is used to build raw transmit packets.
* You may want to use this function for data checksums or to verify received
* data. We enforce 16 bit calling conventions for compatibility with IAR's
* tiny memory model.
*/
extern unsigned usbCrc16Append(unsigned data, uchar len);
#define usbCrc16Append(data, len) usbCrc16Append((unsigned)(data), len)
/* This function is equivalent to usbCrc16() above, except that it appends
* the 2 bytes CRC (lowbyte first) in the 'data' buffer after reading 'len'
* bytes.
*/
#if USB_CFG_HAVE_MEASURE_FRAME_LENGTH
extern unsigned usbMeasureFrameLength(void);
/* This function MUST be called IMMEDIATELY AFTER USB reset and measures 1/7 of
* the number of CPU cycles during one USB frame minus one low speed bit
* length. In other words: return value = 1499 * (F_CPU / 10.5 MHz)
* Since this is a busy wait, you MUST disable all interrupts with cli() before
* calling this function.
* This can be used to calibrate the AVR's RC oscillator.
*/
#endif
extern uchar usbConfiguration;
/* This value contains the current configuration set by the host. The driver
* allows setting and querying of this variable with the USB SET_CONFIGURATION
* and GET_CONFIGURATION requests, but does not use it otherwise.
* You may want to reflect the " configured " status with a LED on the device or
* switch on high power parts of the circuit only if the device is configured.
*/
#if USB_COUNT_SOF
extern volatile uchar usbSofCount;
/* This variable is incremented on every SOF packet. It is only available if
* the macro USB_COUNT_SOF is defined to a value != 0.
*/
#endif
#if USB_CFG_CHECK_DATA_TOGGLING
extern uchar usbCurrentDataToken;
/* This variable can be checked in usbFunctionWrite() and usbFunctionWriteOut()
* to ignore duplicate packets.
*/
#endif

#define USB_STRING_DESCRIPTOR_HEADER(stringLength) ((2*(stringLength)+2) | (3 & lt; & lt; 8))
/* This macro builds a descriptor header for a string descriptor given the
* string's length. See usbdrv.c for an example how to use it.
*/
#if USB_CFG_HAVE_FLOWCONTROL
extern volatile schar usbRxLen;
#define usbDisableAllRequests() usbRxLen = -1
/* Must be called from usbFunctionWrite(). This macro disables all data input
* from the USB interface. Requests from the host are answered with a NAK
* while they are disabled.
*/
#define usbEnableAllRequests() usbRxLen = 0
/* May only be called if requests are disabled. This macro enables input from
* the USB interface after it has been disabled with usbDisableAllRequests().
*/
#define usbAllRequestsAreDisabled() (usbRxLen & lt; 0)
/* Use this macro to find out whether requests are disabled. It may be needed
* to ensure that usbEnableAllRequests() is never called when requests are
* enabled.
*/
#endif

#define USB_SET_DATATOKEN1(token) usbTxBuf1[0] = token
#define USB_SET_DATATOKEN3(token) usbTxBuf3[0] = token
/* These two macros can be used by application software to reset data toggling
* for interrupt-in endpoints 1 and 3. Since the token is toggled BEFORE
* sending data, you must set the opposite value of the token which should come
* first.
*/

#endif /* __ASSEMBLER__ */


/* ------------------------------------------------------------------------- */
/* ----------------- Definitions for Descriptor Properties ----------------- */
/* ------------------------------------------------------------------------- */
/* This is advanced stuff. See usbconfig-prototype.h for more information
* about the various methods to define USB descriptors. If you do nothing,
* the default descriptors will be used.
*/
#define USB_PROP_IS_DYNAMIC (1 & lt; & lt; 14)
/* If this property is set for a descriptor, usbFunctionDescriptor() will be
* used to obtain the particular descriptor. Data directly returned via
* usbMsgPtr are FLASH data by default, combine (OR) with USB_PROP_IS_RAM to
* return RAM data.
*/
#define USB_PROP_IS_RAM (1 & lt; & lt; 15)
/* If this property is set for a descriptor, the data is read from RAM
* memory instead of Flash. The property is used for all methods to provide
* external descriptors.
*/
#define USB_PROP_LENGTH(len) ((len) & 0x3fff)
/* If a static external descriptor is used, this is the total length of the
* descriptor in bytes.
*/

/* all descriptors which may have properties: */
#ifndef USB_CFG_DESCR_PROPS_DEVICE
#define USB_CFG_DESCR_PROPS_DEVICE 0
#endif
#ifndef USB_CFG_DESCR_PROPS_CONFIGURATION
#define USB_CFG_DESCR_PROPS_CONFIGURATION 0
#endif
#ifndef USB_CFG_DESCR_PROPS_STRINGS
#define USB_CFG_DESCR_PROPS_STRINGS 0
#endif
#ifndef USB_CFG_DESCR_PROPS_STRING_0
#define USB_CFG_DESCR_PROPS_STRING_0 0
#endif
#ifndef USB_CFG_DESCR_PROPS_STRING_VENDOR
#define USB_CFG_DESCR_PROPS_STRING_VENDOR 0
#endif
#ifndef USB_CFG_DESCR_PROPS_STRING_PRODUCT
#define USB_CFG_DESCR_PROPS_STRING_PRODUCT 0
#endif
#ifndef USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER
#define USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER 0
#endif
#ifndef USB_CFG_DESCR_PROPS_HID
#define USB_CFG_DESCR_PROPS_HID 0
#endif
#if !(USB_CFG_DESCR_PROPS_HID_REPORT)
# undef USB_CFG_DESCR_PROPS_HID_REPORT
# if USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH /* do some backward compatibility tricks */
# define USB_CFG_DESCR_PROPS_HID_REPORT USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH
# else
# define USB_CFG_DESCR_PROPS_HID_REPORT 0
# endif
#endif
#ifndef USB_CFG_DESCR_PROPS_UNKNOWN
#define USB_CFG_DESCR_PROPS_UNKNOWN 0
#endif

/* ------------------ forward declaration of descriptors ------------------- */
/* If you use external static descriptors, they must be stored in global
* arrays as declared below:
*/
#ifndef __ASSEMBLER__
extern
#if !(USB_CFG_DESCR_PROPS_DEVICE & USB_PROP_IS_RAM)
PROGMEM
#endif
const char usbDescriptorDevice[];

extern
#if !(USB_CFG_DESCR_PROPS_CONFIGURATION & USB_PROP_IS_RAM)
PROGMEM
#endif
PROGMEM const char usbDescriptorConfiguration[];

extern
#if !(USB_CFG_DESCR_PROPS_HID_REPORT & USB_PROP_IS_RAM)
PROGMEM
#endif
const char usbDescriptorHidReport[];

extern
#if !(USB_CFG_DESCR_PROPS_STRING_0 & USB_PROP_IS_RAM)
PROGMEM
#endif
const char usbDescriptorString0[];

extern
#if !(USB_CFG_DESCR_PROPS_STRING_VENDOR & USB_PROP_IS_RAM)
PROGMEM
#endif
const int usbDescriptorStringVendor[];

extern
#if !(USB_CFG_DESCR_PROPS_STRING_PRODUCT & USB_PROP_IS_RAM)
PROGMEM
#endif
const int usbDescriptorStringDevice[];

extern
#if !(USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER & USB_PROP_IS_RAM)
PROGMEM
#endif
const int usbDescriptorStringSerialNumber[];

#endif /* __ASSEMBLER__ */

/* ------------------------------------------------------------------------- */
/* ------------------------ General Purpose Macros ------------------------- */
/* ------------------------------------------------------------------------- */

#define USB_CONCAT(a, b) a ## b
#define USB_CONCAT_EXPANDED(a, b) USB_CONCAT(a, b)

#define USB_OUTPORT(name) USB_CONCAT(PORT, name)
#define USB_INPORT(name) USB_CONCAT(PIN, name)
#define USB_DDRPORT(name) USB_CONCAT(DDR, name)
/* The double-define trick above lets us concatenate strings which are
* defined by macros.
*/

/* ------------------------------------------------------------------------- */
/* ------------------------- Constant definitions -------------------------- */
/* ------------------------------------------------------------------------- */

#if !defined __ASSEMBLER__ & & (!defined USB_CFG_VENDOR_ID || !defined USB_CFG_DEVICE_ID)
#warning " You should define USB_CFG_VENDOR_ID and USB_CFG_DEVICE_ID in usbconfig.h "
/* If the user has not defined IDs, we default to obdev's free IDs.
* See USB-IDs-for-free.txt for details.
*/
#endif

/* make sure we have a VID and PID defined, byte order is lowbyte, highbyte */
#ifndef USB_CFG_VENDOR_ID
# define USB_CFG_VENDOR_ID 0xc0, 0x16 /* = 0x16c0 = 5824 = voti.nl */
#endif

#ifndef USB_CFG_DEVICE_ID
# if USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH
# define USB_CFG_DEVICE_ID 0xdf, 0x05 /* = 0x5df = 1503, shared PID for HIDs */
# elif USB_CFG_INTERFACE_CLASS == 2
# define USB_CFG_DEVICE_ID 0xe1, 0x05 /* = 0x5e1 = 1505, shared PID for CDC Modems */
# else
# define USB_CFG_DEVICE_ID 0xdc, 0x05 /* = 0x5dc = 1500, obdev's free PID */
# endif
#endif

/* Derive Output, Input and DataDirection ports from port names */
#ifndef USB_CFG_IOPORTNAME
#error " You must define USB_CFG_IOPORTNAME in usbconfig.h, see usbconfig-prototype.h "
#endif

#define USBOUT USB_OUTPORT(USB_CFG_IOPORTNAME)
#define USB_PULLUP_OUT USB_OUTPORT(USB_CFG_PULLUP_IOPORTNAME)
#define USBIN USB_INPORT(USB_CFG_IOPORTNAME)
#define USBDDR USB_DDRPORT(USB_CFG_IOPORTNAME)
#define USB_PULLUP_DDR USB_DDRPORT(USB_CFG_PULLUP_IOPORTNAME)

#define USBMINUS USB_CFG_DMINUS_BIT
#define USBPLUS USB_CFG_DPLUS_BIT
#define USBIDLE (1 & lt; & lt; USB_CFG_DMINUS_BIT) /* value representing J state */
#define USBMASK ((1 & lt; & lt; USB_CFG_DPLUS_BIT) | (1 & lt; & lt; USB_CFG_DMINUS_BIT)) /* mask for USB I/O bits */

/* defines for backward compatibility with older driver versions: */
#define USB_CFG_IOPORT USB_OUTPORT(USB_CFG_IOPORTNAME)
#ifdef USB_CFG_PULLUP_IOPORTNAME
#define USB_CFG_PULLUP_IOPORT USB_OUTPORT(USB_CFG_PULLUP_IOPORTNAME)
#endif

#ifndef USB_CFG_EP3_NUMBER /* if not defined in usbconfig.h */
#define USB_CFG_EP3_NUMBER 3
#endif

#ifndef USB_CFG_HAVE_INTRIN_ENDPOINT3
#define USB_CFG_HAVE_INTRIN_ENDPOINT3 0
#endif

#define USB_BUFSIZE 11 /* PID, 8 bytes data, 2 bytes CRC */

/* ----- Try to find registers and bits responsible for ext interrupt 0 ----- */

#ifndef USB_INTR_CFG /* allow user to override our default */
# if defined EICRA
# define USB_INTR_CFG EICRA
# else
# define USB_INTR_CFG MCUCR
# endif
#endif
#ifndef USB_INTR_CFG_SET /* allow user to override our default */
# if defined(USB_COUNT_SOF) || defined(USB_SOF_HOOK)
# define USB_INTR_CFG_SET (1 & lt; & lt; ISC01) /* cfg for falling edge */
/* If any SOF logic is used, the interrupt must be wired to D- where
* we better trigger on falling edge
*/
# else
# define USB_INTR_CFG_SET ((1 & lt; & lt; ISC00) | (1 & lt; & lt; ISC01)) /* cfg for rising edge */
# endif
#endif
#ifndef USB_INTR_CFG_CLR /* allow user to override our default */
# define USB_INTR_CFG_CLR 0 /* no bits to clear */
#endif

#ifndef USB_INTR_ENABLE /* allow user to override our default */
# if defined GIMSK
# define USB_INTR_ENABLE GIMSK
# elif defined EIMSK
# define USB_INTR_ENABLE EIMSK
# else
# define USB_INTR_ENABLE GICR
# endif
#endif
#ifndef USB_INTR_ENABLE_BIT /* allow user to override our default */
# define USB_INTR_ENABLE_BIT INT0
#endif

#ifndef USB_INTR_PENDING /* allow user to override our default */
# if defined EIFR
# define USB_INTR_PENDING EIFR
# else
# define USB_INTR_PENDING GIFR
# endif
#endif
#ifndef USB_INTR_PENDING_BIT /* allow user to override our default */
# define USB_INTR_PENDING_BIT INTF0
#endif

/*
The defines above don't work for the following chips
at90c8534: no ISC0?, no PORTB, can't find a data sheet
at86rf401: no PORTB, no MCUCR etc, low clock rate
atmega103: no ISC0? (maybe omission in header, can't find data sheet)
atmega603: not defined in avr-libc
at43usb320, at43usb355, at76c711: have USB anyway
at94k: is different...

at90s1200, attiny11, attiny12, attiny15, attiny28: these have no RAM
*/

/* ------------------------------------------------------------------------- */
/* ----------------- USB Specification Constants and Types ----------------- */
/* ------------------------------------------------------------------------- */

/* USB Token values */
#define USBPID_SETUP 0x2d
#define USBPID_OUT 0xe1
#define USBPID_IN 0x69
#define USBPID_DATA0 0xc3
#define USBPID_DATA1 0x4b

#define USBPID_ACK 0xd2
#define USBPID_NAK 0x5a
#define USBPID_STALL 0x1e

#ifndef USB_INITIAL_DATATOKEN
#define USB_INITIAL_DATATOKEN USBPID_DATA1
#endif

#ifndef __ASSEMBLER__

typedef struct usbTxStatus{
volatile uchar len;
uchar buffer[USB_BUFSIZE];
}usbTxStatus_t;

extern usbTxStatus_t usbTxStatus1, usbTxStatus3;
#define usbTxLen1 usbTxStatus1.len
#define usbTxBuf1 usbTxStatus1.buffer
#define usbTxLen3 usbTxStatus3.len
#define usbTxBuf3 usbTxStatus3.buffer


typedef union usbWord{
unsigned word;
uchar bytes[2];
}usbWord_t;

typedef struct usbRequest{
uchar bmRequestType;
uchar bRequest;
usbWord_t wValue;
usbWord_t wIndex;
usbWord_t wLength;
}usbRequest_t;
/* This structure matches the 8 byte setup request */
#endif

/* bmRequestType field in USB setup:
* d t t r r r r r, where
* d ..... direction: 0=host- & gt; device, 1=device- & gt; host
* t ..... type: 0=standard, 1=class, 2=vendor, 3=reserved
* r ..... recipient: 0=device, 1=interface, 2=endpoint, 3=other
*/

/* USB setup recipient values */
#define USBRQ_RCPT_MASK 0x1f
#define USBRQ_RCPT_DEVICE 0
#define USBRQ_RCPT_INTERFACE 1
#define USBRQ_RCPT_ENDPOINT 2

/* USB request type values */
#define USBRQ_TYPE_MASK 0x60
#define USBRQ_TYPE_STANDARD (0 & lt; & lt; 5)
#define USBRQ_TYPE_CLASS (1 & lt; & lt; 5)
#define USBRQ_TYPE_VENDOR (2 & lt; & lt; 5)

/* USB direction values: */
#define USBRQ_DIR_MASK 0x80
#define USBRQ_DIR_HOST_TO_DEVICE (0 & lt; & lt; 7)
#define USBRQ_DIR_DEVICE_TO_HOST (1 & lt; & lt; 7)

/* USB Standard Requests */
#define USBRQ_GET_STATUS 0
#define USBRQ_CLEAR_FEATURE 1
#define USBRQ_SET_FEATURE 3
#define USBRQ_SET_ADDRESS 5
#define USBRQ_GET_DESCRIPTOR 6
#define USBRQ_SET_DESCRIPTOR 7
#define USBRQ_GET_CONFIGURATION 8
#define USBRQ_SET_CONFIGURATION 9
#define USBRQ_GET_INTERFACE 10
#define USBRQ_SET_INTERFACE 11
#define USBRQ_SYNCH_FRAME 12

/* USB descriptor constants */
#define USBDESCR_DEVICE 1
#define USBDESCR_CONFIG 2
#define USBDESCR_STRING 3
#define USBDESCR_INTERFACE 4
#define USBDESCR_ENDPOINT 5
#define USBDESCR_HID 0x21
#define USBDESCR_HID_REPORT 0x22
#define USBDESCR_HID_PHYS 0x23

//#define USBATTR_BUSPOWER 0x80 // USB 1.1 does not define this value any more
#define USBATTR_SELFPOWER 0x40
#define USBATTR_REMOTEWAKE 0x20

/* USB HID Requests */
#define USBRQ_HID_GET_REPORT 0x01
#define USBRQ_HID_GET_IDLE 0x02
#define USBRQ_HID_GET_PROTOCOL 0x03
#define USBRQ_HID_SET_REPORT 0x09
#define USBRQ_HID_SET_IDLE 0x0a
#define USBRQ_HID_SET_PROTOCOL 0x0b

/* ------------------------------------------------------------------------- */

#endif /* __usbdrv_h_included__ */


RadKIT-V2.61.rar > usbdrv.c

/* Name: usbdrv.c
* Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers
* Author: Christian Starkjohann
* Creation Date: 2004-12-29
* Tabsize: 4
* Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH
* License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
* This Revision: $Id: usbdrv.c 791 2010-07-15 15:56:13Z cs $
*/

#include " usbportability.h "
#include " usbdrv.h "
#include " oddebug.h "

/*
General Description:
This module implements the C-part of the USB driver. See usbdrv.h for a
documentation of the entire driver.
*/

/* ------------------------------------------------------------------------- */

/* raw USB registers / interface to assembler code: */
uchar usbRxBuf[2*USB_BUFSIZE]; /* raw RX buffer: PID, 8 bytes data, 2 bytes CRC */
uchar usbInputBufOffset; /* offset in usbRxBuf used for low level receiving */
uchar usbDeviceAddr; /* assigned during enumeration, defaults to 0 */
uchar usbNewDeviceAddr; /* device ID which should be set after status phase */
uchar usbConfiguration; /* currently selected configuration. Administered by driver, but not used */
volatile schar usbRxLen; /* = 0; number of bytes in usbRxBuf; 0 means free, -1 for flow control */
uchar usbCurrentTok; /* last token received or endpoint number for last OUT token if != 0 */
uchar usbRxToken; /* token for data we received; or endpont number for last OUT */
volatile uchar usbTxLen = USBPID_NAK; /* number of bytes to transmit with next IN token or handshake token */
uchar usbTxBuf[USB_BUFSIZE];/* data to transmit with next IN, free if usbTxLen contains handshake token */
#if USB_COUNT_SOF
volatile uchar usbSofCount; /* incremented by assembler module every SOF */
#endif
#if USB_CFG_HAVE_INTRIN_ENDPOINT & & !USB_CFG_SUPPRESS_INTR_CODE
usbTxStatus_t usbTxStatus1;
# if USB_CFG_HAVE_INTRIN_ENDPOINT3
usbTxStatus_t usbTxStatus3;
# endif
#endif
#if USB_CFG_CHECK_DATA_TOGGLING
uchar usbCurrentDataToken;/* when we check data toggling to ignore duplicate packets */
#endif

/* USB status registers / not shared with asm code */
uchar *usbMsgPtr; /* data to transmit next -- ROM or RAM address */
static usbMsgLen_t usbMsgLen = USB_NO_MSG; /* remaining number of bytes */
static uchar usbMsgFlags; /* flag values see below */

#define USB_FLG_MSGPTR_IS_ROM (1 & lt; & lt; 6)
#define USB_FLG_USE_USER_RW (1 & lt; & lt; 7)

/*
optimizing hints:
- do not post/pre inc/dec integer values in operations
- assign value of USB_READ_FLASH() to register variables and don't use side effects in arg
- use narrow scope for variables which should be in X/Y/Z register
- assign char sized expressions to variables to force 8 bit arithmetics
*/

/* -------------------------- String Descriptors --------------------------- */

#if USB_CFG_DESCR_PROPS_STRINGS == 0

#if USB_CFG_DESCR_PROPS_STRING_0 == 0
#undef USB_CFG_DESCR_PROPS_STRING_0
#define USB_CFG_DESCR_PROPS_STRING_0 sizeof(usbDescriptorString0)
PROGMEM const char usbDescriptorString0[] = { /* language descriptor */
4, /* sizeof(usbDescriptorString0): length of descriptor in bytes */
3, /* descriptor type */
0x09, 0x04, /* language index (0x0409 = US-English) */
};
#endif

#if USB_CFG_DESCR_PROPS_STRING_VENDOR == 0 & & USB_CFG_VENDOR_NAME_LEN
#undef USB_CFG_DESCR_PROPS_STRING_VENDOR
#define USB_CFG_DESCR_PROPS_STRING_VENDOR sizeof(usbDescriptorStringVendor)
PROGMEM const int usbDescriptorStringVendor[] = {
USB_STRING_DESCRIPTOR_HEADER(USB_CFG_VENDOR_NAME_LEN),
USB_CFG_VENDOR_NAME
};
#endif

#if USB_CFG_DESCR_PROPS_STRING_PRODUCT == 0 & & USB_CFG_DEVICE_NAME_LEN
#undef USB_CFG_DESCR_PROPS_STRING_PRODUCT
#define USB_CFG_DESCR_PROPS_STRING_PRODUCT sizeof(usbDescriptorStringDevice)
PROGMEM const int usbDescriptorStringDevice[] = {
USB_STRING_DESCRIPTOR_HEADER(USB_CFG_DEVICE_NAME_LEN),
USB_CFG_DEVICE_NAME
};
#endif

#if USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER == 0 & & USB_CFG_SERIAL_NUMBER_LEN
#undef USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER
#define USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER sizeof(usbDescriptorStringSerialNumber)
PROGMEM int usbDescriptorStringSerialNumber[] = {
USB_STRING_DESCRIPTOR_HEADER(USB_CFG_SERIAL_NUMBER_LEN),
USB_CFG_SERIAL_NUMBER
};
#endif

#endif /* USB_CFG_DESCR_PROPS_STRINGS == 0 */

/* --------------------------- Device Descriptor --------------------------- */

#if USB_CFG_DESCR_PROPS_DEVICE == 0
#undef USB_CFG_DESCR_PROPS_DEVICE
#define USB_CFG_DESCR_PROPS_DEVICE sizeof(usbDescriptorDevice)
PROGMEM const char usbDescriptorDevice[] = { /* USB device descriptor */
18, /* sizeof(usbDescriptorDevice): length of descriptor in bytes */
USBDESCR_DEVICE, /* descriptor type */
0x10, 0x01, /* USB version supported */
USB_CFG_DEVICE_CLASS,
USB_CFG_DEVICE_SUBCLASS,
0, /* protocol */
8, /* max packet size */
/* the following two casts affect the first byte of the constant only, but
* that's sufficient to avoid a warning with the default values.
*/
(char)USB_CFG_VENDOR_ID,/* 2 bytes */
(char)USB_CFG_DEVICE_ID,/* 2 bytes */
USB_CFG_DEVICE_VERSION, /* 2 bytes */
USB_CFG_DESCR_PROPS_STRING_VENDOR != 0 ? 1 : 0, /* manufacturer string index */
USB_CFG_DESCR_PROPS_STRING_PRODUCT != 0 ? 2 : 0, /* product string index */
USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER != 0 ? 3 : 0, /* serial number string index */
1, /* number of configurations */
};
#endif

/* ----------------------- Configuration Descriptor ------------------------ */

#if USB_CFG_DESCR_PROPS_HID_REPORT != 0 & & USB_CFG_DESCR_PROPS_HID == 0
#undef USB_CFG_DESCR_PROPS_HID
#define USB_CFG_DESCR_PROPS_HID 9 /* length of HID descriptor in config descriptor below */
#endif

#if USB_CFG_DESCR_PROPS_CONFIGURATION == 0
#undef USB_CFG_DESCR_PROPS_CONFIGURATION
#define USB_CFG_DESCR_PROPS_CONFIGURATION sizeof(usbDescriptorConfiguration)
PROGMEM const char usbDescriptorConfiguration[] = { /* USB configuration descriptor */
9, /* sizeof(usbDescriptorConfiguration): length of descriptor in bytes */
USBDESCR_CONFIG, /* descriptor type */
18 + 7 * USB_CFG_HAVE_INTRIN_ENDPOINT + 7 * USB_CFG_HAVE_INTRIN_ENDPOINT3 +
(USB_CFG_DESCR_PROPS_HID & 0xff), 0,
/* total length of data returned (including inlined descriptors) */
1, /* number of interfaces in this configuration */
1, /* index of this configuration */
0, /* configuration name string index */
#if USB_CFG_IS_SELF_POWERED
(1 & lt; & lt; 7) | USBATTR_SELFPOWER, /* attributes */
#else
(1 & lt; & lt; 7), /* attributes */
#endif
USB_CFG_MAX_BUS_POWER/2, /* max USB current in 2mA units */
/* interface descriptor follows inline: */
9, /* sizeof(usbDescrInterface): length of descriptor in bytes */
USBDESCR_INTERFACE, /* descriptor type */
0, /* index of this interface */
0, /* alternate setting for this interface */
USB_CFG_HAVE_INTRIN_ENDPOINT + USB_CFG_HAVE_INTRIN_ENDPOINT3, /* endpoints excl 0: number of endpoint descriptors to follow */
USB_CFG_INTERFACE_CLASS,
USB_CFG_INTERFACE_SUBCLASS,
USB_CFG_INTERFACE_PROTOCOL,
0, /* string index for interface */
#if (USB_CFG_DESCR_PROPS_HID & 0xff) /* HID descriptor */
9, /* sizeof(usbDescrHID): length of descriptor in bytes */
USBDESCR_HID, /* descriptor type: HID */
0x01, 0x01, /* BCD representation of HID version */
0x00, /* target country code */
0x01, /* number of HID Report (or other HID class) Descriptor infos to follow */
0x22, /* descriptor type: report */
USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH, 0, /* total length of report descriptor */
#endif
#if USB_CFG_HAVE_INTRIN_ENDPOINT /* endpoint descriptor for endpoint 1 */
7, /* sizeof(usbDescrEndpoint) */
USBDESCR_ENDPOINT, /* descriptor type = endpoint */
(char)0x81, /* IN endpoint number 1 */
0x03, /* attrib: Interrupt endpoint */
8, 0, /* maximum packet size */
USB_CFG_INTR_POLL_INTERVAL, /* in ms */
#endif
#if USB_CFG_HAVE_INTRIN_ENDPOINT3 /* endpoint descriptor for endpoint 3 */
7, /* sizeof(usbDescrEndpoint) */
USBDESCR_ENDPOINT, /* descriptor type = endpoint */
(char)(0x80 | USB_CFG_EP3_NUMBER), /* IN endpoint number 3 */
0x03, /* attrib: Interrupt endpoint */
8, 0, /* maximum packet size */
USB_CFG_INTR_POLL_INTERVAL, /* in ms */
#endif
};
#endif

/* ------------------------------------------------------------------------- */

static inline void usbResetDataToggling(void)
{
#if USB_CFG_HAVE_INTRIN_ENDPOINT & & !USB_CFG_SUPPRESS_INTR_CODE
USB_SET_DATATOKEN1(USB_INITIAL_DATATOKEN); /* reset data toggling for interrupt endpoint */
# if USB_CFG_HAVE_INTRIN_ENDPOINT3
USB_SET_DATATOKEN3(USB_INITIAL_DATATOKEN); /* reset data toggling for interrupt endpoint */
# endif
#endif
}

static inline void usbResetStall(void)
{
#if USB_CFG_IMPLEMENT_HALT & & USB_CFG_HAVE_INTRIN_ENDPOINT
usbTxLen1 = USBPID_NAK;
#if USB_CFG_HAVE_INTRIN_ENDPOINT3
usbTxLen3 = USBPID_NAK;
#endif
#endif
}

/* ------------------------------------------------------------------------- */

#if !USB_CFG_SUPPRESS_INTR_CODE
#if USB_CFG_HAVE_INTRIN_ENDPOINT
static void usbGenericSetInterrupt(uchar *data, uchar len, usbTxStatus_t *txStatus)
{
uchar *p;
char i;

#if USB_CFG_IMPLEMENT_HALT
if(usbTxLen1 == USBPID_STALL)
return;
#endif
if(txStatus- & gt; len & 0x10){ /* packet buffer was empty */
txStatus- & gt; buffer[0] ^= USBPID_DATA0 ^ USBPID_DATA1; /* toggle token */
}else{
txStatus- & gt; len = USBPID_NAK; /* avoid sending outdated (overwritten) interrupt data */
}
p = txStatus- & gt; buffer + 1;
i = len;
do{ /* if len == 0, we still copy 1 byte, but that's no problem */
*p++ = *data++;
}while(--i & gt; 0); /* loop control at the end is 2 bytes shorter than at beginning */
usbCrc16Append( & txStatus- & gt; buffer[1], len);
txStatus- & gt; len = len + 4; /* len must be given including sync byte */
DBG2(0x21 + (((int)txStatus & gt; & gt; 3) & 3), txStatus- & gt; buffer, len + 3);
}

USB_PUBLIC void usbSetInterrupt(uchar *data, uchar len)
{
usbGenericSetInterrupt(data, len, & usbTxStatus1);
}
#endif

#if USB_CFG_HAVE_INTRIN_ENDPOINT3
USB_PUBLIC void usbSetInterrupt3(uchar *data, uchar len)
{
usbGenericSetInterrupt(data, len, & usbTxStatus3);
}
#endif
#endif /* USB_CFG_SUPPRESS_INTR_CODE */

/* ------------------ utilities for code following below ------------------- */

/* Use defines for the switch statement so that we can choose between an
* if()else if() and a switch/case based implementation. switch() is more
* efficient for a LARGE set of sequential choices, if() is better in all other
* cases.
*/
#if USB_CFG_USE_SWITCH_STATEMENT
# define SWITCH_START(cmd) switch(cmd){{
# define SWITCH_CASE(value) }break; case (value):{
# define SWITCH_CASE2(v1,v2) }break; case (v1): case(v2):{
# define SWITCH_CASE3(v1,v2,v3) }break; case (v1): case(v2): case(v3):{
# define SWITCH_DEFAULT }break; default:{
# define SWITCH_END }}
#else
# define SWITCH_START(cmd) {uchar _cmd = cmd; if(0){
# define SWITCH_CASE(value) }else if(_cmd == (value)){
# define SWITCH_CASE2(v1,v2) }else if(_cmd == (v1) || _cmd == (v2)){
# define SWITCH_CASE3(v1,v2,v3) }else if(_cmd == (v1) || _cmd == (v2) || (_cmd == v3)){
# define SWITCH_DEFAULT }else{
# define SWITCH_END }}
#endif

#ifndef USB_RX_USER_HOOK
#define USB_RX_USER_HOOK(data, len)
#endif
#ifndef USB_SET_ADDRESS_HOOK
#define USB_SET_ADDRESS_HOOK()
#endif

/* ------------------------------------------------------------------------- */

/* We use if() instead of #if in the macro below because #if can't be used
* in macros and the compiler optimizes constant conditions anyway.
* This may cause problems with undefined symbols if compiled without
* optimizing!
*/
#define GET_DESCRIPTOR(cfgProp, staticName) \
if(cfgProp){ \
if((cfgProp) & USB_PROP_IS_RAM) \
flags = 0; \
if((cfgProp) & USB_PROP_IS_DYNAMIC){ \
len = usbFunctionDescriptor(rq); \
}else{ \
len = USB_PROP_LENGTH(cfgProp); \
usbMsgPtr = (uchar *)(staticName); \
} \
}

/* usbDriverDescriptor() is similar to usbFunctionDescriptor(), but used
* internally for all types of descriptors.
*/
static inline usbMsgLen_t usbDriverDescriptor(usbRequest_t *rq)
{
usbMsgLen_t len = 0;
uchar flags = USB_FLG_MSGPTR_IS_ROM;

SWITCH_START(rq- & gt; wValue.bytes[1])
SWITCH_CASE(USBDESCR_DEVICE) /* 1 */
GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_DEVICE, usbDescriptorDevice)
SWITCH_CASE(USBDESCR_CONFIG) /* 2 */
GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_CONFIGURATION, usbDescriptorConfiguration)
SWITCH_CASE(USBDESCR_STRING) /* 3 */
#if USB_CFG_DESCR_PROPS_STRINGS & USB_PROP_IS_DYNAMIC
if(USB_CFG_DESCR_PROPS_STRINGS & USB_PROP_IS_RAM)
flags = 0;
len = usbFunctionDescriptor(rq);
#else /* USB_CFG_DESCR_PROPS_STRINGS & USB_PROP_IS_DYNAMIC */
SWITCH_START(rq- & gt; wValue.bytes[0])
SWITCH_CASE(0)
GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_STRING_0, usbDescriptorString0)
SWITCH_CASE(1)
GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_STRING_VENDOR, usbDescriptorStringVendor)
SWITCH_CASE(2)
GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_STRING_PRODUCT, usbDescriptorStringDevice)
SWITCH_CASE(3)
GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER, usbDescriptorStringSerialNumber)
SWITCH_DEFAULT
if(USB_CFG_DESCR_PROPS_UNKNOWN & USB_PROP_IS_DYNAMIC){
len = usbFunctionDescriptor(rq);
}
SWITCH_END
#endif /* USB_CFG_DESCR_PROPS_STRINGS & USB_PROP_IS_DYNAMIC */
#if USB_CFG_DESCR_PROPS_HID_REPORT /* only support HID descriptors if enabled */
SWITCH_CASE(USBDESCR_HID) /* 0x21 */
GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_HID, usbDescriptorConfiguration + 18)
SWITCH_CASE(USBDESCR_HID_REPORT)/* 0x22 */
GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_HID_REPORT, usbDescriptorHidReport)
#endif
SWITCH_DEFAULT
if(USB_CFG_DESCR_PROPS_UNKNOWN & USB_PROP_IS_DYNAMIC){
len = usbFunctionDescriptor(rq);
}
SWITCH_END
usbMsgFlags = flags;
return len;
}

/* ------------------------------------------------------------------------- */

/* usbDriverSetup() is similar to usbFunctionSetup(), but it's used for
* standard requests instead of class and custom requests.
*/
static inline usbMsgLen_t usbDriverSetup(usbRequest_t *rq)
{
uchar len = 0, *dataPtr = usbTxBuf + 9; /* there are 2 bytes free space at the end of the buffer */
uchar value = rq- & gt; wValue.bytes[0];
#if USB_CFG_IMPLEMENT_HALT
uchar index = rq- & gt; wIndex.bytes[0];
#endif

dataPtr[0] = 0; /* default reply common to USBRQ_GET_STATUS and USBRQ_GET_INTERFACE */
SWITCH_START(rq- & gt; bRequest)
SWITCH_CASE(USBRQ_GET_STATUS) /* 0 */
uchar recipient = rq- & gt; bmRequestType & USBRQ_RCPT_MASK; /* assign arith ops to variables to enforce byte size */
if(USB_CFG_IS_SELF_POWERED & & recipient == USBRQ_RCPT_DEVICE)
dataPtr[0] = USB_CFG_IS_SELF_POWERED;
#if USB_CFG_IMPLEMENT_HALT
if(recipient == USBRQ_RCPT_ENDPOINT & & index == 0x81) /* request status for endpoint 1 */
dataPtr[0] = usbTxLen1 == USBPID_STALL;
#endif
dataPtr[1] = 0;
len = 2;
#if USB_CFG_IMPLEMENT_HALT
SWITCH_CASE2(USBRQ_CLEAR_FEATURE, USBRQ_SET_FEATURE) /* 1, 3 */
if(value == 0 & & index == 0x81){ /* feature 0 == HALT for endpoint == 1 */
usbTxLen1 = rq- & gt; bRequest == USBRQ_CLEAR_FEATURE ? USBPID_NAK : USBPID_STALL;
usbResetDataToggling();
}
#endif
SWITCH_CASE(USBRQ_SET_ADDRESS) /* 5 */
usbNewDeviceAddr = value;
USB_SET_ADDRESS_HOOK();
SWITCH_CASE(USBRQ_GET_DESCRIPTOR) /* 6 */
len = usbDriverDescriptor(rq);
goto skipMsgPtrAssignment;
SWITCH_CASE(USBRQ_GET_CONFIGURATION) /* 8 */
dataPtr = & usbConfiguration; /* send current configuration value */
len = 1;
SWITCH_CASE(USBRQ_SET_CONFIGURATION) /* 9 */
usbConfiguration = value;
usbResetStall();
SWITCH_CASE(USBRQ_GET_INTERFACE) /* 10 */
len = 1;
#if USB_CFG_HAVE_INTRIN_ENDPOINT & & !USB_CFG_SUPPRESS_INTR_CODE
SWITCH_CASE(USBRQ_SET_INTERFACE) /* 11 */
usbResetDataToggling();
usbResetStall();
#endif
SWITCH_DEFAULT /* 7=SET_DESCRIPTOR, 12=SYNC_FRAME */
/* Should we add an optional hook here? */
SWITCH_END
usbMsgPtr = dataPtr;
skipMsgPtrAssignment:
return len;
}

/* ------------------------------------------------------------------------- */

/* usbProcessRx() is called for every message received by the interrupt
* routine. It distinguishes between SETUP and DATA packets and processes
* them accordingly.
*/
static inline void usbProcessRx(uchar *data, uchar len)
{
usbRequest_t *rq = (void *)data;

/* usbRxToken can be:
* 0x2d 00101101 (USBPID_SETUP for setup data)
* 0xe1 11100001 (USBPID_OUT: data phase of setup transfer)
* 0...0x0f for OUT on endpoint X
*/
DBG2(0x10 + (usbRxToken & 0xf), data, len + 2); /* SETUP=1d, SETUP-DATA=11, OUTx=1x */
USB_RX_USER_HOOK(data, len)
#if USB_CFG_IMPLEMENT_FN_WRITEOUT
if(usbRxToken & lt; 0x10){ /* OUT to endpoint != 0: endpoint number in usbRxToken */
usbFunctionWriteOut(data, len);
return;
}
#endif
if(usbRxToken == (uchar)USBPID_SETUP){
if(len != 8) /* Setup size must be always 8 bytes. Ignore otherwise. */
return;
usbMsgLen_t replyLen;
usbTxBuf[0] = USBPID_DATA0; /* initialize data toggling */
usbTxLen = USBPID_NAK; /* abort pending transmit */
usbMsgFlags = 0;
uchar type = rq- & gt; bmRequestType & USBRQ_TYPE_MASK;
if(type != USBRQ_TYPE_STANDARD){ /* standard requests are handled by driver */
replyLen = usbFunctionSetup(data);
}else{
replyLen = usbDriverSetup(rq);
}
#if USB_CFG_IMPLEMENT_FN_READ || USB_CFG_IMPLEMENT_FN_WRITE
if(replyLen == USB_NO_MSG){ /* use user-supplied read/write function */
/* do some conditioning on replyLen, but on IN transfers only */
if((rq- & gt; bmRequestType & USBRQ_DIR_MASK) != USBRQ_DIR_HOST_TO_DEVICE){
if(sizeof(replyLen) & lt; sizeof(rq- & gt; wLength.word)){ /* help compiler with optimizing */
replyLen = rq- & gt; wLength.bytes[0];
}else{
replyLen = rq- & gt; wLength.word;
}
}
usbMsgFlags = USB_FLG_USE_USER_RW;
}else /* The 'else' prevents that we limit a replyLen of USB_NO_MSG to the maximum transfer len. */
#endif
if(sizeof(replyLen) & lt; sizeof(rq- & gt; wLength.word)){ /* help compiler with optimizing */
if(!rq- & gt; wLength.bytes[1] & & replyLen & gt; rq- & gt; wLength.bytes[0]) /* limit length to max */
replyLen = rq- & gt; wLength.bytes[0];
}else{
if(replyLen & gt; rq- & gt; wLength.word) /* limit length to max */
replyLen = rq- & gt; wLength.word;
}
usbMsgLen = replyLen;
}else{ /* usbRxToken must be USBPID_OUT, which means data phase of setup (control-out) */
#if USB_CFG_IMPLEMENT_FN_WRITE
if(usbMsgFlags & USB_FLG_USE_USER_RW){
uchar rval = usbFunctionWrite(data, len);
if(rval == 0xff){ /* an error occurred */
usbTxLen = USBPID_STALL;
}else if(rval != 0){ /* This was the final package */
usbMsgLen = 0; /* answer with a zero-sized data packet */
}
}
#endif
}
}

/* ------------------------------------------------------------------------- */

/* This function is similar to usbFunctionRead(), but it's also called for
* data handled automatically by the driver (e.g. descriptor reads).
*/
static uchar usbDeviceRead(uchar *data, uchar len)
{
if(len & gt; 0){ /* don't bother app with 0 sized reads */
#if USB_CFG_IMPLEMENT_FN_READ
if(usbMsgFlags & USB_FLG_USE_USER_RW){
len = usbFunctionRead(data, len);
}else
#endif
{
uchar i = len, *r = usbMsgPtr;
if(usbMsgFlags & USB_FLG_MSGPTR_IS_ROM){ /* ROM data */
do{
uchar c = USB_READ_FLASH(r); /* assign to char size variable to enforce byte ops */
*data++ = c;
r++;
}while(--i);
}else{ /* RAM data */
do{
*data++ = *r++;
}while(--i);
}
usbMsgPtr = r;
}
}
return len;
}

/* ------------------------------------------------------------------------- */

/* usbBuildTxBlock() is called when we have data to transmit and the
* interrupt routine's transmit buffer is empty.
*/
static inline void usbBuildTxBlock(void)
{
usbMsgLen_t wantLen;
uchar len;

wantLen = usbMsgLen;
if(wantLen & gt; 8)
wantLen = 8;
usbMsgLen -= wantLen;
usbTxBuf[0] ^= USBPID_DATA0 ^ USBPID_DATA1; /* DATA toggling */
len = usbDeviceRead(usbTxBuf + 1, wantLen);
if(len & lt; = 8){ /* valid data packet */
usbCrc16Append( & usbTxBuf[1], len);
len += 4; /* length including sync byte */
if(len & lt; 12) /* a partial package identifies end of message */
usbMsgLen = USB_NO_MSG;
}else{
len = USBPID_STALL; /* stall the endpoint */
usbMsgLen = USB_NO_MSG;
}
usbTxLen = len;
DBG2(0x20, usbTxBuf, len-1);
}

/* ------------------------------------------------------------------------- */

static inline void usbHandleResetHook(uchar notResetState)
{
#ifdef USB_RESET_HOOK
static uchar wasReset;
uchar isReset = !notResetState;

if(wasReset != isReset){
USB_RESET_HOOK(isReset);
wasReset = isReset;
}
#endif
}

/* ------------------------------------------------------------------------- */

USB_PUBLIC void usbPoll(void)
{
schar len;
uchar i;

len = usbRxLen - 3;
if(len & gt; = 0){
/* We could check CRC16 here -- but ACK has already been sent anyway. If you
* need data integrity checks with this driver, check the CRC in your app
* code and report errors back to the host. Since the ACK was already sent,
* retries must be handled on application level.
* unsigned crc = usbCrc16(buffer + 1, usbRxLen - 3);
*/
usbProcessRx(usbRxBuf + USB_BUFSIZE + 1 - usbInputBufOffset, len);
#if USB_CFG_HAVE_FLOWCONTROL
if(usbRxLen & gt; 0) /* only mark as available if not inactivated */
usbRxLen = 0;
#else
usbRxLen = 0; /* mark rx buffer as available */
#endif
}
if(usbTxLen & 0x10){ /* transmit system idle */
if(usbMsgLen != USB_NO_MSG){ /* transmit data pending? */
usbBuildTxBlock();
}
}
for(i = 20; i & gt; 0; i--){
uchar usbLineStatus = USBIN & USBMASK;
if(usbLineStatus != 0) /* SE0 has ended */
goto isNotReset;
}
/* RESET condition, called multiple times during reset */
usbNewDeviceAddr = 0;
usbDeviceAddr = 0;
usbResetStall();
DBG1(0xff, 0, 0);
isNotReset:
usbHandleResetHook(i);
}

/* ------------------------------------------------------------------------- */

USB_PUBLIC void usbInit(void)
{
#if USB_INTR_CFG_SET != 0
USB_INTR_CFG |= USB_INTR_CFG_SET;
#endif
#if USB_INTR_CFG_CLR != 0
USB_INTR_CFG & = ~(USB_INTR_CFG_CLR);
#endif
USB_INTR_ENABLE |= (1 & lt; & lt; USB_INTR_ENABLE_BIT);
usbResetDataToggling();
#if USB_CFG_HAVE_INTRIN_ENDPOINT & & !USB_CFG_SUPPRESS_INTR_CODE
usbTxLen1 = USBPID_NAK;
#if USB_CFG_HAVE_INTRIN_ENDPOINT3
usbTxLen3 = USBPID_NAK;
#endif
#endif
}

/* ------------------------------------------------------------------------- */


RadKIT-V2.61.rar > i2c_lcd_universal.h

/* Name: i2c_lcd_universal.h
* Project: Radioactive@Home KIT Firmware
* Author: Michal 'Szopler' Szoplik
* Creation Date: 04-2014
* License: GNU GPL v3
*/


#ifndef I2C_LCD_UNIVERSAL_H_
#define I2C_LCD_UNIVERSAL_H_

#define _Set 1
#define _Rst 0

#define _On 1
#define _Off 0

#define native 0
#define expander 1

#define _cmd 0
#define _data 1

#define lcdn_bl_port PORTB
#define lcdn_bl_pin PB1
#define lcdn_bl_ddr DDRB
#define lcdn_rs 6

#define lcde_bl 3
#define lcde_en 2
#define lcde_rw 1
#define lcde_rs 0

extern uint8_t disp_addr;

void lcd_init();
void lcd_chr(char ch);
void lcd_str(char* s);
void lcd_home(void);
void lcd_locate(uint8_t y, uint8_t x);
void lcd_num(int val, int type);
void lcd_str_P(const char *str);

uint8_t type_of_display(void);
void lcd_ctrl(uint8_t ctrl_flag);

#endif /* I2C_LCD_UNIVERSAL_H_ */


RadKIT-V2.61.rar > usart.c

/* Name: usart.c
* Project: Radioactive@Home KIT Firmware
* Author: Michal 'Szopler' Szoplik
* Creation Date: 04-2014
* License: GNU GPL v3
*/


#include & lt; avr/io.h & gt;
#include " usart.h "
#include & lt; avr/interrupt.h & gt;
#include & lt; stdlib.h & gt;


#define TxBuffSize 32 // Must be a power of 2
#define TxBuffMask (TxBuffSize - 1) // last sign in TxBuffer should be \0 (ASCII)

volatile char TxBuff[TxBuffSize];
volatile uint8_t TxHead;
volatile uint8_t TxTail;

/*************/
/* Functions */
/*************/

void uart_init( uint16_t baud ) {
UBRR0H = (uint8_t) (baud & gt; & gt; 8);
UBRR0L = (uint8_t) (baud);

UCSR0B |= (1 & lt; & lt; RXEN0) | (1 & lt; & lt; TXEN0); // | (1 & lt; & lt; RXCIE0);
UCSR0C |= (1 & lt; & lt; UCSZ01) | (1 & lt; & lt; UCSZ00); // 8 data bit, 1 stop bit, no partity
}

void uart_putc(char chr) {
uint8_t temp_pos = ( (TxHead + 1) & TxBuffMask );

while ( temp_pos == TxTail ) {}

TxBuff[temp_pos] = chr;
TxHead = temp_pos;

UCSR0B |= (1 & lt; & lt; UDRIE0);
}

void uart_putstr(char *str) {
while (*str != 0) uart_putc(*str++);
}

void uart_putnum(int number, uint8_t base) {
char string[5];
itoa(number, string, base);
uart_putstr(string);
}

/***************/
/* Interrupts: */
/***************/

ISR( USART_UDRE_vect ) {
if ( TxHead != TxTail ) {
TxTail = ( (TxTail + 1) & TxBuffMask );
UDR0 = TxBuff[TxTail];
} else {
UCSR0B & = ~(1 & lt; & lt; UDRIE0);
}
}


RadKIT-V2.61.rar > oddebug.c

/* Name: oddebug.c
* Project: AVR library
* Author: Christian Starkjohann
* Creation Date: 2005-01-16
* Tabsize: 4
* Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH
* License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
* This Revision: $Id: oddebug.c 692 2008-11-07 15:07:40Z cs $
*/

#include " oddebug.h "

#if DEBUG_LEVEL & gt; 0

#warning " Never compile production devices with debugging enabled "

static void uartPutc(char c)
{
while(!(ODDBG_USR & (1 & lt; & lt; ODDBG_UDRE))); /* wait for data register empty */
ODDBG_UDR = c;
}

static uchar hexAscii(uchar h)
{
h & = 0xf;
if(h & gt; = 10)
h += 'a' - (uchar)10 - '0';
h += '0';
return h;
}

static void printHex(uchar c)
{
uartPutc(hexAscii(c & gt; & gt; 4));
uartPutc(hexAscii(c));
}

void odDebug(uchar prefix, uchar *data, uchar len)
{
printHex(prefix);
uartPutc(':');
while(len--){
uartPutc(' ');
printHex(*data++);
}
uartPutc('\r');
uartPutc('\n');
}

#endif


RadKIT-V2.61.rar > delay_nonblock.c

#include " delay_noblock.h "

inline void delayms_nonblock(uint16_t miliseconds) {
uint32_t actual_sc = uptime;
uint32_t new_sc = actual_sc + (uint32_t)miliseconds;
while (uptime & lt; new_sc);
}