forked from RC-Navy/DigisparkArduinoIntegration
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDigiUSB.cpp
More file actions
218 lines (180 loc) · 6.4 KB
/
DigiUSB.cpp
File metadata and controls
218 lines (180 loc) · 6.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
/* Name: DigiUSB.c
* Based on V-USB Arduino Examples by Philip J. Lindsay
* Modification for the Digispark by Erik Kettenburg, Digistump LLC
* VID/PID changed to pair owned by Digistump LLC, code modified to use pinchange int for attiny85
* Original notice below:
* Based on project: hid-data, example how to use HID for data transfer
* (Uses modified descriptor and usbFunctionSetup from it.)
* Original author: Christian Starkjohann
* Arduino modifications by: Philip J. Lindsay
* Creation Date: 2008-04-11
* Tabsize: 4
* Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH
* License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
* This Revision: $Id: main.c 692 2008-11-07 15:07:40Z cs $
*/
/*
This example should run on most AVRs with only little changes. No special
hardware resources except INT0 are used. You may have to change usbconfig.h for
different I/O pins for USB. Please note that USB D+ must be the INT0 pin, or
at least be connected to INT0 as well.
*/
#include <Arduino.h>
#include <avr/io.h>
#include <avr/wdt.h>
#include <avr/interrupt.h> /* for sei() */
#include <util/delay.h> /* for _delay_ms() */
#include <avr/eeprom.h>
#include <avr/pgmspace.h> /* required by usbdrv.h */
#include "usbdrv.h"
#include "oddebug.h" /* This is also an example for using debug macros */
#include "DigiUSB.h"
#if F_CPU != 16500000L
#error "You must use Digispark (Tiny Core) board to use USB libraries"
#endif
// Ring buffer implementation nicked from HardwareSerial.cpp
// TODO: Don't nick it. :)
ring_buffer rx_buffer = { { 0 }, 0, 0 };
ring_buffer tx_buffer = { { 0 }, 0, 0 };
inline int store_char(unsigned char c, ring_buffer *the_buffer)
{
int i = (the_buffer->head + 1) % RING_BUFFER_SIZE;
// if we should be storing the received character into the location
// just before the tail (meaning that the head would advance to the
// current location of the tail), we're about to overflow the buffer
// and so we don't write the character or advance the head.
if (i != the_buffer->tail) {
the_buffer->buffer[the_buffer->head] = c;
the_buffer->head = i;
return 1;
}
return 0;
}
DigiUSBDevice::DigiUSBDevice(ring_buffer *rx_buffer,
ring_buffer *tx_buffer) {
_rx_buffer = rx_buffer;
_tx_buffer = tx_buffer;
}
void DigiUSBDevice::begin() {
cli();
usbInit();
usbDeviceDisconnect();
uchar i;
i = 0;
while(--i){ /* fake USB disconnect for > 250 ms */
_delay_ms(1);
}
usbDeviceConnect();
sei();
}
// TODO: Deprecate update
void DigiUSBDevice::update() {
refresh();
}
void DigiUSBDevice::refresh() {
usbPoll();
}
// wait a specified number of milliseconds (roughly), refreshing in the background
void DigiUSBDevice::delay(long milli) {
unsigned long last = millis();
while (milli > 0) {
unsigned long now = millis();
milli -= now - last;
last = now;
refresh();
}
}
int DigiUSBDevice::available() {
/*
*/
return (RING_BUFFER_SIZE + _rx_buffer->head - _rx_buffer->tail) % RING_BUFFER_SIZE;
}
int DigiUSBDevice::tx_remaining() {
return RING_BUFFER_SIZE - (RING_BUFFER_SIZE + _tx_buffer->head - _tx_buffer->tail) % RING_BUFFER_SIZE;
}
int DigiUSBDevice::read() {
/*
*/
// if the head isn't ahead of the tail, we don't have any characters
if (_rx_buffer->head == _rx_buffer->tail) {
return -1;
} else {
unsigned char c = _rx_buffer->buffer[_rx_buffer->tail];
_rx_buffer->tail = (_rx_buffer->tail + 1) % RING_BUFFER_SIZE;
return c;
}
}
size_t DigiUSBDevice::write(byte c) {
/*
*/
return store_char(c, _tx_buffer);
}
// TODO: Handle this better?
int tx_available() {
/*
*/
return (RING_BUFFER_SIZE + tx_buffer.head - tx_buffer.tail) % RING_BUFFER_SIZE;
}
int tx_read() {
/*
*/
// if the head isn't ahead of the tail, we don't have any characters
if (tx_buffer.head == tx_buffer.tail) {
return -1;
} else {
unsigned char c = tx_buffer.buffer[tx_buffer.tail];
tx_buffer.tail = (tx_buffer.tail + 1) % RING_BUFFER_SIZE;
return c;
}
}
/* ------------------------------------------------------------------------- */
/* ----------------------------- USB interface ----------------------------- */
/* ------------------------------------------------------------------------- */
#ifdef __cplusplus
extern "C"{
#endif
PROGMEM char usbHidReportDescriptor[22] = { /* USB report descriptor */
0x06, 0x00, 0xff, // USAGE_PAGE (Generic Desktop)
0x09, 0x01, // USAGE (Vendor Usage 1)
0xa1, 0x01, // COLLECTION (Application)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x01, // REPORT_COUNT (1)
0x09, 0x00, // USAGE (Undefined)
0xb2, 0x02, 0x01, // FEATURE (Data,Var,Abs,Buf)
0xc0 // END_COLLECTION
};
/* Since we define only one feature report, we don't use report-IDs (which
* would be the first byte of the report). The entire report consists of 1
* opaque data bytes.
*/
/* ------------------------------------------------------------------------- */
usbMsgLen_t usbFunctionSetup(uchar data[8])
{
usbRequest_t *rq = (usbRequest_t*)((void *)data);
if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS){ /* HID class request */
if(rq->bRequest == USBRQ_HID_GET_REPORT){ /* wValue: ReportType (highbyte), ReportID (lowbyte) */
/* since we have only one report type, we can ignore the report-ID */
static uchar dataBuffer[1]; /* buffer must stay valid when usbFunctionSetup returns */
if (tx_available()) {
dataBuffer[0] = tx_read();
usbMsgPtr = dataBuffer; /* tell the driver which data to return */
return 1; /* tell the driver to send 1 byte */
} else {
// Drop through to return 0 (which will stall the request?)
}
}else if(rq->bRequest == USBRQ_HID_SET_REPORT){
/* since we have only one report type, we can ignore the report-ID */
// TODO: Check race issues?
store_char(rq->wIndex.bytes[0], &rx_buffer);
}
}else{
/* ignore vendor type requests, we don't use any */
}
return 0;
}
#ifdef __cplusplus
} // extern "C"
#endif
DigiUSBDevice DigiUSB = DigiUSBDevice(&rx_buffer, &tx_buffer);