Rev Author Line No. Line
4932 kaklik 1 /************************************************************************
2 main.c
3  
4 WFF USB Generic HID Demonstration 3
5 usbGenericHidCommunication reference firmware 3_0_0_0
6 Copyright (C) 2011 Simon Inns
7  
8 This program is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12  
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17  
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
20  
21 Email: simon.inns@gmail.com
22  
23 ************************************************************************/
24  
25 #ifndef MAIN_C
26 #define MAIN_C
27  
28 // Global includes
29 // Note: string.h is required for sprintf commands for debug
30 #include <string.h>
31  
32 // Local includes
33 #include "HardwareProfile.h"
34 #include "debug.h"
35  
36 // Microchip Application Library includes
37 // (expects V2.9a of the USB library from "Microchip Solutions v2011-07-14")
38 //
39 // The library location must be set in:
40 // Project -> Build Options Project -> Directories -> Include search path
41 // in order for the project to compile.
42 #include "./USB/usb.h"
43 #include "./USB/usb_function_hid.h"
44  
45 // Ensure we have the correct target PIC device family
46 #if !defined(__18F4550) && !defined(__18F2550)
47 #error "This firmware only supports either the PIC18F4550 or PIC18F2550 microcontrollers."
48 #endif
49  
50 // Define the globals for the USB data in the USB RAM of the PIC18F*550
51 #pragma udata
52 #pragma udata USB_VARIABLES=0x500
53 unsigned char ReceivedDataBuffer[64];
54 unsigned char ToSendDataBuffer[64];
55 #pragma udata
56  
57 USB_HANDLE USBOutHandle = 0;
58 USB_HANDLE USBInHandle = 0;
59 BOOL blinkStatusValid = FLAG_TRUE;
60  
61 // PIC18F4550/PIC18F2550 configuration for the WFF Generic HID test device
62 #pragma config PLLDIV = 5 // 20Mhz external oscillator
63 #pragma config CPUDIV = OSC1_PLL2
64 #pragma config USBDIV = 2 // Clock source from 96MHz PLL/2
65 #pragma config FOSC = HSPLL_HS
66 #pragma config FCMEN = OFF
67 #pragma config IESO = OFF
68 #pragma config PWRT = OFF
69 #pragma config BOR = ON
70 #pragma config BORV = 3
71 #pragma config VREGEN = ON
72 #pragma config WDT = OFF
73 #pragma config WDTPS = 32768
74 #pragma config MCLRE = ON
75 #pragma config LPT1OSC = OFF
76 #pragma config PBADEN = OFF
77 // #pragma config CCP2MX = ON
78 #pragma config STVREN = ON
79 #pragma config LVP = OFF
80 // #pragma config ICPRT = OFF
81 #pragma config XINST = OFF
82 #pragma config CP0 = OFF
83 #pragma config CP1 = OFF
84 // #pragma config CP2 = OFF
85 // #pragma config CP3 = OFF
86 #pragma config CPB = OFF
87 // #pragma config CPD = OFF
88 #pragma config WRT0 = OFF
89 #pragma config WRT1 = OFF
90 // #pragma config WRT2 = OFF
91 // #pragma config WRT3 = OFF
92 #pragma config WRTB = OFF
93 #pragma config WRTC = OFF
94 // #pragma config WRTD = OFF
95 #pragma config EBTR0 = OFF
96 #pragma config EBTR1 = OFF
97 // #pragma config EBTR2 = OFF
98 // #pragma config EBTR3 = OFF
99 #pragma config EBTRB = OFF
100  
101 // Private function prototypes
102 static void initialisePic(void);
103 void processUsbCommands(void);
104 void applicationInit(void);
105 void USBCBSendResume(void);
106 void highPriorityISRCode();
107 void lowPriorityISRCode();
108  
109 // Remap vectors for compatibilty with Microchip USB boot loaders
110 #if defined(PROGRAMMABLE_WITH_USB_HID_BOOTLOADER)
111 #define REMAPPED_RESET_VECTOR_ADDRESS 0x1000
112 #define REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS 0x1008
113 #define REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS 0x1018
114 #elif defined(PROGRAMMABLE_WITH_USB_MCHPUSB_BOOTLOADER)
115 #define REMAPPED_RESET_VECTOR_ADDRESS 0x800
116 #define REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS 0x808
117 #define REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS 0x818
118 #else
119 #define REMAPPED_RESET_VECTOR_ADDRESS 0x00
120 #define REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS 0x08
121 #define REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS 0x18
122 #endif
123  
124 #if defined(PROGRAMMABLE_WITH_USB_HID_BOOTLOADER) || defined(PROGRAMMABLE_WITH_USB_MCHPUSB_BOOTLOADER)
125 extern void _startup (void);
126 #pragma code REMAPPED_RESET_VECTOR = REMAPPED_RESET_VECTOR_ADDRESS
127 void _reset (void)
128 {
129 _asm goto _startup _endasm
130 }
131 #endif
132  
133 #pragma code REMAPPED_HIGH_INTERRUPT_VECTOR = REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS
134 void Remapped_High_ISR (void)
135 {
136 _asm goto highPriorityISRCode _endasm
137 }
138  
139 #pragma code REMAPPED_LOW_INTERRUPT_VECTOR = REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS
140 void Remapped_Low_ISR (void)
141 {
142 _asm goto lowPriorityISRCode _endasm
143 }
144  
145 #if defined(PROGRAMMABLE_WITH_USB_HID_BOOTLOADER) || defined(PROGRAMMABLE_WITH_USB_MCHPUSB_BOOTLOADER)
146 #pragma code HIGH_INTERRUPT_VECTOR = 0x08
147 void High_ISR (void)
148 {
149 _asm goto REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS _endasm
150 }
151  
152 #pragma code LOW_INTERRUPT_VECTOR = 0x18
153 void Low_ISR (void)
154 {
155 _asm goto REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS _endasm
156 }
157 #endif
158  
159 #pragma code
160  
161 // High-priority ISR handling function
162 #pragma interrupt highPriorityISRCode
163 void highPriorityISRCode()
164 {
165 // Application specific high-priority ISR code goes here
166  
167 #if defined(USB_INTERRUPT)
168 // Perform USB device tasks
169 USBDeviceTasks();
170 #endif
171  
172 }
173  
174 // Low-priority ISR handling function
175 #pragma interruptlow lowPriorityISRCode
176 void lowPriorityISRCode()
177 {
178 // Application specific low-priority ISR code goes here
179 }
180  
181 // String for creating debug messages
182 char debugString[64];
183  
184 // Main program entry point
185 void main(void)
186 {
187 // Initialise and configure the PIC ready to go
188 initialisePic();
189  
190 // If we are running in interrupt mode attempt to attach the USB device
191 #if defined(USB_INTERRUPT)
192 USBDeviceAttach();
193 #endif
194  
195 // Initialise the debug log functions
196 debugInitialise();
197  
198 // Show that we are up and running
199 mStatusLED0_on();
200  
201 sprintf(debugString, "USB Generic HID Demonstration 3");
202 debugOut(debugString);
203  
204 sprintf(debugString, "(C)2011 Simon Inns - http://www.waitingforfriday.com");
205 debugOut(debugString);
206  
207 sprintf(debugString, "USB Device Initialised.");
208 debugOut(debugString);
209  
210 // Main processing loop
211 while(1)
212 {
213 #if defined(USB_POLLING)
214 // If we are in polling mode the USB device tasks must be processed here
215 // (otherwise the interrupt is performing this task)
216 USBDeviceTasks();
217 #endif
218  
219 // Process USB Commands
220 processUsbCommands();
221  
222 // Note: Other application specific actions can be placed here
223 }
224 }
225  
226 // Initialise the PIC
227 static void initialisePic(void)
228 {
229 // PIC port set up --------------------------------------------------------
230  
231 // Default all pins to digital
232 ADCON1 = 0x0F;
233  
234 // Configure ports as inputs (1) or outputs(0)
235 TRISA = 0b00000000;
236 TRISB = 0b00000000;
237 TRISC = 0b00000000;
238 #if defined(__18F4550)
239 TRISD = 0b00000000;
240 TRISE = 0b00000000;
241 #endif
242  
243 // Clear all ports
244 PORTA = 0b00000000;
245 PORTB = 0b00000000;
246 PORTC = 0b00000000;
247 #if defined(__18F4550)
248 PORTD = 0b00000000;
249 PORTE = 0b00000000;
250 #endif
251  
252 // If you have a VBUS sense pin (for self-powered devices when you
253 // want to detect if the USB host is connected) you have to specify
254 // your input pin in HardwareProfile.h
255 #if defined(USE_USB_BUS_SENSE_IO)
256 tris_usb_bus_sense = INPUT_PIN;
257 #endif
258  
259 // In the case of a device which can be both self-powered and bus-powered
260 // the device must respond correctly to a GetStatus (device) request and
261 // tell the host how it is currently powered.
262 //
263 // To do this you must device a pin which is high when self powered and low
264 // when bus powered and define this in HardwareProfile.h
265 #if defined(USE_SELF_POWER_SENSE_IO)
266 tris_self_power = INPUT_PIN;
267 #endif
268  
269 // Application specific initialisation
270 applicationInit();
271  
272 // Initialise the USB device
273 USBDeviceInit();
274 }
275  
276 // Application specific device initialisation
277 void applicationInit(void)
278 {
279 // Initialise the status LEDs
280 mInitStatusLeds();
281  
282 // Initialise the switch
283 mInitAllSwitches();
284  
285 // Initialize the variable holding the USB handle for the last transmission
286 USBOutHandle = 0;
287 USBInHandle = 0;
288 }
289  
290 // Process USB commands
291 void processUsbCommands(void)
292 {
293 // Check if we are in the configured state; otherwise just return
294 if((USBDeviceState < CONFIGURED_STATE) || (USBSuspendControl == 1))
295 {
296 // We are not configured
297 return;
298 }
299  
300 // Check if data was received from the host.
301 if(!HIDRxHandleBusy(USBOutHandle))
302 {
303 // Command mode
304 switch(ReceivedDataBuffer[0])
305 {
306 case 0x10: // Debug information request from host
307 // Copy any waiting debug text to the send data buffer
308 copyDebugToSendBuffer((BYTE*)&ToSendDataBuffer[0]);
309  
310 // Transmit the response to the host
311 if(!HIDTxHandleBusy(USBInHandle))
312 {
313 USBInHandle = HIDTxPacket(HID_EP,(BYTE*)&ToSendDataBuffer[0],64);
314 }
315 break;
316  
317 // Place application specific commands here:
318  
319 case 0x80: // Toggle the LED
320 sprintf(debugString, "Received command 0x80 from host - Toggle LED");
321 debugOut(debugString);
322  
323 // Toggle the LED0
324 mStatusLED0_Toggle();
325 break;
326  
327 case 0x81: // Read the push switch status
328 ToSendDataBuffer[0] = sw0;
329  
330 // Transmit the response to the host
331 if(!HIDTxHandleBusy(USBInHandle))
332 {
333 USBInHandle = HIDTxPacket(HID_EP,(BYTE*)&ToSendDataBuffer[0],64);
334 }
335 break;
336  
337 case 0x82: // Read the LED status
338 // Get the LED state and put it in the send buffer
339 ToSendDataBuffer[0] = mStatusLED0_Get();
340  
341 // Transmit the response to the host
342 if(!HIDTxHandleBusy(USBInHandle))
343 {
344 USBInHandle = HIDTxPacket(HID_EP,(BYTE*)&ToSendDataBuffer[0],64);
345 }
346 break;
347  
348 default: // Unknown command received
349 break;
350 }
351  
352 // Re-arm the OUT endpoint for the next packet
353 USBOutHandle = HIDRxPacket(HID_EP,(BYTE*)&ReceivedDataBuffer,64);
354 }
355 }
356  
357 // USB Callback handling routines -----------------------------------------------------------
358  
359 // Call back that is invoked when a USB suspend is detected
360 void USBCBSuspend(void)
361 {
362 }
363  
364 // This call back is invoked when a wakeup from USB suspend is detected.
365 void USBCBWakeFromSuspend(void)
366 {
367 }
368  
369 // The USB host sends out a SOF packet to full-speed devices every 1 ms.
370 void USBCB_SOF_Handler(void)
371 {
372 // No need to clear UIRbits.SOFIF to 0 here. Callback caller is already doing that.
373 }
374  
375 // The purpose of this callback is mainly for debugging during development.
376 // Check UEIR to see which error causes the interrupt.
377 void USBCBErrorHandler(void)
378 {
379 // No need to clear UEIR to 0 here.
380 // Callback caller is already doing that.
381 }
382  
383 // Check other requests callback
384 void USBCBCheckOtherReq(void)
385 {
386 USBCheckHIDRequest();
387 }
388  
389 // Callback function is called when a SETUP, bRequest: SET_DESCRIPTOR request arrives.
390 void USBCBStdSetDscHandler(void)
391 {
392 // You must claim session ownership if supporting this request
393 }
394  
395 //This function is called when the device becomes initialized
396 void USBCBInitEP(void)
397 {
398 // Enable the HID endpoint
399 USBEnableEndpoint(HID_EP,USB_IN_ENABLED|USB_OUT_ENABLED|USB_HANDSHAKE_ENABLED|USB_DISALLOW_SETUP);
400  
401 // Re-arm the OUT endpoint for the next packet
402 USBOutHandle = HIDRxPacket(HID_EP,(BYTE*)&ReceivedDataBuffer,64);
403 }
404  
405 // Send resume call-back
406 void USBCBSendResume(void)
407 {
408 static WORD delay_count;
409  
410 // Verify that the host has armed us to perform remote wakeup.
411 if(USBGetRemoteWakeupStatus() == FLAG_TRUE)
412 {
413 // Verify that the USB bus is suspended (before we send remote wakeup signalling).
414 if(USBIsBusSuspended() == FLAG_TRUE)
415 {
416 USBMaskInterrupts();
417  
418 // Bring the clock speed up to normal running state
419 USBCBWakeFromSuspend();
420 USBSuspendControl = 0;
421 USBBusIsSuspended = FLAG_FALSE;
422  
423 // Section 7.1.7.7 of the USB 2.0 specifications indicates a USB
424 // device must continuously see 5ms+ of idle on the bus, before it sends
425 // remote wakeup signalling. One way to be certain that this parameter
426 // gets met, is to add a 2ms+ blocking delay here (2ms plus at
427 // least 3ms from bus idle to USBIsBusSuspended() == FLAG_TRUE, yeilds
428 // 5ms+ total delay since start of idle).
429 delay_count = 3600U;
430 do
431 {
432 delay_count--;
433 } while(delay_count);
434  
435 // Start RESUME signaling for 1-13 ms
436 USBResumeControl = 1;
437 delay_count = 1800U;
438 do
439 {
440 delay_count--;
441 } while(delay_count);
442 USBResumeControl = 0;
443  
444 USBUnmaskInterrupts();
445 }
446 }
447 }
448  
449 // USB callback function handler
450 BOOL USER_USB_CALLBACK_EVENT_HANDLER(USB_EVENT event, void *pdata, WORD size)
451 {
452 switch(event)
453 {
454 case EVENT_TRANSFER:
455 // Application callback tasks and functions go here
456 break;
457 case EVENT_SOF:
458 USBCB_SOF_Handler();
459 break;
460 case EVENT_SUSPEND:
461 USBCBSuspend();
462 break;
463 case EVENT_RESUME:
464 USBCBWakeFromSuspend();
465 break;
466 case EVENT_CONFIGURED:
467 USBCBInitEP();
468 break;
469 case EVENT_SET_DESCRIPTOR:
470 USBCBStdSetDscHandler();
471 break;
472 case EVENT_EP0_REQUEST:
473 USBCBCheckOtherReq();
474 break;
475 case EVENT_BUS_ERROR:
476 USBCBErrorHandler();
477 break;
478 default:
479 break;
480 }
481 return FLAG_TRUE;
482 }
483  
484 #endif