Added USE_INTERNAL_SERIAL compile time option to automatically read out the internal...
authorDean Camera <dean@fourwalledcubicle.com>
Sat, 20 Jun 2009 11:43:26 +0000 (11:43 +0000)
committerDean Camera <dean@fourwalledcubicle.com>
Sat, 20 Jun 2009 11:43:26 +0000 (11:43 +0000)
12 files changed:
Demos/Device/LowLevel/USBtoSerial/USBtoSerial.c
Demos/Host/LowLevel/GenericHIDHost/ConfigDescriptor.c
LUFA/Drivers/USB/Class/Device/CDC.c
LUFA/Drivers/USB/Class/Device/CDC.h
LUFA/Drivers/USB/Class/Host/CDC.c
LUFA/Drivers/USB/Class/Host/CDC.h
LUFA/Drivers/USB/HighLevel/StdDescriptors.h
LUFA/Drivers/USB/LowLevel/DevChapter9.c
LUFA/Drivers/USB/LowLevel/DevChapter9.h
LUFA/ManPages/ChangeLog.txt
LUFA/ManPages/CompileTimeTokens.txt
LUFA/ManPages/LUFAPoweredProjects.txt

index 3ed406d..444aa5e 100644 (file)
@@ -265,7 +265,7 @@ void CDC_Task(void)
                        while (!(Endpoint_IsReadWriteAllowed()));\r
                        \r
                        /* Write the bytes from the buffer to the endpoint while space is available */\r
-                       while (Tx_Buffer.Elements && (Endpoint_BytesInEndpoint() < CDC_TXRX_EPSIZE))\r
+                       while (Tx_Buffer.Elements && Endpoint_IsReadWriteAllowed())\r
                        {\r
                                /* Write each byte retreived from the buffer to the endpoint */\r
                                Endpoint_Write_Byte(Buffer_GetElement(&Tx_Buffer));\r
index 2a6e152..26181c1 100644 (file)
@@ -134,7 +134,7 @@ uint8_t DComp_NextHIDInterface(void* CurrentDescriptor)
        /* Determine if the current descriptor is an interface descriptor */\r
        if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface)\r
        {\r
-               /* Check the HID descriptor class and protocol, break out if correct class/protocol interface found */\r
+               /* Check the HID descriptor class, break out if correct class/protocol interface found */\r
                if (DESCRIPTOR_CAST(CurrentDescriptor, USB_Descriptor_Interface_t).Class == HID_CLASS)\r
                {\r
                        /* Indicate that the descriptor being searched for has been found */\r
index cc8161e..fc6ea93 100644 (file)
@@ -74,7 +74,7 @@ void CDC_Device_ProcessControlPacket(USB_ClassInfo_CDC_Device_t* CDCInterfaceInf
                        {                               \r
                                Endpoint_ClearSETUP();\r
                                \r
-                               CDCInterfaceInfo->State.ControlLineState = USB_ControlRequest.wValue;\r
+                               CDCInterfaceInfo->State.ControlLineStates.HostToDevice = USB_ControlRequest.wValue;\r
                                \r
                                EVENT_CDC_Device_ControLineStateChanged(CDCInterfaceInfo);\r
 \r
@@ -178,7 +178,7 @@ uint8_t CDC_Device_ReceiveByte(USB_ClassInfo_CDC_Device_t* CDCInterfaceInfo)
        return DataByte;\r
 }\r
 \r
-void CDC_Device_SendControlLineStateChange(USB_ClassInfo_CDC_Device_t* CDCInterfaceInfo, uint16_t LineStateMask)\r
+void CDC_Device_SendControlLineStateChange(USB_ClassInfo_CDC_Device_t* CDCInterfaceInfo)\r
 {\r
        if (!(USB_IsConnected))\r
          return;\r
@@ -195,7 +195,7 @@ void CDC_Device_SendControlLineStateChange(USB_ClassInfo_CDC_Device_t* CDCInterf
                };\r
 \r
        Endpoint_Write_Stream_LE(&Notification, sizeof(Notification), NO_STREAM_CALLBACK);\r
-       Endpoint_Write_Stream_LE(&LineStateMask, sizeof(LineStateMask), NO_STREAM_CALLBACK);\r
+       Endpoint_Write_Stream_LE(&CDCInterfaceInfo->State.ControlLineStates.DeviceToHost, sizeof(uint8_t), NO_STREAM_CALLBACK);\r
        Endpoint_ClearIN();\r
 }\r
 \r
index 13fa8d3..bcf8ff7 100644 (file)
                        /** Current State information structure for \ref USB_ClassInfo_CDC_Device_t CDC device interface structures. */\r
                        typedef struct\r
                        {\r
-                               uint8_t  ControlLineState; /**< Current control line states, as set by the host */\r
+                               struct\r
+                               {\r
+                                       uint8_t HostToDevice; /**< Control line states from the host to device, as a set of CDC_CONTROL_LINE_OUT_*\r
+                                                              *   masks.\r
+                                                              */\r
+                                       uint8_t DeviceToHost; /**< Control line states from the device to host, as a set of CDC_CONTROL_LINE_IN_*\r
+                                                              *   masks.\r
+                                                              */\r
+                               } ControlLineStates;\r
 \r
                                struct\r
                                {\r
                        /** CDC class driver event for a control line state change on a CDC interface. This event fires each time the host requests a\r
                         *  control line state change (containing the virtual serial control line states, such as DTR) and may be hooked in the\r
                         *  user program by declaring a handler function with the same name and parameters listed here. The new control line states\r
-                        *  are available in the ControlLineState value inside the CDC interface structure passed as a parameter, set as a mask of\r
-                        *  CDC_CONTROL_LINE_OUT_* masks.\r
+                        *  are available in the ControlLineStates.HostToDevice value inside the CDC interface structure passed as a parameter, set as\r
+                        *  a mask of CDC_CONTROL_LINE_OUT_* masks.\r
                         *\r
                         *  \param CDCInterfaceInfo  Pointer to a structure containing a CDC Class configuration and state.\r
                         */             \r
                         */\r
                        uint8_t CDC_Device_ReceiveByte(USB_ClassInfo_CDC_Device_t* CDCInterfaceInfo);\r
                        \r
-                       /** Sends a Serial Control Line State Change notification to the host. This should be called when the virtual serial control\r
-                        *  lines (DCD, DSR, etc.) have changed states, or to give BREAK notfications to the host. Line states persist until they are\r
-                        *  cleared via a second notification.\r
+                       /** Sends a Serial Control Line State Change notification to the host. This should be called when the virtual serial\r
+                        *  control lines (DCD, DSR, etc.) have changed states, or to give BREAK notfications to the host. Line states persist\r
+                        *  until they are cleared via a second notification. This should be called each time the CDC class driver's \r
+                        *  ControlLineStates.DeviceToHost value is updated to push the new states to the USB host.\r
                         *\r
                         *  \param CDCInterfaceInfo  Pointer to a structure containing a CDC Class configuration and state.\r
-                        *  \param LineStateMask  Mask of CDC_CONTROL_LINE_IN_* masks giving the current control line states\r
                         */\r
-                       void CDC_Device_SendControlLineStateChange(USB_ClassInfo_CDC_Device_t* CDCInterfaceInfo, uint16_t LineStateMask);\r
+                       void CDC_Device_SendControlLineStateChange(USB_ClassInfo_CDC_Device_t* CDCInterfaceInfo);\r
 \r
        /* Private Interface - For use in library only: */\r
        #if !defined(__DOXYGEN__)\r
index aef5b35..2d5ec0f 100644 (file)
@@ -71,7 +71,6 @@ static uint8_t CDC_Host_ProcessConfigDescriptor(USB_ClassInfo_CDC_Host_t* CDCInt
                                if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData, \r
                                                              DComp_CDC_Host_NextCDCDataInterface) != DESCRIPTOR_SEARCH_COMP_Found)\r
                                {\r
-                                       /* Descriptor not found, error out */\r
                                        return CDC_ENUMERROR_NoCDCInterfaceFound;\r
                                }\r
                        }\r
@@ -149,10 +148,12 @@ static uint8_t DComp_CDC_Host_NextCDCControlInterface(void* CurrentDescriptor)
 {\r
        if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface)\r
        {\r
-               /* Check the CDC descriptor class, subclass and protocol, break out if correct control interface found */\r
-               if ((DESCRIPTOR_CAST(CurrentDescriptor, USB_Descriptor_Interface_t).Class    == CDC_CONTROL_CLASS)    &&\r
-                   (DESCRIPTOR_CAST(CurrentDescriptor, USB_Descriptor_Interface_t).SubClass == CDC_CONTROL_SUBCLASS) &&\r
-                   (DESCRIPTOR_CAST(CurrentDescriptor, USB_Descriptor_Interface_t).Protocol == CDC_CONTROL_PROTOCOL))\r
+               USB_Descriptor_Interface_t* CurrentInterface = DESCRIPTOR_PCAST(CurrentDescriptor,\r
+                                                                               USB_Descriptor_Interface_t);\r
+       \r
+               if ((CurrentInterface->Class    == CDC_CONTROL_CLASS)    &&\r
+                   (CurrentInterface->SubClass == CDC_CONTROL_SUBCLASS) &&\r
+                       (CurrentInterface->Protocol == CDC_CONTROL_PROTOCOL))\r
                {\r
                        return DESCRIPTOR_SEARCH_Found;\r
                }\r
@@ -165,10 +166,12 @@ static uint8_t DComp_CDC_Host_NextCDCDataInterface(void* CurrentDescriptor)
 {\r
        if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface)\r
        {\r
-               /* Check the CDC descriptor class, subclass and protocol, break out if correct data interface found */\r
-               if ((DESCRIPTOR_CAST(CurrentDescriptor, USB_Descriptor_Interface_t).Class    == CDC_DATA_CLASS)    &&\r
-                   (DESCRIPTOR_CAST(CurrentDescriptor, USB_Descriptor_Interface_t).SubClass == CDC_DATA_SUBCLASS) &&\r
-                   (DESCRIPTOR_CAST(CurrentDescriptor, USB_Descriptor_Interface_t).Protocol == CDC_DATA_PROTOCOL))\r
+               USB_Descriptor_Interface_t* CurrentInterface = DESCRIPTOR_PCAST(CurrentDescriptor,\r
+                                                                               USB_Descriptor_Interface_t);\r
+       \r
+               if ((CurrentInterface->Class    == CDC_DATA_CLASS)    &&\r
+                   (CurrentInterface->SubClass == CDC_DATA_SUBCLASS) &&\r
+                       (CurrentInterface->Protocol == CDC_DATA_PROTOCOL))\r
                {\r
                        return DESCRIPTOR_SEARCH_Found;\r
                }\r
@@ -181,8 +184,10 @@ static uint8_t DComp_CDC_Host_NextInterfaceCDCDataEndpoint(void* CurrentDescript
 {\r
        if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Endpoint)\r
        {\r
-               uint8_t EndpointType = (DESCRIPTOR_CAST(CurrentDescriptor,\r
-                                                       USB_Descriptor_Endpoint_t).Attributes & EP_TYPE_MASK);\r
+               USB_Descriptor_Endpoint_t* CurrentEndpoint = DESCRIPTOR_PCAST(CurrentDescriptor,\r
+                                                                             USB_Descriptor_Endpoint_t)\r
+       \r
+               uint8_t EndpointType = (CurrentEndpoint->Attributes & EP_TYPE_MASK);\r
        \r
                if ((EndpointType == EP_TYPE_BULK) || (EndpointType == EP_TYPE_INTERRUPT))\r
                  return DESCRIPTOR_SEARCH_Found;\r
@@ -215,7 +220,6 @@ void CDC_Host_USBTask(USB_ClassInfo_CDC_Host_t* CDCInterfaceInfo)
                        USB_HostState = HOST_STATE_Configured;\r
                        break;\r
                case HOST_STATE_Configured:\r
-                               \r
                        USB_HostState = HOST_STATE_Ready;\r
                        break;\r
        }\r
index 859c41d..4054cf1 100644 (file)
                                uint16_t DataOUTPipeSize;  /**< Size in bytes of the CDC interface's OUT data pipe */\r
                                uint16_t NotificationPipeSize;  /**< Size in bytes of the CDC interface's IN notification endpoint, if used */\r
 \r
-                               uint8_t  ControlLineState; /**< Current control line states */\r
-\r
+                               struct\r
+                               {\r
+                                       uint8_t HostToDevice; /**< Control line states from the host to device, as a set of CDC_CONTROL_LINE_OUT_*\r
+                                                              *   masks.\r
+                                                              */\r
+                                       uint8_t DeviceToHost; /**< Control line states from the device to host, as a set of CDC_CONTROL_LINE_IN_*\r
+                                                              *   masks.\r
+                                                              */\r
+                               } ControlLineStates;\r
+                               \r
                                struct\r
                                {\r
                                        uint32_t BaudRateBPS; /**< Baud rate of the virtual serial port, in bits per second */\r
@@ -80,7 +88,7 @@
                                                                                  *   CDCDevice_LineCodingParity_t enum\r
                                                                                  */\r
                                        uint8_t  DataBits; /**< Bits of data per character of the virtual serial port */\r
-                               } LineEncoding;                 \r
+                               } LineEncoding;\r
                        } USB_ClassInfo_CDC_Host_State_t;\r
 \r
                        /** Class state structure. An instance of this structure should be made within the user application,\r
                                static uint8_t DComp_CDC_Host_NextCDCDataInterface(void* CurrentDescriptor);\r
                                static uint8_t DComp_CDC_Host_NextInterfaceCDCDataEndpoint(void* CurrentDescriptor);\r
                        #endif\r
+\r
+                       void EVENT_CDC_Host_ControLineStateChanged(USB_ClassInfo_CDC_Host_t* CDCInterfaceInfo);\r
+                       \r
+                       uint8_t CDC_Host_SetLineEncoding(USB_ClassInfo_CDC_Host_t* CDCInterfaceInfo);\r
+                       uint8_t CDC_Host_SendControlLineStateChange(USB_ClassInfo_CDC_Host_t* CDCInterfaceInfo);\r
+                       \r
+                       void CDC_Host_SendString(USB_ClassInfo_CDC_Host_t* CDCInterfaceInfo, char* Data, uint16_t Length);\r
+                       void CDC_Host_SendByte(USB_ClassInfo_CDC_Host_t* CDCInterfaceInfo, uint8_t Data);\r
+                       uint16_t CDC_Host_BytesReceived(USB_ClassInfo_CDC_Host_t* CDCInterfaceInfo);\r
+                       uint8_t CDC_Host_ReceiveByte(USB_ClassInfo_CDC_Host_t* CDCInterfaceInfo);\r
        \r
        #endif\r
                                \r
index 7a0ca52..2ce75b2 100644 (file)
                                                                          */\r
                                uint8_t                 SerialNumStrIndex; /**< String index for the product's globally unique hexadecimal\r
                                                                            *   serial number, in uppercase Unicode ASCII.\r
-                                                                           *\r
+                                                                                                                       *\r
+                                                                                                                       *  \note On some AVR models, there is an embedded serial number\r
+                                                                                                                       *        in the chip which can be used for the device serial number.\r
+                                                                           *        To use this serial number, define USE_INTERNAL_SERIAL to a\r
+                                                                                                                       *        unique string index number in the project makefile and set\r
+                                                                                                                       *        this value to USE_INTERNAL_SERIAL.\r
+                                                                                                                       *\r
                                                                            *  \see ManufacturerStrIndex structure entry.\r
                                                                            */\r
 \r
index 829bd13..9acf300 100644 (file)
@@ -179,6 +179,36 @@ static void USB_Device_GetDescriptor(void)
        void*    DescriptorPointer;\r
        uint16_t DescriptorSize;\r
        \r
+       #if defined(USE_INTERNAL_SERIAL)\r
+       if (USB_ControlRequest.wValue == ((DTYPE_String << 8) | USE_INTERNAL_SERIAL))\r
+       {\r
+               uint8_t SignatureDescriptor[2 + (sizeof(int16_t) * 20)];\r
+\r
+               SignatureDescriptor[0] = sizeof(SignatureDescriptor);\r
+               SignatureDescriptor[1] = DTYPE_String;\r
+               \r
+               uint16_t* SigUnicodeChars = (uint16_t*)&SignatureDescriptor[2];\r
+\r
+               for (uint8_t SerialByteNum = 0; SerialByteNum < 10; SerialByteNum++)\r
+               {\r
+                       char ConvSigString[3];\r
+\r
+                       itoa(boot_signature_byte_get(0x0E + SerialByteNum), ConvSigString, 16);\r
+                       \r
+                       SigUnicodeChars[0] = toupper(ConvSigString[0]);\r
+                       SigUnicodeChars[1] = toupper(ConvSigString[1]);\r
+                       \r
+                       SigUnicodeChars += 2;\r
+               }\r
+               \r
+               Endpoint_ClearSETUP();\r
+               Endpoint_Write_Control_Stream_LE(SignatureDescriptor, sizeof(SignatureDescriptor));\r
+               Endpoint_ClearOUT();\r
+\r
+               return;\r
+       }\r
+       #endif\r
+       \r
        if ((DescriptorSize = CALLBACK_USB_GetDescriptor(USB_ControlRequest.wValue, USB_ControlRequest.wIndex,\r
                                                         &DescriptorPointer)) == NO_DESCRIPTOR)\r
        {\r
@@ -186,7 +216,7 @@ static void USB_Device_GetDescriptor(void)
        }\r
        \r
        Endpoint_ClearSETUP();\r
-       \r
+\r
        #if defined(USE_RAM_DESCRIPTORS)\r
        Endpoint_Write_Control_Stream_LE(DescriptorPointer, DescriptorSize);\r
        #else\r
index 68cb2c4..65fa041 100644 (file)
@@ -35,6 +35,9 @@
                #include <avr/io.h>\r
                #include <avr/pgmspace.h>\r
                #include <avr/eeprom.h>\r
+               #include <avr/boot.h>\r
+               #include <stdlib.h>\r
+               #include <ctype.h>\r
                \r
                #include "../HighLevel/StdDescriptors.h"\r
                #include "../HighLevel/Events.h"\r
                #include "../HighLevel/USBTask.h"\r
                #include "LowLevel.h"\r
 \r
+       /* Preprocessor Checks: */\r
+               #if defined(USE_INTERNAL_SERIAL) && !(defined(USB_SERIES_6_AVR) || defined(USB_SERIES_7_AVR))\r
+                       #error USE_INTERNAL_SERIAL invalid, the selected AVR model does not contain unique serial bytes.\r
+               #endif\r
+               \r
+               #if defined(USE_INTERNAL_SERIAL) && (USE_INTERNAL_SERIAL <= 1)\r
+                       #error USE_INTERNAL_SERIAL must be defined to the string descriptor index chosen for the serial number descriptor.\r
+               #endif\r
+\r
        /* Enable C linkage for C++ Compilers: */\r
                #if defined(__cplusplus)\r
                        extern "C" {\r
index 4644181..f7ae4c6 100644 (file)
@@ -8,7 +8,7 @@
   *\r
   *  \section Sec_ChangeLogXXXXXX Version XXXXXX\r
   *\r
-  *  - Removed psuedo-scheduler, dynamic memory block allocator from the library (no longer needed and not used respectively)\r
+  *  - Deprecated psuedo-scheduler and removed dynamic memory allocator from the library (first no longer needed and second unused)\r
   *  - Added new class drivers and matching demos to the library for rapid application development\r
   *  - Added incomplete device and host mode demos for later enhancement\r
   *  - Changed bootloaders to use FLASHEND rather than the existence of RAMPZ to determine if far FLASH pointers are needed\r
@@ -28,6 +28,7 @@
   *    cleared to prevent endpoint type corruption\r
   *  - Fix documentation mentioning Pipe_GetCurrentToken() function when real name is Pipe_GetPipeToken()\r
   *  - Extend USB_GetDeviceConfigDescriptor() routine to require the configuration number within the device to fetch\r
+  *  - Added new USE_INTERNAL_SERIAL compile time option\r
   *\r
   *  \section Sec_ChangeLog090605 Version 090605\r
   *\r
index d8a7cf7..e1f248d 100644 (file)
  *  compatibility. If this token is defined, the structure element names are switched to the LUFA-specific but more descriptive\r
  *  names documented in the StdDescriptors.h source file.\r
  *\r
+ *  <b>USE_INTERNAL_SERIAL</b> - ( \ref Group_Descriptors ) \n\r
+ *  Some AVR models contain a unique 20-digit serial number which can be used as the device serial number, while in device mode. This\r
+ *  allows the host to uniquely identify the device regardless of if it is moved between USB ports on the same computer, allowing\r
+ *  allocated resources (such as drivers, COM Port number allocations) to be preserved. To make the library use this value for the\r
+ *  device's serial number, define this token in the project makefile, set it to a unique string descriptor index (i.e. one not used\r
+ *  elsewhere in the device for a string descriptor) and set the Device Descriptor's serial number descriptor index entry to the\r
+ *  USE_INTERNAL_SERIAL value.\r
+ *\r
  *  <b>FIXED_CONTROL_ENDPOINT_SIZE</b> - ( \ref Group_EndpointManagement ) \n\r
  *  By default, the library determines the size of the control endpoint (when in device mode) by reading the device descriptor.\r
  *  Normally this reduces the amount of configuration required for the library, allows the value to change dynamically (if\r
index b93604e..1f9a317 100644 (file)
  *  If you have a project that you would like to add to this list, please contact me via the details on the main page of this\r
  *  documentation.\r
  *\r
+ *  \section Sec_BoardsUsingLUFA AVR-USB Development Boards Using LUFA\r
+ *\r
+ *  The following is a list of known AVR USB development boards, which recommend using LUFA for the USB stack. Some of these\r
+ *  are open design, and all are available for purchase as completed development boards suitable for project development.\r
+ *\r
+ *  - AVROpendous, an open design/source set of AVR USB development boards: http://avropendous.org/\r
+ *  - Teensy and Teensy++, two other AVR USB development boards: http://www.pjrc.com/teensy/index.html\r
+ *  - USBFoo, an AT90USB162 based development board: http://shop.kernelconcepts.de/product_info.php?products_id=102\r
+ *  - USB10 AKA "The Ferret", a AT90USB162 development board: http://www.soc-machines.com\r
+ * \r
+ *  \section Sec_LUFAProjects Projects Using LUFA (Hobbyist)\r
+ *\r
+ *  The following are hobbyist projects using LUFA. Most are open source, and show off interesting ways that the LUFA library\r
+ *  can be incorporated into many different applications.\r
  *\r
- *  - Benito #7, an AVR Programmer: http://www.dorkbotpdx.org/blog/feurig/benito_7_the_next_big_thing\r
  *  - Stripe Snoop, a Magnetic Card reader: http://www.ossguy.com/ss_usb/\r
- *  - USB10 AKA "The Ferret", a USB162 development board: http://www.soc-machines.com\r
+ *  - Benito #7, an AVR Programmer: http://www.dorkbotpdx.org/blog/feurig/benito_7_the_next_big_thing\r
  *  - Bicycle POV: http://www.code.google.com/p/bicycleledpov/\r
- *  - Digital Survey Instruments Magnetometer and Pointer: http://www.digitalsurveyinstruments.com/\r
- *  - ARPS Locator: http://la3t.hamradio.no/lab//?id=tracker_en\r
- *  - Lightweight CC110x USB dongle for 868MHz Protocols: http://busware.de/tiki-index.php?page=CUL\r
- *  - AVROpendous, an open design/source AT90USB162 development board: http://avropendous.org/\r
  *  - USB Interface for Playstation Portable Devices: http://forums.ps2dev.org/viewtopic.php?t=11001\r
  *  - USB to Serial Bridge, via SPI and I2C: http://www.tty1.net/userial/\r
- *  - Teensy, another tiny AT90USB162 development board: http://www.pjrc.com/teensy/index.html\r
  *  - SEGA Megadrive/Genesis Development Cartridge: http://www.spritesmind.net/_GenDev/forum/viewtopic.php?t=464\r
  *  - CAMTRIG, a remote Camera Trigger device: http://code.astraw.com/projects/motmot/camtrig\r
  *  - Opendous-JTAG, an open source JTAG device: http://code.google.com/p/opendous-jtag/\r
  *  - Openkubus, an open source hardware-based authentication dongle: http://code.google.com/p/openkubus/\r
+ * \r
+ *  \section Sec_LUFACommercialProjects Projects Using LUFA (Commercial)\r
+ *\r
+ *  The following is a list of known commercial products using LUFA. Some of these are open source, although many are "black-box"\r
+ *  solutions with no source code given.\r
+ *\r
+ *  - ARPS Locator: http://la3t.hamradio.no/lab//?id=tracker_en\r
+ *  - Digital Survey Instruments Magnetometer and Pointer: http://www.digitalsurveyinstruments.com/\r
+ *  - Lightweight CC110x USB dongle for 868MHz Protocols: http://busware.de/tiki-index.php?page=CUL\r
  */
\ No newline at end of file