class library to access fischertechnik interfaces via USB
Dependencies: FatFileSystem mbed myBlueUSB neigbourhood rfcomm sdp
Revision 0:7da612835693, committed 2011-06-15
- Comitter:
- networker
- Date:
- Wed Jun 15 19:12:25 2011 +0000
- Child:
- 1:4676e8b9b357
- Commit message:
- initial version
; Bluetooth support incomplete
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/AvailableMemory.cpp Wed Jun 15 19:12:25 2011 +0000 @@ -0,0 +1,34 @@ +#include "AvailableMemory.h" +#include <stdlib.h> + +namespace segundo { +namespace Utilities { + +int AvailableMemory(int resolution, int maximum, bool disableInterrupts) { + + if (resolution < 1) resolution = 1; + if (maximum < 0) maximum = 0; + + int low = 0; + int high = maximum + 1; + + if (disableInterrupts) __disable_irq(); + + while (high - low > resolution) { + int mid = (low + high) / 2; + void* p = malloc(mid); + if (p == NULL) { + high = mid; + } else { + free(p); + low = mid; + } + } + + if (disableInterrupts) __enable_irq(); + + return low; +} + +} // namespace Utilities +} // namespace segundo \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/AvailableMemory.h Wed Jun 15 19:12:25 2011 +0000 @@ -0,0 +1,46 @@ +/** @file + * Return the memory available for a malloc call. + */ +#ifndef SEGUNDO_UTILITIES_AVAILABLEMEMORY_H +#define SEGUNDO_UTILITIES_AVAILABLEMEMORY_H + +/** + * Segundo Equipo + */ +namespace segundo { +/** + * A collection of utilities + */ +namespace Utilities { + +/** Return the memory available for a malloc call. + * This is done by a binary search approach + * calling malloc/free starting with a maximum. + * + * Example: + * @code + * #include <stdio.h> + * #include "AvailableMemory.h" + * + * int main() { + * + * printf("Available memory (bytes to nearest 256) : %d\n", AvailableMemory()); + * printf("Available memory (exact bytes) : %d\n", AvailableMemory(1)); + * + * } + * @endcode + * @param resolution Resolution in number of bytes, + * 1 will return the exact value, + * default will return the available memory to the nearest 256 bytes + * @param maximum Maximum amount of memory to check, default is 32K (0x8000) + * @param disableInterrupts Disable interrupts whilst checking, default is true + * @return Available memory in bytes accurate to within resolution + */ +int AvailableMemory(int resolution = 256, int maximum = 0x8000, bool disableInterrupts = true); + +} // namespace Utilities +} // namespace segundo + +using namespace segundo::Utilities; + +#endif // SEGUNDO_UTILITIES_AVAILABLEMEMORY_H \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/FATFileSystem.lib Wed Jun 15 19:12:25 2011 +0000 @@ -0,0 +1,1 @@ +http://mbed.co.uk/projects/libraries/svn/FATFileSystem/trunk@19 \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ROBO_TX_FW.h Wed Jun 15 19:12:25 2011 +0000 @@ -0,0 +1,356 @@ +//============================================================================= +// | +// Headerfile | robo_tx_fw.h +// | +// Description | Header file with definition of the software interface +// | to the ROBO TX Controller firmware. +// | Can be used for building C-programs which can run +// | under control of the ROBO TX Controller firmware in +// | download (local) mode or for building PC-programs which +// | can communicate with the ROBO TX Controller firmware in +// | online mode. +// | +//----------------------------------------------------------------------------- +// Disclaimer - Exclusion of Liability +// +// This software is distributed in the hope that it will be useful,but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. It can be used an modified by anyone +// free of any license obligations or authoring rights. +//============================================================================= + +#ifndef __ROBO_TX_FW_H__ +#define __ROBO_TX_FW_H__ + + +#define N_CNT 4 // number of counters +#define N_PWM_CHAN 8 // number of PWM channels +#define N_MOTOR 4 // number of motors +#define N_UNI 8 // number of universal inputs + +// 5kOhm Range +#define R_MIN 10 // [Ohm] +#define R_MAX 4999 // [Ohm] +#define R_OVR 5000 // [Ohm] overload + +// 10V Range +#define U_MIN 0 // [mV] +#define U_MAX 9999 // [mV] +#define U_OVR 10000 // [mV] overload + +// Ultrasonic Sensor Range +#define ULTRASONIC_MIN 2 // [cm] +#define ULTRASONIC_MAX 1023 // [cm] +#define ULTRASONIC_OVR 1024 // [cm] overload +#define NO_ULTRASONIC 4096 // not present + +// Length of strings +#define DEV_NAME_LEN 16 // "ROBO TX-xxxxxxxx" +#define BLUETOOTH_ADDR_LEN 17 // "xx:xx:xx:xx:xx:xx" +#define DISPL_MSG_LEN_MAX 64 // max length of a pop-up display message + + +// Identifiers of the Transfer Area parts +enum ta_id_e +{ + TA_LOCAL = 0, // Local part of Transfer Area. Corresponds to the device on which + // program is currently running in download (local) mode or to the + // remotely controlled device (seen from controlled device not from + // controlling device) in online mode. + TA_EXT_1, // Extension 1 part of Transfer Area + TA_EXT_2, // Extension 2 part of Transfer Area + TA_EXT_3, // Extension 3 part of Transfer Area + TA_EXT_4, // Extension 4 part of Transfer Area + TA_EXT_5, // Extension 5 part of Transfer Area + TA_EXT_6, // Extension 6 part of Transfer Area + TA_EXT_7, // Extension 7 part of Transfer Area + TA_EXT_8, // Extension 8 part of Transfer Area + TA_N_PARTS // Number of Transfer Area parts +}; + +#define N_EXT_DEV (TA_N_PARTS - 1) // Number of extension devices = 8 + + +// Device functioning modes +enum dev_mode_e +{ + DEV_MODE_LOCAL = 0, + DEV_MODE_ONLINE, + DEV_MODE_INVALID +}; + + +// State of connection to an extension device +enum ext_dev_connect_state_e +{ + EXT_DEV_OFFLINE = 0, + EXT_DEV_ONLINE, + EXT_DEV_INVALID +}; + + +// Modes of universal inputs +enum input_mode_e +{ + MODE_U = 0, + MODE_R = 1, + MODE_ULTRASONIC = 3, + MODE_INVALID +}; + + +// Program states +enum pgm_state_e +{ + PGM_STATE_INVALID = 0, + PGM_STATE_RUN, + PGM_STATE_STOP +}; + + +// Timer units for GetSystemTime hook function +enum TimerUnit +{ + TIMER_UNIT_INVALID = 0, + TIMER_UNIT_SECONDS = 2, + TIMER_UNIT_MILLISECONDS = 3, + TIMER_UNIT_MICROSECONDS = 4 +}; + + +//============================================================================= +// Structures for Transfer Area (TA) +//============================================================================= + + +// Program information, 8 bytes +typedef struct +{ + char * name; // name of a program with a full path, for example, "/ramdisk/Program_1" + UINT8 state; // enum pgm_state_e + char reserved[3]; +} PGM_INFO; + + +// Display message, 68 bytes. Used to show pop-up message box on the boards display +typedef struct +{ + unsigned char id; // should be increased by 1 each time a new pop-up message is to be shown + char text[DISPL_MSG_LEN_MAX + 1]; + char reserved[2]; +} DISPLAY_MSG; + + +// Display frame, 8 bytes. Used to refresh boards display with a bitmap image frame +typedef struct +{ + unsigned char * frame; // contents of a frame as a 128x64 pixels bitmap + UINT16 id; // should be increased by 1 each time a new display frame is to be shown + BOOL16 is_pgm_master_of_display; // ++ if program wants to have control over display, + // i.e. image frame is displayed over firmware menus; + // -- if program wants to return control over display + // to the firmware menus +} DISPLAY_FRAME; + + +// Version structure definition, 4 bytes +typedef union +{ + unsigned long abcd; + struct + { + unsigned char a; + unsigned char b; + unsigned char c; + unsigned char d; + } part; +} FT_VER; + + +// Versions of hardware and firmware components, 16 bytes +typedef struct +{ + FT_VER hardware; // version of hardware (hardware.part.a = 'A' or 'B' or 'C') + FT_VER firmware; // version of firmware ("V %d.%02d", firmware.part.c, firmware.part.d) + FT_VER ta; // version of transfer area ("V %d.%02d", ta.part.c, ta.part.d) + char reserved[4]; +} FT_VERSION; + + +// Info structure, 64 bytes +typedef struct +{ + char device_name[DEV_NAME_LEN + 1]; + char bt_addr[BLUETOOTH_ADDR_LEN + 1]; + char reserved; + unsigned long ta_start_addr; + unsigned long pgm_area_start_addr; + unsigned long pgm_area_size; + FT_VERSION version; +} TA_INFO; + + +// State structure, 36 bytes +typedef struct +{ + // Used by local program + BOOL8 pgm_initialized; + char reserved_1[7]; + + // Public state info + BOOL8 dev_mode; // enum dev_mode_e + UCHAR8 id; // Should be increased by 1 each time something (except id fields) + // is changed in this state structure + UCHAR8 info_id; // Should be increased by 1 each time something is changed in info structure + UCHAR8 config_id; // Should be increased by 1 each time something is changed in config structure + BOOL8 ext_dev_connect_state[N_EXT_DEV]; // enum ext_dev_connect_state_e + char reserved_2[8]; + PGM_INFO local_pgm; // Corresponds to the program currently being in the program memory +} TA_STATE; + + +// Universal inputs configuration, 4 bytes +typedef struct +{ + UINT8 mode; // enum input_mode_e + BOOL8 digital; // FALSE = analog input, TRUE = digital input + unsigned char reserved[2]; +} UNI_CONFIG; + + +// Counter inputs configuration, 4 bytes +typedef struct +{ + UINT8 mode; // enum input_mode_e + unsigned char reserved[3]; +} CNT_CONFIG; + + +// Config structure, 88 bytes +typedef struct +{ + UINT8 pgm_state_req; // enum pgm_state_e + char reserved_1[3]; + BOOL8 motor[N_MOTOR]; + UNI_CONFIG uni[N_UNI]; + CNT_CONFIG cnt[N_CNT]; + char reserved_2[32]; +} TA_CONFIG; + + +// Input structure, 40 bytes +typedef struct +{ + INT16 uni[N_UNI]; + INT16 cnt_in[N_CNT]; + INT16 counter[N_CNT]; + // Number of milliseconds during which the left display button is being kept pressed + INT16 display_button_left; + // Number of milliseconds during which the right display button is being kept pressed + INT16 display_button_right; + // Set to 1 by motor control if target position is reached + INT16 motor_pos_reached[N_MOTOR]; +} TA_INPUT; + + +// Output structure, 36 bytes +typedef struct +{ + // Counter reset requests + BOOL8 cnt_reset[N_CNT]; + // If not 0, synchronize this channel with the given channel (1:channel 0, ...) + UINT8 master[N_MOTOR]; + // Selected motor PWM values + INT16 duty[N_PWM_CHAN]; + // Selected distane (counter value) at which motor shall stop + UINT16 distance[N_MOTOR]; + char reserved[4]; +} TA_OUTPUT; + + +// Display structure, 76 bytes +typedef struct +{ + DISPLAY_MSG display_msg; + DISPLAY_FRAME display_frame; +} TA_DISPLAY; + + +// Change structure (only for ftMscLib), 8 bytes +typedef struct +{ + char reserved_1[2]; + UINT8 ChangeStatus; + UINT8 ChangeUni; + UINT8 ChangeCntIn; + UINT8 ChangeCounter; + char reserved_2[2]; +} TA_CHANGE; + + +// 16-bit timers, 12 bytes +typedef struct +{ + UINT16 Timer1ms; + UINT16 Timer10ms; + UINT16 Timer100ms; + UINT16 Timer1s; + UINT16 Timer10s; + UINT16 Timer1min; +} TA_TIMER; + + +// Hook table with pointers to the firmware functions, +// that can be called by local program, 4 bytes +typedef struct +{ + INT32 (*IsRunAllowed) (void); + UINT32 (*GetSystemTime)(enum TimerUnit unit); +} TA_HOOK_TABLE; + + + +// ============================================================================ +// Transfer Area (TA) of ROBO TX Controller (one part of TA_N_PARTS) +// ============================================================================ +#define RESERVED_1_SIZE 4 +#define RESERVED_2_SIZE 28 +#define RESERVED_3_SIZE \ + (512 - ( \ + sizeof(TA_INFO) + \ + sizeof(TA_STATE) + \ + sizeof(TA_CONFIG) + \ + sizeof(TA_INPUT) + \ + sizeof(TA_OUTPUT) + \ + sizeof(TA_DISPLAY) + \ + RESERVED_1_SIZE + \ + sizeof(TA_CHANGE) + \ + sizeof(TA_TIMER) + \ + RESERVED_2_SIZE + \ + sizeof(TA_HOOK_TABLE) \ + )) + + +typedef struct +{ + TA_INFO info; // info structure + TA_STATE state; // state structure + TA_CONFIG config; // config structure + TA_INPUT input; // input structure + TA_OUTPUT output; // output structure + TA_DISPLAY display; // display structure + + char reserved_1[RESERVED_1_SIZE]; + + TA_CHANGE change; // change structure + TA_TIMER timer; // 16-bit timers + + char reserved_2[RESERVED_2_SIZE]; + + TA_HOOK_TABLE hook_table; // hook table with functions pointers + + char reserved_3[RESERVED_3_SIZE]; +} TA; + + +#endif // __ROBO_TX_FW_H__
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ROBO_TX_FW_1_24.h Wed Jun 15 19:12:25 2011 +0000 @@ -0,0 +1,387 @@ +//============================================================================= +// | +// Headerfile | robo_tx_fw.h +// | +// Description | Header file with definition of the software interface +// | to the ROBO TX Controller firmware. +// | Can be used for building C-programs which can run +// | under control of the ROBO TX Controller firmware in +// | download (local) mode or for building PC-programs which +// | can communicate with the ROBO TX Controller firmware in +// | online mode. +// | +//----------------------------------------------------------------------------- +// Disclaimer - Exclusion of Liability +// +// This software is distributed in the hope that it will be useful,but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. It can be used an modified by anyone +// free of any license obligations or authoring rights. +//============================================================================= + +#ifndef __ROBO_TX_FW_H__ +#define __ROBO_TX_FW_H__ +#define FW_1_24 //my own adaptations to comply with FW version 1.24 + +#define N_CNT 4 // number of counters +#define N_PWM_CHAN 8 // number of PWM channels +#define N_MOTOR 4 // number of motors +#define N_UNI 8 // number of universal inputs + +// 5kOhm Range +#define R_MIN 10 // [Ohm] +#define R_MAX 4999 // [Ohm] +#define R_OVR 5000 // [Ohm] overload + +// 10V Range +#define U_MIN 0 // [mV] +#define U_MAX 9999 // [mV] +#define U_OVR 10000 // [mV] overload + +// Ultrasonic Sensor Range +#define ULTRASONIC_MIN 2 // [cm] +#define ULTRASONIC_MAX 1023 // [cm] +#define ULTRASONIC_OVR 1024 // [cm] overload +#define NO_ULTRASONIC 4096 // not present + +// Length of strings +#define DEV_NAME_LEN 16 // "ROBO TX-xxxxxxxx" +#define BLUETOOTH_ADDR_LEN 17 // "xx:xx:xx:xx:xx:xx" +#define DISPL_MSG_LEN_MAX 64 // max length of a pop-up display message + + +// Identifiers of the Transfer Area parts +enum ta_id_e +{ + TA_LOCAL = 0, // Local part of Transfer Area. Corresponds to the device on which + // program is currently running in download (local) mode or to the + // remotely controlled device (seen from controlled device not from + // controlling device) in online mode. + TA_EXT_1, // Extension 1 part of Transfer Area + TA_EXT_2, // Extension 2 part of Transfer Area + TA_EXT_3, // Extension 3 part of Transfer Area + TA_EXT_4, // Extension 4 part of Transfer Area + TA_EXT_5, // Extension 5 part of Transfer Area + TA_EXT_6, // Extension 6 part of Transfer Area + TA_EXT_7, // Extension 7 part of Transfer Area + TA_EXT_8, // Extension 8 part of Transfer Area + TA_N_PARTS // Number of Transfer Area parts +}; + +#define N_EXT_DEV (TA_N_PARTS - 1) // Number of extension devices = 8 + + +// Device functioning modes +enum dev_mode_e +{ + DEV_MODE_LOCAL = 0, + DEV_MODE_ONLINE, + DEV_MODE_INVALID +}; + + +// State of connection to an extension device +enum ext_dev_connect_state_e +{ + EXT_DEV_OFFLINE = 0, + EXT_DEV_ONLINE, + EXT_DEV_INVALID +}; + + +// Modes of universal inputs +enum input_mode_e +{ + MODE_U = 0, + MODE_R = 1, + MODE_ULTRASONIC = 3, + MODE_INVALID +}; + + +// Program states +enum pgm_state_e +{ + PGM_STATE_INVALID = 0, + PGM_STATE_RUN, + PGM_STATE_STOP +}; + + +// Timer units for GetSystemTime hook function +enum TimerUnit +{ + TIMER_UNIT_INVALID = 0, + TIMER_UNIT_SECONDS = 2, + TIMER_UNIT_MILLISECONDS = 3, + TIMER_UNIT_MICROSECONDS = 4 +}; + + +//============================================================================= +// Structures for Transfer Area (TA) +//============================================================================= + +typedef char BD_ADDR[6]; //leftmost byte in lowest address + +// Program information, 8 bytes +typedef struct +{ + char * name; // name of a program with a full path, for example, "/ramdisk/Program_1" + UINT8 state; // enum pgm_state_e + char reserved[3]; +} PGM_INFO; + + +// Display message, 68 bytes. Used to show pop-up message box on the boards display +typedef struct +{ + unsigned char id; // should be increased by 1 each time a new pop-up message is to be shown + char text[DISPL_MSG_LEN_MAX + 1]; + char reserved[2]; +} DISPLAY_MSG; + + +// Display frame, 8 bytes. Used to refresh boards display with a bitmap image frame +typedef struct +{ + unsigned char * frame; // contents of a frame as a 128x64 pixels bitmap + UINT16 id; // should be increased by 1 each time a new display frame is to be shown + BOOL16 is_pgm_master_of_display; // ++ if program wants to have control over display, + // i.e. image frame is displayed over firmware menus; + // -- if program wants to return control over display + // to the firmware menus +} DISPLAY_FRAME; + + +// Version structure definition, 4 bytes +typedef union +{ + unsigned long abcd; + struct + { + unsigned char a; + unsigned char b; + unsigned char c; + unsigned char d; + } part; +} FT_VER; + + +// Versions of hardware and firmware components, 16 bytes +typedef struct//verified +{ + FT_VER hardware; // version of hardware (hardware.part.a = 'A' or 'B' or 'C') + FT_VER firmware; // version of firmware ("V %d.%02d", firmware.part.c, firmware.part.d) firmware.part.b = DLL version + FT_VER ta; // version of transfer area ("V %d.%02d", ta.part.c, ta.part.d) + char reserved[4]; +} FT_VERSION; + + +// Info structure, 64 bytes +typedef struct //verified +{ + char device_name[DEV_NAME_LEN + 1]; + char bt_addr[BLUETOOTH_ADDR_LEN + 1]; + char reserved; + unsigned long ta_start_addr; + unsigned long pgm_area_start_addr; + unsigned long pgm_area_size; + FT_VERSION version; +} TA_INFO; + + +// State structure, 36 bytes +//changed in 1.24 to 24 bytes +typedef struct +{ + // Used by local program +// BOOL8 pgm_initialized; +// char reserved_1[7]; + + // Public state info +// BOOL8 dev_mode; // enum dev_mode_e +// UCHAR8 id; // Should be increased by 1 each time something (except id fields) + // is changed in this state structure +// UCHAR8 info_id; // Should be increased by 1 each time something is changed in info structure +// UCHAR8 config_id; // Should be increased by 1 each time something is changed in config structure + BOOL8 ext_dev_connect_state[N_EXT_DEV]; // enum ext_dev_connect_state_e //verified + char reserved_2[8]; + PGM_INFO local_pgm; // Corresponds to the program currently being in the program memory +} TA_STATE; + + +// Universal inputs configuration, 4 bytes +//changed in 1.24 to 1 byte +typedef struct //verified +{ + UINT8 mode; // enum input_mode_e, for digital inputs msb=1, for analog msb=0 +// BOOL8 digital; // FALSE = analog input, TRUE = digital input +// unsigned char reserved[2]; +} UNI_CONFIG; + + +// Counter inputs configuration, 4 bytes +//changed in 1.24 to 1 byte +typedef struct +{ + UINT8 mode; // enum input_mode_e +// unsigned char reserved[3]; +} CNT_CONFIG; + + +// Config structure, 88 bytes +//changed in 1.24 to 48 bytes +typedef struct +{ + //UINT8 pgm_state_req; // enum pgm_state_e + //char reserved_1[3]; + BOOL8 motor[N_MOTOR];//verified + UNI_CONFIG uni[N_UNI];//verified + CNT_CONFIG cnt[N_CNT];//verfied 1=normal, 0=inverted + char reserved_2[32]; +} TA_CONFIG; + + +// Input structure, 40 bytes (wrong! 44 bytes) +//changed in 1.24 to 48 bytes +typedef struct +{ + INT16 uni[N_UNI];//verified + BOOL8 cnt_in[N_CNT];//was INT16 + INT16 counter[N_CNT];//verified + // Number of milliseconds during which the left display button is being kept pressed + INT16 display_button_left;//verified + // Number of milliseconds during which the right display button is being kept pressed + INT16 display_button_right;//verified + char unknown[8];//new in 1.24 + // Set to 1 by motor control if target position is reached + INT16 motor_pos_reached[N_MOTOR];//verified +} TA_INPUT; + + +// Output structure, 36 bytes +//changed in 1.24 to 44 bytes, don't know what changed, 4 bytes added before duty. 4 after +typedef struct +{ + // Counter reset requests + INT16 cnt_reset[N_CNT];//was BOOL8 + // If not 0, synchronize this channel with the given channel (1:channel 0, ...) + UINT8 master[N_MOTOR]; + // Selected motor PWM values + INT16 duty[N_PWM_CHAN];//verified + // Selected distane (counter value) at which motor shall stop + UINT16 distance[N_MOTOR];//verified + UINT16 reserved[4];//was char +} TA_OUTPUT; + + +// Display structure, 76 bytes +typedef struct +{ + DISPLAY_MSG display_msg; + DISPLAY_FRAME display_frame; +} TA_DISPLAY; + +//new in 1.24 message structure, 24 bytes +typedef struct +{ + UINT16 index; + UINT16 status; + UINT16 length; + UINT8 hwid; + UINT8 subid; + UINT16 cmd; + UINT16 val; + UINT16 unknown2[6];//possibly another message or room for larger messages +} TA_MESSAGE; + +//new in 1.24 message structure, 32 bytes, note: this struct is not preceded by a transferarea-ID +typedef struct +{ + UINT16 result; //??? 1 for the first (empty) result, 2 for each real result, 5 for the last (empty) result. + BD_ADDR bd_addr; + UINT16 unknown; + char device_name[DEV_NAME_LEN + 1]; + char pad[1]; + UINT32 unknown2; +} TA_INQUIRY; + +// Change structure (only for ftMscLib), 8 bytes +typedef struct +{ + char reserved_1[2]; + UINT8 ChangeStatus; + UINT8 ChangeUni; + UINT8 ChangeCntIn; + UINT8 ChangeCounter; + char reserved_2[2]; +} TA_CHANGE; + + +// 16-bit timers, 12 bytes +typedef struct +{ + UINT16 Timer1ms; + UINT16 Timer10ms; + UINT16 Timer100ms; + UINT16 Timer1s; + UINT16 Timer10s; + UINT16 Timer1min; +} TA_TIMER; + + +// Hook table with pointers to the firmware functions, +// that can be called by local program, 4 bytes +typedef struct +{ + INT32 (*IsRunAllowed) (void); + UINT32 (*GetSystemTime)(enum TimerUnit unit); +} TA_HOOK_TABLE; + + + +// ============================================================================ +// Transfer Area (TA) of ROBO TX Controller (one part of TA_N_PARTS) +// ============================================================================ +#define RESERVED_1_SIZE 4 +#define RESERVED_2_SIZE 28 +#define RESERVED_3_SIZE \ + (512 - ( \ + sizeof(TA_INFO) + \ + sizeof(TA_STATE) + \ + sizeof(TA_CONFIG) + \ + sizeof(TA_INPUT) + \ + sizeof(TA_OUTPUT) + \ + sizeof(TA_DISPLAY) + \ + RESERVED_1_SIZE + \ + sizeof(TA_CHANGE) + \ + sizeof(TA_TIMER) + \ + RESERVED_2_SIZE + \ + sizeof(TA_HOOK_TABLE) \ + )) + + +typedef struct +{ + TA_INFO info; // info structure + TA_STATE state; // state structure + TA_CONFIG config; // config structure + TA_INPUT input; // input structure + TA_OUTPUT output; // output structure + TA_DISPLAY display; // display structure + + char reserved_1[RESERVED_1_SIZE]; + + TA_CHANGE change; // change structure + TA_TIMER timer; // 16-bit timers + + char reserved_2[RESERVED_2_SIZE]; + + TA_HOOK_TABLE hook_table; // hook table with functions pointers + + char reserved_3[RESERVED_3_SIZE]; +} TA; + + +#endif // __ROBO_TX_FW_H__
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fifo.h Wed Jun 15 19:12:25 2011 +0000 @@ -0,0 +1,61 @@ +#ifndef FIFO_H +#define FIFO_H + +class fifo { + char *buf; + int size, in, out, free; +// fifo() {} +public: + fifo(int sz = 127):size(sz), in(0), out(0), free(sz) { + buf = new char[sz]; + } + ~fifo() { + delete[] buf; + } + + void put(char c) { + if (free) { + buf[in++] = c; + if (in==size) in = 0; + free--; + } else + printf("fifo full\n"); + } + + int get() { + if (free == size) + return -1; + free++; + int c = buf[out++]; + if (out == size) out = 0; + return c; + } + int gets(char *line, int len) { + int i = out, n = size-free, l = 0; + while (n>0 && buf[i] != '\n' && l<len-1) { + if (buf[i] != '\r') + line[l++] = buf[i++]; + else + i++; //skip the \r + if (i==size) i = 0; + n--; + } + if (n==0) //buf does not contain EOLN + return -1; + if (buf[i] == '\n') { + line[l] = '\0'; + out = i+1; + if (out==size) out = 0; + free = size - n + 1; + return 0; //success + } else //line too short + return -2; + } + void flush() { + free = size; + in = 0; + out = 0; + } +}; + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ftlib/ROBO_TX_FW_1_24.h Wed Jun 15 19:12:25 2011 +0000 @@ -0,0 +1,387 @@ +//============================================================================= +// | +// Headerfile | robo_tx_fw.h +// | +// Description | Header file with definition of the software interface +// | to the ROBO TX Controller firmware. +// | Can be used for building C-programs which can run +// | under control of the ROBO TX Controller firmware in +// | download (local) mode or for building PC-programs which +// | can communicate with the ROBO TX Controller firmware in +// | online mode. +// | +//----------------------------------------------------------------------------- +// Disclaimer - Exclusion of Liability +// +// This software is distributed in the hope that it will be useful,but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. It can be used an modified by anyone +// free of any license obligations or authoring rights. +//============================================================================= + +#ifndef __ROBO_TX_FW_H__ +#define __ROBO_TX_FW_H__ +#define FW_1_24 //my own adaptations to comply with FW version 1.24 + +#define N_CNT 4 // number of counters +#define N_PWM_CHAN 8 // number of PWM channels +#define N_MOTOR 4 // number of motors +#define N_UNI 8 // number of universal inputs + +// 5kOhm Range +#define R_MIN 10 // [Ohm] +#define R_MAX 4999 // [Ohm] +#define R_OVR 5000 // [Ohm] overload + +// 10V Range +#define U_MIN 0 // [mV] +#define U_MAX 9999 // [mV] +#define U_OVR 10000 // [mV] overload + +// Ultrasonic Sensor Range +#define ULTRASONIC_MIN 2 // [cm] +#define ULTRASONIC_MAX 1023 // [cm] +#define ULTRASONIC_OVR 1024 // [cm] overload +#define NO_ULTRASONIC 4096 // not present + +// Length of strings +#define DEV_NAME_LEN 16 // "ROBO TX-xxxxxxxx" +#define BLUETOOTH_ADDR_LEN 17 // "xx:xx:xx:xx:xx:xx" +#define DISPL_MSG_LEN_MAX 64 // max length of a pop-up display message + + +// Identifiers of the Transfer Area parts +enum ta_id_e +{ + TA_LOCAL = 0, // Local part of Transfer Area. Corresponds to the device on which + // program is currently running in download (local) mode or to the + // remotely controlled device (seen from controlled device not from + // controlling device) in online mode. + TA_EXT_1, // Extension 1 part of Transfer Area + TA_EXT_2, // Extension 2 part of Transfer Area + TA_EXT_3, // Extension 3 part of Transfer Area + TA_EXT_4, // Extension 4 part of Transfer Area + TA_EXT_5, // Extension 5 part of Transfer Area + TA_EXT_6, // Extension 6 part of Transfer Area + TA_EXT_7, // Extension 7 part of Transfer Area + TA_EXT_8, // Extension 8 part of Transfer Area + TA_N_PARTS // Number of Transfer Area parts +}; + +#define N_EXT_DEV (TA_N_PARTS - 1) // Number of extension devices = 8 + + +// Device functioning modes +enum dev_mode_e +{ + DEV_MODE_LOCAL = 0, + DEV_MODE_ONLINE, + DEV_MODE_INVALID +}; + + +// State of connection to an extension device +enum ext_dev_connect_state_e +{ + EXT_DEV_OFFLINE = 0, + EXT_DEV_ONLINE, + EXT_DEV_INVALID +}; + + +// Modes of universal inputs +enum input_mode_e +{ + MODE_U = 0, + MODE_R = 1, + MODE_ULTRASONIC = 3, + MODE_INVALID +}; + + +// Program states +enum pgm_state_e +{ + PGM_STATE_INVALID = 0, + PGM_STATE_RUN, + PGM_STATE_STOP +}; + + +// Timer units for GetSystemTime hook function +enum TimerUnit +{ + TIMER_UNIT_INVALID = 0, + TIMER_UNIT_SECONDS = 2, + TIMER_UNIT_MILLISECONDS = 3, + TIMER_UNIT_MICROSECONDS = 4 +}; + + +//============================================================================= +// Structures for Transfer Area (TA) +//============================================================================= + +typedef char BT_ADDR[6]; //leftmost byte in lowest address + +// Program information, 8 bytes +typedef struct +{ + char * name; // name of a program with a full path, for example, "/ramdisk/Program_1" + UINT8 state; // enum pgm_state_e + char reserved[3]; +} PGM_INFO; + + +// Display message, 68 bytes. Used to show pop-up message box on the boards display +typedef struct +{ + unsigned char id; // should be increased by 1 each time a new pop-up message is to be shown + char text[DISPL_MSG_LEN_MAX + 1]; + char reserved[2]; +} DISPLAY_MSG; + + +// Display frame, 8 bytes. Used to refresh boards display with a bitmap image frame +typedef struct +{ + unsigned char * frame; // contents of a frame as a 128x64 pixels bitmap + UINT16 id; // should be increased by 1 each time a new display frame is to be shown + BOOL16 is_pgm_master_of_display; // ++ if program wants to have control over display, + // i.e. image frame is displayed over firmware menus; + // -- if program wants to return control over display + // to the firmware menus +} DISPLAY_FRAME; + + +// Version structure definition, 4 bytes +typedef union +{ + unsigned long abcd; + struct + { + unsigned char a; + unsigned char b; + unsigned char c; + unsigned char d; + } part; +} FT_VER; + + +// Versions of hardware and firmware components, 16 bytes +typedef struct//verified +{ + FT_VER hardware; // version of hardware (hardware.part.a = 'A' or 'B' or 'C') + FT_VER firmware; // version of firmware ("V %d.%02d", firmware.part.c, firmware.part.d) firmware.part.b = DLL version + FT_VER ta; // version of transfer area ("V %d.%02d", ta.part.c, ta.part.d) + char reserved[4]; +} FT_VERSION; + + +// Info structure, 64 bytes +typedef struct //verified +{ + char device_name[DEV_NAME_LEN + 1]; + char bt_addr[BLUETOOTH_ADDR_LEN + 1]; + char reserved; + unsigned long ta_start_addr; + unsigned long pgm_area_start_addr; + unsigned long pgm_area_size; + FT_VERSION version; +} TA_INFO; + + +// State structure, 36 bytes +//changed in 1.24 to 24 bytes +typedef struct +{ + // Used by local program +// BOOL8 pgm_initialized; +// char reserved_1[7]; + + // Public state info +// BOOL8 dev_mode; // enum dev_mode_e +// UCHAR8 id; // Should be increased by 1 each time something (except id fields) + // is changed in this state structure +// UCHAR8 info_id; // Should be increased by 1 each time something is changed in info structure +// UCHAR8 config_id; // Should be increased by 1 each time something is changed in config structure + BOOL8 ext_dev_connect_state[N_EXT_DEV]; // enum ext_dev_connect_state_e //verified + char reserved_2[8]; + PGM_INFO local_pgm; // Corresponds to the program currently being in the program memory +} TA_STATE; + + +// Universal inputs configuration, 4 bytes +//changed in 1.24 to 1 byte +typedef struct //verified +{ + UINT8 mode; // enum input_mode_e, for digital inputs msb=1, for analog msb=0 +// BOOL8 digital; // FALSE = analog input, TRUE = digital input +// unsigned char reserved[2]; +} UNI_CONFIG; + + +// Counter inputs configuration, 4 bytes +//changed in 1.24 to 1 byte +typedef struct +{ + UINT8 mode; // enum input_mode_e +// unsigned char reserved[3]; +} CNT_CONFIG; + + +// Config structure, 88 bytes +//changed in 1.24 to 48 bytes +typedef struct +{ + //UINT8 pgm_state_req; // enum pgm_state_e + //char reserved_1[3]; + BOOL8 motor[N_MOTOR];//verified + UNI_CONFIG uni[N_UNI];//verified + CNT_CONFIG cnt[N_CNT];//verfied 1=normal, 0=inverted + char reserved_2[32]; +} TA_CONFIG; + + +// Input structure, 40 bytes (wrong! 44 bytes) +//changed in 1.24 to 48 bytes +typedef struct +{ + INT16 uni[N_UNI];//verified + BOOL8 cnt_in[N_CNT];//was INT16 + INT16 counter[N_CNT];//verified + // Number of milliseconds during which the left display button is being kept pressed + INT16 display_button_left;//verified + // Number of milliseconds during which the right display button is being kept pressed + INT16 display_button_right;//verified + char unknown[8];//new in 1.24 + // Set to 1 by motor control if target position is reached + INT16 motor_pos_reached[N_MOTOR];//verified +} TA_INPUT; + + +// Output structure, 36 bytes +//changed in 1.24 to 44 bytes, don't know what changed, 4 bytes added before duty. 4 after +typedef struct +{ + // Counter reset requests + INT16 cnt_reset[N_CNT];//was BOOL8 + // If not 0, synchronize this channel with the given channel (1:channel 0, ...) + UINT8 master[N_MOTOR]; + // Selected motor PWM values + INT16 duty[N_PWM_CHAN];//verified + // Selected distane (counter value) at which motor shall stop + UINT16 distance[N_MOTOR];//verified + UINT16 reserved[4];//was char +} TA_OUTPUT; + + +// Display structure, 76 bytes +typedef struct +{ + DISPLAY_MSG display_msg; + DISPLAY_FRAME display_frame; +} TA_DISPLAY; + +//new in 1.24 message structure, 24 bytes +typedef struct +{ + UINT16 index; + UINT16 status; + UINT16 length; + UINT8 hwid; + UINT8 subid; + UINT16 cmd; + UINT16 val; + UINT16 unknown2[6];//possibly another message or room for larger messages +} TA_MESSAGE; + +//new in 1.24 message structure, 32 bytes, note: this struct is not preceded by a transferarea-ID +typedef struct +{ + UINT16 result; //??? 1 for the first (empty) result, 2 for each real result, 5 for the last (empty) result. + BT_ADDR bd_addr; + UINT16 unknown; + char device_name[DEV_NAME_LEN + 1]; + char pad[1]; + UINT32 unknown2; +} TA_INQUIRY; + +// Change structure (only for ftMscLib), 8 bytes +typedef struct +{ + char reserved_1[2]; + UINT8 ChangeStatus; + UINT8 ChangeUni; + UINT8 ChangeCntIn; + UINT8 ChangeCounter; + char reserved_2[2]; +} TA_CHANGE; + + +// 16-bit timers, 12 bytes +typedef struct +{ + UINT16 Timer1ms; + UINT16 Timer10ms; + UINT16 Timer100ms; + UINT16 Timer1s; + UINT16 Timer10s; + UINT16 Timer1min; +} TA_TIMER; + + +// Hook table with pointers to the firmware functions, +// that can be called by local program, 4 bytes +typedef struct +{ + INT32 (*IsRunAllowed) (void); + UINT32 (*GetSystemTime)(enum TimerUnit unit); +} TA_HOOK_TABLE; + + + +// ============================================================================ +// Transfer Area (TA) of ROBO TX Controller (one part of TA_N_PARTS) +// ============================================================================ +#define RESERVED_1_SIZE 4 +#define RESERVED_2_SIZE 28 +#define RESERVED_3_SIZE \ + (512 - ( \ + sizeof(TA_INFO) + \ + sizeof(TA_STATE) + \ + sizeof(TA_CONFIG) + \ + sizeof(TA_INPUT) + \ + sizeof(TA_OUTPUT) + \ + sizeof(TA_DISPLAY) + \ + RESERVED_1_SIZE + \ + sizeof(TA_CHANGE) + \ + sizeof(TA_TIMER) + \ + RESERVED_2_SIZE + \ + sizeof(TA_HOOK_TABLE) \ + )) + + +typedef struct +{ + TA_INFO info; // info structure + TA_STATE state; // state structure + TA_CONFIG config; // config structure + TA_INPUT input; // input structure + TA_OUTPUT output; // output structure + TA_DISPLAY display; // display structure + + char reserved_1[RESERVED_1_SIZE]; + + TA_CHANGE change; // change structure + TA_TIMER timer; // 16-bit timers + + char reserved_2[RESERVED_2_SIZE]; + + TA_HOOK_TABLE hook_table; // hook table with functions pointers + + char reserved_3[RESERVED_3_SIZE]; +} TA; + + +#endif // __ROBO_TX_FW_H__
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ftlib/ft.h Wed Jun 15 19:12:25 2011 +0000 @@ -0,0 +1,31 @@ +#ifndef FT_H +#define FT_H + +typedef unsigned char BYTE; +typedef unsigned short USHORT; +typedef unsigned int DWORD; + +#pragma pack( push, 1 ) +typedef union { + BYTE aucMsg[6]; + struct { + BYTE ucHwId; + BYTE ucSubId; + union { + struct { + BYTE ucB0; + BYTE ucB1; + BYTE ucB2; + BYTE ucB3; + }; + struct { + USHORT uiMsgId; + USHORT uiMsg; + } ; + DWORD dw; + } ; + } ; +} SMESSAGE; +#pragma pack( pop ) + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ftlib/ftErrCode.h Wed Jun 15 19:12:25 2011 +0000 @@ -0,0 +1,87 @@ +//============================================================================= +// | +// Headerfile | ftErrCode.h +// | +// Description | Definition of error codes +// | +//----------------------------------------------------------------------------- +// Disclaimer - Exclusion of Liability +// +// This software is distributed in the hope that it will be useful,but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. It can be used an modified by anyone +// free of any license obligations or authoring rights. +//============================================================================= + +#ifndef __FTERRCODE_H__ +#define __FTERRCODE_H__ + +//--- FTLIB Error Codes + +#define FTLIB_ERR_SUCCESS 0x00000000L +#define FTLIB_ERR_NO_MEMORY 0xE0000100L + +#define FTLIB_ERR_FAILED 0xE0001000L +#define FTLIB_ERR_TIMEOUT 0xE000100CL +#define FTLIB_ERR_INVALID_PARAM 0xE0001018L + +#define FTLIB_ERR_SOME_DEVICES_ARE_OPEN 0xE0001101L +#define FTLIB_ERR_DEVICE_IS_OPEN 0xE0001102L +#define FTLIB_ERR_DEVICE_NOT_OPEN 0xE0001103L +#define FTLIB_ERR_NO_SUCH_DEVICE_INSTANCE 0xE0001104L + +#define FTLIB_ERR_UNKNOWN_DEVICE_HANDLE 0xE0001283L +#define FTLIB_ERR_LIB_IS_INITIALIZED 0xE0001286L +#define FTLIB_ERR_LIB_IS_NOT_INITIALIZED 0xE0001287L +#define FTLIB_ERR_THREAD_NOT_STARTABLE 0xE00012A0L +#define FTLIB_ERR_THREAD_IS_RUNNING 0xE00012A5L +#define FTLIB_ERR_THREAD_NOT_RUNNING 0xE00012A6L +#define FTLIB_ERR_THREAD_SYNCHRONIZED 0xE00012AFL + +#define FTLIB_ERR_TIMEOUT_TA 0xE00012B0L +#define FTLIB_ERR_CREATE_EVENT 0xE00012B1L +#define FTLIB_ERR_CREATE_MM_TIMER 0xE00012B2L + +#define FTLIB_ERR_UPLOAD_FILE_NOT_OPEN 0xE0001400L +#define FTLIB_ERR_UPLOAD_FILE_READ_ERR 0xE0001401L +#define FTLIB_ERR_UPLOAD_INVALID_FSIZE 0xE0001402L +#define FTLIB_ERR_UPLOAD_START 0xE0001403L +#define FTLIB_ERR_UPLOAD_CANCELED 0xE0001404L +#define FTLIB_ERR_UPLOAD_FAILED 0xE0001405L +#define FTLIB_ERR_UPLOAD_TIMEOUT 0xE0001406L +#define FTLIB_ERR_UPLOAD_ACK 0xE0001407L +#define FTLIB_ERR_UPLOAD_NAK 0xE0001408L +#define FTLIB_ERR_UPLOAD_DONE 0xE0001409L +#define FTLIB_ERR_UPLOAD_FLASHWRITE 0xE000140AL +#define FTLIB_ERR_REM_CMD_FAILED 0xE000140BL +#define FTLIB_ERR_REM_CMD_NOT_SUPPORTED 0xE000140CL +#define FTLIB_ERR_FWUPD_GET_FILES 0xE000140DL +#define FTLIB_ERR_FWUPD_NO_FILES 0xE000140EL + +#define FTLIB_ERR_ACCESS_DENIED 0xE0001905L +#define FTLIB_ERR_OPEN_COM 0xE0001906L +#define FTLIB_ERR_INIT_COM 0xE0001908L +#define FTLIB_ERR_INIT_COM_TIMEOUT 0xE0001909L + +#define FTLIB_ERR_WRONG_HOSTNAME_LEN 0xE0002000L + +#define FTLIB_FWUPD_UPLOAD_START 0xE0003000L +#define FTLIB_FWUPD_UPLOAD_DONE 0xE0003001L +#define FTLIB_FWUPD_TIMEOUT 0xE0003002L +#define FTLIB_FWUPD_FLUSH_DISK 0xE0003003L +#define FTLIB_FWUPD_CLEAN_DISK 0xE0003004L +#define FTLIB_FWUPD_ERR_FILE_READ 0xE0003005L +#define FTLIB_FWUPD_UPLOAD_FAILED 0xE0003006L +#define FTLIB_FWUPD_STARTING 0xE0003007L +#define FTLIB_FWUPD_FINISHED 0xE0003008L +#define FTLIB_FWUPD_REM_COMMAND 0xE0003009L +#define FTLIB_FWUPD_REM_TIMEOUT 0xE000300AL +#define FTLIB_FWUPD_REM_FAILED 0xE000300BL +#define FTLIB_FWUPD_IZ_STEPS 0xE000300CL +#define FTLIB_FWUPD_STEP 0xE000300DL + + +#define FTLIB_ERR_UNKNOWN 0xEFFFFFFFL + + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ftlib/ftlib.h Wed Jun 15 19:12:25 2011 +0000 @@ -0,0 +1,1213 @@ +/** @file */ +/******************************************************************************* + * (c) by Knobloch GmbH + * Weedgasse 14 + * D-55234 Erbes-B�im + * + * Header: FtLib.h Headerfile for fischertechnik USB-Library + * + * Version: 0.60 + * Date: 10. May 2006 + * + * Revision: + * 0.60: 10. May 2006 + * New Name: GetAnzFtUsbDevice() --> GetNumFtUsbDevice() + * ClearFtMessagePuffer() --> ClearFtMessageBuffer() + ********************************************************************************/ + + +#ifndef _FT_LIBRARY_H_ +#define _FT_LIBRARY_H_ + +/** \cond doxygen ignore start */ +#define DWORD unsigned +#define BYTE unsigned char +#define USHORT unsigned short int +#define UINT unsigned int +#define UCHAR unsigned char + +#define HANDLE int +#define HWND int +#define __stdcall +#define LPCSTR char * +#define LPVOID void * +/** \endcond doxygen ignore end */ + +struct _ftdev; + +/// \brief Communication Area for ft-Device +typedef struct _FT_TRANSFER_AREA +{ + /// \brief Digital Inputs Main Module + /// Base+0x00: | E8 | E7 | E6 | E5 | E4 | E3 | E2 | E1 | + unsigned char E_Main; + + /// \brief Digital Inputs Extension Modules 1 + /// Base+0x01: | E16| E15| E14| E13| E12| E11| E10| E9 | + unsigned char E_Sub1; + /// \brief Digital Inputs Extension Modules 2 + /// Base+0x02: | E24| E23| E22| E21| E20| E19| E18| E17| + unsigned char E_Sub2; + /// \brief Digital Inputs Extension Modules 3 + /// Base+0x03: | E32| E31| E30| E29| E28| E27| E26| E25| + unsigned char E_Sub3; + + /// \brief Reserved + /// Base+0x04..0x0B + unsigned char rsvd1[8]; + + /// \brief Abstandsensoren (1=detektiert) + /// Base+0x0C: | 0 | 0 | 0 | 0 | 0 | 0 | D2 | D1 | + unsigned char Distance; + + /// \brief Base+0x0D: reserved + unsigned char rsvd2; + + /// \brief IR-Receiver input code + /// + /// Base+0x0E: | 0 | 0 | 0 | C | T | T | T | T + /// C = Code: 0 = Code 1 active, 1 = Code 2 active + /// TTTT = Keycode 0..11 + /// Arangement of keys on Transmitter + /// 1 8 + /// 2 7 + /// 3 10 + /// 4 9 + /// 5 11 + /// 6 + /// Taste 1 = M3 right + /// Taste 2 = M3 left + /// Taste 3 = Speed. M1 + /// Taste 4 = Speed. M2 + /// Taste 5 = Speed. M3 + /// Taste 6 = Code 2 + /// Taste 7 = M1 backward + /// Taste 8 = M1 forward + /// Taste 9 = M2 left + /// Taste 10 = M2 right + /// Taste 11 = Code 1 + unsigned char IRKeys; + + /// \brief Base+0x0F: | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | + unsigned char res_1; + + /// \brief Analoginput of main module + /// + /// 8x 16 Bit, Range 0..1023, L:H Format (intel) ) + /// Base+0x10..0x11: AX (Master Modul) + unsigned short AX; + /// \brief Analoginput of main module + /// + /// 8x 16 Bit, Range 0..1023, L:H Format (intel) ) + /// Base+0x12..0x13: AY (Master Modul) + unsigned short AY; + /// \brief Analoginput of main module + /// + /// 8x 16 Bit, Range 0..1023, L:H Format (intel) ) + /// Base+0x14..0x15: A1 (Master Modul) + unsigned short A1; + /// \brief Analoginput of main module + /// + /// 8x 16 Bit, Range 0..1023, L:H Format (intel) ) + /// Base+0x16..0x17: A2 (Master Modul) + unsigned short A2; + /// \brief Analoginput of main module + /// + /// 8x 16 Bit, Range 0..1023, L:H Format (intel) ) + /// Base+0x18..0x19: AZ (Master Modul, vom SLAVE-Modul-BUS) + unsigned short AZ; + /// \brief Analoginput of main module + /// + /// 8x 16 Bit, Range 0..1023, L:H Format (intel) ) + /// Base+0x1A..0x1B: AV (Versorgungsspannung Master Modul) + unsigned short AV; + /// \brief Analoginput of main module + /// + /// 8x 16 Bit, Range 0..1023, L:H Format (intel) ) + /// Base+0x1C..0x1D: D1 (Abstandssensor 1) + unsigned short D1; + /// \brief Analoginput of main module + /// + /// 8x 16 Bit, Range 0..1023, L:H Format (intel) ) + /// Base+0x1E..0x1F: D2 (Abstandssensor 2) + unsigned short D2; + + /// \brief Analoginput of slave module 1 + /// + /// Base+0x20..0x21: AX (Slave 1 Modul) + unsigned short AXS1; + /// \brief Analoginput of slave module 1 + /// + /// Base+0x22..0x23: AX (Slave 2 Modul) + unsigned short AXS2; + /// \brief Analoginput of slave module 1 + /// + /// Base+0x24..0x25: AX (Slave 3 Modul) + unsigned short AXS3; + + /// \brief Detection limit for distance sensor 1 ( to generate digital from analog input ) + /// + /// Base+0x26..0x27: DS1 + unsigned short DS1; + /// \brief Detection limit for distance sensor 2 ( to generate digital from analog input ) + /// + /// Base+0x28..0x29: DS2 + unsigned short DS2; + + /// \brief Reserved + /// Base+0x2A..0x2B + unsigned short ZE; + + /// \brief Reserved + /// Base+0x2C..0x2F + unsigned char rsvd3[4]; + + /// \brief 16-Bit Timer + /// + /// Base+0x30..0x31: Timer 1ms Inkrement + unsigned short Timer1ms; + /// \brief 16-Bit Timer + /// + /// Base+0x32..0x33: Timer 10ms Inkrement + unsigned short Timer10ms; + /// \brief 16-Bit Timer + /// + /// Base+0x34..0x35: Timer 100ms Inkrement + unsigned short Timer100ms; + /// \brief 16-Bit Timer + /// + /// Base+0x36..0x37: Timer 1s Inkrement + unsigned short Timer1s; + /// \brief 16-Bit Timer + /// + /// Base+0x38..0x39: Timer 10s Inkrement + unsigned short Timer10s; + /// \brief 16-Bit Timer + /// + /// Base+0x3A..0x3B: Timer 1min Inkrement + unsigned short Timer1min; + + /// \brief Reserved + /// Base+0x3C..0x3D + unsigned short res_bF; + /// \brief Reserved + /// Base+0x3E + unsigned char res_bT; + + /// \brief Reserved + /// Base+0x3F + unsigned char rsvd4[1]; + + /// \brief Outputs of the main module ( polarity ) + /// + /// Base+0x40: |M4B |M4A |M3B |M3A |M2B |M2A |M1B |M1A | + unsigned char M_Main; + /// \brief Outputs of extension module 1 + /// + /// Base+0x41: |M8B |M8A |M7B |M7A |M6B |M6A |M5B |M5A | + unsigned char M_Sub1; + /// \brief Outputs of extension module 2 + /// + /// Base+0x42: |M12B|M12A|M11B|M11A|M10B|M10A|M9B |M9A | + unsigned char M_Sub2; + /// \brief Outputs of extension module 3 + /// + /// Base+0x43: |M16B|M16A|M15B|M15A|M14B|M14A|M13B|M13A| + unsigned char M_Sub3; + + /// \brief Reserved + /// Base+0x44..0x47 + unsigned char rsvd5[4]; + + ///\brief Outputs of the main module ( energy saver mode ) + /// + /// 1 = energy saver mode, 0 = operational, PowerUp = 1 + /// Base+0x48: | 0 | 0 | 0 | 0 | M4 | M3 | M2 | M1 | + unsigned char MES_Main; + /// \brief Outputs of extension module 1 ( energy saver mode ) + /// + /// Base+0x49: | 0 | 0 | 0 | 0 | M8 | M7 | M6 | M5 | + unsigned char MES_Sub1; + /// \brief Outputs of extension module 2 ( energy saver mode ) + /// + /// Base+0x4A: | 0 | 0 | 0 | 0 | M12| M11| M10| M9 | + unsigned char MES_Sub2; + /// \brief Outputs of extension module 3 ( energy saver mode ) + /// + /// Base+0x4B: | 0 | 0 | 0 | 0 | M16| M15| M14| M13| + unsigned char MES_Sub3; + + /// \brief Reserved + /// Base+0x4C + unsigned char rsvd6[1]; + + /// \brief Reserved + /// Base+0x4D: + unsigned char reserved_l1; + /// \brief Reserved + /// Base+0x4E: + unsigned char reserved_l2; + /// \brief Reserved + /// Base+0x4F: + unsigned char reserved_l3; + + /// \brief Outputs of the main module (PWM values, range =0..7) + /// + /// Base+0x50: M1A + /// Base+0x51: M1B + /// Base+0x52: M2A + /// Base+0x53: M2B + /// Base+0x54: M3A + /// Base+0x55: M3B + /// Base+0x56: M4A + /// Base+0x57: M4B + unsigned char MPWM_Main[8]; + + /// \brief Outputs of slave module 1 (PWM values, range =0..7) + /// + /// Base+0x58: M5A + /// Base+0x59: M5B + /// Base+0x5A: M6A + /// Base+0x5B: M6B + /// Base+0x5C: M7A + /// Base+0x5D: M7B + /// Base+0x5E: M8A + /// Base+0x5F: M8B + unsigned char MPWM_Sub1[8]; + + /// \brief Outputs of slave module 2 (PWM values, range =0..7) + /// + /// Base+0x60: M9A + /// Base+0x61: M9B + /// Base+0x62: M10A + /// Base+0x63: M10B + /// Base+0x64: M11A + /// Base+0x65: M11B + /// Base+0x66: M12A + /// Base+0x67: M12B + unsigned char MPWM_Sub2[8]; + + /// \brief Outputs of slave module 3 (PWM values, range =0..7) + /// + /// Base+0x68: M13A + /// Base+0x69: M13B + /// Base+0x6A: M14A + /// Base+0x6B: M14B + /// Base+0x6C: M15A + /// Base+0x6D: M15B + /// Base+0x6E: M16A + /// Base+0x6F: M16B + unsigned char MPWM_Sub3[8]; + + /// \brief Reserved + /// Base+0x70..0x8F + unsigned char rsvd7[32]; + + + /// \brief Analoginput of slave module 1 (Update-Time: 20ms) + /// + /// Base+0x90..0x91: A1 (Slave 1 Modul) + unsigned short A1S1; + /// \brief Analoginput of slave module 2 (Update-Time: 20ms) + /// + /// Base+0x92..0x93: A1 (Slave 2 Modul) + unsigned short A1S2; + /// \brief Analoginput of slave module 3 (Update-Time: 20ms) + /// + /// Base+0x94..0x95: A1 (Slave 3 Modul) + unsigned short A1S3; + + /// \brief Analoginput of slave modules 1 (Update-Time: 20ms) + /// + /// Base+0x96..0x97: AV (Slave 1 Modul) + unsigned short AVS1; + /// \brief Analoginput of slave modules 2 (Update-Time: 20ms) + /// + /// Base+0x98..0x99: AV (Slave 2 Modul) + unsigned short AVS2; + /// \brief Analoginput of slave modules 3 (Update-Time: 20ms) + /// + /// Base+0x9A..0x9B: AV (Slave 3 Modul) + unsigned short AVS3; + + /// \brief Reserved + /// Base+0x9C..0x9F + unsigned char rsvd8[4]; + + /// \brief Reserved + /// Base+0xA0..0xA1: AX (Interface) Resistor-Value (0..5662 Ohm) + unsigned short AX_R; + + /// \brief Base+0xA2..0xA3: AY (Interface) Resistor-Value (0..5662 Ohm) + unsigned short AY_R; + + /// \brief Base+0xA4..0xA5: AX (Slave 1 Modul) Resistor-Value (0..5662 Ohm) + unsigned short AXS1_R; + + /// \brief Base+0xA6..0xA7: AX (Slave 2 Modul) Resistor-Value (0..5662 Ohm) + unsigned short AXS2_R; + + /// \brief Base+0xA8..0xA9: AX (Slave 3 Modul) Resistor-Value (0..5662 Ohm) + unsigned short AXS3_R; + + /// \brief Reserved + /// Base+0xAA..0xDF + unsigned char rsvd10[54]; + + /// \brief Operation mode + /// Base+0xE0: 0x00=online, 0x01=binary download + unsigned char Mode; + + /// \brief Output PWM update (0x01=always, 0x02=once) + /// Base+0xE1: | 0 | 0 | 0 | 0 | 0 | 0 |ONCE|ALWA| + unsigned char MPWM_Update; + + /// \brief Base+0xE2 + /// + /// 0 = Transfer Area closed + /// 1 = Transfer Area is working (Library Thread is running) + unsigned char TransferAktiv; + + /// \brief Reserved + /// Base+0xE3..0xE5 + unsigned char rsvd11[3]; + + /// \brief I/O Extension modules connected + /// + /// Base+0xE6: | 0 | 0 | 0 | 0 | 0 | S2 | S1 | S0 | + /// S2..S0 = Number of connected I/O Extension Modules + unsigned char BusModules; + + /// \brief Slot 1 connected extension module type + /// Base+0xE7: ? + unsigned char SlotModule1; + + /// \brief Slot 2 connected extension module type + /// Base+0xE8: ? + unsigned char SlotModule2; + + /// \brief Reserved + /// Base+0xE9..0xEF + unsigned char rsvd12[7]; + + + /// \brief Change Bytes + /// + /// 1 = EG (Master or Slave 1..3) have changed + /// The Application must read and change this byte to "0" + /// Base+0xF0: + unsigned char ChangeEg; + + /// \brief 1 = Analog Inputs (Master AX, AY, A1, A2, AV, AZ or Extension 1..3 AX,AY,AV) + /// + /// or RfPower, RfError have changed + /// The Application must read and change this byte to "0" + /// Base+0xF1: + unsigned char ChangeAn; + + /// \brief 1 = Infrared Input (Robo-IF) or RfStatus have changed + /// + /// The Application must read and change this byte to "0" + /// Base+0xF2: + unsigned char ChangeIr; + + + /// \brief Reserved + /// Base+0xF3..0xFF + unsigned char rsvd13[13]; + + + /// \brief Digital inputs as 16 bit values + /// + /// Base+0x100..0x101 Input 1 (Master-Modul) + /// Base+0x102..0x103 Input 2 (Master-Modul) + /// Base+0x104..0x105 Input 3 (Master-Modul) + /// Base+0x106..0x107 Input 4 (Master-Modul) + /// Base+0x108..0x109 Input 5 (Master-Modul) + /// Base+0x10A..0x10B Input 6 (Master-Modul) + /// Base+0x10C..0x10D Input 7 (Master-Modul) + /// Base+0x10E..0x10F Input 8 (Master-Modul) + unsigned short E16_Main[8]; + /// \brief Digital inputs as 16 bit values + /// + /// Base+0x110..0x111 Input 9 (Slave1-Modul) + /// Base+0x112..0x113 Input 10 (Slave1-Modul) + /// Base+0x114..0x115 Input 11 (Slave1-Modul) + /// Base+0x116..0x117 Input 12 (Slave1-Modul) + /// Base+0x118..0x119 Input 13 (Slave1-Modul) + /// Base+0x11A..0x11B Input 14 (Slave1-Modul) + /// Base+0x11C..0x11D Input 15 (Slave1-Modul) + /// Base+0x11E..0x11F Input 16 (Slave1-Modul) + unsigned short E16_Sub1[8]; + /// \brief Digital inputs as 16 bit values + /// + /// Base+0x120..0x121 Input 17 (Slave2-Modul) + /// Base+0x122..0x123 Input 18 (Slave2-Modul) + /// Base+0x124..0x125 Input 19 (Slave2-Modul) + /// Base+0x126..0x127 Input 20 (Slave2-Modul) + /// Base+0x128..0x129 Input 21 (Slave2-Modul) + /// Base+0x12A..0x12B Input 22 (Slave2-Modul) + /// Base+0x12C..0x12D Input 23 (Slave2-Modul) + /// Base+0x12E..0x12F Input 24 (Slave2-Modul) + unsigned short E16_Sub2[8]; + /// \brief Digital inputs as 16 bit values + /// + /// Base+0x130..0x131 Input 25 (Slave3-Modul) + /// Base+0x132..0x133 Input 26 (Slave3-Modul) + /// Base+0x134..0x135 Input 27 (Slave3-Modul) + /// Base+0x136..0x137 Input 28 (Slave3-Modul) + /// Base+0x138..0x139 Input 29 (Slave3-Modul) + /// Base+0x13A..0x13B Input 30 (Slave3-Modul) + /// Base+0x13C..0x13D Input 31 (Slave3-Modul) + /// Base+0x13E..0x13F Input 32 (Slave3-Modul) + unsigned short E16_Sub3[8]; + /// \brief Distance sensors D1 & D2 (Master Modul) + /// + /// Base+0x140..0x141 Distance sensor D1 (Master-Modul) + /// Base+0x142..0x143 Distance sensor D2 (Master-Modul) + unsigned short Distance16[2]; + + /// \brief Reserved + /// Base+0x144..0x14F + unsigned char rsvd14[12]; + + /// \brief IR-Keys as 16 bit values (independent of code) + /// + /// Base+0x150..0x151 IR Taste 1 (M3R) + /// Base+0x152..0x153 IR Taste 2 (M3L) + /// Base+0x154..0x155 IR Taste 3 (M1) + /// Base+0x156..0x157 IR Taste 4 (M2) + /// Base+0x158..0x159 IR Taste 5 (M3) + /// Base+0x15A..0x15B IR Taste 6 (Code2) + /// Base+0x15C..0x15D IR Taste 7 (M1BW) + /// Base+0x15E..0x15F IR Taste 8 (M1FW) + /// Base+0x160..0x161 IR Taste 9 (M2L) + /// Base+0x162..0x163 IR Taste 10 (M2R) + /// Base+0x164..0x165 IR Taste 11 (Code1) + unsigned short IRKeys16[11]; + /// \brief Reserved + /// Base+0x166..0x16F + unsigned char rsvd15[10]; + + /// \brief IR-Keys as 16 bit values (code 1) + /// + /// Base+0x170..0x171 IR Taste 1 (M3R) Code1 + /// Base+0x172..0x173 IR Taste 2 (M3L) Code1 + /// Base+0x174..0x175 IR Taste 3 (M1) Code1 + /// Base+0x176..0x177 IR Taste 4 (M2) Code1 + /// Base+0x178..0x179 IR Taste 5 (M3) Code1 + /// Base+0x17A..0x17B always 0 + /// Base+0x17C..0x17D IR Taste 7 (M1BW) Code1 + /// Base+0x17E..0x17F IR Taste 8 (M1FW) Code1 + /// Base+0x180..0x181 IR Taste 9 (M2L) Code1 + /// Base+0x182..0x183 IR Taste 10 (M2R) Code1 + /// Base+0x184..0x185 IR Taste 11 (Code1) Code1 + unsigned short IRKeys16Code1[11]; + + /// \brief Reserved + /// + /// Base+0x186..0x18F + unsigned char rsvd16[10]; + + /// \brief IR-Keys as 16 bit values (code 1) + /// + /// Base+0x190..0x191 IR Taste 1 (M3R) Code2 + /// Base+0x192..0x193 IR Taste 2 (M3L) Code2 + /// Base+0x194..0x195 IR Taste 3 (M1) Code2 + /// Base+0x196..0x197 IR Taste 4 (M2) Code2 + /// Base+0x198..0x199 IR Taste 5 (M3) Code2 + /// Base+0x19A..0x19B IR Taste 6 (Code2) Code2 + /// Base+0x19C..0x19D IR Taste 7 (M1BW) Code2 + /// Base+0x19E..0x19F IR Taste 8 (M1FW) Code2 + /// Base+0x1A0..0x1A1 IR Taste 9 (M2LE) Code2 + /// Base+0x1A2..0x1A3 IR Taste 10 (M2RI) Code2 + /// Base+0x1A4..0x1A5 always 0 + unsigned short IRKeys16Code2[11]; + + /// \brief Reserved + /// + /// Base+0x1A6..0x1AF + unsigned char rsvd17[10]; + + /// \brief 1 = RfError (0x1B4..0x1B5) is > 25. We think, Rf connection (only Onlinemodus) is lost + /// + /// Base+0x1B0..0x1B1 + unsigned short RfStatus; + + /// \brief Signal Power of the RF Signal entering the RF input (only Onlinemodus, 7 bit, 0..127) + /// + /// Base+0x1B2..0x1B3 + unsigned short RfPower; + + /// \brief Rf-Error Count (0..250) + /// + /// Base+0x1B4..0x1B5 + unsigned short RfError; + + /// \brief Number of Messages inside the Buffer + /// + /// Base+0x1B6..0x1B7 + unsigned short MsgNumInBuffer; + + /// \brief Number of Interface-RF-Modul if installed or "-1" if not installed + /// + /// Base+0x1B8..0x1B9 + unsigned short RfModulNr; + + /// \brief Reserved + /// Base+0x1BA..0x1BB + unsigned char rsvd19[2]; + + /// \brief Reserved for Internal Use + /// Base+0x1BC..0x1BF + DWORD dwTC; + + /// \brief Reserved + /// Base+0x1C0..0x1FF + unsigned char rsvd20[64]; + +} FT_TRANSFER_AREA; +/** \fn typedef FT_TRANSFER_AREA + * Type definition for the transfer area. + */ + +struct ft_handle_devices;//forward declaration +typedef struct ft_handle_devices *FT_HANDLE; + +/** \cond doxygen ignore start */ + +bool test_and_set(int& s); +void increment(int& s); + +FT_HANDLE OpenFtCommDevice(char *sDevice, long int dwTyp, long int dwZyklus); +int GetFtStatus(FT_HANDLE hFt, int *num); +DWORD GetFtDeviceTypeString(FT_HANDLE hft, char *dest, int len); +char *GetLibVersionStrg(); +long int SetRFMode(FT_HANDLE hFt, long int frequency, long int callSign); +long int GetRFMode(FT_HANDLE hFt, long int *frequency, long int *callSign); +long int SetRealSerial(FT_HANDLE hFt, unsigned char bOn); +char IsFtInterfaceConnected(FT_HANDLE hFt); + + // Numbers from GetFtDeviceTyp() +#define NO_FT_DEVICE 0 // No ft Device connected +#define FT_AUTO_TYPE 1 // Search for Device +#define FT_INTELLIGENT_IF 10 // FT-Intelligent Interface connect (serial) +#define FT_INTELLIGENT_IF_SLAVE 20 // FT-Intelligent Interface with Extension connect (serial) +#define FT_ROBO_IF_IIM 50 // FT-Robo Interface with Intelligent-Interface-Modus connect (serial) +#define FT_ROBO_IF_USB 60 // FT-Robo Interface connect with USB-Port +#define FT_ROBO_IF_COM 70 // FT-Robo Interface connect with COM- (serial-) Port +#define FT_ROBO_IF_OVER_RF 80 // FT-Robo Interface connect over RF-Data-Link +#define FT_ROBO_IO_EXTENSION 90 // FT-Robo I/O-Extension +#define FT_ROBO_RF_DATA_LINK 110 // FT-Robo RF Data Link +#define FT_MAX_TYP_NUMBER 999 // Max Typ Number + + +#define FT_ANALOG_CYCLE 5 // Standard: 5*Read Digital Inputs, then EX, EY + // Only for old Intelligent Interface { for OpenFtCommDevice() } + + +#define PORT_NONE 0 +#define PORT_COM 1 // Standard: COM1 +#define PORT_COM1 1 +#define PORT_COM2 2 +#define PORT_COM3 3 +#define PORT_COM4 4 +#define PORT_USB 50 + + // Moduletypes for Robo Interface +#define MODULE_NOT_INSTALLED 0 // Not installed +#define MODULE_RF1 1 // RF Data Link Module is installed + + +#define LEN_STRG1 30 // Length of SN / FW Strings +#define LEN_STRG2 255 // Length of Name-Strigs +#define ANZ_DISTANCE_TYPES 2 // Number of supported Distance-Modes +#define LEN_DIST_TYPE_NAMES 30 // Lenght of Mode-Names +#define LEN_DIST_VAR_NAMES 20 // Lenght of Variable-Names +#define NAME_LEN 85 // Lenght of Prog-Names + + +#define MEM_FLASH1 0 // Use Memory FLASH-1 Block +#define MEM_FLASH2 1 // Use Memory FLASH-2 Block +#define MEM_RAM 2 // Use Memory RAM Block +#define MEM_NO_ACCESS -1 // No Memory Select (for SetFtProgramActiv() ) +#define DOWNLOAD_PROG_NAMELEN 80 // Max. 80 characters/bytes for the programname + + // Values for "dwParameter" from DownloadFtProgram() +#define PROG_TYP_NORMAL 1 // Program can bei Start with Software and Switch +#define PROG_TYP_AUTOSTART 2 // Program is startable at Power-On + + + // COM-Modes for SetFtDeviceCommMode() +#define IF_COM_ONLINE 1 // Online Mode +#define IF_COM_MESSAGE 3 // Messagemode +#define IF_COM_DATA 4 // Datatransfer +#define IF_COM_PARAMETER 5 // Get Mode + + + // Message-System +#define MSG_HWID_SELF 0 // Message for himself +#define MSG_HWID_SER 1 // Message for the Robo-Interface serial port +#define MSG_HWID_RF 2 // Message for other Interfaces (over RF) +#define MSG_HWID_RF_SELF 3 // Message for other Interfaces (over RF) and for himself (back over RF) + +#define MSG_BUFF_SER 1 // SER-Messagebuffer (for ClearRfMessage() ) +#define MSG_BUFF_RF 2 // RF-Messagebuffer (for ClearRfMessage() ) +#define MSG_BUFF_SELF 4 // SELF-Messagebuffer (for ClearRfMessage() ) + +#define MSG_SEND_NORMAL 0 // Message send "normal" +#define MSG_SEND_OTHER_THAN_LAST 1 // Message send "if not the same as the last message" +#define MSG_SEND_IF_NOT_PRESENT 2 // Message send "if not present in the send buffer" + + + + // Interface Distancesensor-Inputs Type +#define IF_DS_INPUT_VOLTAGE 0 // Voltage +#define IF_DS_INPUT_DISTANCE 1 // Distance +#define IF_DS_INPUT_TOL_STD 20 // Toleranz (Standard) +#define IF_DS_INPUT_REP_STD 3 // Repeat (Standard) + + +#ifndef FT_H + #pragma pack( push, 1 ) + typedef union + { + BYTE aucMsg[6]; + + struct + { + BYTE ucHwId; + BYTE ucSubId; + BYTE ucB0; + BYTE ucB1; + BYTE ucB2; + BYTE ucB3; + } B; + + struct + { + BYTE ucHwId; + BYTE ucSubId; + USHORT uiMsgId; + USHORT uiMsg; + } W; + + struct + { + BYTE ucHwId; + BYTE ucSubId; + DWORD dw; + } L; + } SMESSAGE; + #pragma pack( pop ) +#endif + + //typedef void * FT_HANDLE; + typedef void (*DATA_UPDATE_CALLBACK)(void* Context); + typedef void (*MSG_UPDATE_CALLBACK)(SMESSAGE *); + + + + // Important: + // Initialise all unused Variables in this Structure with "NULL" + // + // Every Time the driver reads new information from the Device + // the Library checks this structure + typedef struct _NOTIFICATION_EVENTS + { + // Callback-Procedure + DATA_UPDATE_CALLBACK NotificationCallback; // Pointer to the Callback-Procedure + void* Context; // Pointer to the Context for the Callback-Procedure + + // for SetEvent() + HANDLE hEvent; + + // for posting a Message (PostMessage() with wParam & lParam = 0) + HWND WindowsHandle; // handle to the destination window + DWORD Message; // message ID + + + // Callback-Procedure for Messaging + MSG_UPDATE_CALLBACK CallbackMessage; // Pointer to the Callback-Procedure for Receiving Messages + + } + NOTIFICATION_EVENTS; + + + + + typedef struct _FT_SERIAL_NUMBER + { + DWORD dwSn; // actually Serial Number at Power On + DWORD dwSn1; // Serial Number-1 + DWORD dwSn2; // Serial Number-2 + DWORD dwSnAktiv; // Serial Number Activ (1/2) for next Power On + } FT_SERIAL_NUMBER; + + + + typedef struct _FT_DISTANCE // Robo Interface Distance Sensor + { + unsigned char aDistModeNames[LEN_DIST_TYPE_NAMES]; // RO Names for the Modes + + DWORD dwEnableDisVal1; // RO 1=Ask for Distance Value 1 + unsigned char aDisVal1Name[LEN_DIST_VAR_NAMES]; // RO Value 1 Name + DWORD dwDisVal1; // RW Value 1 + + DWORD dwEnableDisVal2; // RO 1=Ask for Distance Value 2 + unsigned char aDisVal2Name[LEN_DIST_VAR_NAMES]; // RO Value 2 Name + DWORD dwDisVal2; // RW Value 2 + + DWORD dwEnableDisVal3; // RO 1=Ask for Distance Value 3 + unsigned char aDisVal3Name[LEN_DIST_VAR_NAMES]; // RO Value 3 Name + DWORD dwDisVal3; // RW Value 3 + + DWORD dwEnableDisVal4; // RO 1=Ask for Distance Value 4 + unsigned char aDisVal4Name[LEN_DIST_VAR_NAMES]; // RO Value 4 Name + DWORD dwDisVal4; // RW Value 4 + + DWORD dwEnableDisVal5; // RO 1=Ask for Distance Value 5 + unsigned char aDisVal5Name[LEN_DIST_VAR_NAMES]; // RO Value 5 Name + DWORD dwDisVal5; // RW Value 5 + + DWORD dwEnableDisVal6; // RO 1=Ask for Distance Value 6 + unsigned char aDisVal6Name[LEN_DIST_VAR_NAMES]; // RO Value 6 Name + DWORD dwDisVal6; // RW Value 6 + + DWORD dwEnableDisVal7; // RO 1=Ask for Distance Value 7 + unsigned char aDisVal7Name[LEN_DIST_VAR_NAMES]; // RO Value 7 Name + DWORD dwDisVal7; // RW Value 7 + + DWORD dwEnableDisVal8; // RO 1=Ask for Distance Value 8 + unsigned char aDisVal8Name[LEN_DIST_VAR_NAMES]; // RO Value 8 Name + DWORD dwDisVal8; // RW Value 8 + } FT_DISTANCE; + + + + typedef union _FT_SETTING + { + struct // RO = Read Only, RW = Read / Write + { + DWORD dwIfTyp; // RO Type of connected Device + // possible Values: + // NO_FT_DEVICE no answer from the Device - is it gone ? + // FT_INTELLIGENT_IF FT-Intelligent Interface connect (serial) + // FT_ROBO_IF_IIM FT-Robo Interface with Intelligent-Interface-Modus connect (serial) + // FT_ROBO_IF_USB FT-Robo Interface connect with USB-Port + // FT_ROBO_IF_COM FT-Robo Interface connect with COM- (serial-) Port + // FT_ROBO_IO_EXTENSION FT-Robo I/O-Extension + // FT_ROBO_RF_DATA_LINK FT-Robo RF Data Link + // FT_ROBO_IF_OVER_RF FT-Robo Interface connect over RF-Data-Link + + // Serial numbers section + DWORD dwSn; // RO actually Serial Number at Power On + DWORD dwSn1; // RW Serial Number-1 (only FT-Robo Products) + DWORD dwSn2; // RO Serial Number-2 (only FT-Robo Products) + DWORD dwSnAktiv; // RW Set Serial Number Activ (1/2) for next Power On + + DWORD dwFw; // RO Is Firmware Version for this product (only FT-Robo Products) + + unsigned char aSnStrg[LEN_STRG1]; // RO String with Serialnumber (only FT-Robo Products) + unsigned char aSn1Strg[LEN_STRG1]; // RO String with Serialnumber1 (only FT-Robo Products) + unsigned char aSn2Strg[LEN_STRG1]; // RO String with Serialnumber2 (only FT-Robo Products) + unsigned char aFwStrg[LEN_STRG1]; // RO String with Firmware (only FT-Robo Products) + unsigned char aSNaStrg[LEN_STRG2]; // RO String with Short-Name (only FT-Robo Products) + unsigned char aLNaStrg[LEN_STRG2]; // RO String with Long-Name (only FT-Robo Products) + + DWORD dwFwRoboIfVerAtLibIsMade; // RO Robo-If Firmware Version as this Lib is made + DWORD dwFwIoExtVerAtLibIsMade; // RO IO-Extension Firmware Version as this Lib is made + DWORD dwFwRfDataVerAtLibIsMade; // RO RF-DataLink Firmware Version as this Lib is made + unsigned char aFwRoboIfVerAtLibIsMadeStrg[LEN_STRG1]; // RO String with Robo-If Firmware Version as this Lib is made + unsigned char aFwIoExtVerAtLibIsMadeStrg[LEN_STRG1]; // RO String with IO-Extension Firmware Version as this Lib is made + unsigned char aFwRfDataVerAtLibIsMadeStrg[LEN_STRG1]; // RO String with Rf-Data-Link Firmware Version as this Lib is made + + DWORD dwReserved; // Reserved for later use + + + // Output Section + DWORD dwOutputAutoOff[4]; // RW M1=[0]...M4=[3] Energy saver: + // "1" = "Power Off" motor driver when both outputs logical "0" (reduces Energy) + // "0" = do not automatically disable the motor driver + DWORD dwOutputPwmType; // RW PWM-Type (Today only "0" supported) + + + // Robo Interface Distance Sensor + DWORD dwAnzDistanceModes; // RO Number of supported Distance Modes (Array Entries) + DWORD dwDistanceMode; // RW Type and Mode for Distance-Sensor (Index-Number in the range 0...ANZ_DISTANCE_TYPES) + FT_DISTANCE sDistance[ANZ_DISTANCE_TYPES]; // RW Values for setting + + + // Robo Interface Memory Section + DWORD dwProg[3]; // RO 1=Program is saved in the Memory block; [0]=Flash-1 [1]=Flash-2 [2]=Ram + unsigned char aProgNames[3][NAME_LEN]; // RO [0]=Flash-1 Prog Name; [1]=Flash-2 Prog Name; [2]=Ram Prog-Name + DWORD dwF1AutoStart; // RO 1=Autostart Flash-1 programm, 0=no autostart + + + // Robo Interface Module Section + DWORD dwMod1Typ; // RO Type of left Module (only Robo-If) + DWORD dwMod2Typ; // RO Type of right Module (only Robo-If) + // possible Values: + // MODULE_NOT_INSTALLED No Module is installed + // MODULE_RF1 RF Data Link is installed + + unsigned char aMod1Strg[LEN_STRG1]; // RO String with Module-1 Name (only FT-Robo Products) + unsigned char aMod2Strg[LEN_STRG1]; // RO String with Module-2 Name (only FT-Robo Products) + + + // Robo Interface & RF Data Link Section + DWORD dwRfOn; // RW 0=disable RF 1=Enable RF + DWORD dwRfChannel; // RW Channel-Number (2..80) for RF-Communication + DWORD dwRfSubChannel; // RW Sub-Channel of Device for the specified Channel (1..3) + DWORD dwRfMessage; // RW 0=Disable Message-Router Function 1=Enable Message-Rounter Function + DWORD dwRfWrite; // W 0=write values permanent (FLASH); 1=write values temporary (RAM) + DWORD dwRfFw; // RO Firmwareversion of RF-Module + unsigned char aRfFwStrg[LEN_STRG1]; // RO String with Firmware of RF-Module + + // Information for the PC-RF Module + DWORD dwRfStopTransferOnError; // RW 1=Stop the RF-Transfer Thread on bad RF Connection + + // Information for the Interface RF-Module + DWORD dwRfMotorOffOnError; // RW 1=Motor Off on bad RF Connection + } sIf; + } FT_SETTING; + + + // ****** Function Prototypes ****** + DWORD __stdcall GetLibVersion(void); + DWORD __stdcall InitFtLib(void); + DWORD __stdcall CloseFtLib(void); + DWORD __stdcall IsFtLibInit(void); + DWORD __stdcall InitFtUsbDeviceList(void); + UINT __stdcall GetNumFtUsbDevice(void); + FT_HANDLE __stdcall GetFtUsbDeviceHandle(UCHAR ucDevNr); + FT_HANDLE __stdcall GetFtUsbDeviceHandleSerialNr(DWORD dwSN, DWORD dwTyp); + DWORD __stdcall OpenFtUsbDevice(FT_HANDLE hFt); + //FT_HANDLE __stdcall OpenFtCommDevice(DWORD dwPort, DWORD dwTyp, DWORD dwZyklus, DWORD *pdwError); + DWORD __stdcall SetFtDeviceCommMode (FT_HANDLE hFt, DWORD dwMode, DWORD dwParameter, USHORT *puiValue); + DWORD __stdcall CloseAllFtDevices(void); + DWORD __stdcall CloseFtDevice(FT_HANDLE hFt); + DWORD __stdcall GetFtDeviceTyp(FT_HANDLE hFt); + LPCSTR __stdcall GetFtSerialNrStrg(FT_HANDLE hFt); + DWORD __stdcall GetFtSerialNr(FT_HANDLE hFt); + LPCSTR __stdcall GetFtFirmwareStrg(FT_HANDLE hFt); + DWORD __stdcall GetFtFirmware(FT_HANDLE hFt); + LPCSTR __stdcall GetFtManufacturerStrg(FT_HANDLE hFt); + LPCSTR __stdcall GetFtShortNameStrg(FT_HANDLE hFt); + LPCSTR __stdcall GetFtLongNameStrg(FT_HANDLE hFt); + LPCSTR __stdcall GetFtLibErrorString(DWORD dwErrorCode, DWORD dwTyp); + DWORD __stdcall GetFtDeviceSetting(FT_HANDLE hFt, FT_SETTING *pSet); + DWORD __stdcall SetFtDeviceSetting(FT_HANDLE hFt, FT_SETTING *pSet); + DWORD __stdcall SetFtDistanceSensorMode(FT_HANDLE hFt, DWORD dwMode, DWORD dwTol1, DWORD dwTol2, + DWORD dwSchwell1, DWORD dwSchwell2, DWORD dwRepeat1, DWORD dwRepeat2); + + + DWORD __stdcall StartFtTransferArea(FT_HANDLE hFt, NOTIFICATION_EVENTS* sNEvent ); + DWORD __stdcall StartFtTransferAreaWithCommunication(FT_HANDLE hFt, NOTIFICATION_EVENTS* sNEvent ); + DWORD __stdcall StopFtTransferArea(FT_HANDLE hFt); + FT_TRANSFER_AREA* __stdcall GetFtTransferAreaAddress(FT_HANDLE hFt); + DWORD __stdcall IsFtTransferActiv(FT_HANDLE hFt); + DWORD __stdcall ResetFtTransfer (FT_HANDLE hFt); + + + DWORD __stdcall GetFtMemoryLayout(FT_HANDLE hFt, BYTE * pbArray, DWORD dwSize); + DWORD __stdcall DownloadFtProgram(FT_HANDLE hFt, DWORD dwMemBlock, BYTE* pbArray, DWORD dwSize, DWORD dwParameter, BYTE *pbName, DWORD dwNameLen); + DWORD __stdcall StartFtProgram(FT_HANDLE hFt, DWORD dwMemBlock); + DWORD __stdcall StopFtProgram(FT_HANDLE hFt); + DWORD __stdcall DeleteFtProgram(FT_HANDLE hFt, DWORD dwMemBlock); + DWORD __stdcall SetFtProgramActiv(FT_HANDLE hFt, DWORD dwMemBlock); + DWORD __stdcall GetFtProgramName(FT_HANDLE hFt, DWORD dwMemBlock, DWORD dwSize, LPVOID pName); + DWORD __stdcall WriteFtMemoryData(FT_HANDLE hFt, DWORD dwData, DWORD dwAddress); + DWORD __stdcall GetFtMemoryData(FT_HANDLE hFt, BYTE * pbArray, DWORD dwSize, DWORD dwAddress); + + + DWORD __stdcall SendFtMessage(FT_HANDLE hFt, BYTE bHwId, BYTE bSubId, DWORD dwMessage, DWORD dwWaitTime, DWORD dwOption); + DWORD __stdcall ClearFtMessageBuffer(FT_HANDLE hFt); + + + + +// +// FTLIB Error Codes +// + #define FTLIB_ERR_SUCCESS 0x00000000L + #define FTLIB_ERR_CRC 0xE0000001L + #define FTLIB_ERR_BTSTUFF 0xE0000002L + #define FTLIB_ERR_DATA_TOGGLE_MISMATCH 0xE0000003L + #define FTLIB_ERR_STALL_PID 0xE0000004L + #define FTLIB_ERR_DEV_NOT_RESPONDING 0xE0000005L + #define FTLIB_ERR_PID_CHECK_FAILURE 0xE0000006L + #define FTLIB_ERR_UNEXPECTED_PID 0xE0000007L + #define FTLIB_ERR_DATA_OVERRUN 0xE0000008L + #define FTLIB_ERR_DATA_UNDERRUN 0xE0000009L + #define FTLIB_ERR_RESERVED1 0xE000000AL + #define FTLIB_ERR_RESERVED2 0xE000000BL + #define FTLIB_ERR_BUFFER_OVERRUN 0xE000000CL + #define FTLIB_ERR_BUFFER_UNDERRUN 0xE000000DL + #define FTLIB_ERR_NOT_ACCESSED 0xE000000FL + #define FTLIB_ERR_FIFO 0xE0000010L + #define FTLIB_ERR_XACT_ERROR 0xE0000011L + #define FTLIB_ERR_BABBLE_DETECTED 0xE0000012L + #define FTLIB_ERR_DATA_BUFFER_ERROR 0xE0000013L + + #define FTLIB_ERR_ENDPOINT_HALTED 0xE0000030L + #define FTLIB_ERR_NO_MEMORY 0xE0000100L + #define FTLIB_ERR_INVALID_URB_FUNCTION 0xE0000200L + #define FTLIB_ERR_INVALID_PARAMETER 0xE0000300L + #define FTLIB_ERR_ERROR_BUSY 0xE0000400L + #define FTLIB_ERR_INVALID_PIPE_HANDLE 0xE0000600L + #define FTLIB_ERR_NO_BANDWIDTH 0xE0000700L + #define FTLIB_ERR_INTERNAL_HC_ERROR 0xE0000800L + #define FTLIB_ERR_ERROR_SHORT_TRANSFER 0xE0000900L + #define FTLIB_ERR_BAD_START_FRAME 0xE0000A00L + #define FTLIB_ERR_ISOCH_REQUEST_FAILED 0xE0000B00L + #define FTLIB_ERR_FRAME_CONTROL_OWNED 0xE0000C00L + #define FTLIB_ERR_FRAME_CONTROL_NOT_OWNED 0xE0000D00L + #define FTLIB_ERR_NOT_SUPPORTED 0xE0000E00L + #define FTLIB_ERR_INVALID_CONFIGURATION_DESCRIPTOR 0xE0000F00L + + #define FTLIB_ERR_INSUFFICIENT_RESOURCES 0xE8001000L + #define FTLIB_ERR_SET_CONFIG_FAILED 0xE0002000L + #define FTLIB_ERR_USBD_BUFFER_TOO_SMALL 0xE0003000L + #define FTLIB_ERR_USBD_INTERFACE_NOT_FOUND 0xE0004000L + #define FTLIB_ERR_INVALID_PIPE_FLAGS 0xE0005000L + #define FTLIB_ERR_USBD_TIMEOUT 0xE0006000L + #define FTLIB_ERR_DEVICE_GONE 0xE0007000L + #define FTLIB_ERR_STATUS_NOT_MAPPED 0xE0008000L + + #define FTLIB_ERR_CANCELED 0xE0010000L + #define FTLIB_ERR_ISO_NOT_ACCESSED_BY_HW 0xE0020000L + #define FTLIB_ERR_ISO_TD_ERROR 0xE0030000L + #define FTLIB_ERR_ISO_NA_LATE_USBPORT 0xE0040000L + #define FTLIB_ERR_ISO_NOT_ACCESSED_LATE 0xE0050000L + + #define FTLIB_ERR_FAILED 0xE0001000L + #define FTLIB_ERR_INVALID_INBUFFER 0xE0001001L + #define FTLIB_ERR_INVALID_OUTBUFFER 0xE0001002L + #define FTLIB_ERR_OUT_OF_MEMORY 0xE0001003L + #define FTLIB_ERR_PENDING_REQUESTS 0xE0001004L + #define FTLIB_ERR_ALREADY_CONFIGURED 0xE0001005L + #define FTLIB_ERR_NOT_CONFIGURED 0xE0001006L + #define FTLIB_ERR_OPEN_PIPES 0xE0001007L + #define FTLIB_ERR_ALREADY_BOUND 0xE0001008L + #define FTLIB_ERR_NOT_BOUND 0xE0001009L + #define FTLIB_ERR_DEVICE_NOT_PRESENT 0xE000100AL + #define FTLIB_ERR_CONTROL_NOT_SUPPORTED 0xE000100BL + #define FTLIB_ERR_TIMEOUT 0xE000100CL + #define FTLIB_ERR_INVALID_RECIPIENT 0xE000100DL + #define FTLIB_ERR_INVALID_TYPE 0xE000100EL + #define FTLIB_ERR_INVALID_IOCTL 0xE000100FL + #define FTLIB_ERR_INVALID_DIRECTION 0xE0001010L + #define FTLIB_ERR_TOO_MUCH_ISO_PACKETS 0xE0001011L + #define FTLIB_ERR_POOL_EMPTY 0xE0001012L + #define FTLIB_ERR_PIPE_NOT_FOUND 0xE0001013L + #define FTLIB_ERR_INVALID_ISO_PACKET 0xE0001014L + #define FTLIB_ERR_OUT_OF_ADDRESS_SPACE 0xE0001015L + #define FTLIB_ERR_INTERFACE_NOT_FOUND 0xE0001016L + #define FTLIB_ERR_INVALID_DEVICE_STATE 0xE0001017L + #define FTLIB_ERR_INVALID_PARAM 0xE0001018L + #define FTLIB_ERR_INVALID_POWER_STATE 0xE000101AL + #define FTLIB_ERR_POWER_DOWN 0xE000101BL + #define FTLIB_ERR_VERSION_MISMATCH 0xE000101CL + #define FTLIB_ERR_SET_CONFIGURATION_FAILED 0xE000101DL + + #define FTLIB_ERR_VID_RESTRICTION 0xE0001080L + #define FTLIB_ERR_ISO_RESTRICTION 0xE0001081L + #define FTLIB_ERR_BULK_RESTRICTION 0xE0001082L + #define FTLIB_ERR_EP0_RESTRICTION 0xE0001083L + #define FTLIB_ERR_PIPE_RESTRICTION 0xE0001084L + #define FTLIB_ERR_PIPE_SIZE_RESTRICTION 0xE0001085L + #define FTLIB_ERR_CONTROL_RESTRICTION 0xE0001086L + #define FTLIB_ERR_INTERRUPT_RESTRICTION 0xE0001087L + + #define FTLIB_ERR_DEVICE_NOT_FOUND 0xE0001100L + #define FTLIB_ERR_SOME_DEVICES_ARE_OPEN 0xE0001101L + #define FTLIB_ERR_DEVICE_IS_OPEN 0xE0001102L + #define FTLIB_ERR_DEVICE_NOT_OPEN 0xE0001103L + #define FTLIB_ERR_NO_SUCH_DEVICE_INSTANCE 0xE0001104L + #define FTLIB_ERR_INVALID_FUNCTION_PARAM 0xE0001105L + #define FTLIB_ERR_DESTROY_DEVICE_LIST 0xE0001106L + #define FTLIB_ERR_USB_NOT_SUPPORTET_FROM_OS 0xE0001107L + #define FTLIB_ERR_CLOSE_DEVICE 0xE0001108L + + #define FTLIB_ERR_DEVICE_NOT_SUPPORTET 0xE0001281L + #define FTLIB_ERR_WRONG_DEVICE_NUMBER 0xE0001282L + #define FTLIB_ERR_UNKNOWN_DEVICE_HANDLE 0xE0001283L + #define FTLIB_ERR_WRONG_USB_HANDLE 0xE0001284L + #define FTLIB_ERR_WRONG_PATHNAME 0xE0001285L + #define FTLIB_ERR_LIB_IS_INITIALIZED 0xE0001286L + #define FTLIB_ERR_LIB_IS_NOT_INITIALIZED 0xE0001287L + #define FTLIB_ERR_SERIAL_NR_UNKNOWN 0xE0001288L + #define FTLIB_ERR_POWER_TOO_LOW 0xE0001289L + #define FTLIB_ERR_WRONG_RETURN_VALUE 0xE000128AL + #define FTLIB_ERR_USB_SUPPORT_IS_NOT_INITIALIZED 0xE000128BL + + #define FTLIB_ERR_USB_MUT0 0xE0001290L + #define FTLIB_ERR_USB_MUT1 0xE0001291L + #define FTLIB_ERR_USB_MUT2 0xE0001292L + #define FTLIB_ERR_USB_MUT3 0xE0001293L + #define FTLIB_ERR_USB_DEVICE_IS_IN_USE 0xE0001295L + + #define FTLIB_ERR_THREAD_NOT_STARTABLE 0xE00012A0L + #define FTLIB_ERR_THREAD_NOT_STARTABLE_X1 0xE00012A1L + #define FTLIB_ERR_THREAD_NOT_STARTABLE_X2 0xE00012A2L + #define FTLIB_ERR_THREAD_NOT_STARTABLE_X3 0xE00012A3L + #define FTLIB_ERR_OTHER_THREAD_FOR_SAME_DEVICE_IS_RUN 0xE00012A4L + #define FTLIB_ERR_THREAD_IS_RUNNING 0xE00012A5L + #define FTLIB_ERR_THREAD_NOT_RUNNING 0xE00012A6L + #define FTLIB_ERR_THREAD_X1 0xE00012A7L + #define FTLIB_ERR_THREAD_X2 0xE00012A8L + #define FTLIB_ERR_THREAD_WRITE_USB 0xE00012A9L + #define FTLIB_ERR_THREAD_READ_USB 0xE00012AAL + #define FTLIB_ERR_THREAD_IS_NORMAL_STOPPED 0xE00012ABL + #define FTLIB_ERR_THREAD_WAIT_TIMEOUT 0xE00012ACL + #define FTLIB_ERR_THREAD_WRITE_COM 0xE00012ADL + #define FTLIB_ERR_THREAD_READ_COM 0xE00012AEL + + #define FTLIB_ERR_DOWNLOAD 0xE00012C0L + #define FTLIB_ERR_DOWNLOAD_WRONG_PARAMETER 0xE00012C1L + #define FTLIB_ERR_DOWNLOAD_WRONG_MEM_BLOCK 0xE00012C2L + #define FTLIB_ERR_DOWNLOAD_DATA_SIZE_IS_NULL 0xE00012C3L + #define FTLIB_ERR_DOWNLOAD_DATA_SIZE_TOO_BIG 0xE00012C4L + #define FTLIB_ERR_DOWNLOAD_DATA_SIZE 0xE00012C5L + #define FTLIB_ERR_DOWNLOAD_ERASE 0xE00012C6L + #define FTLIB_ERR_DOWNLOAD_F5 0xE00012C7L + #define FTLIB_ERR_DOWNLOAD_PROG_SNF1 0xE00012C8L + #define FTLIB_ERR_DOWNLOAD_PROG_SNF2 0xE00012C9L + #define FTLIB_ERR_DOWNLOAD_BLOCK 0xE00012CAL + #define FTLIB_ERR_DOWNLOAD_BLOCK_NR 0xE00012CBL + #define FTLIB_ERR_DOWNLOAD_CRC 0xE00012CDL + + #define FTLIB_ERR_IF_NO_PROGRAM 0xE00012E0L + #define FTLIB_ERR_IF_PROGRAM_IS_RUNNING 0xE00012E1L + #define FTLIB_ERR_IF_NO_PROGRAM_IS_RUNNING 0xE00012E2L + #define FTLIB_ERR_IF_WRONG_PROG_NUMBER 0xE00012E3L + #define FTLIB_ERR_IF_BUFFER_TOO_SMALL 0xE00012E4L + #define FTLIB_ERR_IF_MEM_ADDRESS 0xE00012E5L + #define FTLIB_ERR_IF_MEM_VERIFY 0xE00012E6L + #define FTLIB_ERR_IF_NOT_SUPPORTET_MODUS 0xE00012E7L + #define FTLIB_ERR_IF_FUNCTION_NOT_SUPPORT 0xE00012E8L + #define FTLIB_ERR_FUNCTION_OVER_RF_NOT_ALLOWED 0xE00012E9L + + + #define FTLIB_INFO_PROGRAM_0_IS_RUNNING 0xE0001600L + #define FTLIB_INFO_PROGRAM_1_IS_RUNNING 0xE0001601L + #define FTLIB_INFO_PROGRAM_2_IS_RUNNING 0xE0001602L + #define FTLIB_INFO_ONLINE_MODUS 0xE0001620L + + #define FTLIB_FIRMWARE_UPDATE_FILE_WRONG_0 0xE0001800L + #define FTLIB_FIRMWARE_UPDATE_CRC 0xE0001801L + #define FTLIB_FIRMWARE_UPDATE_FILE_OLD 0xE0001802L + #define FTLIB_FIRMWARE_UPDATE_FILE_WRONG_1 0xE0001803L + + + #define FTLIB_ERR_PORT_NUMBER 0xE0001900L + #define FTLIB_ERR_WRONG_PORT 0xE0001901L + #define FTLIB_ERR_PORT_NUMBER_IS_NULL 0xE0001902L + #define FTLIB_ERR_TYP 0xE0001903L + #define FTLIB_ERR_PORT_NOT_FOUND 0xE0001904L + #define FTLIB_ERR_ACCESS_DENIED 0xE0001905L + #define FTLIB_ERR_OPEN_COM 0xE0001906L + #define FTLIB_ERR_CLOSE_COM 0xE0001907L + #define FTLIB_ERR_INIT_COM 0xE0001908L + #define FTLIB_ERR_INIT_COM_TIMEOUT 0xE0001909L + #define FTLIB_ERR_WRITE_COM 0xE000190AL + #define FTLIB_ERR_READ_COM 0xE000190BL + #define FTLIB_ERR_READ_COM_NUMBER 0xE000190CL + #define FTLIB_ERR_READ_COM_NOTHING 0xE000190DL + + #define FTLIB_ERR_RF_NOT_INSTALLED 0xE0001A00L + #define FTLIB_ERR_RF_WRONG_CHANNEL 0xE0001A01L + #define FTLIB_ERR_RF_WRONG_SUB_CHANNEL 0xE0001A02L + #define FTLIB_ERR_RF_NO_CONNECTION 0xE0001A03L + #define FTLIB_ERR_RF_NO_CONNECTION_A 0xE0001A04L + #define FTLIB_ERR_RF_NO_CONNECTION_B 0xE0001A05L + #define FTLIB_ERR_RF_NO_CONNECTION_C 0xE0001A06L + #define FTLIB_ERR_RF_TIMEOUT_1 0xE0001A08L + #define FTLIB_ERR_RF_TIMEOUT_2 0xE0001A09L + #define FTLIB_ERR_RF_FW_OLD1 0xE0001A0AL + #define FTLIB_ERR_RF_INTERNAL_1 0xE0001A0DL + #define FTLIB_ERR_RF_NO_INTERFACE_MODULE_FOUND 0xE0001A0EL + + #define FTLIB_ERR_DLL_NOT_LOADABLE 0xE0001B00L + #define FTLIB_ERR_DLL_FUNCTION_ERROR 0xE0001B01L + + #define FTLIB_ERR_MSG_HWID_WRONG 0xE0001C00L + #define FTLIB_ERR_MSG_BUFFER_FULL_TIMEOUT 0xE0001C01L + + #define FTLIB_ERR_UNKNOWN_OPTION_VALUE 0xE0001D00L + + #define FTLIB_ERR_INTERFACE_00 0xE0001F00L + #define FTLIB_ERR_INTERFACE_01 0xE0001F01L + #define FTLIB_ERR_INTERFACE_02 0xE0001F02L + #define FTLIB_ERR_INTERFACE_03 0xE0001F03L + #define FTLIB_ERR_INTERFACE_04 0xE0001F04L + #define FTLIB_ERR_INTERFACE_05 0xE0001F05L + #define FTLIB_ERR_INTERFACE_06 0xE0001F06L + #define FTLIB_ERR_INTERFACE_07 0xE0001F07L + #define FTLIB_ERR_INTERFACE_08 0xE0001F08L + #define FTLIB_ERR_INTERFACE_09 0xE0001F09L + #define FTLIB_ERR_INTERFACE_0A 0xE0001F0AL + #define FTLIB_ERR_INTERFACE_0B 0xE0001F0BL + #define FTLIB_ERR_INTERFACE_0C 0xE0001F0CL + #define FTLIB_ERR_INTERFACE_0D 0xE0001F0DL + #define FTLIB_ERR_INTERFACE_0E 0xE0001F0EL + #define FTLIB_ERR_INTERFACE_0F 0xE0001F0FL + + #define FTLIB_ERR_INTERFACE_D0 0xE0001FD0L + #define FTLIB_ERR_INTERFACE_D1 0xE0001FD1L + #define FTLIB_ERR_INTERFACE_D2 0xE0001FD2L + #define FTLIB_ERR_INTERFACE_D3 0xE0001FD3L + #define FTLIB_ERR_INTERFACE_D4 0xE0001FD4L + #define FTLIB_ERR_INTERFACE_D5 0xE0001FD5L + #define FTLIB_ERR_INTERFACE_D6 0xE0001FD6L + #define FTLIB_ERR_INTERFACE_D7 0xE0001FD7L + #define FTLIB_ERR_INTERFACE_D8 0xE0001FD8L + #define FTLIB_ERR_INTERFACE_D9 0xE0001FD9L + #define FTLIB_ERR_INTERFACE_DA 0xE0001FDAL + #define FTLIB_ERR_INTERFACE_DB 0xE0001FDBL + #define FTLIB_ERR_INTERFACE_DC 0xE0001FDCL + #define FTLIB_ERR_INTERFACE_DD 0xE0001FDDL + #define FTLIB_ERR_INTERFACE_DE 0xE0001FDEL + #define FTLIB_ERR_INTERFACE_DF 0xE0001FDFL + + #define FTLIB_ERR_INTERFACE_E0 0xE0001FE0L + #define FTLIB_ERR_INTERFACE_E1 0xE0001FE1L + #define FTLIB_ERR_INTERFACE_E2 0xE0001FE2L + #define FTLIB_ERR_INTERFACE_E3 0xE0001FE3L + #define FTLIB_ERR_INTERFACE_E4 0xE0001FE4L + #define FTLIB_ERR_INTERFACE_E5 0xE0001FE5L + #define FTLIB_ERR_INTERFACE_E6 0xE0001FE6L + #define FTLIB_ERR_INTERFACE_E7 0xE0001FE7L + #define FTLIB_ERR_INTERFACE_E8 0xE0001FE8L + #define FTLIB_ERR_INTERFACE_E9 0xE0001FE9L + #define FTLIB_ERR_INTERFACE_EA 0xE0001FEAL + #define FTLIB_ERR_INTERFACE_EB 0xE0001FEBL + #define FTLIB_ERR_INTERFACE_EC 0xE0001FECL + #define FTLIB_ERR_INTERFACE_ED 0xE0001FEDL + #define FTLIB_ERR_INTERFACE_EE 0xE0001FEEL + #define FTLIB_ERR_INTERFACE_EF 0xE0001FEFL + + #define FTLIB_ERR_INTERFACE_F0 0xE0001FF0L + #define FTLIB_ERR_INTERFACE_F1 0xE0001FF1L + #define FTLIB_ERR_INTERFACE_F2 0xE0001FF2L + #define FTLIB_ERR_INTERFACE_F3 0xE0001FF3L + #define FTLIB_ERR_INTERFACE_F4 0xE0001FF4L + #define FTLIB_ERR_INTERFACE_F5 0xE0001FF5L + #define FTLIB_ERR_INTERFACE_F6 0xE0001FF6L + #define FTLIB_ERR_INTERFACE_F7 0xE0001FF7L + #define FTLIB_ERR_INTERFACE_F8 0xE0001FF8L + #define FTLIB_ERR_INTERFACE_F9 0xE0001FF9L + #define FTLIB_ERR_INTERFACE_FA 0xE0001FFAL + #define FTLIB_ERR_INTERFACE_FB 0xE0001FFBL + #define FTLIB_ERR_INTERFACE_FC 0xE0001FFCL + #define FTLIB_ERR_INTERFACE_FD 0xE0001FFDL + #define FTLIB_ERR_INTERFACE_FE 0xE0001FFEL + #define FTLIB_ERR_INTERFACE_FF 0xE0001FFFL + +/** \endcond doxygen ignore end */ + +#endif + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ftlib/ftlibclass.cpp Wed Jun 15 19:12:25 2011 +0000 @@ -0,0 +1,105 @@ +#include "mbed.h" +#include "ftlib.h" +#include "ftlibclass.h" +#include "ftlibclasscom.h" +#include "ftlibclassusb.h" + + + +ftlib* ftlib::lib = 0; + +unsigned ftlib::InitFtLib() { + lib = new ftlib; + return FTLIB_ERR_SUCCESS; +} + +void ftlib::onTick() { + ftusbdev::onTick(); + ftcommdev::onTick(); +} + +void ftlib::poll() { + ftusbdev::poll(); //this function should be called repetetively from the main event loop + ftcommdev::poll(); +} + +unsigned ftlib::CloseFtLib() { + delete lib; + lib = 0; + return FTLIB_ERR_SUCCESS; +} + +unsigned ftlib::IsFtLibInit() { + return lib ? FTLIB_ERR_LIB_IS_INITIALIZED : FTLIB_ERR_LIB_IS_NOT_INITIALIZED; +} + +unsigned ftlib::CloseAllFtDevices() { + ftusbdev::CloseAllFtDevices(); + ftcommdev::CloseAllFtDevices(); + return FTLIB_ERR_SUCCESS; +} + +int ftlib::FtproductIDToInterfaceID(int iProductID) { + switch (iProductID) { + case ROBO_IF_PRODUCT_ID: + return FT_ROBO_IF_USB; + case EXT_IF_PRODUCT_ID: + return FT_ROBO_IO_EXTENSION; + case RF_DATA_LINK_PRODUCT_ID: + return FT_ROBO_RF_DATA_LINK; + } + + return 0; +} + +char * ftlib::GetFtLibErrorString(unsigned dwErrorCode, unsigned dwTyp) { + char *buffer = new char[128]; + + switch (dwErrorCode) { + case FTLIB_ERR_IF_NO_PROGRAM: + if (dwTyp) strncpy(buffer, "There is no program stored to work with", 128); + else strncpy(buffer, "FTLIB_ERR_IF_NO_PROGRAM", 128); + break; + case FTLIB_ERR_SUCCESS: + if (dwTyp) strncpy(buffer, "Everything is fine", 128); + else strncpy(buffer, "FTLIB_ERR_SUCCESS", 128); + break; + case FTLIB_ERR_THREAD_IS_RUNNING: + if (dwTyp) strncpy(buffer, "Thread has been started successfully", 128); + else strncpy(buffer, "FTLIB_ERR_THREAD_IS_RUNNING", 128); + break; + case FTLIB_ERR_DOWNLOAD: + if (dwTyp) strncpy(buffer, "Failed to upload the program", 128); + else strncpy(buffer, "FTLIB_ERR_DOWNLOAD", 128); + break; + case FTLIB_ERR_DOWNLOAD_WRONG_MEM_BLOCK: + if (dwTyp) strncpy(buffer, "Bad target to upload the program to", 128); + else strncpy(buffer, "FTLIB_ERR_DOWNLOAD_WRONG_MEM_BLOCK", 128); + break; + case FTLIB_ERR_INVALID_PARAM: + if (dwTyp) strncpy(buffer, "A parameter specified has a wrong value", 128); + else strncpy(buffer, "FTLIB_ERR_INVALID_PARAM", 128); + break; + case FTLIB_ERR_LIB_IS_INITIALIZED: + if (dwTyp) strncpy(buffer, "This library has been initialized", 128); + else strncpy(buffer, "FTLIB_ERR_LIB_IS_INITIALIZED", 128); + break; + case FTLIB_ERR_NOT_SUPPORTED: + if (dwTyp) strncpy(buffer, "The requested action is not supported", 128); + else strncpy(buffer, "FTLIB_ERR_NOT_SUPPORTED", 128); + break; + case FTLIB_ERR_PORT_NUMBER_IS_NULL: + if (dwTyp) strncpy(buffer, "No handle given", 128); + else strncpy(buffer, "FTLIB_ERR_PORT_NUMBER_IS_NULL", 128); + break; + case FTLIB_ERR_THREAD_NOT_RUNNING: + if (dwTyp) strncpy(buffer, "Unable to start the thread", 128); + else strncpy(buffer, "FTLIB_ERR_THREAD_NOT_RUNNING", 128); + break; + default: + strncpy(buffer, "Unknown", 128); + } + + return buffer; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ftlib/ftlibclass.h Wed Jun 15 19:12:25 2011 +0000 @@ -0,0 +1,40 @@ +#ifndef FTLIBCLASS_H +#define FTLIBCLASS_H + +#include "mbed.h" + +#define LIBFT_VERSION_MAJOR 1 +#define LIBFT_VERSION_MINOR 0 +#define LIBFT_VERSION_PATCH 0 + +#define INTERFACE_QUERY_TIME 10000 // �s == 5ms + + +class ftusbdev; +class ftcommdev; + +class ftlib { + friend ftusbdev; + friend ftcommdev; + static ftlib* lib; + Ticker tick;//the ticker indicates the moments that transfers should be conducted + void onTick(); + ftlib() { + tick.attach_us(this, &ftlib::onTick, INTERFACE_QUERY_TIME); + } + ~ftlib() { + tick.detach(); + } + static int FtproductIDToInterfaceID(int iProductID); +public: + static void poll(); +//public API: These functions match those of the original ftlib + static unsigned GetLibVersion(); + static unsigned InitFtLib(); + static unsigned CloseFtLib(); + static unsigned IsFtLibInit(); + static char* GetFtLibErrorString(unsigned dwErrorCode, unsigned dwTyp); + static unsigned CloseAllFtDevices() ; +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ftlib/ftlibclasscom.cpp Wed Jun 15 19:12:25 2011 +0000 @@ -0,0 +1,456 @@ +#include "mbed.h" +#include "ftlibclasscom.h" +vector<ftcommdev*> ftcommdev::devs; + +ftcommdev::ftcommdev(Serial *s, unsigned t, unsigned c): ftdev(t, 0) { + device = s; + port = 0; + FT_TRANSFER_AREA *area = new FT_TRANSFER_AREA; + memset(area, 0, sizeof(struct _FT_TRANSFER_AREA)); + area->TransferAktiv = 0; + //query_time = INTERFACE_QUERY_TIME_SERIAL; + area->RfModulNr = -1; + if (t == FT_INTELLIGENT_IF) + area->BusModules = 1; + else if (t == FT_INTELLIGENT_IF_SLAVE) + area->BusModules = 2; + ta = area; +} + +//blocking +int ftcommdev::read(Serial *stream, unsigned char *buf, int n, int timeout_ms) { + Timer t; + t.start(); + int i = 0; + while (t.read_ms() < timeout_ms && i < n) { + if (stream->readable()) + buf[i++] = stream->getc(); + } + return i; +} + +int ftcommdev::write(Serial *d, unsigned char *ptr, int n, int timeout_ms) { + Timer t; + t.start(); + int i = 0; + while (t.read_ms() < timeout_ms && i < n) { + if (d->writeable()) + d->putc(ptr[i++]); + } + return i; +} + +//non-blocking +int ftcommdev::write() { + windex = 0; + writeByte(); //write the first byte, callback will take care of the rest + return num_write; +} +void ftcommdev::writeByte() { + if (windex < num_write) { + device->putc(out[windex++]); + if (windex == num_write) + rindex = 0; + } +} +void ftcommdev::readByte() { + if (rindex < num_read) { + in[rindex++] = device->getc(); + if (rindex == num_read) { + FtThreadEnd(); + } + } +} + +ftcommdev* ftcommdev::OpenFtCommDevice(unsigned sDevice, unsigned dwTyp, unsigned dwZyklus, unsigned *pdwError) {//makes a (blocking) comm request to the interface + Serial *dev = 0; + switch (sDevice) { + case 1: + dev = new Serial(p9, p10); + break; + case 2: + dev = new Serial(p13, p14); + break; + case 3: + dev = new Serial(p28, p27); + break; +// default: dev = new Serial(p9, p10); break; + default: +// dev = &viaUsb; + break; + } + ftcommdev* com = OpenFtCommDevice(dev, dwTyp, dwZyklus, pdwError); + if (com) { + com->port = sDevice; + printf("opening of COM%d OK\n", sDevice); + } + return com; +} + +ftcommdev* ftcommdev::OpenFtCommDevice(Serial *dev, unsigned dwTyp, unsigned dwZyklus, unsigned *pdwError) {//makes a (blocking) comm request to the interface + unsigned char in[5]; + unsigned char on[] = " ft-Robo-ON-V1"; + on[0] = 0xA1; + ftcommdev* ret = 0; + if (dwTyp != FT_ROBO_IF_COM) { + ret = new ftcommdevii(dev, dwTyp, dwZyklus); + dev->baud(BAUDRATE_II); + } else {// dwTyp == FT_ROBO_IF_COM + ret = new ftcommdev(dev, dwTyp, dwZyklus); + dev->baud(BAUDRATE_RI); + } + printf("about to send '%s'\n", on); + if (dwTyp == FT_ROBO_IF_COM) { + int sent = write(dev, on, strlen((const char*)on), 100/*ms*/); +// int sent = dev->printf("%s", on); + printf("sent %d bytes to COM\n", sent); + if (sent == strlen((const char*)on)) { + if (read(dev, in, 5, 1000/*ms*/) == 5) { // if (dev->scanf("%5c", in) == 1) { does not work, could have to do with NUL chars or needs a lookahead char + printf("%02X: interface version: %d.%d.%d.%d\n", in[0], in[4], in[3], in[2], in[1]); + ret->fw = *(unsigned*)(in+1); + if ((in[0] ^ on[0]) == 0x0FFU) { + printf("opening of %s OK\n", "UNKNOWN"); + } else { + printf("return code is %02X but should be %02X\n", in[0], ~on[0]&0xFF); + delete ret; + return NULL; + } + } else { + printf("read did not return 5\n"); + delete ret; + return NULL; + } + } else { + printf("only %d chars were sent i.o %d\n", sent, strlen((const char*)on)); + delete ret; + return NULL; + } + } + devs.push_back(ret); + return ret; +} + +unsigned ftcommdev::CloseFtDevice() {//sends a comm request + unsigned char off = 0xA2; + unsigned char in[1]; + + while (ta->TransferAktiv != 0) { + fprintf(stderr, "Transfer ta still active\n"); + sleep(1); + } + + if (type == FT_ROBO_IF_COM) { + if (write(device, &off, 1, 500) != 1 || read(device, in, 1, 1000) != 1 || (in[0]^off != 0xFF)) { + fprintf(stderr, "CloseFtDevice: Error communicating with serial\n"); + } + } + for (vector<ftcommdev*>::iterator it = devs.begin(); it < devs.end(); it++) + if (*it == this) { + devs.erase(it); + delete this; + return 0; + } + return 0; +} + +unsigned ftcommdev::GetFtSerialNr() { + int ret; + unsigned char buffer[35] = { 0 }; + if (sn > 0) + return sn; + switch (type) { + case FT_INTELLIGENT_IF: + case FT_INTELLIGENT_IF_SLAVE: + return 0; + case FT_ROBO_IF_COM: + buffer[0] = 0xf0; + buffer[1] = 0x02; + ret = write(device, buffer, 2, 500); + if (ret != 2) { + fprintf(stderr, "Error writing msg 0xF0 0x02\n"); + return 0; + } + ret = read(device, buffer, 5, 1000); + if (ret != 5) { + fprintf(stderr, "Error reading msg 0xF0 0x02\n"); + return 0; + } + //sn = buffer[1] + buffer[2]*100 + buffer[3]*10000 + buffer[4]*1000000; + sn = *(unsigned*)(buffer+1); + break; + default: + return FTLIB_ERR_NOT_SUPPORTED; + } + return sn; +} + +char * ftcommdev::GetFtLongNameStrg() { + switch (type) { + case FT_INTELLIGENT_IF: + return strdup("Intelligent Interface"); + case FT_INTELLIGENT_IF_SLAVE: + return strdup("Intelligent Interface with Slave"); + case FT_ROBO_IF_IIM: + return strdup("Robo Interface in Intelligent Interface mode"); + case FT_ROBO_IF_COM: + return strdup("Robo Interface on Com"); + default: + return strdup("Unknown interface type"); + } +} + +char * ftcommdev::GetFtShortNameStrg() { + switch (type) { + case FT_INTELLIGENT_IF: + return strdup("IIF"); + case FT_INTELLIGENT_IF_SLAVE: + return strdup("IIF w/Slave"); + case FT_ROBO_IF_IIM: + return strdup("RI_IIM"); + case FT_ROBO_IF_COM: + return strdup("RICom"); + default: + return strdup("Unknown"); + } +} + +void ftcommdev::poll() { + for (int i = 0; i < devs.size(); i++) { + if (devs[i]->triggered) { + if (devs[i]->guardedFtThreadBegin()) + devs[i]->triggered = 0; + } + } +} + +void ftcommdev::FtThreadInit() {//setup buffers for this type of interface + device->attach(this, &ftcommdev::writeByte, Serial::TxIrq); + device->attach(this, &ftcommdev::readByte, Serial::RxIrq); + ftdev::FtThreadInit(); + out[0] = 0xf2; + num_write = 17; + num_read = 21; +} + +//here the real data exchange starts +void ftcommdev::FtThreadBegin() {//called every 10ms to issue a request, should be non-blocking + if (!test_and_set()) {//return when transferarea is in use + busy = false; //release the mutex, otherwise the thread effectively stops + return;//return because there is no point in sending a nonsense request, alternatively the lock can be ignored in which case the data may be inconsistent + } + out[1] = ta->M_Main; + out[2] = (ta->MPWM_Main[0] & 0x7) | (ta->MPWM_Main[1]<<3 & 0x38) | (ta->MPWM_Main[2]<<6 & 0xC0); + out[3] = (ta->MPWM_Main[2] & 0x1) | (ta->MPWM_Main[3]<<1 & 0xE) | (ta->MPWM_Main[4]<<4 & 0x70) | (ta->MPWM_Main[5]<<7 & 0x80); + out[4] = (ta->MPWM_Main[5] & 0x3) | (ta->MPWM_Main[6]<<2 & 0x1C) | (ta->MPWM_Main[7]<<5 & 0xE0); + out[5] = ta->M_Sub1; + out[6] = (ta->MPWM_Sub1[0] & 0x7) | (ta->MPWM_Sub1[1]<<3 & 0x38) | (ta->MPWM_Sub1[2]<<6 & 0xC0); + out[7] = (ta->MPWM_Sub1[2] & 0x1) | (ta->MPWM_Sub1[3]<<1 & 0xE) | (ta->MPWM_Sub1[4]<<4 & 0x70) | (ta->MPWM_Sub1[5]<<7 & 0x80); + out[8] = (ta->MPWM_Sub1[5] & 0x3) | (ta->MPWM_Sub1[6]<<2 & 0x1C) | (ta->MPWM_Sub1[7]<<5 & 0xE0); + out[9] = ta->M_Sub2; + out[10] = (ta->MPWM_Sub2[0] & 0x7) | (ta->MPWM_Sub2[1]<<3 & 0x38) | (ta->MPWM_Sub2[2]<<6 & 0xC0); + out[11] = (ta->MPWM_Sub2[2] & 0x1) | (ta->MPWM_Sub2[3]<<1 & 0xE) | (ta->MPWM_Sub2[4]<<4 & 0x70) | (ta->MPWM_Sub2[5]<<7 & 0x80); + out[12] = (ta->MPWM_Sub2[5] & 0x3) | (ta->MPWM_Sub2[6]<<2 & 0x1C) | (ta->MPWM_Sub2[7]<<5 & 0xE0); + out[13] = ta->M_Sub3; + out[14] = (ta->MPWM_Sub3[0] & 0x7) | (ta->MPWM_Sub3[1]<<3 & 0x38) | (ta->MPWM_Sub3[2]<<6 & 0xC0); + out[15] = (ta->MPWM_Sub3[2] & 0x1) | (ta->MPWM_Sub3[3]<<1 & 0xE) | (ta->MPWM_Sub3[4]<<4 & 0x70) | (ta->MPWM_Sub3[5]<<7 & 0x80); + out[16] = (ta->MPWM_Sub3[5] & 0x3) | (ta->MPWM_Sub3[6]<<2 & 0x1C) | (ta->MPWM_Sub3[7]<<5 & 0xE0); + out[17] = 0; + out[18] = 0; + out[19] = 0; + out[20] = 0; + out[21] = 0; + out[22] = 0; + out[23] = 0; + out[24] = 0; + out[25] = 0; + out[26] = 0; + out[27] = 0; + out[28] = 0; + out[29] = 0; + out[30] = 0; + out[31] = 0; + + increment();//release the lock on shared memeory + write(); +} +#if 0 +void ftcommdev::FtThreadEnd() {//called by the receiver/dma callback when the reply is complete + if (!test_and_set()) {//skip when busy + busy = false; + return; + } + ta->ChangeEg = ta->E_Main != in[0] || ta->E_Sub1 != in[1] || ta->E_Sub2 != in[2] || ta->E_Sub3 != in[3]; + ta->E_Main = in[0]; + ta->E_Sub1 = in[1]; + ta->E_Sub2 = in[2]; + ta->E_Sub3 = in[3]; + ta->ChangeAn = 1; //assume that analog always changes (noise) + ta->AX = in[4]; + ta->AY = in[5]; + ta->A1 = in[6]; + ta->A2 = in[7]; + ta->AX |= (in[8] & 0x3) << 8; + ta->AY |= (in[8] & 0xC) << 6; + ta->A1 |= (in[8] & 0x30) << 4; + ta->A2 |= (in[8] & 0xC0) << 2; + ta->AZ = in[9]; + ta->D1 = in[10]; + ta->D2 = in[11]; + ta->AV = in[12]; + ta->AZ |= (in[13] & 0x3) << 8; + ta->D1 |= (in[13] & 0xC) << 6; + ta->D2 |= (in[13] & 0x30) << 4; + ta->AV |= (in[13] & 0xC0) << 2; + if (ta->IRKeys != in[14]) + ta->ChangeIr = 1; + ta->IRKeys = in[14]; + ta->BusModules = in[15]; + // 16 + ta->AXS1 = in[17]; + ta->AXS2 = in[18]; + ta->AXS3 = in[19]; + ta->AXS1 |= (in[20] & 0x3) << 8; + ta->AXS2 |= (in[20] & 0xC) << 6; + ta->AXS3 |= (in[20] & 0x30) << 4; + // 21 + ta->AVS1 = in[22]; + ta->AVS2 = in[23]; + ta->AVS3 = in[24]; + ta->AVS1 |= (in[25] & 0x3) << 8; + ta->AVS2 |= (in[25] & 0xC) << 6; + ta->AVS3 |= (in[25] & 0x30) << 4; + // 26...42 + increment(); + interface_connected = 1; + if (ne.NotificationCallback) { + (*ne.NotificationCallback)(ne.Context); + } + busy = false; +} +#endif + +void ftcommdev::FtThreadFinish() {//called by StopFtTransferArea + device->attach(0,Serial::RxIrq); + device->attach(0,Serial::TxIrq); + ftdev::FtThreadFinish(); +} + +void ftcommdevii::FtThreadBegin() {//called every 10ms to issue a request, should be non-blocking + if (!test_and_set()) {//return when transferarea is in use + busy = false; //release the mutex, otherwise the thread effectively stops + return;//return because there is no point in sending a nonsense request, alternatively the lock can be ignored in which case the data may be inconsistent + } + out[1] = ta->M_Main; + out[2] = ta->M_Sub1; + + // For the II we need to simulate different speeds here + for (int iCurMotor = 0; iCurMotor < 7; iCurMotor++) { + if (ta->MPWM_Main[iCurMotor] < ii_speed) out[1] &= ~(1 << iCurMotor); + if (ta->MPWM_Sub1[iCurMotor] < ii_speed) out[2] &= ~(1 << iCurMotor); + } + ii_speed++; + if (ii_speed > 7) ii_speed = 0; + + num_write=2; + switch (cycle) { + case 0: + num_read=3; + out[0] = 0xc5; + break; + case 1: + num_read=3; + out[0] = 0xc9; + break; + default: + num_read=1; + out[0] = 0xc1; + break; + } + if (type == FT_INTELLIGENT_IF_SLAVE) { + num_write++; + num_read++; + out[0]++; + } + if (cycle++ > analogcycle) cycle=0; + increment();//release the lock on shared memeory + write(); +} + +void ftcommdevii::FtThreadEnd() {//called by the receiver/dma callback when the reply is complete + if (!test_and_set()) {//skip when busy + busy = false; + return; + } + ta->ChangeEg = ta->E_Main != in[0]; + ta->E_Main = in[0]; + ta->BusModules = type==FT_INTELLIGENT_IF_SLAVE; + switch (out[0]) { + case 0xc1: + break; + case 0xc5: + ta->AX = in[1] | (8<<in[2]); + break; + case 0xc9: + ta->AY = in[1] | (8<<in[2]); + break; + case 0xc2: + ta->ChangeEg = ta->ChangeEg || ta->E_Sub1 != in[1]; + ta->E_Sub1 = in[1]; + break; + case 0xc6: + ta->ChangeEg = ta->ChangeEg || ta->E_Sub1 != in[1]; + ta->E_Sub1 = in[1]; + ta->AX = in[2] | (8<<in[3]); + break; + case 0xca: + ta->ChangeEg = ta->ChangeEg || ta->E_Sub1 != in[1]; + ta->E_Sub1 = in[1]; + ta->AY = in[2] | (8<<in[3]); + break; + } + increment(); + interface_connected = 1; + if (ne.NotificationCallback) { + (*ne.NotificationCallback)(ne.Context); + } + busy = false; +} + +unsigned ftcommdev::SetFtDistanceSensorMode(unsigned dwMode, unsigned dwTol1, unsigned dwTol2, unsigned dwLevel1, unsigned dwLevel2, unsigned dwRepeat1, unsigned dwRepeat2) { + unsigned char buffer[11]; + + if (type != FT_ROBO_IF_COM) + return FTLIB_ERR_NOT_SUPPORTED; + + buffer[0] = 0xf1; + buffer[1] = 0x01; + buffer[2] = dwMode; + buffer[3] = dwTol1; + buffer[4] = dwTol2; + buffer[5] = dwLevel1; + buffer[6] = dwLevel1>>8; + buffer[7] = dwLevel2; + buffer[8] = dwLevel2>>8; + buffer[9] = dwRepeat1; + buffer[10] = dwRepeat2; + + if ((write(device, buffer, 11, 500)) != 11 || (read(device, buffer, 1, 500)) != 1 || buffer[0] != 0x01) { + fprintf(stderr, "SetFtDistanceSensorMode: Error communicating with serial\n"); + return buffer[0]; + } + usleep(100000); // wait before continue, else it doesn't always work + return FTLIB_ERR_SUCCESS; +} + +unsigned ftcommdev::pgm_message(unsigned code, unsigned dwMemBlock) { + unsigned char buffer[2]; + if (type != FT_ROBO_IF_COM) return FTLIB_ERR_NOT_SUPPORTED; + buffer[0] = code; + buffer[1] = dwMemBlock; + if ((write(device, buffer, 2, 500)) != 2 || (read(device, buffer, 1, 500)) != 1) { + return FTLIB_ERR_IF_NO_PROGRAM; + } + if ((buffer[0]) == 0x1) return FTLIB_ERR_SUCCESS; + else return FTLIB_ERR_IF_NO_PROGRAM; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ftlib/ftlibclasscom.h Wed Jun 15 19:12:25 2011 +0000 @@ -0,0 +1,82 @@ +#ifndef FTLIBCLASSCOM_H +#define FTLIBCLASSCOM_H + +#include "ftlibclassdev.h" +#include <vector> + +#define BAUDRATE_II 9600 +#define BAUDRATE_RI 38400 + +#define usleep(x) wait_us(x) +#define sleep(x) wait(x) + +class ftlib; + +class ftcommdev: public ftdev { //for serial devices (Robo over Com), IIF devices are derived from this + friend ftlib; + virtual unsigned pgm_message(unsigned code, unsigned dwMemBlock); +protected: + static vector<ftcommdev*> devs; + Serial *device; + unsigned port; + int windex, rindex; + ftcommdev() {} + ftcommdev(Serial *s, unsigned t, unsigned c); + static int write(Serial *d, unsigned char *ptr, int n, int timeout_ms); + static int read(Serial *stream, unsigned char *buf, int n, int timeout_ms); + int write(); + void writeByte(); + void readByte(); + static void onTick() { + for (int i = 0; i < devs.size(); i++) devs[i]->trigger(); + } + static void CloseAllFtDevices() { + for (int i = 0; i < devs.size(); i++) devs[i]->CloseFtDevice(); + } + virtual void FtThreadInit(); + virtual void FtThreadBegin(); +// virtual void FtThreadEnd(); + virtual void FtThreadFinish(); +public: + virtual ~ftcommdev() { + if (port>0) delete device; + } + static void poll(); +//public API: These functions match those of the original ftlib + static ftcommdev* OpenFtCommDevice(unsigned dwPort, unsigned dwTyp, unsigned dwZyklus, unsigned *pdwError); + static ftcommdev* OpenFtCommDevice(Serial *port, unsigned dwTyp, unsigned dwZyklus, unsigned *pdwError); + virtual unsigned CloseFtDevice(); + virtual unsigned GetFtSerialNr(); + virtual char* GetFtManufacturerStrg() { + return strdup("Knobloch GMBH"); + } + virtual char* GetFtShortNameStrg(); + virtual char* GetFtLongNameStrg(); + virtual unsigned SetFtDistanceSensorMode(unsigned dwMode, unsigned dwTol1, unsigned dwTol2, + unsigned dwSchwell1, unsigned dwSchwell2, unsigned dwRepeat1, unsigned dwRepeat2); + /* + virtual unsigned GetFtDeviceSetting(FT_SETTING *pSet); + virtual unsigned SetFtDeviceSetting(FT_SETTING *pSet); + */ + virtual unsigned StartFtProgram(unsigned dwMemBlock) { + return pgm_message(0xf4, dwMemBlock); + } + virtual unsigned StopFtProgram() { + return pgm_message(0xf8, 0); + } +}; + +class ftcommdevii: public ftcommdev {//specialisation of intelligent interface like devices + friend ftcommdev; + int analogcycle, cycle; + int ii_speed; + ftcommdevii() {} + ftcommdevii(Serial *s, unsigned t, unsigned c):ftcommdev(s, t, c), analogcycle(c) { + cycle = 0; + ii_speed = 0; + } + virtual void FtThreadBegin(); + virtual void FtThreadEnd(); +}; + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ftlib/ftlibclassdev.cpp Wed Jun 15 19:12:25 2011 +0000 @@ -0,0 +1,229 @@ +#include "mbed.h" +#include "USBHost.h" +#include "ftlibclassdev.h" + +#define usleep(x) wait_us(x) +#define sleep(x) wait(x) + +//incorrect: should clear outputs when thread is NOT running +unsigned ftdev::ResetFtTransfer() { + if (ta) { + ta->M_Main = 0; + ta->M_Sub1 = 0; + ta->M_Sub2 = 0; + ta->M_Sub3 = 0; + return FTLIB_ERR_SUCCESS; + } + return FTLIB_ERR_DEVICE_NOT_OPEN; +} + +unsigned ftdev::IsFtTransferActiv() { + if (transferAktiv > 0) + return FTLIB_ERR_THREAD_IS_RUNNING; + return FTLIB_ERR_THREAD_NOT_RUNNING; +} + +//not sure about this conversion +char * ftdev::GetFtFirmwareStrg() { + unsigned ifw = GetFtFirmware(); + char *s = new char[16]; + int byte1 = ifw & 0xff; + int byte2 = (ifw & 0xff00) >> 8; + int byte3 = (ifw & 0xff0000) >> 16; + int byte4 = (ifw & 0xff000000) >> 24; + snprintf(s, 16, "%d.%02d.%02d.%02d", byte4, byte3, byte2, byte1); + return s; +} + +//not sure about this conversion +char * ftdev::GetFtSerialNrStrg() { + DWORD ifw = GetFtSerialNr(); + char *s = new char[16]; + int byte1, byte2, byte3, byte4; + byte1 = ifw % 100; + ifw /= 100; + byte2 = ifw % 100; + ifw /= 100; + byte3 = ifw % 100; + ifw /= 100; + byte4 = ifw % 100; + ifw /= 100; + snprintf(s, 16, "%d.%02d.%02d.%02d", byte4, byte3, byte2, byte1); + return s; +} + +unsigned ftdev::StartFtTransferArea(NOTIFICATION_EVENTS* ev) { + int err = IsFtTransferActiv(); + if (err == FTLIB_ERR_THREAD_IS_RUNNING) + return err; + if (ta==0) + return FTLIB_ERR_DEVICE_NOT_OPEN; + if (ev) + ne = *ev; //copy the entire struct + else + memset(&ne, 0, sizeof(NOTIFICATION_EVENTS)); + FtThreadInit();//setup buffers and serial handlers + transferAktiv = FTX1RUN; + return FTLIB_ERR_SUCCESS; +} + +unsigned ftdev::StartFtTransferAreaWithCommunication(NOTIFICATION_EVENTS* ev) { + if (type == FT_INTELLIGENT_IF || type == FT_INTELLIGENT_IF_SLAVE || type == FT_ROBO_IF_IIM) + return FTLIB_ERR_NOT_SUPPORTED; + if (messages == 0) + messages = new msgbuffer<SMESSAGE, 10>; + int ret = StartFtTransferArea(ev); + if (ret) { + delete messages; + messages = 0; + } + return ret; +} + +unsigned ftdev::StopFtTransferArea() { + while (!guardedStop()) { + USBLoop();//otherwise this loop gets stuck + printf("waiting for thread to finish\r"); + } + FtThreadFinish(); + if (messages) { + delete messages; + messages = 0; + } + busy = false; + printf("\nthread stopped\n"); + return FTLIB_ERR_SUCCESS; +} + +bool ftdev::guardedFtThreadBegin() {//called every 10ms by the main loop to issue a request, should be non-blocking, guarded by busy flag to avoid multiple pending requests + // printf("busy:%d-%d ", busy, triggered); + __disable_irq(); + if (busy) { + if (triggered > 100) { //interface has not responded within 100 slots or response was missed + printf("Missed reply??? releasing busy\n"); + busy = false; //release the busy flag to reenable the request-reply process + } + __enable_irq(); + return false; //skip the timeslot when previous was not yet handled + } + busy = true; + printf("trig=%d\n", triggered); + __enable_irq(); + FtThreadBegin();//here the request is sent to the interface + return true; +} + +bool ftdev::guardedStop() {//called every 10ms by the main loop to issue a request, should be non-blocking, guarded by busy flag to avoid multiple pending requests + __disable_irq(); + if (busy) { + if (triggered > 100) { //interface has not responded within 10 slots or response was missed + printf("busy "); + } + __enable_irq(); + return false; //skip the timeslot when previous was not yet handled + } + busy = true; + __enable_irq(); + triggered = 0; + transferAktiv = FTX1STOP; + return true; +} + +bool ftdev::test_and_set() { + bool tmp; + __disable_irq(); + if (tmp = (lock>0)) + lock--; + __enable_irq(); + return tmp; +} + +void ftdev::increment() { + __disable_irq(); + lock++; + __enable_irq(); +} + +void ftdev::FtThreadEnd() {//called by the receiver/dma callback when the reply is complete + if (!test_and_set()) {//skip when busy + busy = false; + printf("ftdev::FtThreadEnd: release busy\n"); + return; + } + ta->ChangeEg = ta->E_Main != in[0] || ta->E_Sub1 != in[1] || ta->E_Sub2 != in[2] || ta->E_Sub3 != in[3]; + ta->E_Main = in[0]; + ta->E_Sub1 = in[1]; + ta->E_Sub2 = in[2]; + ta->E_Sub3 = in[3]; + ta->ChangeAn = 1; //assume that analog always changes (noise) + ta->AX = in[4]; + ta->AY = in[5]; + ta->A1 = in[6]; + ta->A2 = in[7]; + ta->AX |= (in[8] & 0x3) << 8; + ta->AY |= (in[8] & 0xC) << 6; + ta->A1 |= (in[8] & 0x30) << 4; + ta->A2 |= (in[8] & 0xC0) << 2; + ta->AZ = in[9]; + ta->D1 = in[10]; + ta->D2 = in[11]; + ta->AV = in[12]; + ta->AZ |= (in[13] & 0x3) << 8; + ta->D1 |= (in[13] & 0xC) << 6; + ta->D2 |= (in[13] & 0x30) << 4; + ta->AV |= (in[13] & 0xC0) << 2; + if (ta->IRKeys != in[14]) + ta->ChangeIr = 1; + ta->IRKeys = in[14]; + ta->BusModules = in[15]; + // 16 + ta->AXS1 = in[17]; + ta->AXS2 = in[18]; + ta->AXS3 = in[19]; + ta->AXS1 |= (in[20] & 0x3) << 8; + ta->AXS2 |= (in[20] & 0xC) << 6; + ta->AXS3 |= (in[20] & 0x30) << 4; + // 21 + ta->AVS1 = in[22]; + ta->AVS2 = in[23]; + ta->AVS3 = in[24]; + ta->AVS1 |= (in[25] & 0x3) << 8; + ta->AVS2 |= (in[25] & 0xC) << 6; + ta->AVS3 |= (in[25] & 0x30) << 4; + // 26...42 + ta->AV *= 3; + ta->AVS1 *= 3; + ta->AVS2 *= 3; + ta->AVS3 *= 3; + //message processing + if (messages && ne.CallbackMessage) { //just to check if communication was enabled + if (in[28]) + ne.CallbackMessage((SMESSAGE*)(in+29)); + if (in[35]) + ne.CallbackMessage((SMESSAGE*)(in+36)); + } + increment(); + interface_connected = 1; + if (ne.NotificationCallback) { + (*ne.NotificationCallback)(ne.Context); + } + busy = false; + printf("ftdev::FtThreadEnd: release busy at exit\n"); +} + +unsigned ftdev::SendFtMessage(unsigned char bHwId, unsigned char bSubId, unsigned dwMessage, unsigned dwWaitTime, unsigned dwOption) { + SMESSAGE m; + m.L.ucHwId = bHwId; + m.L.ucSubId = bSubId; + m.L.dw = dwMessage; + //waittime ignored + if (messages) + return messages->push(m, dwOption) < 0 ? FTLIB_ERR_MSG_BUFFER_FULL_TIMEOUT : 0; + return FTLIB_ERR_MSG_HWID_WRONG; //not the correct error code +} + +unsigned ftdev::ClearFtMessageBuffer() { + if (messages) + messages->clear(); + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ftlib/ftlibclassdev.h Wed Jun 15 19:12:25 2011 +0000 @@ -0,0 +1,148 @@ +#ifndef FTLIBCLASSDEV_H +#define FTLIBCLASSDEV_H + +#include "ftlib.h" +#include "message.h" + +#define ABF_IF_COMPLETE_NUM_WRITE 32 +#define ABF_IF_COMPLETE_NUM_READ 42 + +/***************************************************************************************** + The interfaces use a combination of synchronous (blocking) and asynchronous (non-blocking) + I/O. For serial I/O it is essential that non-blocking I/O is used otherwise the entire + transfer timeslot would be consumed with busy waiting. For USB this constraint is less + severe but I nevertheless used non-blocking I/O also for USB in the transfer thread (which + is not a real thread). Outside the transfer thread, I/O can be synchronous which I indeed + used because it is easier to write and easier to understand. + The timing of the transfer thread is determined by a Ticker interrupt. But in order not + to occupy the interrupt system for too long, it just increments a counter in every + interface object. The main event loop polls this counter, initiates a transfer and resets + it. Starting a thread works by calling FtThreadInit (which does some initialisation) and + setting transferAktiv to FTX1RUN. The poll routine will then call guardedFtThreadBegin + which in turn will call FtThreadBegin provided the previous run of the thread has ended. + The thead is protected by a busy flag which is set in guardedFtThreadBegin and released + in FtThreadEnd, as long as busy is active a new thread should not be begun (enforced by + guardedFtThreadBegin). FtThreadBegin copies the transferArea (TA) to a buffer and calls + the send routine which (being non-blocking) returns immediately. When the send completes + a callback (interrupt) occurs which initiates the corresponding read (request-reply model). + When the read finished another callback (interrupt) occurs which invokes FtThreadEnd. + FtThreadEnd may call notification routines which will all like FtThreadEnd but unlike + FtThreadBegin run in interrupt context. Both FtThreadBegin and FtThreadEnd operate on + the TA which is shared between the application and the transfer thread. As this transfer- + thread is not a real thread synchronisation is not strictly neccesary because FtThreadBegin + runs in the background (like the application) and FtThreadEnd+callback run as interrupt + and cannot be interrupted by the background. Still a semaphore 'lock' is in place to + protect the TA from simultaneous access. When the area is locked, the transfer is simply + skipped. A user application cal call test_and_set() which returns falls when the area is + locked and true when it is free. After using the TA the user must then call increment() + to release the lock on the TA. At the moment the onlu use-case is to provide a consistent + set of motor-settings to the TX which will be communicated in the same packet. +*****************************************************************************************/ + +inline char* strdup(const char *s) { + char *d = new char[strlen(s)+1]; + strcpy(d, s); + return d; +} + +class ftdev { +protected: + FT_TRANSFER_AREA* ta; + NOTIFICATION_EVENTS ne; + msgbuffer<SMESSAGE, 10> *messages; + int type, sn; + unsigned fw; + unsigned char out[ABF_IF_COMPLETE_NUM_WRITE]; //these buffers have maximum size, alternatively each subclass could have its own properly sized buffer + unsigned char in[ABF_IF_COMPLETE_NUM_READ]; + int num_write, num_read; + enum _ta_state {FTX1STOP, FTX1RUN, FTX1SYNC} transferAktiv; + volatile int lock; //semaphore to control concurrent access to transferarea, FtThreadEnd is called in interrupt context + volatile bool busy; //semaphore to prevent a transfer from being started while another is still in progress + volatile bool interface_connected; + volatile int triggered;//when >0 indicates that the next transfer should take place + ftdev() {} //private default, construction takes place through subclasses + ftdev(int t, int s): type(t), sn(s) { + ta = 0; + fw = 0; + triggered = 0; + busy = false; + lock = 1; + interface_connected = false; + messages = 0; + transferAktiv = FTX1STOP; + } + void trigger() { + if (transferAktiv != FTX1STOP) triggered++; //called by onTick + } + bool guardedFtThreadBegin(); //called by 'poll' + bool guardedStop(); + virtual void FtThreadInit() { busy = false; if (ta) ta->TransferAktiv = true;} //called by StartFtTransferArea + virtual void FtThreadBegin() = 0; //called by 'guardedFtThreadBegin' + virtual void FtThreadEnd(); //called by interrupt when transfer completes + virtual void FtThreadFinish() { if(ta) ta->TransferAktiv = false;} //called by StopFtTransferArea + bool test_and_set(); //'lock' semphore + void increment(); //'lock' semphore + virtual unsigned pgm_message(unsigned code, unsigned dwMemBlock) = 0; +public: + virtual ~ftdev() { + delete ta; + delete messages; + } +//public API: These functions match those of the original ftlib + virtual unsigned CloseFtDevice() = 0; + virtual unsigned GetFtDeviceTyp() { + return type; + } + virtual char* GetFtSerialNrStrg(); + virtual unsigned GetFtSerialNr() { + return sn; + } + virtual char* GetFtFirmwareStrg(); + virtual unsigned GetFtFirmware() { + return fw; + } + virtual char* GetFtManufacturerStrg() = 0; + virtual char* GetFtShortNameStrg() = 0; + virtual char* GetFtLongNameStrg() = 0; + /* + virtual unsigned GetFtDeviceSetting(FT_SETTING *pSet); + virtual unsigned SetFtDeviceSetting(FT_SETTING *pSet); + */ + virtual unsigned SetFtDistanceSensorMode(unsigned dwMode, unsigned dwTol1, unsigned dwTol2, + unsigned dwSchwell1, unsigned dwSchwell2, unsigned dwRepeat1, unsigned dwRepeat2) { + return FTLIB_ERR_NOT_SUPPORTED; + } + virtual unsigned StartFtTransferArea(NOTIFICATION_EVENTS* sNEvent = 0); + virtual unsigned StartFtTransferAreaWithCommunication(NOTIFICATION_EVENTS* sNEvent = 0); + virtual unsigned StopFtTransferArea(); + virtual FT_TRANSFER_AREA* GetFtTransferAreaAddress() { + return ta; + } + virtual unsigned IsFtTransferActiv(); + unsigned ResetFtTransfer (); + unsigned SendFtMessage(unsigned char bHwId, unsigned char bSubId, unsigned dwMessage, unsigned dwWaitTime, unsigned dwOption); + unsigned ClearFtMessageBuffer(); + virtual unsigned StartFtProgram(unsigned dwMemBlock) { + return FTLIB_ERR_NOT_SUPPORTED; + } + virtual unsigned StopFtProgram() { + return FTLIB_ERR_NOT_SUPPORTED; + } + unsigned DeleteFtProgram(unsigned dwMemBlock) { + return pgm_message(0xf5, dwMemBlock); + } + unsigned SetFtProgramActiv(unsigned dwMemBlock) { + return pgm_message(0xf9, dwMemBlock); + } +}; + + +/* still to be implemented + unsigned GetFtMemoryLayout(unsigned char * pbArray, unsigned dwSize); + unsigned DownloadFtProgram(unsigned dwMemBlock, unsigned char* pbArray, unsigned dwSize, unsigned dwParameter, unsigned char *pbName, unsigned dwNameLen); + unsigned GetFtProgramName(unsigned dwMemBlock, unsigned dwSize, char* pName); + unsigned WriteFtMemoryData(unsigned dwData, unsigned dwAddress); + unsigned GetFtMemoryData(unsigned char * pbArray, unsigned dwSize, unsigned dwAddress); +*/ + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ftlib/ftlibclasstxc.cpp Wed Jun 15 19:12:25 2011 +0000 @@ -0,0 +1,501 @@ +#include "mbed.h" +#include "USBHost.h" +#include "ftlibclasstxc.h" +#include "ftErrCode.h" + +ftusbdevtx::ftusbdevtx(): ftusbdev(0, FT_TXC, 0) { + sid = 0; + tid = 0; + active = 0; + transferAktiv = FTX1STOP; + cbRoboExtState = 0; + for (int i = TA_LOCAL; i < TA_N_PARTS; i++) ta[i] = 0; +} + +ftusbdevtx::ftusbdevtx(int d): ftusbdev(d, FT_TXC, 0) { + sid = 0; + tid = 0; + active = 0; + transferAktiv = FTX1STOP; + cbRoboExtState = 0; + for (int i = TA_LOCAL; i < TA_N_PARTS; i++) ta[i] = 0; + set_baudrate(38400); + send_msg(1); //ping + GetFtSerialNr(); +} + +void ftusbdevtx::getSlaveInfo() { + send_msg(7, 1); //get state for master + for (int i = 1; i <= N_EXT_DEV; i++) + if (ta[0]->state.ext_dev_connect_state[i-1]) { + if (ta[i] == 0) { //new slave + ta[i] = new TA; + memset(ta[i], 0, sizeof(TA)); + active |= 1<<i; + send_msg(6, 1<<i); //get info for slave; + printf("New Extension %d = %s\n", i, ta[i]->info.device_name); + if (cbRoboExtState) cbRoboExtState(i, 1); + } + } else { + if (ta[i]) { + delete ta[i]; + ta[i] = 0; + active &= ~(1<<i); + printf("Extension %d went offline\n", i); + if (cbRoboExtState) cbRoboExtState(i, 0); + } + } +// send_msg(6, active & ~1); //get info for slaves; +} + +unsigned ftusbdevtx::OpenFtUsbDevice() { + ta[0] = new TA; + memset(ta[0], 0, sizeof(TA)); + active = 1; + send_msg(6, 1); //get info for master + printf("Master=%s\n", ta[0]->info.device_name); + getSlaveInfo(); /* + send_msg(7, 1); //get state for master + for (int i = 0; i < N_EXT_DEV; i++) + if (ta[0]->state.ext_dev_connect_state[i]) { + ta[i+1] = new TA; + memset(ta[i+1], 0, sizeof(TA)); + active |= 1<<(i+1); + send_msg(6, 1<<(i+1)); //get info for slave; + printf("Extension %d = %s\n", i+1, ta[i+1]->info.device_name); + }*/ +// send_msg(6, active & ~1); //get info for slaves; + return 0; +} + +unsigned ftusbdevtx::CloseFtDevice() { + if (ta[0]==0) + return FTLIB_ERR_DEVICE_NOT_OPEN; + while (transferAktiv != FTX1STOP) { + fprintf(stderr, "Transfer ta still active\n"); + wait(1); + } + for (int i = 0; i < N_EXT_DEV; i++) + if (ta[i]!=0) { + delete ta[i]; + ta[i] = 0; + } + return 0; +} + +unsigned ftusbdevtx::IsFtTransferActiv() { + if (ta[0] == 0) + return FTLIB_ERR_DEVICE_NOT_OPEN;//or just say not running + if (transferAktiv == FTX1RUN) + return FTLIB_ERR_THREAD_IS_RUNNING; + if (transferAktiv == FTX1STOP) + return FTLIB_ERR_THREAD_NOT_RUNNING; + return FTLIB_ERR_THREAD_SYNCHRONIZED; +} + + +unsigned ftusbdevtx::set_baudrate(unsigned br) { + unsigned char buffer[7] = {0x00, 0x96, 0x00, 0x00, 0, 0, 8}; + *(unsigned*)buffer = br; + int ret = USBControlTransfer(device, 0x21, 0x20, 0, 0, buffer, 7); + if (ret != 7) + printf("error setting Baudrate: %d\n", ret); + ret = USBControlTransfer(device, 0xa1, 0x21, 0, 0, buffer, 7); + if (ret == 7) + printf("baudrate=%d, format=%d, parity=%d, bits=%d\n", *(int*)buffer, buffer[4], buffer[5], buffer[6]); + else + printf("error getting Baudrate: %d\n", ret); + return *(unsigned*)buffer; +} + +unsigned ftusbdevtx::GetFtSerialNr() { + if (sn) return sn; + unsigned char req_sn[] = "\x0dget_ser_num\x0d"; + char ser[80]; + memset(ser, 0, sizeof(ser)); + int ret=write_data(req_sn, sizeof(req_sn)-1); + if (ret != sizeof(req_sn)-1) + printf("bulk write error: %d\n", ret); + ret=read_data((unsigned char*)ser, sizeof(ser)); + if (ret < 0) + printf("bulk read error: %d\n", ret); + char s1[41],s3[31]; + unsigned num=0; + int n = sscanf(ser,"\x0d\x0a%40[^\n\r]%u\x0d\x0a%30[^\n\r]", s1, &num, s3); + if (n==3) { + sn = num; + printf("%010u %s\n", num, s3); + } else + printf("could not parse serial number [%s]\n", ser); + return sn; +} + +char* ftusbdevtx::GetFtLongNameStrg() { + unsigned char req_sn[] = "\x0dget_ser_num\x0d"; + char ser[80]; + memset(ser, 0, sizeof(ser)); + int ret=write_data(req_sn, sizeof(req_sn)-1); + if (ret != sizeof(req_sn)-1) + printf("bulk write error: %d\n", ret); + ret=read_data((unsigned char*)ser, sizeof(ser)); + if (ret < 0) + printf("bulk read error: %d\n", ret); + char s1[41],s3[31]=""; + unsigned num=0; + int n = sscanf(ser,"\x0d\x0a%40[^\n\r]%u\x0d\x0a%30[^\n\r]", s1, &num, s3); + return strdup(s3); +} + +TA* ftusbdevtx::GetFtTransferAreaAddress(int i) { + if (i < N_EXT_DEV) + if (ta[i]) + return ta[i]; + else + printf("TX%d is not open\n", i); + else + printf("Index out of range (%d)\n", i); + return 0; +} + +unsigned ftusbdevtx::StartFtTransferArea(NOTIFICATION_EVENTS* ev) { + int err = IsFtTransferActiv(); + if (err == FTLIB_ERR_THREAD_IS_RUNNING) + return err; + if (active==0) + return FTLIB_ERR_DEVICE_NOT_OPEN; + if (ev) + ne = *ev; //copy the entire struct + else + memset(&ne, 0, sizeof(NOTIFICATION_EVENTS)); + FtThreadInit(); //sets busy to false + transferAktiv = FTX1RUN;//indicate that thread is running + return FTLIB_ERR_SUCCESS; +} + +void ftusbdevtx::FtThreadBegin() { + if (!test_and_set()) {//return when transferarea is in use + busy = false; //release the mutex, otherwise the thread effectively stops + printf("TA busy: skip begin slot\n"); + return;//return because there is no point in sending a nonsense request, alternatively the lock can be ignored in which case the data may be inconsistent + } + transferAktiv = FTX1SYNC;//indicate that TA is being updated (like busy) + send_msg(2, active, false); + increment(); +} + +void ftusbdevtx::FtThreadEnd() { + if (!test_and_set()) {//skip when busy + busy = false; + printf("TA busy: skip end slot\n"); + return; + } + rec_msg(); //parse the message + increment(); //release the TA mutex + if (ne.NotificationCallback) { + ne.NotificationCallback(ne.Context); + } + if (tid%100 == 0) { //about every 1 seconds + //getSlaveInfo(); //synchronous! TODO: change to non-blocking + } + transferAktiv = FTX1RUN;//TA update complete + busy = false; //ready for the next tick +// printf("Busy released\n"); +} + +UINT16 ftusbdevtx::checksum(unsigned char *p, unsigned n) { + UINT16 sum = 0; + do { + sum -= *p++; + } while (--n); + return (sum<<8)|(sum>>8); +} + +void ftusbdevtx::dump_buffer(int size) { + if (buffer==0) { + printf("No buffer\n"); + return; + } + for (int i = 0; i < size; i++) { + printf("%02X ", buffer[i]); + if (i%16 == 15) printf("\n"); + } + printf("----------------------\n"); +} + +unsigned ftusbdevtx::send_msg(unsigned cmd, unsigned set, bool sync) { + const unsigned sizes[] = {0, 0, //cmd 1 + sizeof(TA_OUTPUT)+sizeof(UINT32), //cmd 2 + 0, //unknown + 0, //unknown + sizeof(TA_CONFIG)+sizeof(UINT32), //cmd 5 + sizeof(UINT32), //cmd 6 + sizeof(UINT32), //cmd 7 + sizeof(DISPLAY_MSG)+sizeof(UINT32), //cmd 8 + DEV_NAME_LEN + 1+3 + sizeof(UINT32) //cmd 9 + }; + int ret = 0; + int n = 0; + for (int i = TA_LOCAL; i < TA_N_PARTS; i++) { + if (set & (1<<i)) { + n++; + } + } + unsigned size = 0; + if (cmd < sizeof(sizes)/sizeof(unsigned)) + size = sizes[cmd]; + unsigned payload_size = n*size; + num_read = sizeof(header)+sizeof(trailer); + unsigned total_size = sizeof(header)+payload_size+sizeof(trailer); + buffer = new unsigned char[total_size]; //size must be known in advance + + unsigned net_size = total_size-sizeof(UINT32)-sizeof(trailer);//exclude start,len,crc,etx + header *hdr = (header*)buffer; + hdr->start = 0x5502; + hdr->bytesH = net_size>>8; + hdr->bytesL = net_size&0xff; + hdr->body.snd = 2; + hdr->body.rec = 1; + hdr->body.trans = ++tid; + hdr->body.session = sid; + hdr->body.cmd = cmd; + hdr->body.structs = n; + unsigned char* payload = buffer+sizeof(header); + for (int i = TA_LOCAL; i < TA_N_PARTS; i++) { + if (ta[i]==0 || !(set & (1<<i))) { + if (set & (1<<i)) printf("TX %d is not open yet!\n", i); + continue; + } + unsigned *id = (unsigned*)payload; + *id = i; + payload = (unsigned char*)(id+1); + num_read += sizeof(UINT32); + switch (cmd) { + case 1: + break; + case 2: + memcpy(payload, &ta[i]->output, sizeof(TA_OUTPUT)); + payload += sizeof(TA_OUTPUT); + num_read += sizeof(TA_INPUT); + break; + case 5: + memcpy(payload, &ta[i]->config, sizeof(TA_CONFIG)); + payload += sizeof(TA_OUTPUT); + break; + case 6: + num_read += sizeof(TA_INFO); + break; + case 7: + num_read += sizeof(TA_STATE); + break; + case 8: + memcpy(payload, &ta[i]->display.display_msg, sizeof(DISPLAY_MSG)); + payload += sizeof(DISPLAY_MSG); + break; + case 9: + memcpy(payload, ta[i]->info.device_name, DEV_NAME_LEN + 1+3); + payload += sizeof(DEV_NAME_LEN + 1+3); + break; + default: + printf("Unknown message type %d\n", cmd); + break; + } + } + trailer *trl = (trailer*)payload; + trl->chksum = checksum(buffer+2, net_size+2); + trl->etx = '\x03'; + num_read--; + //dump_buffer(total_size); + //printf("Expecting %d bytes for transaction %d\n", num_read, tid); + if (sync) { + ret = write_data(buffer, total_size-1);//send 1 less because trailer is 1 too long due to alignment + delete[] buffer; + if (ret < 0) + printf("synchronous send_message failed (%d)\n", ret); + else { + buffer = new unsigned char[num_read]; + ret = read_data(buffer, num_read); + if (ret < 0) { + printf("synchronous read failed (%d)\n", ret); + delete[] buffer; + } else { + //dump_buffer(num_read); + rec_msg(); + } + } + } else + write_data(buffer, total_size-1, &ftusbdevtx::write_finished_cb, this); + return ret; +} +#if 0 +unsigned ftusbdevtx::rec_msg() { + header *hdr = (header*)buffer; + //dump_buffer(num_read); + if (hdr->start != 0x5502) printf("Invalid packet\n"); + unsigned net_size = (hdr->bytesH<<8) + hdr->bytesL; + if (net_size+7 != num_read) printf("message has %d bytes, was expecting %d bytes\n", net_size+7, num_read); + //printf("message %d from %d\n", hdr->cmd, hdr->snd); + if (hdr->rec != 2) printf("Wrong destination (%d)\n", hdr->rec); + if (hdr->trans != tid) printf("Response to request %d, expected %d\n", hdr->trans, tid); + if (hdr->session != sid) { + printf("Session number has changed from %d to %d\n", sid, hdr->session); + sid = hdr->session; + tid = 1; //restart transaction sequence + } + unsigned cmd = hdr->cmd - 100; + unsigned n = hdr->structs; + unsigned char* payload = buffer+sizeof(header); + trailer *trl = (trailer*)(buffer+net_size+4); + for (int i = 0; i < n && payload < (unsigned char*)trl; i++) { + unsigned *id = (unsigned*)payload; + if (*id >= TA_N_PARTS) { + printf("Illegal extension nr %d\n", *id); + continue; + } + if (ta[*id]==0) { + printf("Message for new device %d\n", *id); + continue;//skip the copy to avoid assignment to null ta but the payload pointer is not advanced! stopping further copying + } + payload = (unsigned char*)(id+1); + switch (cmd) { + case 1: + break; + case 2: + memcpy(&ta[*id]->input, payload, sizeof(TA_INPUT)); + payload += sizeof(TA_INPUT); + break; + case 5: + break; + case 6: + memcpy(&ta[*id]->info, payload, sizeof(TA_INFO)); + payload += sizeof(TA_INFO); + break; + case 7: + memcpy(&ta[*id]->state, payload, sizeof(TA_STATE)); + payload += sizeof(TA_STATE); + break; + case 8: + break; + case 9: + break; + default: + printf("Unknown message type %d\n", cmd); + break; + } + } + if (payload != (unsigned char*)trl) printf("expected %d sections with in total %d bytes; got %d bytes\n", n, payload-buffer-sizeof(header), net_size-sizeof(header)); + if (trl->chksum != checksum(buffer+2, net_size+2)) printf("Checksum error\n"); + if (trl->etx != '\x03') printf("Expected ETX(03), got %02X\n", trl->etx); + delete[] buffer; + return 0; +} +#else +unsigned ftusbdevtx::rec_msg() { + header *hdr = (header*)buffer; + //dump_buffer(num_read); + if (hdr->start != 0x5502) printf("Invalid packet\n"); + unsigned net_size = (hdr->bytesH<<8) + hdr->bytesL; + if (net_size+7 != num_read) printf("message has %d bytes, was expecting %d bytes\n", net_size+7, num_read); + rec_msg2(&hdr->body, net_size); + trailer *trl = (trailer*)(buffer+net_size+4); + if (trl->chksum != checksum(buffer+2, net_size+2)) printf("Checksum error\n"); + if (trl->etx != '\x03') printf("Expected ETX(03), got %02X\n", trl->etx); + delete[] buffer; + return 0; +} + +unsigned ftusbdevtx::rec_msg2(headerbody *hdr, unsigned net_size) { + //printf("message %d from %d\n", hdr->cmd, hdr->snd); + if (hdr->rec != 2) printf("Wrong destination (%d)\n", hdr->rec); + if (hdr->trans != tid) printf("Response to request %d, expected %d\n", hdr->trans, tid); + if (hdr->session != sid) { + printf("Session number has changed from %d to %d\n", sid, hdr->session); + sid = hdr->session; + tid = 1; //restart transaction sequence + } + unsigned cmd = hdr->cmd - 100; + unsigned n = hdr->structs; + if (n==0) + printf("Got reply to cmd %d\n", cmd); + unsigned char* payload = (unsigned char *)(hdr+1); + unsigned char* trl = (unsigned char*)hdr+net_size; + for (int i = 0; i < n && payload < trl; i++) { + unsigned *id = (unsigned*)payload; + if (*id >= TA_N_PARTS) { + printf("Illegal extension nr %d\n", *id); + continue; + } + if (ta[*id]==0) { + printf("Message for new device %d\n", *id); + continue;//skip the copy to avoid assignment to null ta but the payload pointer is not advanced! stopping further copying + } + payload = (unsigned char*)(id+1); + switch (cmd) { + case 1: + break; + case 2: + memcpy(&ta[*id]->input, payload, sizeof(TA_INPUT)); + payload += sizeof(TA_INPUT); + break; + case 5: + break; + case 6: + memcpy(&ta[*id]->info, payload, sizeof(TA_INFO)); + payload += sizeof(TA_INFO); + break; + case 7: + memcpy(&ta[*id]->state, payload, sizeof(TA_STATE)); + payload += sizeof(TA_STATE); + if (*id == 0) + for (int i = 1; i <= N_EXT_DEV; i++) + if (ta[0]->state.ext_dev_connect_state[i-1]) { + if (!(active & (1<<i))) { //new slave + active |= 1<<i; + if (ta[i] == 0) { //new slave + ta[i] = new TA; + memset(ta[i], 0, sizeof(TA)); + } + send_msg(6, 1<<i, false); //get info for slave; + printf("New Extension %d = %s\n", i, ta[i]->info.device_name); + if (cbRoboExtState) cbRoboExtState(i, 1); + } + } else { + if (active & (1<<i)) { + active &= ~(1<<i); + printf("Extension %d went offline\n", i); + if (cbRoboExtState) cbRoboExtState(i, 0); + } + } + + break; + case 8: + break; + case 9: + break; + default: + printf("Unknown message type %d\n", cmd); + break; + } + } + if (payload != trl) + printf("expected %d sections with in total %d bytes; got %d bytes\n", n, payload-(unsigned char*)(hdr+1), net_size-sizeof(headerbody)); + return cmd; +} +#endif +void ftusbdevtx::read_finished_cb(int device, int endpoint, int status, u8* data, int len, void* userData) { +//end of reply transfer +//printf("read_finished_cb: %d bytes\n", len); + ftusbdevtx *fth = (ftusbdevtx*)userData; + if (fth->transferAktiv == FTX1SYNC) + fth->FtThreadEnd(); + else + fth->rec_msg(); +} + +void ftusbdevtx::write_finished_cb(int device, int endpoint, int status, u8* data, int len, void* userData) { //end of request transfer, issue, reply transfer + ftusbdevtx *fth = (ftusbdevtx*)userData; +//printf("write_finished_cb: wrote %d bytes, reading %d bytes\n", len, fth->num_read); + delete[] fth->buffer; + fth->buffer = new unsigned char[fth->num_read]; + USBInterruptTransfer(fth->device, 0x82, fth->buffer, fth->num_read, read_finished_cb, fth); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ftlib/ftlibclasstxc.h Wed Jun 15 19:12:25 2011 +0000 @@ -0,0 +1,279 @@ +#ifndef FTLIBCLASSTXC_H +#define FTLIBCLASSTXC_H +#include "ftlibclassusb.h" +#include <string.h> +#include "fifo.h" +#define FT_TXC 300 + + +typedef unsigned char UINT8; +typedef unsigned char BOOL8; +typedef unsigned char UCHAR8; +typedef unsigned short UINT16; +typedef short INT16; +typedef unsigned short BOOL16; +typedef int INT32; +typedef unsigned UINT32; + +//#include "ROBO_TX_FW.h" //"../PC_programming_RoboTXC_V1-2_11_Dec_2009/PC_Programming_RoboTXC/Demo_Static_Lib_C/Inc/" +#include "ROBO_TX_FW_1_24.h" //"../PC_programming_RoboTXC/PC_Programming_RoboTXC/Demo_Static_Lib_C/Inc/" +typedef struct { + UINT32 snd, rec; + UINT16 trans, session; + UINT32 cmd, structs; + } headerbody; + +typedef struct { + UINT16 start; + union { //the message format is HL, the native format is LH, receiver routine swaps HL to LH, send routine writes as HL UINT16 bytes; + struct { + UINT8 bytesH, bytesL; + }/*anonymous*/; //as_bytes; + UINT16 bytes; + };//winavr allows anonymous structs and unions + headerbody body; +// UINT32 ta_id;//ta_id is normally not considered part of the header but part of the payload, it is repeated for each struct +} header; + + +typedef struct { + UINT16 chksum; + UCHAR8 etx; +} trailer; + +class ftusbdevtx: public ftusbdev { + friend ftusbdev; +protected: + typedef TA *pTA; + pTA ta[TA_N_PARTS]; + unsigned short tid, sid; + unsigned char *buffer; + fifo console; + unsigned active; + unsigned short checksum(unsigned char *p, unsigned n); + void getSlaveInfo(); + void (*cbRoboExtState)(unsigned, unsigned); + ftusbdevtx(); + ftusbdevtx(int d); + virtual void FtThreadInit() { + busy = false; + } + virtual void FtThreadBegin() ; + virtual void FtThreadEnd() ; + virtual unsigned set_baudrate(unsigned br); + void dump_buffer(int); + //unsigned set_name(unsigned index, char *name) { return send_msg(9, 1<<index, name);} + unsigned send_msg(unsigned cmd, unsigned set=0, bool sync = true); + unsigned rec_msg(); + unsigned rec_msg2(headerbody *hdr, unsigned net_size); + static void read_finished_cb(int device, int endpoint, int status, unsigned char* data, int len, void* userData); + static void write_finished_cb(int device, int endpoint, int status, unsigned char* data, int len, void* userData); + virtual int read_data(unsigned char *data, int size, USBCallback callback = 0, void* userData = 0) { return USBBulkTransfer(device, 0x82, data, size, callback, userData);} + virtual int write_data(unsigned char *data, int size, USBCallback callback = 0, void* userData = 0) { return USBBulkTransfer(device, 0x03, data, size, callback, userData);} +public: + virtual ~ftusbdevtx() { + for (int i = 0; i < TA_N_PARTS; i++) if (ta[i]) { + delete ta[i]; + ta[i]=0; + } + } +//public API: These functions match those of the original ftlib + virtual unsigned OpenFtUsbDevice(); //ftxOpenComDevice, we regard a TXC as a USB device + virtual unsigned CloseFtDevice(); //ftxCloseDevice, ftxCloseAllDevices (ftlibclass) + virtual unsigned IsFtTransferActiv(); + virtual unsigned GetFtFirmware() { + if (ta[0]) return ta[0]->info.version.firmware.abcd; + return 0; + } + virtual unsigned GetFtSerialNr(); + virtual char* GetFtManufacturerStrg() { //ftxGetManufacturerStrg + return strdup("MSC Vertriebs GmbH"); + } + virtual char* GetFtShortNameStrg() {//ftxGetShortNameStrg + return strdup("ROBO TX Controller");; + } + virtual char* GetFtLongNameStrg();//ftxGetLongNameStrg + virtual FT_TRANSFER_AREA* GetFtTransferAreaAddress() { +#ifdef COMPATIBILITY + if (ftdev::ta==0) ftdev::ta = new FT_TRANSFER_AREA; +#else + printf("TXC does not support Robo TA\n"); //or create a compatible copy +#endif + return ftdev::ta; + } + TA* GetFtTransferAreaAddress(int i) ; + virtual unsigned StartFtTransferArea(NOTIFICATION_EVENTS* sNEvent ); + virtual unsigned StartFtTransferAreaWithCommunication(NOTIFICATION_EVENTS* sNEvent ) { + return FTLIB_ERR_NOT_SUPPORTED; + } +//FtRemoteCmd + void SetCBRoboExtState(void(*f)(unsigned, unsigned)) { + cbRoboExtState = f; + } + unsigned GetRoboTxDevName(int dev, char *strbuf, int len) { + if (ta[dev]==0) return 0; + strncpy(strbuf, ta[dev]->info.device_name, len); + return strlen(strbuf); + } + unsigned SetRoboTxDevName(int dev, char *strbuf) { + if (ta[dev]==0) return FTLIB_ERR_DEVICE_NOT_OPEN; + strncpy(ta[dev]->info.device_name, strbuf, 17); + send_msg(9, 1<<dev); + return FTLIB_ERR_SUCCESS; + } + unsigned GetRoboTxBtAddr(int dev, char *strbuf, int len) { + if (ta[dev]==0) return 0; + strncpy(strbuf, ta[dev]->info.bt_addr, len); + return strlen(strbuf); + } + unsigned GetFirmware(int dev) { + if (ta[dev]==0) return 0; + return ta[dev]->info.version.firmware.abcd; + } + //unsigned GetRoboTxFwStr(char *strbuf, int len) { return sprintf(strbuf, "%010d", 123456789);} + unsigned GetRoboTxHwStr(int dev, char *strbuf, int len) { + if (ta[dev]==0) return 0; + if (len>0) { + *strbuf = ta[dev]->info.version.hardware.part.a; + return 1; + } else return 0; + } + unsigned GetRoboTxDllStr(int dev, char *strbuf, int len) { + const char *dll = dev==0 ? "2" : "0";//seems to be '2' for master and '0' for slaves, source unknown + strcpy(strbuf, dll); + return strlen(dll); + } + unsigned SetOutCounterReset(int dev, unsigned cnt) { + if (ta[dev]==0) return FTLIB_ERR_DEVICE_NOT_OPEN; + if (cnt >= N_CNT) return -1; + ta[dev]->output.cnt_reset[cnt] = true; + return FTLIB_ERR_SUCCESS; + } + unsigned SetOutMotorValues(int dev, unsigned mId, float speed) { + int dutyp = 0, dutym = 0; + if (ta[dev]==0) return FTLIB_ERR_DEVICE_NOT_OPEN; + if (mId >= N_MOTOR) return -1; + if (speed >= 1) dutyp = 512; + else if (speed >= 0) dutyp = 512*speed; + else if (speed <= -1) dutym = 512; + else dutym = 512*speed; + ta[dev]->output.duty[mId<<1] = dutym; + ta[dev]->output.duty[(mId<<1)+1] = dutyp; + return FTLIB_ERR_SUCCESS; + } + unsigned SetOutPwmValues(int dev, unsigned mId, float speed) { + int duty = 0; + if (ta[dev]==0) return FTLIB_ERR_DEVICE_NOT_OPEN; + if (mId >= N_PWM_CHAN) return -1; + if (speed >= 1) duty = 512; + else if (speed >= 0) duty = 512*speed; + ta[dev]->output.duty[mId] = duty; + return FTLIB_ERR_SUCCESS; + } + //SetFtUniConfig + //SetFtCntConfig + //SetMotorExConfig + //StopMotorExConfig + //ResetMotorExConfig + //SetCBMotorExReached + //GetInIOValue + //GetInCounterValue + //GetInDisplayButtonValue + //SetRoboTxMessage +}; + +#endif + +#if 0 +class ta_txc: private TA { +public: + unsigned GetRoboTxDevName(char *strbuf, int len) { + strncpy(strbuf, info.device_name, len); + return strlen(info.device_name); + } + unsigned SetRoboTxDevName(char *strbuf); + unsigned GetRoboTxBtAddr(char *strbuf, int len) { + strncpy(strbuf, info.bt_addr, len); + return strlen(info.bt_addr); + } + unsigned GetRoboTxFwVal(unsigned *buf) { + *buf = info.version.firmware.abcd; + return 0; + } + //unsigned GetRoboTxFwStr(char *strbuf, int len) { return sprintf(strbuf, "%010d", 123456789);} + unsigned GetRoboTxHwStr(char *strbuf, int len) { + if (len>0) { + *strbuf = info.version.hardware.part.a; + return 1; + } else return 0; + } + unsigned GetRoboTxDllStr(char *strbuf, int len) { + char *dll ="0"; + strcpy(strbuf, dll); + return strlen(dll); + } + //SetOutCounterReset + //SetOutMotorValues + //SetOutPwmValues + //SetFtUniConfig + //SetFtCntConfig + //SetMotorExConfig + //StopMotorExConfig + //ResetMotorExConfig + //SetCBMotorExReached + //GetInIOValue + //GetInCounterValue + //GetInDisplayButtonValue + //SetRoboTxMessage +}; + +class ftusbdevtx; +class ftdevtxslave { + ftusbdevtx *mstr; + int dev; +//protected: + ftdevtxslave() {} + ftdevtxslave(int d); + //unsigned set_name(unsigned index, char *name) { return send_msg(9, 1<<index, name);} +public: + virtual ~ftdevtxslave() { } +//public API: These functions match those of the original ftlib + virtual unsigned GetFtFirmware() { + if (ta[0]) return ta[0]->info.version.firmware.abcd; + return 0; + } + virtual unsigned GetFtSerialNr(); + virtual char* GetFtManufacturerStrg() { //ftxGetManufacturerStrg + return strdup("MSC Vertriebs GmbH"); + } + virtual char* GetFtShortNameStrg() {//ftxGetShortNameStrg + return GetFtLongNameStrg(); + } + virtual char* GetFtLongNameStrg();//ftxGetLongNameStrg + virtual FT_TRANSFER_AREA* GetFtTransferAreaAddress() { +#ifdef COMPATIBILITY + if (ftdev::ta==0) ftdev::ta = new FT_TRANSFER_AREA; +#else + printf("TXC does not support Robo TA\n"); //or create a compatible copy +#endif + return ftdev::ta; + } + TA* GetFtTransferAreaAddress(int i) ; + //SetOutCounterReset + unsigned SetOutMotorValues(int mId, float speed) { + return mstr->SetOutMotorValues(dev, mId, speed); + } + //SetOutPwmValues + //SetFtUniConfig + //SetFtCntConfig + //SetMotorExConfig + //StopMotorExConfig + //ResetMotorExConfig + //SetCBMotorExReached + //GetInIOValue + //GetInCounterValue + //GetInDisplayButtonValue + //SetRoboTxMessage +}; + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ftlib/ftlibclasstxcbt.cpp Wed Jun 15 19:12:25 2011 +0000 @@ -0,0 +1,474 @@ +#include "mbed.h" +#include "USBHost.h" +#include "ftlibclasstxcbt.h" +#include "ftErrCode.h" +#include "Utils.h" + +ftusbdevtxbt::ftusbdevtxbt(BTDevice *bd): ftusbdevtx() { + init = idle; + message_pending = 0; + parseState = 0; + if (bd) { + memcpy((char*)&btaddr, (char*)bd->GetAddress(), sizeof(BD_ADDR)); + name = bd->_name; + } + set_baudrate(38400);//no effect + //further com not possible because device is not open +// send_msg(1); //ping +// GetFtSerialNr(); +} + +unsigned ftusbdevtxbt::InitFtUsbDeviceList() { + ftusbdev::InitFtUsbDeviceList(); + BTDevice* btdevs[8]; + int count = Bluetooth.GetDevices(btdevs,8); + for (int i = 0; i < count; i++) + //if (memcmp(devs[i]->_info.dev_class, FtDevClass, 3)==0) + { + devs.push_back(new ftusbdevtxbt(btdevs[i])); + printf("%d: %s\n", i, btdevs[i]->_name); + } + return 0; +} + +int ftusbdevtxbt::read_data(unsigned char *data, int size, USBCallback callback, void* userData) { + return 0; +} + +int ftusbdevtxbt::write_data(unsigned char *data, int size, USBCallback callback, void* userData) { + return Socket_Send(device, data, size); +} + +unsigned ftusbdevtxbt::GetFtSerialNr() { + return sn; +} + +void ftusbdevtxbt::parse (const unsigned char *buf, unsigned len) { + unsigned i = 0; + //printf("start parse, state = %d, len = %d\n", parseState, len); + while (i < len) { + char c = buf[i++]; + switch (parseState) { + case 0: //ascii state + if (c==2) + parseState = 1; + else { + putc(c, stdout); + console.put(c); + } + break; + case 1: + if (c==0x55) + parseState = 2; + else { + parseState = 0; + printf("expected 0x55 in X1 header, found %02X\n", c); + } + break; + case 2: + X1_len = c<<8; + X1_crc = c; + parseState= 3; + break; + case 3: + X1_len += c; + X1_crc += c; + parseState= 4; + X1_pkt = new unsigned char[X1_len]; + //printf("net length = %d\n", X1_len); + X1_pos = 0; + break; + case 4: + if (X1_pos < X1_len) { + X1_pkt[X1_pos++] = c; + X1_crc += c; + } else { //c is first checksum byte (MSB!) + parseState = 6; + X1_crc += c<<8; + } + break; + case 5: + //X1_crc = c<<8; + X1_crc += c; + parseState= 6; + break; + case 6: + X1_crc += c; + parseState= 7; + break; + case 7: + if (c == 3 && X1_crc == 0) { + //printHex(X1_pkt, X1_len); + if (transferAktiv == FTX1SYNC) + FtThreadEnd(); + else + X1_cmd = rec_msg2((headerbody*)X1_pkt, X1_len); + delete[] X1_pkt; + } else + printf("framing or checksum error, end char = %02X, sum=%04X\n", c, X1_crc); + + parseState = 0; + break; + } + } + //printf("Leaving parse, state = %d, i = %d (last char = %02X)\n", parseState, i, buf[i-1]); +} + +void ftusbdevtxbt::receive(int socket, SocketState state, const u8* data, int len) { + //printf("ftusbdevtxbt::receive was called: socket %d, state=%d, length=%d\n", socket, state, len); + static const unsigned char req[] = "\xdget_ser_num\xd"; + char line[80]; + if (len==0) { + switch (state) { + case SocketState_Opening: + break; + case SocketState_Open: + console.flush(); + send_msg(1, 0, false); //ping + init = ping; + break; + case SocketState_Closing: + case SocketState_Closed: + return; + } + } else { + //printHex(data, len); + parse(data, len); + switch (init) { + case idle: + break; + case ping: + if (X1_cmd == 1) { + printf("sending sernum request \n%s\n", req); + Socket_Send(socket, req, strlen((char*)req)); + init = serial; + } + break; + case serial: + while (console.gets(line, 80)==0) { + printf("Line=%s\n", line); + if (sscanf(line, "%d", &sn) == 1) { + printf("Got S/N=%d\n", sn); + send_msg(6, 1, false); //get INFO for master + init = info; + } + } + break; + case info: + if (X1_cmd == 6) { + printf("Master=%s\n", ta[0]->info.device_name); + send_msg(7, 1, false); //get state for master + init = slaves; + } + break; + case slaves: + if (X1_cmd == 7) {/* + for (int i = 1; i <= N_EXT_DEV; i++) + if (ta[0]->state.ext_dev_connect_state[i-1]) { + if (ta[i] == 0) { //new slave + ta[i] = new TA; + memset(ta[i], 0, sizeof(TA)); + active |= 1<<i; + printf("New Extension %d = %s\n", i, ta[i]->info.device_name); + if (cbRoboExtState) cbRoboExtState(i, 1); + } + } else { + if (ta[i]) {//should not happen during initialisation + delete ta[i]; + ta[i] = 0; + active &= ~(1<<i); + printf("Extension %d went offline\n", i); + if (cbRoboExtState) cbRoboExtState(i, 0); + } + } + if (active != 1) { + send_msg(6, active & ~1, false); //get info for slaves; + init = slaves_info; + } else*/ + init = ready; + } + break; + case slaves_info: + if (X1_cmd == 6) { + init = ready; + } + break; + case ready://normal message processing + break; + } + } +} + +unsigned ftusbdevtxbt::OpenFtUsbDevice() { + ta[0] = new TA; + memset(ta[0], 0, sizeof(TA)); + active = 1; + L2CAPAddr s; + s.bdaddr = btaddr; + s.psm = 1;//abuse the psm for the channelID + device = Socket_Open(SOCKET_RFCOM, &s.hdr, recv, this);//Open the serial connection via RFCOMM + if (device<=0) { + printf("Opening of RFCOMM socket for ftdevice failed (%d)\n", device); + delete ta[0]; + ta[0] = 0; + return FTLIB_ERR_FAILED; + } + return 0; +} + +unsigned ftusbdevtxbt::CloseFtDevice() { + if (ta[0]==0) + return FTLIB_ERR_DEVICE_NOT_OPEN; + while (transferAktiv != FTX1STOP) { + fprintf(stderr, "Transfer ta still active\n"); + wait(1); + } + for (int i = 0; i < N_EXT_DEV; i++) + if (ta[i]!=0) { + delete ta[i]; + ta[i] = 0; + } + init = idle; + unsigned retval = Socket_Close(device); + if (retval) { + printf("Socket_Close(%d) returned %d\n", device, retval); + return FTLIB_ERR_FAILED; //or whatever + } + return 0; +} + + + +void ftusbdevtxbt::FtThreadBegin() { + if (init != ready) {//still initialising + busy = false; + return; + } + ftusbdevtx::FtThreadBegin(); +} + +void ftusbdevtxbt::FtThreadEnd() { + if (!test_and_set()) {//skip when busy + busy = false; + printf("TA busy: skip end slot\n"); + return; + } + X1_cmd = rec_msg2((headerbody*)X1_pkt, X1_len); //parse the message + increment(); //release the TA mutex + if (ne.NotificationCallback) { + ne.NotificationCallback(ne.Context); + } + transferAktiv = FTX1RUN;//TA update complete + if (tid%100 == 0) { //about every 1 seconds +// getSlaveInfo(); //synchronous! TODO: change to non-blocking + } + busy = false; //ready for the next tick +// printf("Busy released\n"); +} +#if 0 + +UINT16 ftusbdevtxbt::checksum(unsigned char *p, unsigned n) { + UINT16 sum = 0; + do { + sum -= *p++; + } while (--n); + return (sum<<8)|(sum>>8); +} + +void ftusbdevtxbt::dump_buffer(int size) { + if (buffer==0) { + printf("No buffer\n"); + return; + } + for (int i = 0; i < size; i++) { + printf("%02X ", buffer[i]); + if (i%16 == 15) printf("\n"); + } + printf("----------------------\n"); +} + +unsigned ftusbdevtxbt::send_msg(unsigned cmd, unsigned set, bool sync) { + const unsigned sizes[] = {0, 0, //cmd 1 + sizeof(TA_OUTPUT)+sizeof(UINT32), //cmd 2 + 0, //unknown + 0, //unknown + sizeof(TA_CONFIG)+sizeof(UINT32), //cmd 5 + sizeof(UINT32), //cmd 6 + sizeof(UINT32), //cmd 7 + sizeof(DISPLAY_MSG)+sizeof(UINT32), //cmd 8 + DEV_NAME_LEN + 1+3 + sizeof(UINT32) //cmd 9 + }; + int ret = 0; + int n = 0; + for (int i = TA_LOCAL; i < TA_N_PARTS; i++) { + if (set & (1<<i)) { + n++; + } + } + unsigned size = 0; + if (cmd < sizeof(sizes)/sizeof(unsigned)) + size = sizes[cmd]; + unsigned payload_size = n*size; + num_read = sizeof(header)+sizeof(trailer); + unsigned total_size = sizeof(header)+payload_size+sizeof(trailer); + buffer = new unsigned char[total_size]; //size must be known in advance + + unsigned net_size = total_size-sizeof(UINT32)-sizeof(trailer);//exclude start,len,crc,etx + header *hdr = (header*)buffer; + hdr->start = 0x5502; + hdr->bytesH = net_size>>8; + hdr->bytesL = net_size&0xff; + hdr->snd = 2; + hdr->rec = 1; + hdr->trans = ++tid; + hdr->session = sid; + hdr->cmd = cmd; + hdr->structs = n; + unsigned char* payload = buffer+sizeof(header); + for (int i = TA_LOCAL; i < TA_N_PARTS; i++) { + if (ta[i]==0 || !(set & (1<<i))) { + if (set & (1<<i)) printf("TX %d is not open yet!\n", i); + continue; + } + unsigned *id = (unsigned*)payload; + *id = i; + payload = (unsigned char*)(id+1); + num_read += sizeof(UINT32); + switch (cmd) { + case 1: + break; + case 2: + memcpy(payload, &ta[i]->output, sizeof(TA_OUTPUT)); + payload += sizeof(TA_OUTPUT); + num_read += sizeof(TA_INPUT); + break; + case 5: + memcpy(payload, &ta[i]->config, sizeof(TA_CONFIG)); + payload += sizeof(TA_OUTPUT); + break; + case 6: + num_read += sizeof(TA_INFO); + break; + case 7: + num_read += sizeof(TA_STATE); + break; + case 8: + memcpy(payload, &ta[i]->display.display_msg, sizeof(DISPLAY_MSG)); + payload += sizeof(DISPLAY_MSG); + break; + case 9: + memcpy(payload, ta[i]->info.device_name, DEV_NAME_LEN + 1+3); + payload += sizeof(DEV_NAME_LEN + 1+3); + break; + default: + printf("Unknown message type %d\n", cmd); + break; + } + } + trailer *trl = (trailer*)payload; + trl->chksum = checksum(buffer+2, net_size+2); + trl->etx = '\x03'; + num_read--; + //dump_buffer(total_size); + //printf("Expecting %d bytes for transaction %d\n", num_read, tid); + if (sync) { + ret = USBBulkTransfer(device, 3, buffer, total_size-1);//send 1 less because trailer is 1 too long due to alignment + delete[] buffer; + if (ret < 0) + printf("synchronous send_message failed (%d)\n", ret); + else { + buffer = new unsigned char[num_read]; + ret = USBInterruptTransfer(device, 0x82, buffer, num_read); + if (ret < 0) { + printf("synchronous read failed (%d)\n", ret); + delete[] buffer; + } else { + //dump_buffer(num_read); + rec_msg(); + } + } + } else + USBBulkTransfer(device, 3, buffer, total_size-1, &ftusbdevtxbt::write_finished_cb, this); + return ret; +} + +unsigned ftusbdevtxbt::rec_msg() { + header *hdr = (header*)buffer; + //dump_buffer(num_read); + if (hdr->start != 0x5502) printf("Invalid packet\n"); + unsigned net_size = (hdr->bytesH<<8) + hdr->bytesL; + if (net_size+7 != num_read) printf("message has %d bytes, was expecting %d bytes\n", net_size+7, num_read); + //printf("message %d from %d\n", hdr->cmd, hdr->snd); + if (hdr->rec != 2) printf("Wrong destination (%d)\n", hdr->rec); + if (hdr->trans != tid) printf("Response to request %d, expected %d\n", hdr->trans, tid); + if (hdr->session != sid) { + printf("Session number has changed from %d to %d\n", sid, hdr->session); + sid = hdr->session; + tid = 1; //restart transaction sequence + } + unsigned cmd = hdr->cmd - 100; + unsigned n = hdr->structs; + unsigned char* payload = buffer+sizeof(header); + trailer *trl = (trailer*)(buffer+net_size+4); + for (int i = 0; i < n && payload < (unsigned char*)trl; i++) { + unsigned *id = (unsigned*)payload; + if (*id >= TA_N_PARTS) { + printf("Illegal extension nr %d\n", *id); + continue; + } + if (ta[*id]==0) { + printf("Message for new device %d\n", *id); + continue;//skip the copy to avoid assignment to null ta but the payload pointer is not advanced! stopping further copying + } + payload = (unsigned char*)(id+1); + switch (cmd) { + case 1: + break; + case 2: + memcpy(&ta[*id]->input, payload, sizeof(TA_INPUT)); + payload += sizeof(TA_INPUT); + break; + case 5: + break; + case 6: + memcpy(&ta[*id]->info, payload, sizeof(TA_INFO)); + payload += sizeof(TA_INFO); + break; + case 7: + memcpy(&ta[*id]->state, payload, sizeof(TA_STATE)); + payload += sizeof(TA_STATE); + break; + case 8: + break; + case 9: + break; + default: + printf("Unknown message type %d\n", cmd); + break; + } + } + if (payload != (unsigned char*)trl) printf("expected %d sections with in total %d bytes; got %d bytes\n", n, payload-buffer-sizeof(header), net_size-sizeof(header)); + if (trl->chksum != checksum(buffer+2, net_size+2)) printf("Checksum error\n"); + if (trl->etx != '\x03') printf("Expected ETX(03), got %02X\n", trl->etx); + delete[] buffer; + return 0; +} + +void ftusbdevtxbt::read_finished_cb(int device, int endpoint, int status, u8* data, int len, void* userData) { +//end of reply transfer +//printf("read_finished_cb: %d bytes\n", len); + ftusbdevtx *fth = (ftusbdevtx*)userData; + if (fth->transferAktiv == FTX1SYNC) + fth->FtThreadEnd(); + else + fth->rec_msg(); +} + +void ftusbdevtxbt::write_finished_cb(int device, int endpoint, int status, u8* data, int len, void* userData) { //end of request transfer, issue, reply transfer + ftusbdevtx *fth = (ftusbdevtx*)userData; +//printf("write_finished_cb: wrote %d bytes, reading %d bytes\n", len, fth->num_read); + delete[] fth->buffer; + fth->buffer = new unsigned char[fth->num_read]; + USBInterruptTransfer(fth->device, 0x82, fth->buffer, fth->num_read, read_finished_cb, fth); +} +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ftlib/ftlibclasstxcbt.h Wed Jun 15 19:12:25 2011 +0000 @@ -0,0 +1,57 @@ +#ifndef FTLIBCLASSTXCBT_H +#define FTLIBCLASSTXCBT_H +#include "ftlibclasstxc.h" +#include "ftusb.h" +//#include <string.h> +//#define FT_TXC 300 + +//#include "ROBO_TX_FW.h" //"../PC_programming_RoboTXC_V1-2_11_Dec_2009/PC_Programming_RoboTXC/Demo_Static_Lib_C/Inc/" +#include "ROBO_TX_FW_1_24.h" //"../PC_programming_RoboTXC/PC_Programming_RoboTXC/Demo_Static_Lib_C/Inc/" + +class ftusbdevtxbt: public ftusbdevtx { + friend ftusbdev; + BD_ADDR btaddr; + char *name; + enum { idle, ping, serial, info, slaves, slaves_info, ready} init; + int message_pending; + int parseState; + unsigned short X1_crc, X1_len, X1_pos, X1_cmd; + unsigned char *X1_pkt; + //ftusbdevtxbt() {} + ftusbdevtxbt(BTDevice *bd); + //virtual void FtThreadInit() ; + virtual void FtThreadBegin() ; + virtual void FtThreadEnd() ; + //unsigned set_baudrate(unsigned br); + //unsigned send_msg(unsigned cmd, unsigned set=0, bool sync = true); + //unsigned rec_msg(); + //static void read_finished_cb(int device, int endpoint, int status, unsigned char* data, int len, void* userData); + //static void write_finished_cb(int device, int endpoint, int status, unsigned char* data, int len, void* userData); + virtual int read_data(unsigned char *data, int size, USBCallback callback = 0, void* userData = 0);// { return USBBulkTransfer(device, 0x82, data, size, callback, userData);} + virtual int write_data(unsigned char *data, int size, USBCallback callback = 0, void* userData = 0);// { return USBBulkTransfer(device, 0x03, data, size, callback, userData);} + static void recv(int socket, SocketState state, const u8* data, int len, void* userData) { + if (userData) ((ftusbdevtxbt*)userData)->receive(socket, state, data, len); + } + void receive(int socket, SocketState state, const u8* data, int len);// {printf("ftdev::receive was called: socket %d, state=%d, length=%d\n", socket, state, len);} + void parse (const unsigned char *buf, unsigned len); +public: + //virtual ~ftusbdevtxbt() ; +//public API: These functions match those of the original ftlib + virtual unsigned set_baudrate(unsigned br) { + return 0; + } + static unsigned InitFtUsbDeviceList();//overrides ftusbdev (also adds BT devices) + virtual unsigned OpenFtUsbDevice(); //ftxOpenComDevice, we regard a TXC as a USB device + virtual unsigned CloseFtDevice(); //ftxCloseDevice, ftxCloseAllDevices (ftlibclass) + //virtual unsigned IsFtTransferActiv(); + //virtual unsigned GetFtFirmware() ; + virtual unsigned GetFtSerialNr(); + virtual char* GetFtLongNameStrg() { + return strdup(name); + } + //TA* GetFtTransferAreaAddress(int i) ; + //virtual unsigned StartFtTransferArea(NOTIFICATION_EVENTS* sNEvent ); +}; + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ftlib/ftlibclassusb.cpp Wed Jun 15 19:12:25 2011 +0000 @@ -0,0 +1,454 @@ +#include "mbed.h" +#include "ftusb.h" +#include "ftlibclass.h" +#include "ftlibclassusb.h" +#include "ftlibclasstxc.h" + +#ifdef USE_DOWNLOAD +#include "crc.h" +#endif + +#define VERSION_MAJOR LIBFT_VERSION_MAJOR +#define VERSION_MINOR LIBFT_VERSION_MINOR +#define VERSION_PATCH LIBFT_VERSION_PATCH +#define ABF_IF_COMPLETE 0x8b // 0xf2 +#define INTERFACE_QUERY_TIME_SERIAL 10000 +#define FT_ENDPOINT_INTERRUPT_IN 0x81 +#define FT_ENDPOINT_INTERRUPT_OUT 0x1 +#define FT_ENDPOINT_BULK_IN 0x82 +#define FT_ENDPOINT_BULK_OUT 0x2 +#define FT_RF_ENDPOINT_INTERRUPT_IN 0x82 +#define FT_RF_ENDPOINT_INTERRUPT_OUT 0x2 +#define FT_USB_TIMEOUT 1000 +#define FT_USB_TIMEOUT_LONG 10000 +#define PROGRAM_UPLOAD_PACKET_SIZE 128 + +#define GET_MAN 1 +#define GET_LONG 2 +#define GET_SN 3 +#define GET_FW 4 +#define GET_SHORT 5 + +#define usleep(x) wait_us(x) +#define sleep(x) wait(x) + +vector<ftusbdev*> ftusbdev::devs; + +int ftusbdev::GetNumFtDevicesFromRF(int device) { + unsigned iNum = 0; + int ret; + unsigned char buffer[35] = { 0 }; + for (int i=1; i<9; i++) { + ret = USBControlTransfer(device, 0xc0, 0x52, i<<8 | 0x05, 0, buffer, 35, 0, 0); + if (ret < 0) { + fprintf(stderr, "Error sending control msg 0xC0 0x52\n"); + return ret; + } else if (buffer[0] == 0xfa && buffer[1] == 0) { // buffer[1] == 0xff => no device + iNum++; + unsigned snr = *(unsigned*)(buffer+3); //buffer[3] + buffer[4]*100 + buffer[5]*10000 + buffer[6]*1000000; + ftusbdev *d = new ftusbdev(device, FT_ROBO_IF_OVER_RF, snr, i); + d->fw = *(unsigned*)(buffer+20); + devs.push_back(d);//use datalink as type and assume little endianness + } + } + return iNum; +} + +unsigned ftusbdev::InitFtUsbDeviceList() { + char buffer[128]; + devs.clear(); + for (vector<_ftdev>::iterator i = ::devs.begin(); i < ::devs.end(); i++) { + unsigned sn = 0; + if (i->product == 0x1000) { //TXC + devs.push_back(new ftusbdevtx(i->device)); + continue; + } + if (GetString(i->device, GET_SN, buffer, 18) >= 0) { + sn = atoi(buffer); + } else { + printf("device %d did not respond\n", i->device); + continue; + } + if (i->product == RF_DATA_LINK_PRODUCT_ID) {//robo over RF + ftusbdev *dl = new ftusbdev(i->device, ftlib::FtproductIDToInterfaceID(i->product), sn, 0); //the RF call ID of the link is 0 but this is useless + devs.push_back(dl); + int pos = devs.size(); //position of first appended RF interface + int n = GetNumFtDevicesFromRF(i->device); + if (n > 0) { + dl->rf = devs[pos]->rf; //use the rf of the first child + } + } else { + if (i->product == EXT_IF_PRODUCT_ID) + devs.push_back(new ftusbdevext(i->device, ftlib::FtproductIDToInterfaceID(i->product), sn)); + else + devs.push_back(new ftusbdev(i->device, ftlib::FtproductIDToInterfaceID(i->product), sn)); + } + } + return FTLIB_ERR_SUCCESS; +} + + +ftusbdev* ftusbdev::GetFtUsbDeviceHandle(unsigned Num) { + if (Num < devs.size()) { + return devs[Num]; + } + return 0; +} + +ftusbdev* ftusbdev::GetFtUsbDeviceHandleSerialNr(unsigned dwSN, unsigned dwTyp) { + for (int i = 0; i < devs.size(); i++) + if (devs[i]->sn == dwSN) { + if (dwTyp == 0 || dwTyp == devs[i]->type) + return GetFtUsbDeviceHandle(i); + } + fprintf(stderr, "GetFtUsbDeviceSerialNr(%d, %d) not found\n", dwSN, dwTyp); + return 0; +} + +unsigned ftusbdev::OpenFtUsbDevice() { + FT_TRANSFER_AREA *area = new FT_TRANSFER_AREA; + memset(area, 0, sizeof(struct _FT_TRANSFER_AREA)); + area->RfModulNr = rf; + area->TransferAktiv = 0; + ta = area; + return 0; +} + +unsigned ftusbdev::CloseFtDevice() { + if (ta==0) + return FTLIB_ERR_DEVICE_NOT_OPEN; + while (ta->TransferAktiv != 0) { + fprintf(stderr, "Transfer ta still active\n"); + sleep(1); + } + delete ta; + ta = 0; + return 0; +} + +unsigned ftusbdev::GetFtFirmware() { + int ret; + unsigned char buffer[35] = { 0 }; + if (fw > 0) + return fw; + switch (type) { + case FT_ROBO_IF_USB: + case FT_ROBO_IO_EXTENSION: + case FT_ROBO_RF_DATA_LINK: + ret = USBControlTransfer(device, 0xc0, 0xf0, 0x1, 0, buffer, 5); + if (ret < 0) { + fprintf(stderr, "Error sending control msg 0xC0 0xF0\n"); + return 0; + } + fw = buffer[1] | buffer[2]<<8 | buffer[3]<<16 | buffer[4]<<24; + break; + case FT_ROBO_IF_OVER_RF: + ret = USBControlTransfer(device, 0xc0, 0x52, rf<<8 | 0x05, 0, buffer, 35); + if (ret < 0) { + fprintf(stderr, "Error sending control msg 0xC0 0x52\n"); + return 0; + } + if (buffer[0] == 0xfa && buffer[1] == 0) { // buffer[1] == 0xff => no device + fw = buffer[23]<<24 | buffer[22]<<16 | buffer[21]<<8 | buffer[20]; + } + break; + default: + return FTLIB_ERR_NOT_SUPPORTED; + } + return fw; +} + +char * ftusbdev::GetFtLongNameStrg() { + const int sz = 128; + char *buffer = new char[sz]; + buffer[0] = '\0'; + + switch (type) { + case FT_ROBO_IF_USB: + case FT_ROBO_RF_DATA_LINK: + case FT_ROBO_IO_EXTENSION: + GetString(device, GET_LONG, buffer, sz); + break; + case FT_ROBO_IF_OVER_RF: + sprintf(buffer, " Robo Interface (RF:%d)", rf); + break; + } + return buffer; +} + +char * ftusbdev::GetFtShortNameStrg() { + const int sz = 128; + char *buffer = new char[sz]; + buffer[0] = '\0'; + + switch (type) { + case FT_ROBO_IF_USB: + case FT_ROBO_RF_DATA_LINK: + case FT_ROBO_IO_EXTENSION: + GetString(device, GET_SHORT, buffer, sz); + break; + case FT_ROBO_IF_OVER_RF: + sprintf(buffer, " (RF:%d)", rf); + break; + } + return buffer; +} + +char * ftusbdev::GetFtManufacturerStrg() { + const int sz = 128; + char *buffer = new char[sz]; + buffer[0] = '\0'; + GetString(device, GET_MAN, buffer, sz); + return buffer; +} + +void ftusbdev::poll() { + for (int i = 0; i < devs.size(); i++) { + if (devs[i]->triggered) { + if (devs[i]->guardedFtThreadBegin()) + devs[i]->triggered = 0; + } + } + //USBLoop(); +} + +void ftusbdev::FtThreadInit() {//setup buffers for this type of interface + num_write = ABF_IF_COMPLETE_NUM_WRITE; + num_read = ABF_IF_COMPLETE_NUM_READ; + out[0] = ABF_IF_COMPLETE; + ftdev::FtThreadInit(); + unsigned ret; + switch (type) { + case FT_ROBO_IF_OVER_RF: + case FT_ROBO_RF_DATA_LINK: + usb_endpoint_write = FT_RF_ENDPOINT_INTERRUPT_OUT; + usb_endpoint_read = FT_RF_ENDPOINT_INTERRUPT_IN; + ret = USBControlTransfer(device, 0xc0, 0xfb, rf << 8 | 0x02, 0x1, in, 2, 0, 0); + if (ret != 2) { + fprintf(stderr, "%d FtThread: Error initiating RF Module!\n"); + //ta->TransferAktiv = 0; + } + break; + default: //FT_ROBO_USB + usb_endpoint_write = FT_ENDPOINT_INTERRUPT_OUT; + usb_endpoint_read = FT_ENDPOINT_INTERRUPT_IN; + break; + } +} + +void ftusbdev::read_finished_cb(int device, int endpoint, int status, u8* data, int len, void* userData) { +//end of reply transfer + ftusbdev *fth = (ftusbdev*)userData; + fth->FtThreadEnd(); +} + +void ftusbdev::write_finished_cb(int device, int endpoint, int status, u8* data, int len, void* userData) { //end of request transfer, issue, reply transfer + ftusbdev *fth = (ftusbdev*)userData; + USBInterruptTransfer(fth->device, fth->usb_endpoint_read, fth->in, fth->num_read, read_finished_cb, fth); +} + +//here the real data exchange starts +void ftusbdev::FtThreadBegin() {//called every 10ms to issue a request, should be non-blocking + if (!test_and_set()) {//return when transferarea is in use + busy = false; //release the mutex, otherwise the thread effectively stops + return;//return because there is no point in sending a nonsense request, alternatively the lock can be ignored in which case the data may be inconsistent + } +//putc('(', stderr); + out[1] = ta->M_Main; + out[2] = (ta->MPWM_Main[0] & 0x7) | (ta->MPWM_Main[1]<<3 & 0x38) | (ta->MPWM_Main[2]<<6 & 0xC0); + out[3] = (ta->MPWM_Main[2] & 0x1) | (ta->MPWM_Main[3]<<1 & 0xE) | (ta->MPWM_Main[4]<<4 & 0x70) | (ta->MPWM_Main[5]<<7 & 0x80); + out[4] = (ta->MPWM_Main[5] & 0x3) | (ta->MPWM_Main[6]<<2 & 0x1C) | (ta->MPWM_Main[7]<<5 & 0xE0); + out[5] = ta->M_Sub1; + out[6] = (ta->MPWM_Sub1[0] & 0x7) | (ta->MPWM_Sub1[1]<<3 & 0x38) | (ta->MPWM_Sub1[2]<<6 & 0xC0); + out[7] = (ta->MPWM_Sub1[2] & 0x1) | (ta->MPWM_Sub1[3]<<1 & 0xE) | (ta->MPWM_Sub1[4]<<4 & 0x70) | (ta->MPWM_Sub1[5]<<7 & 0x80); + out[8] = (ta->MPWM_Sub1[5] & 0x3) | (ta->MPWM_Sub1[6]<<2 & 0x1C) | (ta->MPWM_Sub1[7]<<5 & 0xE0); + out[9] = ta->M_Sub2; + out[10] = (ta->MPWM_Sub2[0] & 0x7) | (ta->MPWM_Sub2[1]<<3 & 0x38) | (ta->MPWM_Sub2[2]<<6 & 0xC0); + out[11] = (ta->MPWM_Sub2[2] & 0x1) | (ta->MPWM_Sub2[3]<<1 & 0xE) | (ta->MPWM_Sub2[4]<<4 & 0x70) | (ta->MPWM_Sub2[5]<<7 & 0x80); + out[12] = (ta->MPWM_Sub2[5] & 0x3) | (ta->MPWM_Sub2[6]<<2 & 0x1C) | (ta->MPWM_Sub2[7]<<5 & 0xE0); + out[13] = ta->M_Sub3; + out[14] = (ta->MPWM_Sub3[0] & 0x7) | (ta->MPWM_Sub3[1]<<3 & 0x38) | (ta->MPWM_Sub3[2]<<6 & 0xC0); + out[15] = (ta->MPWM_Sub3[2] & 0x1) | (ta->MPWM_Sub3[3]<<1 & 0xE) | (ta->MPWM_Sub3[4]<<4 & 0x70) | (ta->MPWM_Sub3[5]<<7 & 0x80); + out[16] = (ta->MPWM_Sub3[5] & 0x3) | (ta->MPWM_Sub3[6]<<2 & 0x1C) | (ta->MPWM_Sub3[7]<<5 & 0xE0); + out[17] = 0; + if (messages && messages->nrOfMessages()>0) { + out[18] = 0; + *(SMESSAGE*)(out+19) = messages->pop(); + } else { + memset(out+18, 0, 7); + } + if (messages && messages->nrOfMessages()>0) { + out[25] = 0; + *(SMESSAGE*)(out+26) = messages->pop(); + } else { + memset(out+25, 0, 7); + } + increment();//release the lock on shared memeory + USBInterruptTransfer(device, usb_endpoint_write, out, num_write, write_finished_cb, this); //return immediately and call the callback when finished +} +#if 0 //use the parent version +void ftusbdev::FtThreadEnd() {//called by the receiver/dma callback when the reply is complete + if (!test_and_set()) {//skip when busy + busy = false; + return; + } + ta->ChangeEg = ta->E_Main != in[0] || ta->E_Sub1 != in[1] || ta->E_Sub2 != in[2] || ta->E_Sub3 != in[3]; + ta->E_Main = in[0]; + ta->E_Sub1 = in[1]; + ta->E_Sub2 = in[2]; + ta->E_Sub3 = in[3]; + ta->ChangeAn = 1; //assume that analog always changes (noise) + ta->AX = in[4]; + ta->AY = in[5]; + ta->A1 = in[6]; + ta->A2 = in[7]; + ta->AX |= (in[8] & 0x3) << 8; + ta->AY |= (in[8] & 0xC) << 6; + ta->A1 |= (in[8] & 0x30) << 4; + ta->A2 |= (in[8] & 0xC0) << 2; + ta->AZ = in[9]; + ta->D1 = in[10]; + ta->D2 = in[11]; + ta->AV = in[12]; + ta->AZ |= (in[13] & 0x3) << 8; + ta->D1 |= (in[13] & 0xC) << 6; + ta->D2 |= (in[13] & 0x30) << 4; + ta->AV |= (in[13] & 0xC0) << 2; + if (ta->IRKeys != in[14]) + ta->ChangeIr = 1; + ta->IRKeys = in[14]; + ta->BusModules = in[15]; + // 16 + ta->AXS1 = in[17]; + ta->AXS2 = in[18]; + ta->AXS3 = in[19]; + ta->AXS1 |= (in[20] & 0x3) << 8; + ta->AXS2 |= (in[20] & 0xC) << 6; + ta->AXS3 |= (in[20] & 0x30) << 4; + // 21 + ta->AVS1 = in[22]; + ta->AVS2 = in[23]; + ta->AVS3 = in[24]; + ta->AVS1 |= (in[25] & 0x3) << 8; + ta->AVS2 |= (in[25] & 0xC) << 6; + ta->AVS3 |= (in[25] & 0x30) << 4; + // 26...42 + ta->AV *= 3; + ta->AVS1 *= 3; + ta->AVS2 *= 3; + ta->AVS3 *= 3; + //message processing + if (messages && ne.CallbackMessage) { //just to check if communication was enabled + if (in[28]) + ne.CallbackMessage((SMESSAGE*)(in+29)); + if (in[35]) + ne.CallbackMessage((SMESSAGE*)(in+36)); + } + increment(); + interface_connected = 1; + if (ne.NotificationCallback) { + (*ne.NotificationCallback)(ne.Context); + } + busy = false; +} +#endif + +void ftusbdev::FtThreadFinish() {//called by StopFtTransferArea + if (type == FT_ROBO_IF_OVER_RF || type == FT_ROBO_RF_DATA_LINK) { + int ret = USBControlTransfer(device, 0xc0, 0x21, rf << 8, 0, in, 1); + if (ret != 1 || in[0] != 0xd7) { + fprintf(stderr, "Error uninitiating RF Module!\n"); + } + } + ftdev::FtThreadFinish(); +} + +unsigned ftusbdev::SetFtDeviceCommMode (unsigned dwMode, unsigned dwParameter, unsigned short *puiValue) { + unsigned char buf[3]; + unsigned ret = USBControlTransfer(device, 0xc0, 0xf0, 0x0040, dwMode|(dwParameter<<8), buf, 3); + if (puiValue && dwMode == IF_COM_PARAMETER) + *puiValue = buf[1]; + return ret; +} + +void ftusbdevext::FtThreadInit() {//setup buffers for this type of interface + usb_endpoint_write = FT_ENDPOINT_INTERRUPT_OUT; + usb_endpoint_read = FT_ENDPOINT_INTERRUPT_IN; + ftdev::FtThreadInit(); + out[0] = 0xf2; + num_write = 6; + num_read = 6; +} + +void ftusbdevext::FtThreadEnd() {//called by the receiver/dma callback when the reply is complete + if (!test_and_set()) {//skip when busy + busy = false; + return; + } + ta->ChangeEg = ta->E_Main != in[0]; + ta->E_Main = in[0]; + ta->ChangeAn = 1; //assume that analog always changes (noise) + ta->AX = in[1]; + ta->A1 = in[2]; + ta->AV = in[3]; + ta->AX |= (in[4] & 0x3) << 8; + ta->A1 |= (in[4] & 0xC) << 6; + ta->AV |= (in[4] & 0x30) << 4; + ta->AV *= 3; + increment(); + interface_connected = 1; +//printf("%02X) ", ta->E_Main); + if (ne.NotificationCallback) { +// printf("%02X\r", transfer_area.E_Main); + (*ne.NotificationCallback)(ne.Context); + } + busy = false; +} + +unsigned ftusbdev::SetFtDistanceSensorMode(unsigned dwMode, unsigned dwTol1, unsigned dwTol2, unsigned dwLevel1, unsigned dwLevel2, unsigned dwRepeat1, unsigned dwRepeat2) { + int ret; + unsigned char buffer[] = {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // 34 + + buffer[1] = dwTol1; + buffer[2] = dwTol2; + buffer[3] = dwLevel1; + buffer[4] = dwLevel1>>8; + buffer[5] = dwLevel2; + buffer[6] = dwLevel2>>8; + buffer[7] = dwRepeat1; + buffer[8] = dwRepeat2; + + switch (type) { + case FT_ROBO_IF_USB: + ret = USBControlTransfer(device, 0x40, 0xf1, 0x1, dwMode, buffer+1, 8); + if (ret != 8) { + fprintf(stderr, "Error sending control msg 0x40 0xf1\n"); + return ret; + } + break; + case FT_ROBO_RF_DATA_LINK: + case FT_ROBO_IF_OVER_RF: + ret = USBControlTransfer(device, 0x40, 0x53, rf<<8 | 0x01, 0, buffer, 34); + if (ret != 34) { + fprintf(stderr, "Error sending control msg 0x40 0x53\n"); + return ret; + } + break; + default: + return FTLIB_ERR_NOT_SUPPORTED; + } + usleep(100000); // wait before continue, else it doesn't always work + return FTLIB_ERR_SUCCESS; +} + +unsigned ftusbdev::pgm_message(unsigned code, unsigned dwMemBlock) { + unsigned char buffer[2]; + if (type != FT_ROBO_IF_USB) return FTLIB_ERR_NOT_SUPPORTED; + int ret = USBControlTransfer(device, 0xc0, code, dwMemBlock, 0, buffer, 1); + if (ret < 0) { + fprintf(stderr, "Error sending control msg 0xC0 %02X\n", code); + return ret; + } + if ((buffer[0]) == 0x1) return FTLIB_ERR_SUCCESS; + else return FTLIB_ERR_IF_NO_PROGRAM; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ftlib/ftlibclassusb.h Wed Jun 15 19:12:25 2011 +0000 @@ -0,0 +1,78 @@ +#ifndef FTLIBCLASSUSB_H +#define FTLIBCLASSUSB_H + +#include <vector> +#include "ftlibclassdev.h" + +#define FT_VENDOR_ID 0x146a +#define ROBO_IF_PRODUCT_ID 0x1 +#define EXT_IF_PRODUCT_ID 0x2 +#define RF_DATA_LINK_PRODUCT_ID 0x3 +/* +#define usleep(x) wait_us(x) +#define sleep(x) wait(x) +*/ +class ftlib; + +class ftusbdev: public ftdev { + friend ftlib; + virtual unsigned pgm_message(unsigned code, unsigned dwMemBlock); +protected: + static vector<ftusbdev*> devs; + int device; //usb device nr + int rf; //rf call nr + int usb_endpoint_read, usb_endpoint_write; + ftusbdev() {} + ftusbdev(int d, int t, int s = 0, int r = -1): ftdev(t, s), device(d), rf(r) {} + static int GetNumFtDevicesFromRF(int device); + static void onTick() { + for (int i = 0; i < devs.size(); i++) devs[i]->trigger(); + } + static void CloseAllFtDevices() { + for (int i = 0; i < devs.size(); i++) devs[i]->CloseFtDevice(); + } + static void read_finished_cb(int device, int endpoint, int status, unsigned char* data, int len, void* userData); + static void write_finished_cb(int device, int endpoint, int status, unsigned char* data, int len, void* userData); + virtual void FtThreadInit(); + virtual void FtThreadBegin(); +// virtual void FtThreadEnd(); + virtual void FtThreadFinish(); +public: + static void poll(); +//public API: These functions match those of the original ftlib + static unsigned InitFtUsbDeviceList(); + static unsigned GetNumFtUsbDevice() { + return devs.size(); + } + virtual unsigned OpenFtUsbDevice(); + static ftusbdev* GetFtUsbDeviceHandle(unsigned DevNr); + static ftusbdev* GetFtUsbDeviceHandleSerialNr(unsigned dwSN, unsigned dwTyp); + unsigned SetFtDeviceCommMode (unsigned dwMode, unsigned dwParameter, unsigned short *puiValue); + virtual unsigned CloseFtDevice(); + virtual unsigned GetFtFirmware(); + virtual char* GetFtManufacturerStrg(); + virtual char* GetFtShortNameStrg(); + virtual char* GetFtLongNameStrg(); + virtual unsigned SetFtDistanceSensorMode(unsigned dwMode, unsigned dwTol1, unsigned dwTol2, + unsigned dwSchwell1, unsigned dwSchwell2, unsigned dwRepeat1, unsigned dwRepeat2); + /* + virtual unsigned GetFtDeviceSetting(FT_SETTING *pSet); + virtual unsigned SetFtDeviceSetting(FT_SETTING *pSet); + */ + virtual unsigned StartFtProgram(unsigned dwMemBlock) { + return pgm_message(0x12, dwMemBlock); + } + virtual unsigned StopFtProgram() { + return pgm_message(0x13, 0); + } +}; + +class ftusbdevext: public ftusbdev { + friend ftusbdev; + ftusbdevext() {} + ftusbdevext(int d, int t, int s): ftusbdev(d, t, s) {} + virtual void FtThreadInit(); + virtual void FtThreadEnd(); +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ftlib/ftusb.cpp Wed Jun 15 19:12:25 2011 +0000 @@ -0,0 +1,177 @@ +#include "mbed.h" +#include "USBHost.h" +#include "ftusb.h" +#include <vector> +#include "HCITransportUSB.h" +#include "Socket.h" +#include "RFCOMM.h" +#include "sdp.h" + +// these should be placed in the DMA SRAM +typedef struct { + u8 _hciBuffer[MAX_HCL_SIZE]; + u8 _aclBuffer[MAX_ACL_SIZE]; +} SRAMPlacement; + +const char FtDevClass[3] = {0x00, 0x1F, 0x82 }; +const char SerDevClass[3] = {4, 1, 0x00}; + +HCITransportUSB _HCITransportUSB; //use USB as the transport to the radio +BTApp Bluetooth; +vector<_ftdev> devs; + +void OnLoadFtDevice(int device, DeviceDescriptor* deviceDesc, InterfaceDescriptor* interfaceDesc) { + for (int i = 0; i < devs.size(); i++) + if (devs[i].device == device) { + printf("device %d was already in the list\n", device); + return; + } + switch (deviceDesc->idProduct) { + case 1: + devs.push_back(*new _ftdev(device, deviceDesc->idProduct, deviceDesc->iSerialNumber)); + printf("RoboInterface\n"); + break; + case 2: + devs.push_back(*new _ftdev(device, deviceDesc->idProduct, deviceDesc->iSerialNumber)); + printf("RoboExtension\n"); + break; + case 3: + devs.push_back(*new _ftdev(device, deviceDesc->idProduct, deviceDesc->iSerialNumber, 0)); + printf("Robo RF Interface\n"); + break; + case 4: + printf("Sound\n"); + break; + case 4096: + devs.push_back(*new _ftdev(device, deviceDesc->idProduct, deviceDesc->iSerialNumber)); + printf("TX Controller\n"); + break; + default: + printf("fischertechnik product %d\n", deviceDesc->idProduct); + break; + } +} + + +int OnBluetoothInsert(int device) {//install the HCI and start discovery, user callbacks are made to HciCalback + printf("Bluetooth inserted of %d\n",device); + u32 sramLen; + u8* sram = USBGetBuffer(&sramLen); + sram = (u8*)(((u32)sram + 1023) & ~1023); + SRAMPlacement* s = (SRAMPlacement*)sram; + _HCITransportUSB.Open(device,s->_hciBuffer,s->_aclBuffer);//setup buffers for USB host, incoming data goes first to HCIRecv and ACLRecv + RegisterSocketHandler(SOCKET_L2CAP,&Bluetooth); //register the application::hci as handler for L2CAP events + RegisterSocketHandler(SOCKET_RFCOM, &rfcomm_manager);//set the RFCOMMManager as the RFCOM socket handler + if (RegisterSocketHandler(SOCKET_SDP, &SDP)) + printf("Could not register SDP socket type\n"); + Bluetooth.Open(&_HCITransportUSB);//the callback is virtual, calls BTApp::Callback + Bluetooth.Inquiry();//start discovery of BT devices phase 0 + return 0; +} + +void printf(const BD_ADDR* addr) { + const u8* a = addr->addr; + printf("%02X:%02X:%02X:%02X:%02X:%02X",a[5],a[4],a[3],a[2],a[1],a[0]); +} + +// We have connected to a device +void BTApp::ConnectionComplete(connection_info* info) { + printf("ConnectionComplete "); + BD_ADDR* a = &info->bdaddr; + printf(a); + printf("\n"); + RemoteNameRequest(a); + for (i++; i < count; i++) {//find the next ft device to open + //printfBytes("DEVICE CLASS",devs[i]->_info.dev_class,3); + if (devs[i]->_handle == 0 && memcmp(devs[i]->_info.dev_class, FtDevClass, 3)==0) {//or some other way to connect to RFCOMM devices + BD_ADDR* bd = &devs[i]->_info.bdaddr; + printf("Connecting to "); + printf(bd); + printf("\n"); + pending++; + CreateConnection(bd); //some low level connect, just let it happen for now (sets pin, mtu etc.) + printf("connection cmd was sent\n"); + return; + } + } +} + +void BTApp::ConnectDevices() { + count = GetDevices(devs,8);//get pointers to all bluetooth devices + pending = 0; + for (i = 0; i < count; i++) {//find first ft device (when filter works, all devices are ft devices) + //printfBytes("DEVICE CLASS",devs[i]->_info.dev_class,3); + if (devs[i]->_handle == 0 && memcmp(devs[i]->_info.dev_class, FtDevClass, 3)==0) {//or some other way to connect to RFCOMM devices + BD_ADDR* bd = &devs[i]->_info.bdaddr; + printf("Connecting to "); + printf(bd); + printf("\n"); + pending++; + CreateConnection(bd); //some low level connect, just let it happen for now (sets pin, mtu etc.) + printf("connection cmd was sent\n"); + return; + } + } +} + +void BTApp::Callback(HCI_CALLBACK_EVENT evt, const u8* data, int len) {//these events are forwarded (in)directly from HCIRecv + unsigned char pin[] = "1234"; + u8 filter[] = {0x00, 0x1F, 0x82, 0xFF, 0xFF, 0xFF }; + printf("\x1b[%dm", 33); + switch (evt) { + case CALLBACK_READY: + printf("CALLBACK_READY\n"); + printf("my address = "); + printf((BD_ADDR*)data); + SetEventFilter(1, 1, filter); + Inquiry();//start the second phase of the discovery + break; + + case CALLBACK_INQUIRY_RESULT: //optionally build the list of FT devices here + printf("CALLBACK_INQUIRY_RESULT "); + printf((BD_ADDR*)data); + printf("\n");//data points to inquiry_info struct + break; + + case CALLBACK_INQUIRY_DONE: + printf("CALLBACK_INQUIRY_DONE\n"); + ConnectDevices(); + break; + + case CALLBACK_REMOTE_NAME: { + BD_ADDR* addr = (BD_ADDR*)data; + const char* name = (const char*)(data + 6); + printf(addr); + printf(" = % s\n",name); + pending--; + } + break; + + case CALLBACK_CONNECTION_COMPLETE: { + connection_info *ci = (connection_info*)data; + if (ci->status>0) { + printf("Connection failed, status=0x%02X\n", ci->status); + break; + } + ConnectionComplete(ci); + /* + printf("Going to open sdp socket\n"); + L2CAPAddr addr; + memcpy(&addr.bdaddr, &ci->bdaddr, 6); + int s = SDP.Open(&addr.hdr); + */ + } + break; + case CALLBACK_PIN_REQ: + printf("Enter PIN for "); + printf((BD_ADDR*)data); + printf(" : submitting %s\n", pin); + PinCodeReply(data, pin); + break; + default: + printf("Unhandled HCI Callback %d\n", evt); + }; + printf("\x1b[%dm", 0); +} + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ftlib/ftusb.h Wed Jun 15 19:12:25 2011 +0000 @@ -0,0 +1,37 @@ +#ifndef FTUSB_H +#define FTUSB_H +#include "USBHost.h" +#include <vector> +#include "hci.h" + +struct _ftdev { + int device; + int product; + int serial; + int rf; + _ftdev(int d, int p, int s, int r=-1): device(d), product(p), serial(s), rf(r) {} +}; + +extern vector<_ftdev> devs; +/* +unsigned InitFtUsbList (void); +_ftdev& GetFtUsbDevice(int n); +_ftdev* GetFtUsbDevicePtr(int n); +int GetUsbDeviceSerialNr(unsigned s, unsigned t=0); +unsigned int GetNthFtDeviceFromRF(int Num, int iRf); +*/ +void OnLoadFtDevice(int device, DeviceDescriptor* deviceDesc, InterfaceDescriptor* interfaceDesc); +int OnBluetoothInsert(int device); + + +class BTApp : public HCI { + BTDevice* devs[8]; + int count, i, pending; +public: + void ConnectionComplete(connection_info* info) ; + void ConnectDevices(); + virtual void Callback(HCI_CALLBACK_EVENT c, const u8* data, int len); +}; + +extern BTApp Bluetooth; +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Wed Jun 15 19:12:25 2011 +0000 @@ -0,0 +1,190 @@ +/* +Copyright (c) 2010 Peter Barrett + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "mbed.h" +#include "USBHost.h" +#include "Utils.h" +#include "ftlibclass.h" +#include "ftlibclassusb.h" +#include "ftlibclasstxc.h" +#include "ftlibclasstxcbt.h" + +Serial pc(USBTX, USBRX); + +FT_TRANSFER_AREA *ta = 0; +TA *tax = 0; +NOTIFICATION_EVENTS ne; + +int main() { + pc.baud(460800); + printf("USBShell\nNow get a bunch of usb things and plug them in\n"); + USBInit(); + int state = 0; + Timer time; + time.start(); + int n, r0, r1, r2, r3=0; +// ftusbdev* h = 0; + ftusbdevtxbt* h = 0; + printf("Start enumeration\n"); + for (;;) { + switch (state) { + case 0: //enumeration, allow 3 seconds + if (time.read() >= 20) { + state = 1; + printf("Start initialisation\n"); + } + break; + case 1: //init program + r0 = ftlib::InitFtLib(); + printf("InitFtLib() returns %d\n", r0); + r1 = ftusbdevtxbt::InitFtUsbDeviceList(); + printf("InitFtUsbDeviceList() returns %d\n", r1); + n = ftusbdev::GetNumFtUsbDevice(); + printf("GetNumFtUsbDevice() returns %d\n", n); + for (int i = 0; i < n; i++) { + ftdev* h = ftusbdev::GetFtUsbDeviceHandle(i); + printf("handle = %p\n", h); + unsigned sn = h->GetFtSerialNr(); + printf("S/N=%d\n", sn); + char *name = h->GetFtLongNameStrg(); + printf("%d: %s SN=%08d\n", i, name, sn); + delete[] name; + //USBLoop(); + } + h = dynamic_cast<ftusbdevtxbt*>(ftusbdev::GetFtUsbDeviceHandle(0)); + if (h==0) { + printf("Cast failed\n"); + state = 4; + break; + } + r2 = h->OpenFtUsbDevice(); + printf("OpenFtUsbDevice() returns %08x\n", r2); +// ta = h->GetFtTransferAreaAddress(); + tax = h->GetFtTransferAreaAddress(0); + r3 = h->StartFtTransferArea(&ne); + if (r3) { + printf("Could not start thread %08X\n", r3); + state = 3; + break; + } + state = 2; + printf("Start main loop\n"); + break; + case 2: //main loop + ftlib::poll(); + /* if (ta->ChangeEg) { + printf("%02X %d %d %d\n", ta->E_Main, ta->AX, ta->A1, ta->AV); + ta->ChangeEg = 0; + }*/ + //printf("%02X %d %d %d\r", tax->input.uni[0],tax->input.uni[1],tax->input.uni[2],tax->input.uni[3]); + if (time.read() >= 30) { + state = 3; + printf("\nEnd of main loop\n"); + } + break; + case 3: //finalizing + h->StopFtTransferArea(); + h->CloseFtDevice(); + ftlib::CloseFtLib(); + state = 4; + break; + case 4: + break; + default: + return 0; + } + USBLoop(); + } +} + +int OnDiskInsert(int device) { + return 0; +} + + +#if 0 +#include "FATFileSystem.h" + +int MassStorage_ReadCapacity(int device, u32* blockCount, u32* blockSize); +int MassStorage_Read(int device, u32 blockAddr, u32 blockCount, u8* dst, u32 blockSize); +int MassStorage_Write(int device, u32 blockAddr, u32 blockCount, u8* dst, u32 blockSize); + +class USBFileSystem : public FATFileSystem { + int _device; + u32 _blockSize; + u32 _blockCount; + +public: + USBFileSystem() : FATFileSystem("usb"),_device(0),_blockSize(0),_blockCount(0) { + } + + void SetDevice(int device) { + _device = device; + } + + virtual int disk_initialize() { + return MassStorage_ReadCapacity(_device,&_blockCount,&_blockSize); + } + + virtual int disk_write(const char *buffer, int block_number) { + return MassStorage_Write(_device,block_number,1,(u8*)buffer,_blockSize); + } + + virtual int disk_read(char *buffer, int block_number) { + return MassStorage_Read(_device,block_number,1,(u8*)buffer,_blockSize); + } + + virtual int disk_sectors() { + return _blockCount; + } +}; + + +void DumpFS(int depth, int count) { + DIR *d = opendir("/usb"); + if (!d) { + printf("USB file system borked\n"); + return; + } + + printf("\nDumping root dir\n"); + struct dirent *p; + while ((p = readdir(d))) { + int len = sizeof( dirent); + printf("%s %d\n", p->d_name, len); + } + closedir(d); +} + +int OnDiskInsert(int device) { + USBFileSystem fs; + fs.SetDevice(device); + DumpFS(0,0); + return 0; +} + +/* + Simple test shell to exercise mouse,keyboard,mass storage and hubs. + Add 2 15k pulldown resistors between D+/D- and ground, attach a usb socket and have at it. +*/ + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.lib Wed Jun 15 19:12:25 2011 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/projects/libraries/svn/mbed/trunk@28 \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/message.h Wed Jun 15 19:12:25 2011 +0000 @@ -0,0 +1,61 @@ +#ifndef MESSAGE_H +#define MESSAGE_H + +template <class T, int N> class msgbuffer { + T buffer[N]; + int in, out, n; +public: + int push(T msg, int mode = 0); + int nrOfMessages() { + return n; + } + T pop(); + msgbuffer() { + in = 0; + out = 0; + n = 0; + } + void clear() { + in = 0; + out = 0; + n = 0; + } +}; + +template <class T> bool operator==(T a, T b) { + return memcmp(&a, &b, sizeof(T))==0; +} + +template <class T, int N> int msgbuffer<T, N> ::push(T msg, int mode) { + if (n>=N) return -1; //buffer full + switch (mode) { + case 2: + for (int i = 0, j = out; i < n; i++, j++) { + if (j >= N) j = 0; + if (buffer[j] == msg) + return 0; + } + goto insert; + case 1: + if (buffer[in] == msg) + return 0; + goto insert; + case 0: +insert: + in++; + if (in >= N) in = 0; + buffer[in] = msg; + n++; + return 0; + } + return -2; //illegal option +} + +template <class T, int N> T msgbuffer<T, N> ::pop() { + T tmp = buffer[out++]; + if (out >= N) + out = 0; + return tmp; +} + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/myBlueUSB/HCITransportUSB.h Wed Jun 15 19:12:25 2011 +0000 @@ -0,0 +1,67 @@ +#ifndef HCITRANSPORTUSB_H +#define HCITRANSPORTUSB_H +#define MAX_HCL_SIZE 260 +#define MAX_ACL_SIZE 400 +#include "USBHost.h" +#include "hci.h" +#include "Utils.h" + +//extern int bulk; + +class HCITransportUSB : public HCITransport { + int _device; + u8* _hciBuffer; + u8* _aclBuffer; + +public: + void Open(int device, u8* hciBuffer, u8* aclBuffer) { + _device = device; + _hciBuffer = hciBuffer; + _aclBuffer = aclBuffer; + USBInterruptTransfer(_device,0x81,_hciBuffer,MAX_HCL_SIZE,HciCallback,this); + USBBulkTransfer(_device,0x82,_aclBuffer,MAX_ACL_SIZE,AclCallback,this); + } + + static void HciCallback(int device, int endpoint, int status, u8* data, int len, void* userData) { + HCI* t = ((HCITransportUSB*)userData)->_target; //printf("HCI: %d bytes avail\n", len); + if (t){ + //printfBytes("HCICallback:", data, min(len,16)); + t->HCIRecv(data,len); + } + USBInterruptTransfer(device,0x81,data,MAX_HCL_SIZE,HciCallback,userData); + } + + static void AclCallback(int device, int endpoint, int status, u8* data, int len, void* userData) { + HCI* t = ((HCITransportUSB*)userData)->_target; //printf("ACL: %d bytes avail\n", len); + if (t){ + //printfBytes("ACLCallback:", data, min(len,16)); + t->ACLRecv(data,len); + } + //printf("ACL Read pending..\n"); + USBBulkTransfer(device,0x82,data,MAX_ACL_SIZE,AclCallback,userData); + } + + virtual void HCISend(const u8* data, int len) { + //printfBytes("HCISend:", data, min(len,16)); + USBControlTransfer(_device,REQUEST_TYPE_CLASS, 0, 0, 0,(u8*)data,len); + } + + virtual int ACLSend(const u8* data, int len) { //printf("send %d bytes to usb\n", len); + if (len > _acl_mtu) { + printf("Max outgoing packet(%d) size exceeded, segmenting necessary, pktlen = %d\n", _acl_mtu, len); + return 0; + } +#ifdef HOST_CONTR_FLOW +/* if (data_credits == 0) + printf("Waiting for ACL buffers...\n");*/ + while (data_credits < 1) { + USBLoop(); + } + data_credits--; +#endif + //printfBytes("ACLSend:", data, min(len,16)); + return USBBulkTransfer(_device,0x02,(u8*)data,len); + } +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/myBlueUSB/L2CAP.cpp Wed Jun 15 19:12:25 2011 +0000 @@ -0,0 +1,585 @@ +/* +Copyright (c) 2010 Peter Barrett + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + + +#include <stdio.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "Utils.h" +#include "hci.h" +#include "HCITransportUSB.h" +#include "sdp.h" +#include "RFCOMM.h" + +#define L2CAP_COMMAND_REJ 0x01 +#define L2CAP_CONN_REQ 0x02 +#define L2CAP_CONN_RSP 0x03 +#define L2CAP_CONF_REQ 0x04 +#define L2CAP_CONF_RSP 0x05 +#define L2CAP_DISCONN_REQ 0x06 +#define L2CAP_DISCONN_RSP 0x07 +#define L2CAP_ECHO_REQ 0x08 +#define L2CAP_ECHO_RSP 0x09 +#define L2CAP_INFO_REQ 0x0a +#define L2CAP_INFO_RSP 0x0b + +#define TXID (++_txid?_txid:1) +//template <class T> T min(T a, T b) { return a<b ? a : b;} + +/* L2CAP command codes */ +const char* L2CAP_ComandCodeStr(int c) { + switch (c) { + case L2CAP_COMMAND_REJ: + return "L2CAP_COMMAND_REJ"; + case L2CAP_CONN_REQ: + return "L2CAP_CONN_REQ"; + case L2CAP_CONN_RSP: + return "L2CAP_CONN_RSP"; + case L2CAP_CONF_REQ: + return "L2CAP_CONF_REQ"; + case L2CAP_CONF_RSP: + return "L2CAP_CONF_RSP"; + case L2CAP_DISCONN_REQ: + return "L2CAP_DISCONN_REQ"; + case L2CAP_DISCONN_RSP: + return "L2CAP_DISCONN_RSP"; + case L2CAP_ECHO_REQ: + return "L2CAP_ECHO_REQ"; + case L2CAP_ECHO_RSP: + return "L2CAP_ECHO_RSP"; + case L2CAP_INFO_REQ: + return "L2CAP_INFO_REQ"; + case L2CAP_INFO_RSP: + return "L2CAP_INFO_RSP"; + } + return "unknown"; +} + +#define OFFSET 8 //means the buffer also has space for the l2cap/hci headers and need not be allocated and copied +//#define OFFSET 0 //means the buffer only has space for the payload which need to be copied +#if OFFSET == 0 +#define L2CAPBUFSIZE 128 +#else +#define L2CAPBUFSIZE 0 +#endif + +typedef struct { + u16 handle; + u16 length; // total + u16 l2capLength; // length -4 + u16 cid; // Signaling packet CID = 1 + u8 data[L2CAPBUFSIZE]; // Largest thing to send!!! todo +} L2CAPData; + +// +void BTDevice::Init() { + memset(&_info,0,sizeof(inquiry_info)); + _handle = 0; + _name[0] = 0; + _state = 0; + _txid = 1; + //cntr_cred = 1; +} + +// virtual SocketHandler +int BTDevice::Open(SocketInternal* sock, SocketAddrHdr* addr) { + L2CAPSocket* s = (L2CAPSocket*)sock; + L2CAPAddr* a = (L2CAPAddr*)addr; + s->scid = 0x40 + sock->ID-1; // are these reserved? + s->dcid = 0; + Connect(s->scid,a->psm); + sock->State = SocketState_L2CAP_WaitConnectRsp; + contState = 0; + return sock->ID; +} + +// virtual SocketHandler +int BTDevice::Accept(SocketInternal* sock, int scid, int rxid) { + L2CAPSocket* s = (L2CAPSocket*)sock; + s->scid = 0x40 + sock->ID-1; // are these reserved? + s->dcid = scid; + u16 p[4]; + p[0] = s->scid; + p[1] = scid; + p[2] = 0; //success + p[3] = 0; //no further information + Send(L2CAP_CONN_RSP,rxid,p,4); + printf("send conn_rsp with dcid=%#x and scid=%#x\n", p[0],p[1]); + sock->State = SocketState_L2CAP_Config_wait; + contState = 0; + return sock->ID; +} + +// virtual SocketHandler, called from HCI which is ABOVE L2CAP +int BTDevice::Send(SocketInternal* sock, const u8* data, int len) { + L2CAPSocket* s = (L2CAPSocket*)sock; +#if OFFSET == 8 //sizeof L2CAPData header + L2CAPData &d = *const_cast<L2CAPData*>((L2CAPData*)data); +#else + L2CAPData d; +#endif + if (len > peer_mtu) {//mtu concerns the l2cap mtu, because we use basic mode we cannot segment + printf("MTU (%d) for outgoing packet (%d) exceeded\n", peer_mtu, len); + return 0; + } + d.handle = _handle | 0x2000; + d.length = 4 + len - OFFSET; + d.l2capLength = len - OFFSET; + d.cid = s->dcid; + //printf("cid=%d: ", d.cid); + //printfBytes("sending: ", data, len); +#if OFFSET == 0 + if (len > L2CAPBUFSIZE) + return -1; + memcpy(d.data,data,len); + return Send((u8*)&d,len+8); +#else + return Send(data, len); +#endif +} + +// virtual SocketHandler +int BTDevice::Close(SocketInternal* sock) { + printf("L2CAP close %d\n",sock->ID); + sock->State = SocketState_L2CAP_WaitDisconnect; + L2CAPSocket* s = (L2CAPSocket*)sock; + return Disconnect(s->scid,s->dcid); +} + +L2CAPSocket* BTDevice::SCIDToSocket(int scid) { + return (L2CAPSocket*)GetSocketInternal(scid-0x40+1); +} + +int BTDevice::Send(const u8* data, int len) {//printfBytes("Transport : ", data, len); +#ifdef HOST_CONTR_FLOW + pkts_sent++; +#endif + _transport->ACLSend(data,len); + return 0; +} + +void BTDevice::repeat_cmd() { + printf("Cmd on handle %#x timed out, resending txid=%d\n", _handle, last_req.id); +// Send ((u8*)&last_req, last_req.length+4);//danger! interrupt context, Send is not reentrant + //optionally set new larger timeout +} + +int BTDevice::Send(u8 c, u8 id, u16* params, int count) { + L2CAPCmd cmd; + cmd.handle = _handle | 0x2000; + cmd.length = 8 + count*2; + + cmd.l2capLength = cmd.length-4; + cmd.cid = 1; // Signaling packet + + cmd.cmd = c; + cmd.id = id; + cmd.cmdLength = count*2; + for (int i = 0; i < count; i++) + cmd.params[i] = params[i]; + if ((c & 1) == 0) { //this is a request + last_req = cmd; + rtx.attach(this, &BTDevice::repeat_cmd, 30.0); + //printf("Starting timeout for %#x, txid=%d\n", _handle, id); + } + return Send((u8*)&cmd,cmd.length+4); +} + +int BTDevice::Connect(int scid, int psm) { + u16 p[2]; + p[0] = psm; + p[1] = scid; + return Send(L2CAP_CONN_REQ,TXID,p,2); +} + +int BTDevice::Disconnect(int scid, int dcid) { + u16 p[2]; + p[0] = dcid; + p[1] = scid; + return Send(L2CAP_DISCONN_REQ,TXID,p,2); +} + +int BTDevice::ConfigureRequest(int dcid) { + u16 p[4]; + p[0] = dcid; + p[1] = 0; + p[2] = 0x0201; // Options + p[3] = min(0x02A0, MAX_ACL_SIZE); // my receiving MTU 672 + return Send(L2CAP_CONF_REQ,TXID,p,4); +} + +int BTDevice::CommandReject(u16 reason, u16 data0, u16 data1) { + u16 p[3]; + p[0] = reason; + p[1] = data0; + p[2] = data1; + int parlen = 2; + switch(reason){ + case 0: //command not understood + break; + case 1: //MTU exceeded + parlen = 4; //return actual mtu in data + break; + case 2: //invalid CID + parlen = 6; //return local, remote cid + break; + } + return Send(L2CAP_COMMAND_REJ,TXID,p,parlen); +} + +int BTDevice::ConfigureResponse(u8 rxid, int dcid) { + u16 p[3]; + p[0] = dcid; //source cid + p[1] = 0; //flags (no continuation) + p[2] = 0; //result (success) + return Send(L2CAP_CONF_RSP,rxid,p,3); +} + +int BTDevice::DisconnectResponse(u8 rxid, int scid, int dcid) { + u16 p[2]; + p[0] = dcid; + p[1] = scid; + return Send(L2CAP_DISCONN_RSP,rxid,p,2); +} + +void server(int socket, SocketState state, const u8* data, int len, void* userData) { + // printfBytes("Server: ", data, len); + if (state==SocketState_Open && len>0) + SDP.SDPServer(socket, state, data, len, userData); +} + +void serserver(int socket, SocketState state, const u8* data, int len, void* userData) { + printfBytes("serserver: ", data, len); + SocketHandler *h = (SocketHandler*)userData; + printf("userData refers to %s, state = %d\n", h->Name(), state); + if (state==SocketState_Open) { + if (len == 0) { //assume that the socket has just been opened and bind it to a new rfcomm server entity + printf("Calling RFCOMMManager::BindSocket\n"); + rfcomm_manager.BindSocket(socket); + } else { + printf("Calling RFCOMMManager::SerServer\n"); + rfcomm_manager.SerServer(socket, state, data, len, userData); + } + } else if (state==SocketState_L2CAP_WaitDisconnect) { + printf("Calling RFCOMMManager::SerServer\n"); + rfcomm_manager.SerServer(socket, state, data, len, userData); + } +} + +//code8, tid8, lengthData16 +// 0, 1, 2, 3 +void BTDevice::Control(const u8* data, int len) { //control channel receive + printf("\x1B[%dm", 31); + int cc = data[0];//command code + if (cc & 1) { //it is a response or a reject + rtx.detach(); //kill the timeout + //printf("timeout cancelled for handle %#x, txid=%d\n", _handle, data[1]); + } + printf(L2CAP_ComandCodeStr(cc)); + switch (cc) { + case L2CAP_COMMAND_REJ://bad command, eg. MTU, check (reason) + printf(" rejection reason=%d\n", LE16(data+4)); + break; + case L2CAP_CONN_REQ://incoming connection request, not expected but should reply with proper rejection (or accept) + //when a connection is accepted a new socket must be opened + printf(" Remote side requested a connection\n"); + { + int scid = LE16(data+6); + int psm = LE16(data+4); + int rxid = data[1]; + u16 p[4]; + p[0] = 0; //no dcid + p[1] = scid; + p[3] = 0; //no further information + printf(" scid=%d, psm=%d\n", scid, psm); + int s = 0; + switch (psm) { + case L2CAP_PSM_SDP: + s = Socket_Accept(SOCKET_SDP, scid, rxid, server, this);//allocate an sdp socket but use it as L2CAP + break; + case L2CAP_PSM_RFCOMM: //SOCKET_RFCOM; +#if 0 + s = Socket_Accept(SOCKET_RFCOM, scid, rxid, serserver, this);//allocate an rfcomm socket + //using L2CAP i.o. RFCOM makes little difference in processing but it also changes the handler to HCI i.o. RFCOMMManager +#else +//an RFCOMM requests comes in from a known (this) device +//the channel is not yet known + s = rfcomm_manager.FindSocket(this);//this should return 0 otherwise the remote device was asking a second rfcomm on the same device + if (s==0) { + printf("No connection to this device yet, allocate L2CAP Socket and accept\n"); + //accept the connection, even though there may be no listener??? + //have no choice because w/o acceptance no rfcomm req. + s = Socket_Accept(SOCKET_L2CAP, scid, rxid, serserver, this);//allocate an l2cap socket + //get a new l2cap socket, call HCI::Accept (fill in btdevice internals), then call BTDevice::Accept (send accept message) + //serserver is called on state changes (SocketInternal::SetState) and on received packets from the peer device to the new l2cap handle + //after sending the accept message, the devices will execute the normal l2cap connection state-machine + //ending in a call to SetState(Open) which will invoke 'serserver' for the first time +//or something like: +// s = Socket_Create(SOCKET_L2CAP, serserver, this);//allocate an l2cap socket +// Accept(GetSocketInternal(s), scid, rxid);//send accept response, this would bypass HCI::Accept() + } else { + printf("Already had an L2CAP connection on socket %d\n", s); + } +#endif + break; + default: + printf("PSM %d not supported\n", psm); + } + switch (s) { + case 0: + printf("Not a valid socket\n"); + break; + case ERR_SOCKET_TYPE_NOT_FOUND: + p[2] = 2; //psm not supported + Send(L2CAP_CONN_RSP,rxid,p,4); + break; + case ERR_SOCKET_NONE_LEFT: + p[2] = 4; //no resources available + Send(L2CAP_CONN_RSP,rxid,p,4); + break; + } + } + break; + // Response to our initial connect from Remote + case L2CAP_CONN_RSP: { + int dcid = LE16(data+4); + int scid = LE16(data+6); + L2CAPSocket* s = SCIDToSocket(scid); + int result = LE16(data+8); + printf(" Result=%d, Status = %d\n", result, LE16(data+10)); + if (s->si.State != SocketState_L2CAP_WaitConnectRsp) { + printf("Unexpected event ignored\n"); + break; + } + if (result == 0) { + if (s) { + s->si.State = SocketState_L2CAP_Config_wait; + s->dcid = dcid; + ConfigureRequest(dcid); + s->si.State = SocketState_L2CAP_Config_wait_reqrsp; + printf("Sent ConfigureRequest, state=WAIT_CONFIG_REQ_RSP\n"); + } + } else if (result == 1) {//pending, stay in the present state + } else { + s->si.SetState(SocketState_Closed); + printf("Connect failed\n"); + } + } + break; + + case L2CAP_CONF_RSP: { + int result = LE16(data+8); + printf("Result=%d, datalen=%d, %smore conf to follow\n", result, LE16(data+2), LE16(data+6)?"":"No "); + //should parse the config + printfBytes("CONF RSP:", data, LE16(data+2)+4); + int scid = LE16(data+4); + SocketInternal* s = (SocketInternal*)SCIDToSocket(scid); + if (s == 0) break; + if (s->State != SocketState_L2CAP_Config_wait_reqrsp && s->State != SocketState_L2CAP_Config_wait_rsp) { + printf("Unexpected event ignored\n"); + break; + } + if (result == 0) { //configuration acceptable + if (s->State == SocketState_L2CAP_Config_wait_reqrsp) { + s->State = SocketState_L2CAP_Config_wait_req; + printf("State=WAIT_CONFIG_REQ\n"); + } else { + ConfigureResponse(data[1],((L2CAPSocket*)s)->dcid);//data[1]==txid + printf("Sent ConfigureResponse, state=Open\n"); + s->SetState(SocketState_Open); + } + } else { + printf("Renegotiate configuration\n"); + } + } + break; + + case L2CAP_CONF_REQ: { + int len = LE16(data+2); + int scid = LE16(data+4);//flags (data[6] LSB is continuation flag, data[10],[11] are the MTU + int flags = LE16(data+6); + if (flags) + printf("Warning! Continuation flag in L2CAP configuration not supported\n"); + L2CAPSocket* s = SCIDToSocket(scid); + printfBytes("CONF REQ: ", data, LE16(data+2)+4);//data+8 contains option type 1-4 1=MTU, 2=flush timeout, 3=QoS, 4=FCM + if (s == 0) break; + if (s->si.State == SocketState_Closed || + s->si.State == SocketState_L2CAP_WaitConnectRsp || + s->si.State == SocketState_L2CAP_WaitDisconnect) { + //Send Reject command + printf("Connection should be rejected\n"); + break; + } + if (len > 4) + switch (data[8]) { + case 1: + peer_mtu = LE16(data+10); + printf("Peer L2CAP MTU = %d bytes\n", peer_mtu); + break; + default: + printf("Unsupported configuration option %d, value = %#X\n", data[8], LE16(data+10)); + break; + } + if (1 /* options acceptable */) { + printf("Sending ConfigureResponse, old state=%d ", s->si.State); + ConfigureResponse(data[1],s->dcid);//data[1]==txid, success + switch (s->si.State) { + case SocketState_L2CAP_Config_wait: + s->si.State = SocketState_L2CAP_Config_wait_send; + ConfigureRequest(s->dcid); + s->si.State = SocketState_L2CAP_Config_wait_rsp; + break; + case SocketState_L2CAP_Config_wait_req: + ((SocketInternal*)s)->SetState(SocketState_Open); + break; + case SocketState_L2CAP_Config_wait_rsp: + break; + case SocketState_L2CAP_Config_wait_reqrsp: + s->si.State = SocketState_L2CAP_Config_wait_rsp; + break; + } + printf("new state=%d\n", s->si.State); + } else { //options not acceptable + printf("Configure failure should be indicated\n"); + ConfigureResponse(data[1],s->dcid);//indicates success but should indicate fail + } + } + break; + case L2CAP_DISCONN_REQ: { + int dcid = LE16(data+4); + int scid = LE16(data+6); + L2CAPSocket* s = SCIDToSocket(dcid); + if (s){ + s->si.SetState(SocketState_Closed); + DisconnectResponse(data[1], scid, dcid); + } else { + printf("request to disconnect cid %d fails, no such cid\n", dcid); + CommandReject(0, dcid, scid); + } + } + break; + case L2CAP_DISCONN_RSP: { + int scid = LE16(data+6); + L2CAPSocket* s = SCIDToSocket(scid); + if (s->si.State == SocketState_L2CAP_WaitDisconnect) + s->si.SetState(SocketState_Closed); + } + break; + default: + printf("Unsupported L2CAP message %d\n", cc); + } + printf("\x1b[0m"); +} + +void BTDevice::ACLFwd(const u8* data, int len) { + if (l2cap_sock == 1) + Control(data, len); + else { + SocketInternal* s = (SocketInternal*)SCIDToSocket(l2cap_sock);//in fact cid in the l2cap header + if (s) + s->Recv(data,len);//forward to the sockethandler for the type + else + printf("Bad event cid %d\n",l2cap_sock); + } +} +//sometimes acl packets are segmented, in that case the l2cap payload length does not correspond to the acl pkt length +//and the l2cap packet length. L2CAP works in basic mode and cannot be segmented hence the l2cap pkt size corresponds to +//the acl pkt size +int BTDevice::ACLRecv(const u8* data, int acllen) { + //printfBytes("L2CP",data,acllen); + //cntr_cred--; + u16 handle = LE16(data); + if ((handle&0x0fff) != _handle) { + printf("unexpected handle %#x, this _handle=%#x\n", handle, _handle); + return 1; + } + //below is the ACL packet recombination engine + char pb = (handle>>12) & 3; + if (pb == 2) + segments = 1; + else + segments++; + int p = 4; //start of l2cap packet + int len = LE16(data+2); //length of l2cap pkt + while (p < acllen) + switch (contState) { + case 0://allow even for fragmented length field + plen = data[p++];//payload length lsb + contState = 1; + break; + case 1: + plen += data[p++]<<8; //payload length msb + if (pb == 2 && plen == acllen-8) {//normal case, l2cap pkt is contained completely in this hci pkt + l2cap_sock = data[p] + (data[p+1]<<8); + contState = 0; + ACLFwd(data+8, plen); //forward the packet in its original buffer + return segments; //all data was dealt with + } else { //packet is segmented + //printf("ACL packet is segmented\n"); + contState = 2; + contBuf = new unsigned char[plen];//allocate recombination buffer + contPos = 0; + } + break; + case 2: + l2cap_sock = data[p++]; + contState = 3; + break; + case 3: + l2cap_sock += data[p++]<<8; + contState = 4; + break; + case 4: //data, recombine segmented ACL (not l2cap!) frames + if (contPos < plen) {//buffer not yet full + int datalen = acllen - p; //data in this incoming pkt + int remcap = plen - contPos; //remaining capacity in the recombination buffer + if (datalen <= remcap) { + memcpy(contBuf+contPos, data+p, datalen); + contPos += datalen; + p = acllen;//end of data, stop the while loop + if (contPos == plen) {//buffer is full now + //printfBytes("Recombined packet is:", contBuf, plen); + ACLFwd(contBuf, plen); //forward the recombination buffer + delete[] contBuf;//and free the buffer + contState = 0; + return segments; + }//else stay in this state to wait for the rest + } else {//data contains (part of) next packet, never seen this happen + memcpy(contBuf+contPos, data+p, plen-contPos);//this packet is complete + p += plen-contPos; + printfBytes("Recombined packet is:", contBuf, plen); + printfBytes("Next packet starts with:", data+p, acllen-p); + ACLFwd(contBuf, plen); //forward the recombination buffer + delete[] contBuf;//and free the buffer + contState = 0; //continue with the next packet + } + } else { + printf("Cannot append to buffer (size=%d, pos=%d, datalen = %d)\n", plen, contPos, len-p); + contState = 0; + return segments;//flushed + } + break; + }//switch (and while) + return 0;//the buffers are not processed yet +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/myBlueUSB/Socket.cpp Wed Jun 15 19:12:25 2011 +0000 @@ -0,0 +1,227 @@ +/* +Copyright (c) 2010 Peter Barrett + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "Utils.h" +#include "Socket.h" + +#define MAX_SOCKET_HANDLERS 4 +#define MAX_SOCKETS 16 + +class SocketInternalPad +{ + public: + SocketInternal si; + u8 pad[8]; +}; + +class SocketManager +{ + SocketHandler* _handlers[MAX_SOCKET_HANDLERS]; + SocketInternalPad _sockets[MAX_SOCKETS]; + + public: + SocketManager() + { + memset(_handlers,0,sizeof(_handlers)); + memset(_sockets,0,sizeof(_sockets)); + } + + SocketHandler* GetHandler(int type) + { + if (type < 1 || type > MAX_SOCKET_HANDLERS) + return 0; + return _handlers[type - 1]; + } + + SocketInternal* GetInternal(int s) + { + if (s < 1 || s > MAX_SOCKETS) + return 0; + return &_sockets[s - 1].si; + } + + int RegisterSocketHandler(int type, SocketHandler* handler) + { + if (type < 1 || type > MAX_SOCKET_HANDLERS) + return ERR_SOCKET_TYPE_NOT_FOUND; + _handlers[type - 1] = handler; + return 0; + } + + int Create(int type, SocketCallback callback, void* userData) + { + SocketHandler* h = GetHandler(type); + if (!h) + return ERR_SOCKET_TYPE_NOT_FOUND; + + for (int i = 0; i < MAX_SOCKETS; i++) + { + SocketInternal* si = (SocketInternal*)(_sockets+i); + if (si->ID == 0) + { + si->ID = i+1; + si->Type = type; + si->Callback = callback; + si->userData = userData; + printf("Creating socket %d for type %d, invoking 'Open' on %p (=%s)\n", si->ID, type, h, h->Name()); + return h->Create(si); + } + } + return ERR_SOCKET_NONE_LEFT; + } + + int Open(int type, SocketAddrHdr* addr, SocketCallback callback, void* userData) + { + SocketHandler* h = GetHandler(type); + if (!h) + return ERR_SOCKET_TYPE_NOT_FOUND; + + for (int i = 0; i < MAX_SOCKETS; i++) + { + SocketInternal* si = (SocketInternal*)(_sockets+i); + if (si->ID == 0) + { + si->ID = i+1; + si->Type = type; + si->Callback = callback; + si->userData = userData; + printf("Opening socket %d for type %d, invoking 'Open' on %p (=%s)\n", si->ID, type, h, h->Name()); + return h->Open(si,addr); + } + } + return ERR_SOCKET_NONE_LEFT; + } + + int Listen(int type, int channel, SocketCallback callback, void* userData) + { + SocketHandler* h = GetHandler(type); + if (!h) + return ERR_SOCKET_TYPE_NOT_FOUND; + + for (int i = 0; i < MAX_SOCKETS; i++) + { + SocketInternal* si = (SocketInternal*)(_sockets+i); + if (si->ID == 0) + { + si->ID = i+1; + si->Type = type; + si->Callback = callback; + si->userData = userData; + printf("Passively opening socket %d for type %d, invoking 'Listen' on %p (=%s)\n", si->ID, type, h, h->Name()); + int sn = h->Listen(si, channel); + if (sn < 0) + si->ID = 0;//free the socket when error + return sn; + } + } + return ERR_SOCKET_NONE_LEFT; + } + + int Accept(int type, int scid, int rxid, SocketCallback callback, void* userData) + { + SocketHandler* h = GetHandler(type); + if (!h) + return ERR_SOCKET_TYPE_NOT_FOUND; + + for (int i = 0; i < MAX_SOCKETS; i++) + { + SocketInternal* si = (SocketInternal*)(_sockets+i); + if (si->ID == 0) + { + si->ID = i+1; + si->Type = type; + si->Callback = callback; + si->userData = userData; + printf("Accepting socket %d for type %d, invoking 'Accept' on %p (=%s)\n", si->ID, type, h, h->Name()); + return h->Accept(si, scid, rxid); + } + } + return ERR_SOCKET_NONE_LEFT; + } + + int Send(int socket, const u8* data, int len) + { + SocketInternal* si = GetInternal(socket); + if (!si || si->ID != socket) + return ERR_SOCKET_NOT_FOUND; + // printf("sending %d bytes to socket %d (ID=%d)\n", len, socket, si->ID); + return GetHandler(si->Type)->Send(si,data,len); + } + + int Close(int socket) + { + SocketInternal* si = GetInternal(socket); + if (!si || si->ID != socket){ + printf("Close: socket %d not found\n", socket); + return ERR_SOCKET_NOT_FOUND; + } + printf("Close: socket %d (type=%d)\n", socket, si->Type); + si->SetState(SocketState_Closing); + int retval = GetHandler(si->Type)->Close(si); + //si->SetState(Socket_Closed); + //si->ID = 0; + return retval; + } +}; + +SocketManager gSocketManager; + +int Socket_Open(int type, SocketAddrHdr* addr, SocketCallback callback, void* userData) +{ + return gSocketManager.Open(type,addr,callback,userData); +} + +int Socket_Listen(int type, int channel, SocketCallback callback, void* userData) // Open a socket for listening +{ + return gSocketManager.Listen(type,channel,callback,userData); +} + +int Socket_Accept(int type, int scid, int rxid, SocketCallback callback, void* userData) // Open a socket for an incoming connection +{ + return gSocketManager.Accept(type,scid,rxid,callback,userData); +} + +int Socket_Send(int socket, const u8* data, int len) +{ + return gSocketManager.Send(socket,data,len); +} + +int Socket_Close(int socket) +{ + return gSocketManager.Close(socket); +} + +int RegisterSocketHandler(int type, SocketHandler* handler) +{ + return gSocketManager.RegisterSocketHandler(type,handler); +} + +SocketInternal* GetSocketInternal(int socket) +{ + return gSocketManager.GetInternal(socket); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/myBlueUSB/Socket.h Wed Jun 15 19:12:25 2011 +0000 @@ -0,0 +1,119 @@ +/* +Copyright (c) 2010 Peter Barrett + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef SOCKET_H_INCLUDED +#define SOCKET_H_INCLUDED + +#define SOCKET_HCI 1 +#define SOCKET_L2CAP 2 +#define SOCKET_RFCOM 3 +#define SOCKET_SDP 4 + +typedef struct +{ + u8 AddressSpecific[0]; // BDADDR,psm etc +} SocketAddrHdr; + +enum SocketState +{ + SocketState_Unknown, + SocketState_Opening, + SocketState_Open, + SocketState_Closing, + SocketState_Closed, + SocketState_Listen, + SocketState_Accepting, + SocketState_L2CAP_WaitConnect = 8, + SocketState_L2CAP_WaitConnectRsp, + SocketState_L2CAP_WaitDisconnect, + SocketState_L2CAP_Config_wait = 16, + SocketState_L2CAP_Config_wait_send, + SocketState_L2CAP_Config_wait_req, + SocketState_L2CAP_Config_wait_rsp, + SocketState_L2CAP_Config_wait_reqrsp +}; + +typedef void (*SocketCallback)(int socket, SocketState state, const u8* data, int len, void* userData); + +int Socket_Create(int type, SocketCallback callback, void* userData); // Allocate a socket +int Socket_Open(int type, SocketAddrHdr* addr, SocketCallback callback, void* userData); // Open a socket +int Socket_Listen(int type, int channel, SocketCallback callback, void* userData); // Open a socket passive +int Socket_Accept(int type, int scid, int rxid, SocketCallback callback, void* userData); // Open a socket for an incoming connection +int Socket_Send(int socket, const u8* data, int len); +int Socket_State(int socket); +int Socket_Close(int socket); + +//=========================================================================== +//=========================================================================== +// Don't need to look at or use anything below this line: +// Internal representation of socket + +class SocketHandler; +class SocketInternal +{ + public: + + u8 ID; + u8 State; + u8 Type; + u8 B0; + SocketCallback Callback; + void* userData; + u8 Data[0]; // Extra socket data starts here + + void Recv(const u8* data, int len) + { + Callback(ID,(SocketState)State,data,len,userData); + } + + void SetState(SocketState state) + { + State = state; + Callback(ID,(SocketState)State,0,0,userData); + if (state == SocketState_Closed) { + printf("Socket %d has been freed\n", ID); + ID = 0; + } + } +}; + +class SocketHandler +{ + public: + virtual int Create(SocketInternal* sock) { printf("SocketHandler::Create: not implemented for %s\n", Name()); return sock->ID;} + virtual int Open(SocketInternal* sock, SocketAddrHdr* addr) = 0; + virtual int Send(SocketInternal* sock, const u8* data, int len) = 0; + virtual int Close(SocketInternal* sock) = 0; + virtual int Listen(SocketInternal* sock, int channel) { printf("SocketHandler::Listen: not implemented for %s\n", Name());return 0;} + virtual int Accept(SocketInternal* sock, int scid, int rxid) { printf("SocketHandler::Accept: not implemented for %s\n", Name());return 0;} + virtual char* Name() { return "Base_SocketHandler";} +}; + +int RegisterSocketHandler(int type, SocketHandler* handler); +SocketInternal* GetSocketInternal(int socket); + +#define ERR_SOCKET_TYPE_NOT_FOUND -200 +#define ERR_SOCKET_NOT_FOUND -201 +#define ERR_SOCKET_NONE_LEFT -202 +#define ERR_SOCKET_CANT_LISTEN -203 + +#endif // SOCKET_H_INCLUDED
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/myBlueUSB/Utils.cpp Wed Jun 15 19:12:25 2011 +0000 @@ -0,0 +1,49 @@ + + +#include "mbed.h" +#include "Utils.h" + +void printfBytes(const char* s, const u8* data, int len) +{ + printf("%s %d:",s,len); + if (len > 256) + len = 256; + while (len-- > 0) + printf(" %02X",*data++); + printf("\n"); +} + +void printHexLine(const u8* d, int addr, int len) +{ + printf("%04X ",addr); + int i; + for (i = 0; i < len; i++) + printf("%02X ",d[i]); + for (;i < 16; i++) + printf(" "); + char s[16+1]; + memset(s,0,sizeof(s)); + for (i = 0; i < len; i++) + { + int c = d[i]; + if (c < 0x20 || c > 0x7E) + c = '.'; + s[i] = c; + } + printf("%s\n",s); +} + +void printHex(const u8* d, int len) +{ + int addr = 0; + while (len) + { + int count = len; + if (count > 16) + count = 16; + printHexLine(d+addr,addr,count); + addr += 16; + len -= count; + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/myBlueUSB/Utils.h Wed Jun 15 19:12:25 2011 +0000 @@ -0,0 +1,42 @@ +#ifndef UTILS_H +#define UTILS_H + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned long u32; + +void DelayMS(int ms); + +void printfBytes(const char* label,const u8* data, int len); +void printHex(const u8* d, int len); +//void printf(const BD_ADDR* addr); + +#ifndef min +#define min(_a,_b) ((_a) < (_b) ? (_a) : (_b)) +#endif + +inline int LE16(const u8* d) +{ + return d[0] | (d[1] << 8); +} + +inline u32 BE32(const u8* d) +{ + return (d[0] << 24) | (d[1] << 16) | (d[2] << 8) | d[3]; +} + +inline void BE32(u32 n, u8* d) +{ + d[0] = (u8)(n >> 24); + d[1] = (u8)(n >> 16); + d[2] = (u8)(n >> 8); + d[3] = (u8)n; +} + +inline void BE16(u32 n, u8* d) +{ + d[0] = (u8)(n >> 8); + d[1] = (u8)n; +} + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/myBlueUSB/hci.cpp Wed Jun 15 19:12:25 2011 +0000 @@ -0,0 +1,572 @@ + +/* +Copyright (c) 2010 Peter Barrett + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "Utils.h" +#include "hci.h" +#include "hci_private.h" +#include "USBHost.h" //for USBLoop +#include "HCITransportUSB.h" //for ACL/HCL buffer size + +enum hci_callback_evt { + NONE, + CONNECT, + DISCONECT, + INQUIRYRESULT +}; + +#define MAX_BLUETOOTH_ADAPTERS 1 + +static const u8 local_name[] = "MBED"; + + +int HCI::Open(HCITransport* transport, HCICallback callback) { + _transport = transport; + _transport->Set(this); + _callback = callback; + _state = 0; + for (int i = 0; i < MAX_BTDEVICES; i++) { + _devices[i].Init(); + _devices[i]._transport = transport; + } +#ifdef COMMAND_FLOW + cmd_credits = 1; +#endif + return SendCmd(HCI_OP_RESET); +} + +void printf(const BD_ADDR* addr); + +BTDevice* HCI::Find(const BD_ADDR* addr) { + for (int i = 0; i < MAX_BTDEVICES; i++) + if (_devices[i]._state != 0 && memcmp(addr,&_devices[i]._info.bdaddr,6) == 0) + return &_devices[i]; + return 0; +} + +BTDevice* HCI::Find(int handle) { + for (int i = 0; i < MAX_BTDEVICES; i++) + if (_devices[i]._state != 0 && handle == _devices[i]._handle) + return &_devices[i]; + return 0; +} + +//reports that some commands are still in progress +bool HCI::Busy() { + return (_state & (MASK_INQUIRY | MASK_REMOTE_NAME | MASK_CREATE_CONNECTION)) != 0; +} + +int HCI::Inquiry(int duration) { + _state |= MASK_INQUIRY; + u8 buf[5]; + buf[0] = 0x33;//LAP=0x9e8b33 + buf[1] = 0x8B; + buf[2] = 0x9E; + buf[3] = duration; + buf[4] = 5; // 5 results + SendCmd(HCI_OP_INQUIRY,buf,sizeof(buf)); + return 0; +} + +int HCI::SetEventFilter(u8 filterType, u8 filterConditionType, u8* condition) { + int len = 2; + u8 buf[8]; + buf[0] = filterType; + buf[1] = filterConditionType; + switch (filterConditionType) { + case 0://all devices + if (filterType==2) { //connection setup + buf[2] = condition[0]; + len++; + } + break; + case 1: //filter by class + case 2: //filter by BDADDR + memcpy(buf+2, condition, 6); + len += 6; + break; + default: + printf("Unknown filter condition type %d, filter type=%d\n", filterConditionType, filterType); + } + SendCmd(HCI_OP_SET_EVENT_FLT, buf, len); + return 0; +} + +int HCI::SendCmd(int cmd, const u8* params, int len) { + u8 b[256]; + b[0] = cmd; + b[1] = (cmd >> 8); + b[2] = len; + if (params) + memcpy(b+3,params,len); +#ifdef COMMAND_FLOW + //printf("%d cmd_credits\n", cmd_credits); + while (cmd_credits == 0) {//blocks when command credits run out + USBLoop(); + putc('_', stdout); + } +#endif + _transport->HCISend(b,len+3); + return 0; +} + +void HCI::OnCommandComplete(int cmd, const u8* data, int len) {//data is exclusive the status byte + //printf("%04X %s",cmd,CmdStr(cmd)); + if (len < 0) + return; + //printfBytes(" complete",data,len/*min(16,len)*/); + + switch (cmd) { + case 0: //NOP + printf("Received NOP command (for cmd_credits)\n"); + break; + // Init phase 0 + case HCI_OP_RESET: // Reset done, init chain to HCI_OP_READ_LOCAL_NAME + SendCmd(HCI_OP_READ_BUFFER_SIZE); + _state |= MASK_RESET; + break; + + // Init phase 1 + case HCI_OP_READ_BUFFER_SIZE: + _acl_mtu = LE16(data); + _sco_mtu = data[2]; + _acl_max_pkt = LE16(data+3); + _sco_max_pkt = LE16(data+5); + printf("acl_mtu=%d, acl_max_pkt=%d\n", _acl_mtu, _acl_max_pkt); +#ifdef HOST_CONTR_FLOW + _transport->data_credits = _acl_max_pkt; + _transport->_acl_mtu = _acl_mtu; +#endif + SendCmd(HCI_OP_READ_BD_ADDR); + _state |= MASK_READ_BUFFER_SIZE; + break; + + // Init phase 2 + case HCI_OP_READ_BD_ADDR: + _localAddr = *((BD_ADDR*)data); // Local Address + _state |= MASK_READ_BD_ADDR; + _state |= MASK_INITED; + { +#ifdef CONTR_HOST_FLOW + unsigned char param[7]; + param[0] = (u8)(MAX_ACL_SIZE-8); + param[1] = (u8)((MAX_ACL_SIZE-8)>>8); + param[2] = 0;//MAX_HCL_SIZE-8; + param[3] = 10; + param[4] = 0; //1 ACL buffer + param[5] = 0; + param[6] = 0; //0 Synchronous buffers + SendCmd(HCI_OP_HOST_BUFFER_SIZE, param, 7); + const unsigned char flow = 1;//ACL on, Synchonous off + SendCmd(HCI_OP_CONTR_TO_HOST_FLOW, &flow, 1); +#endif + const unsigned char scan_enable = 3; + SendCmd(HCI_OP_WRITE_SCAN_ENABLE, &scan_enable, 1); + SendCmd(HCI_OP_WRITE_LOCAL_NAME, local_name, 248); + } + Callback(CALLBACK_READY,data,6); + break; + + // 0CXX + case HCI_OP_READ_LOCAL_NAME: + case HCI_OP_LINK_KEY_NEG_REPLY: + case HCI_OP_WRITE_SCAN_ENABLE: + case HCI_OP_WRITE_LOCAL_NAME: + break; +#ifdef CONTR_HOST_FLOW + case HCI_OP_CONTR_TO_HOST_FLOW: + case HCI_OP_HOST_BUFFER_SIZE: + break; + case HCI_OP_NUM_COMP_PKTS: + printf("Host number of Completed Packets: Invalid HCI Command Parameter\n"); + break; +#endif + case HCI_OP_READ_LOCAL_VERSION: + // params + //SendCmd(HCI_OP_READ_LOCAL_NAME); + break; + + case HCI_OP_READ_LOCAL_COMMANDS: + break; + + case HCI_OP_READ_LOCAL_FEATURES: + //SendCmd(HCI_OP_READ_LOCAL_VERSION); + break; + + case HCI_OP_READ_LOCAL_EXT_FEATURES: + break; + + case HCI_OP_PIN_CODE_REPLY: + printf("Got pin reply\n"); + break; + + default: + printf("Unrecognized Command Completion %04X\n",cmd); + break; + } +} + +void HCI::Callback(HCI_CALLBACK_EVENT c, const u8* data, int len) { + if (_callback) _callback(this,c,data,len); +// (this->*_callback)(c, data, len); +} + +int HCI::RemoteNameRequest(const BD_ADDR* addr) { + _state |= MASK_REMOTE_NAME; + u8 buf[6+4]; + memset(buf,0,sizeof(buf)); + memcpy(buf,addr,6); + //buf[7] = 1; + return SendCmd(HCI_OP_REMOTE_NAME_REQ,buf,sizeof(buf)); +} + +int HCI::RemoteNameRequest(inquiry_info *ii) { + _state |= MASK_REMOTE_NAME; + u8 buf[6+4]; + //memset(buf,0,sizeof(buf)); + memcpy(buf,&ii->bdaddr,6); + buf[6] = ii->pscan_rep_mode; + buf[7] = 0; + *(unsigned short*)(buf+8) = 0; + return SendCmd(HCI_OP_REMOTE_NAME_REQ,buf,sizeof(buf)); +} + +int HCI::CreateConnection(const BD_ADDR* remoteAddr) { + _state |= MASK_CREATE_CONNECTION; + u8 buf[6+7]; + memset(buf,0,sizeof(buf)); + memcpy(buf,remoteAddr,6); + buf[6] = 0x18; // DM1,DH1 + buf[7] = 0xCC; // DM3, DH3, DM5, DH5 + buf[8] = 1; // Page Repetition R1 + return SendCmd(HCI_OP_CREATE_CONN,buf,sizeof(buf)); +} + +int HCI::Disconnect(const BD_ADDR* bdaddr) { + BTDevice* d = Find(bdaddr); + if (!d) + return ERR_HCI_DEVICE_NOT_FOUND; + int handle = d->_handle; + printf("Disconnect from %d\n",handle); + _state |= MASK_CREATE_CONNECTION; + u8 buf[3]; + buf[0] = handle; + buf[1] = (handle >> 8); + buf[2] = 0x13; + return SendCmd(HCI_OP_DISCONNECT,buf,sizeof(buf)); +} + +void HCI::DisconnectComplete(int handle) { + BTDevice* d = Find(handle); + if (!d) + return; + d->_handle = 0; +} + +int HCI::DisconnectAll() { + BTDevice* devs[8]; + int count = GetDevices(devs,8); + for (int i = 0; i < count; i++) + Disconnect(&devs[i]->_info.bdaddr); + return 0; +} + +int HCI::PinCodeReply(const u8* data, const u8* pin) { + u8 b[6+1+16]; + memset(b,0,sizeof(b)); + memcpy(b,data,6); + b[6] = 4; + memcpy(b+7, pin, 4); + return SendCmd(HCI_OP_PIN_CODE_REPLY,b,sizeof(b)); +} + +void HCI::InquiryResult(const inquiry_info* info) { + BTDevice* bt = Find(&info->bdaddr); + if (!bt) { // new device + for (int i = 0; i < MAX_BTDEVICES; i++) { + if (_devices[i]._state == 0) { + bt = _devices + i; + bt->_state = 1; + break; + } + } + if (!bt) { + printf("HCI::InquiryResult too many devices\n"); + return; // Too many devices! + } + } + + bt->_info = *info; +} + +int HCI::GetDevices(BTDevice** devices, int maxDevices) { + int j = 0; + for (int i = 0; i < MAX_BTDEVICES; i++) { + if (_devices[i]._state != 0) { + devices[j++] = _devices + i; + if (j == maxDevices) + break; + } + } + return j; +} + +void HCI::RemoteName(const BD_ADDR* addr, const char* name) { + BTDevice* d = Find(addr); + if (d) { + strncpy(d->_name,name,sizeof(d->_name)-1); + d->_name[sizeof(d->_name)-1] = 0; + } +} + +void HCI::ConnectComplete(const connection_info* info) { + BTDevice* d = Find(&info->bdaddr); + if (!d) { + printf("BT Device not known!?! "); + printf(&info->bdaddr); + printf("\n"); + return; + } + if (info->status == 0) { + d->_handle = info->handle; +#ifdef HOST_CONTR_FLOW + d->pkts_sent = 0; +#endif + printf("Connected on %04X\n",info->handle); + } else + printf("Connection failed with %d\n",info->status); +} + +void HCI::Accept_Connection(const BD_ADDR* addr, bool slave) { + unsigned char b[7]; + memcpy(b, addr, 6); + b[6] = slave; + BTDevice* bt = Find(addr); + if (!bt) { + printf("Received connection request from undiscovered device\n"); + for (int i = 0; i < MAX_BTDEVICES; i++) { + if (_devices[i]._state == 0) { + bt = _devices + i; + bt->_state = 1; + memcpy(&(bt->_info.bdaddr), addr, 6);//rest of inquiry info unknown!!! + break; + } + } + if (!bt) { + printf("HCI::InquiryResult too many devices\n"); + return; // Too many devices! + } + } + SendCmd(HCI_OP_ACCEPT_CONN_REQ, b , 7); +} + +void HCI::HCIRecv(const u8* data, int len) {//[0]=event, [1]=parlen, [2...]=pars + //printfBytes(EvtStr(data[0]),data,min(len,16)); + switch (data[0]) { + case HCI_EV_INQUIRY_COMPLETE: + printfBytes("Inquiry Complete",data,data[1]); + _state &= ~MASK_INQUIRY; + Callback(CALLBACK_INQUIRY_DONE,0,0); + break; + + case HCI_EV_INQUIRY_RESULT: { + const u8* end = data[1] + data + 2; + data += 3; + while (data < end) { + inquiry_info align; + memcpy(&align,data,sizeof(inquiry_info)); + InquiryResult(&align); + Callback(CALLBACK_INQUIRY_RESULT,(u8*)&align,sizeof(inquiry_info)); + data += 14; + } + } + break; + + case HCI_EV_CONN_COMPLETE: + _state &= ~MASK_CREATE_CONNECTION; + { + connection_info align; + memcpy(&align,data+2,sizeof(connection_info)); + ConnectComplete(&align); + Callback(CALLBACK_CONNECTION_COMPLETE,(u8*)&align,sizeof(connection_info)); + } + break; + + case HCI_EV_CONN_REQUEST: + printf("Got Connection request \n"); + Callback(CALLBACK_CONNECTION_REQUEST, data+2, data[1]); + Accept_Connection((BD_ADDR*)(data+2)); + break; + + case HCI_EV_DISCONN_COMPLETE: + DisconnectComplete(LE16(data+3)); + break; + + case HCI_EV_REMOTE_NAME: { + BD_ADDR* addr = (BD_ADDR*)(data+3); + const char* name = (const char*)(data + 9); + RemoteName(addr,name); + } + Callback(CALLBACK_REMOTE_NAME,data+3,LE16(data+1)); // addr is in here too + _state &= ~MASK_REMOTE_NAME; + break; + + case HCI_EV_CMD_STATUS: { + const char* errs = HCIErrStr(data[2]); + printf("Status %s %s %d cmd pkts\n",CmdStr(LE16(data+4)),errs, data[3]); +#ifdef COMMAND_FLOW + cmd_credits = data[3]; +#endif + } + Callback(CALLBACK_CMD_STATUS, data+2, 4); + break; + + case HCI_EV_CMD_COMPLETE://[2]=cmd-pkts, [3-4]=cmd, [5...]=pars + if (data[5]) { //[5]=usually status + printf("HCIRecv error status: %s\n", HCIErrStr(data[5])); + } + OnCommandComplete(data[3] | (data[4] << 8), data+6, data[1]-4); +#ifdef COMMAND_FLOW + cmd_credits = data[2]; +#endif + break; + + case HCI_EV_PIN_CODE_REQ: + Callback(CALLBACK_PIN_REQ, data+2, 6); + //PinCodeReply(data+2); + break; + + case HCI_EV_LINK_KEY_REQ: + SendCmd(HCI_OP_LINK_KEY_NEG_REPLY,data+2,6); + break; +#ifdef HOST_CONTR_FLOW + case HCI_EV_NUM_COMP_PKTS: + for (int k = 0; k < data[2]; k++) {//data[2] and 'c' are usually 1 + u16 h = LE16(data+3+2*k); + u16 c = LE16(data+5+2*k); + BTDevice *d = Find(h); + if (!d) + continue;//skip no existing devices + if (d->pkts_sent >= c) { + d->pkts_sent -= c; + _transport->data_credits += c; + } else + d->pkts_sent = 0; + //printf("%d Outstanding pkts for handle %03X (total credits=%d)\n", d->pkts_sent, h, _transport->data_credits); + } + break; +#endif + case HCI_EV_LINK_KEY_NOTIFY: + case HCI_EV_ENCRYPT_CHANGE: + //for(int k=0; k<1000000;k++) USBLoop(); + break; + + default: + printfBytes("HCIRecv:",data,data[1]+2); + break; + } +} + +int HCI::Open(SocketInternal* sock, SocketAddrHdr* addr) { + L2CAPSocket* l2capsock = (L2CAPSocket*)sock; + L2CAPAddr* l2capaddr = (L2CAPAddr*)addr; + BTDevice* bt = Find(&l2capaddr->bdaddr); + if (!bt) { + printf("Can't open l2cap %d on ",l2capaddr->psm); + printf(&l2capaddr->bdaddr); + printf("\n"); + return ERR_HCI_DEVICE_NOT_FOUND; + } + l2capsock->btdevice = bt; + return bt->Open(sock,addr); +} + +int HCI::Accept(SocketInternal* sock, int scid, int rxid) { + L2CAPSocket* l2capsock = (L2CAPSocket*)sock; + BTDevice* bt = (BTDevice*)sock->userData; + if (!bt) { + printf("Can't accept l2cap on socket %d\n", sock->ID); + return ERR_HCI_DEVICE_NOT_FOUND; + } + l2capsock->btdevice = bt; + return bt->Accept(sock, scid, rxid); +} + +int HCI::Send(SocketInternal* sock, const u8* data, int len) {//check here for appropriate buffersize on the device + /* these checks are HCI functions but this 'Send' does not catch all ACL traffic, so it is better done in L2CAP or transport + //assume acl packet + //FIXME: treatment of OFFSET is dubious, OFFSET is not defined?! + #if OFFSET==8 //sizeof ACL/L2CAP is include in data/len + if (len > _acl_mtu) + #else //OFFSET==0, data is bare application frame + if (len+8 > _acl_mtu) + #endif + { printf("Max outgoing packet(%d) size exceeded, segmenting necessary, pktlen = %d\n", _acl_mtu, len); + } + if (data_credits == 0) { + printf("Out of ACL data credits\n"); + return 0; + } + data_credits--; + */ + L2CAPSocket* l2capsock = (L2CAPSocket*)sock; + return l2capsock->btdevice->Send(sock,data,len); // Pointless double dispatch +} + +int HCI::Close(SocketInternal* sock) { + L2CAPSocket* l2capsock = (L2CAPSocket*)sock; + return l2capsock->btdevice->Close(sock); // Pointless double dispatch +} + +void HCI::Compl_pkts(int handle, u8 p) { + u8 b[8] = {(u8)HCI_OP_NUM_COMP_PKTS, HCI_OP_NUM_COMP_PKTS >> 8, 5, 1, 0, 0, 1, 0}; + b[4] = handle; + b[5] = (handle&0x0f00)>>8; + b[6] = p;//only one packet + _transport->HCISend(b, 8);//directly call the transport layer to prevent the command flow control from interfering +} + +void HCI::ACLRecv(const u8* data, int len) { + int handle = LE16(data); + BTDevice* d = Find(handle & 0x0FFF); + int bufs = 1; + if (!d) { + printfBytes("unk. dest. HCI:ACLRecv ", data, len); + } else + bufs = d->ACLRecv(data,len); + //controller to host flow control +#ifdef CONTR_HOST_FLOW +//the ACLRecv function returned so we assume that the buffer is free, and tell this to the controller + if (bufs) { + Compl_pkts(handle, bufs);//this packet is completed + printf("%d ACL buffers completed\n", bufs); + } +#endif +} + +//=================================================================== +//===================================================================
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/myBlueUSB/hci.h Wed Jun 15 19:12:25 2011 +0000 @@ -0,0 +1,288 @@ +/* +Copyright (c) 2010 Peter Barrett + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef HCI_H_INCLUDED +#define HCI_H_INCLUDED + +//#define CONTR_HOST_FLOW //Controller to Host flow control +#define HOST_CONTR_FLOW //Host to Controller flow control +#define COMMAND_FLOW //Command flow control + +#include "mbed.h" +#include "Socket.h" + +#pragma pack(1) + +#define ERR_HCI_DEVICE_NOT_FOUND -300 + +class HCI; +class HCITransport; +class BTDevice; + +enum StateMask { + MASK_RESET = 1, + MASK_READ_BUFFER_SIZE = 2, + MASK_READ_BD_ADDR = 4, + MASK_INITED = 8, + MASK_INQUIRY = 16, + MASK_REMOTE_NAME = 32, + MASK_CREATE_CONNECTION = 64 +}; + +typedef struct +{ + u8 addr[6]; +} BD_ADDR; + +typedef struct +{ + BD_ADDR bdaddr; + u8 pscan_rep_mode; + u8 pscan_period_mode; + u8 pscan_mode; + u8 dev_class[3]; + u16 clock_offset; +} inquiry_info; + +typedef struct +{ + u8 status; + u16 handle; + BD_ADDR bdaddr; + u8 link_type; + u8 encr_mode; +} connection_info; + +// Address struct for creating L2CAP sockets +typedef struct { + SocketAddrHdr hdr; + BD_ADDR bdaddr; + u16 psm; +} L2CAPAddr; + +typedef struct { + u16 handle; + u16 length; // total + u16 l2capLength; // length -4 + u16 cid; // Signaling packet CID = 1 + + // Payload + u8 cmd; // + u8 id; + u16 cmdLength; // total-8 + u16 params[4]; // Params +} L2CAPCmd; + +#pragma pack(4) + +class BTDevice; + +typedef struct +{ + public: + SocketInternal si; + BTDevice* btdevice; + u16 scid; + u16 dcid; +} L2CAPSocket; + +#define MAX_HCL_NAME_LENGTH 20 // TODO - BTDevice wants to be a multiple of 4 + +// BTDevice encapsulates individual device state +// It provides L2CAP layer sockets + +class BTDevice : public SocketHandler +{ + public: + HCITransport* _transport; + inquiry_info _info; + u16 _handle; // acl connection handle + u8 _state; // connection state + u8 _txid; + u16 peer_mtu; +#ifdef HOST_CONTR_FLOW + u8 pkts_sent; //host to controller flow control +#endif +//u8 cntr_cred; +u8 segments; + char _name[MAX_HCL_NAME_LENGTH]; + + void Init(); + + BD_ADDR* GetAddress() { return &_info.bdaddr; } + + // Called from HCI + int ACLRecv(const u8* data, int len); + void ACLFwd(const u8* data, int len); + + // SocketHandler + virtual int Open(SocketInternal* sock, SocketAddrHdr* addr); + virtual int Accept(SocketInternal* sock, int scid, int rxid); + virtual int Send(SocketInternal* sock, const u8* data, int len); + virtual int Close(SocketInternal* sock); + virtual char* Name() { return "BTDevice SocketHandler";} + +private: + int l2cap_sock, plen, contPos, contState; + unsigned char *contBuf; + Timeout rtx; + L2CAPCmd last_req; + void repeat_cmd(); + + L2CAPSocket* SCIDToSocket(int scid); + int Send(const u8* data, int len); + int Send(u8 c, u8 id, u16* params, int count); + int Connect(int scid, int psm); + int Disconnect(int scid, int dcid); + int ConfigureRequest(int dcid); + int CommandReject(u16 reason=0, u16 data0=0, u16 data1=0); + int ConfigureResponse(u8 rxid, int dcid); + int DisconnectResponse(u8 rxid, int scid, int dcid); + void Control(const u8* data, int len); +}; + +enum HCI_CALLBACK_EVENT +{ + CALLBACK_NONE, + CALLBACK_READY, + CALLBACK_INQUIRY_RESULT, + CALLBACK_INQUIRY_DONE, + CALLBACK_REMOTE_NAME, + CALLBACK_CONNECTION_COMPLETE, + CALLBACK_CONNECTION_FAILED, + CALLBACK_PIN_REQ, + CALLBACK_CMD_STATUS, + CALLBACK_CONNECTION_REQUEST +}; + +// L2CAP Protocol/Service Multiplexor (PSM) values + +#define L2CAP_PSM_ANY 0x0000 /* Any/Invalid PSM */ +#define L2CAP_PSM_SDP 0x0001 /* Service Discovery Protocol */ +#define L2CAP_PSM_RFCOMM 0x0003 /* RFCOMM protocol */ +#define L2CAP_PSM_TCP 0x0005 /* Telephony Control Protocol */ +#define L2CAP_PSM_TCS 0x0007 /* TCS cordless */ +#define L2CAP_PSM_BNEP 0x000f /* Bluetooth Network Encapsulation Protocol*/ +#define L2CAP_PSM_HID_CNTL 0x0011 /* HID Control */ +#define L2CAP_PSM_HID_INTR 0x0013 /* HID Interrupt */ +#define L2CAP_PSM_ESDP 0x0015 /* Extended Service Discovery Profile */ +#define L2CAP_PSM_AVCTP 0x0017 /* Audio/Visual Control Transport Protocol */ +#define L2CAP_PSM_AVDTP 0x0019 /* Audio/Visual Distribution */ + +// Callback from inquiry +typedef int (*HCICallback)(HCI* hci, HCI_CALLBACK_EVENT evt, const u8* data, int len); +//typedef int (HCI::*HCICallback)(HCI_CALLBACK_EVENT evt, const u8* data, int len); + +#define MAX_BTDEVICES 8 + +class HCITransport; +class HCI : public SocketHandler +{ + HCITransport* _transport; + HCICallback _callback; + BD_ADDR _localAddr; + + BTDevice _devices[MAX_BTDEVICES]; + int _deviceCount; + + int _acl_mtu; + int _acl_max_pkt; + int _sco_mtu; + int _sco_max_pkt; + + int _state; +#ifdef COMMAND_FLOW + char cmd_credits;//command flow control +#endif +//, data_credits;//host to controller flow control is per handle, hence is handled in BTDevice + public: + + // Open a local adapter + int Open(HCITransport* transport, HCICallback callback=0); + + // Return list of discovered addreses + int GetDevices(BTDevice** devices, int maxDevices); + + // Lookup a device by address or handle + BTDevice* Find(const BD_ADDR* addr); + BTDevice* Find(int handle); + + // Disconnect from a remote device + int Disconnect(const BD_ADDR* addr); + int DisconnectAll(); + + // see what devies are in the system + int Inquiry(int duration = 10); + + int SetEventFilter(u8 filterType, u8 filterConditionType, u8* condition); + // get a name, delivered in callback + int RemoteNameRequest(const BD_ADDR* addr); + int RemoteNameRequest(inquiry_info* ii); + + // Connect to a remote device + int CreateConnection(const BD_ADDR* remoteAddr); + + bool Busy(); + int State() { return _state;} + + // called from transport + void HCIRecv(const u8* data, int len); + + // called from transport + void ACLRecv(const u8* data, int len); + + // SocketHandler methods for maintaining L2CAP sockets + virtual int Open(SocketInternal* sock, SocketAddrHdr* addr); + virtual int Accept(SocketInternal* sock, int scid, int rxid); + virtual int Send(SocketInternal* sock, const u8* data, int len); + virtual int Close(SocketInternal* sock); + virtual char* Name() { return "HCI SocketHandler";} + +private: + void InquiryResult(const inquiry_info* info); + void RemoteName(const BD_ADDR* addr, const char* name); + void ConnectComplete(const connection_info* info); + void DisconnectComplete(int handle); + int SendCmd(int cmd, const u8* params = 0, int len = 0); + void OnCommandComplete(int cmd, const u8* data, int len); + virtual void Callback(HCI_CALLBACK_EVENT c, const u8* data, int len); + void Compl_pkts(int handle, u8 p = 1); +protected: + int PinCodeReply(const u8* data, const u8* pin = "0000"); + void Accept_Connection(const BD_ADDR* addr, bool slave=true); +}; + +class HCITransport +{ +protected: + HCI* _target; +public: +#ifdef HOST_CONTR_FLOW + u8 data_credits; +#endif + u16 _acl_mtu; + void Set(HCI* target) { _target = target; }; + virtual void HCISend(const u8* data, int len) = 0; + virtual int ACLSend(const u8* data, int len) = 0; +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/myBlueUSB/hci_private.h Wed Jun 15 19:12:25 2011 +0000 @@ -0,0 +1,325 @@ +/* +Copyright (c) 2010 Peter Barrett + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef HCI_PRIVATE_H_INCLUDED +#define HCI_PRIVATE_H_INCLUDED + +#define HCI_OP_INQUIRY 0x0401 +#define HCI_OP_INQUIRY_CANCEL 0x0402 +#define HCI_OP_EXIT_PERIODIC_INQ 0x0404 +#define HCI_OP_CREATE_CONN 0x0405 +#define HCI_OP_DISCONNECT 0x0406 +#define HCI_OP_ADD_SCO 0x0407 +#define HCI_OP_CREATE_CONN_CANCEL 0x0408 +#define HCI_OP_ACCEPT_CONN_REQ 0x0409 +#define HCI_OP_REJECT_CONN_REQ 0x040a +#define HCI_OP_LINK_KEY_REPLY 0x040b +#define HCI_OP_LINK_KEY_NEG_REPLY 0x040c +#define HCI_OP_PIN_CODE_REPLY 0x040d +#define HCI_OP_PIN_CODE_NEG_REPLY 0x040e +#define HCI_OP_CHANGE_CONN_PTYPE 0x040f +#define HCI_OP_AUTH_REQUESTED 0x0411 +#define HCI_OP_SET_CONN_ENCRYPT 0x0413 +#define HCI_OP_CHANGE_CONN_LINK_KEY 0x0415 +#define HCI_OP_REMOTE_NAME_REQ 0x0419 +#define HCI_OP_REMOTE_NAME_REQ_CANCEL 0x041a +#define HCI_OP_READ_REMOTE_FEATURES 0x041b +#define HCI_OP_READ_REMOTE_EXT_FEATURES 0x041c +#define HCI_OP_READ_REMOTE_VERSION 0x041d +#define HCI_OP_SETUP_SYNC_CONN 0x0428 +#define HCI_OP_ACCEPT_SYNC_CONN_REQ 0x0429 +#define HCI_OP_REJECT_SYNC_CONN_REQ 0x042a + +#define HCI_OP_SNIFF_MODE 0x0803 +#define HCI_OP_EXIT_SNIFF_MODE 0x0804 +#define HCI_OP_ROLE_DISCOVERY 0x0809 +#define HCI_OP_SWITCH_ROLE 0x080b +#define HCI_OP_READ_LINK_POLICY 0x080c +#define HCI_OP_WRITE_LINK_POLICY 0x080d +#define HCI_OP_READ_DEF_LINK_POLICY 0x080e +#define HCI_OP_WRITE_DEF_LINK_POLICY 0x080f +#define HCI_OP_SNIFF_SUBRATE 0x0811 + + +#define HCI_OP_SET_EVENT_MASK 0x0c01 +#define HCI_OP_RESET 0x0c03 +#define HCI_OP_SET_EVENT_FLT 0x0c05 +#define HCI_OP_WRITE_LOCAL_NAME 0x0c13 +#define HCI_OP_READ_LOCAL_NAME 0x0c14 +#define HCI_OP_WRITE_CA_TIMEOUT 0x0c16 +#define HCI_OP_WRITE_PG_TIMEOUT 0x0c18 +#define HCI_OP_WRITE_SCAN_ENABLE 0x0c1a +#define HCI_OP_READ_AUTH_ENABLE 0x0c1f +#define HCI_OP_WRITE_AUTH_ENABLE 0x0c20 +#define HCI_OP_READ_ENCRYPT_MODE 0x0c21 +#define HCI_OP_WRITE_ENCRYPT_MODE 0x0c22 + #define ENCRYPT_DISABLED 0x00 + #define ENCRYPT_P2P 0x01 + #define ENCRYPT_BOTH 0x02 +#define HCI_OP_READ_CLASS_OF_DEV 0x0c23 +#define HCI_OP_WRITE_CLASS_OF_DEV 0x0c24 +#define HCI_OP_READ_VOICE_SETTING 0x0c25 +#define HCI_OP_WRITE_VOICE_SETTING 0x0c26 +#define HCI_OP_CONTR_TO_HOST_FLOW 0x0c31 +#define HCI_OP_HOST_BUFFER_SIZE 0x0c33 +#define HCI_OP_NUM_COMP_PKTS 0x0c35 +#define HCI_OP_READ_SSP_MODE 0x0c55 +#define HCI_OP_WRITE_SSP_MODE 0x0c56 + +#define HCI_OP_READ_LOCAL_VERSION 0x1001 +#define HCI_OP_READ_LOCAL_COMMANDS 0x1002 +#define HCI_OP_READ_LOCAL_FEATURES 0x1003 +#define HCI_OP_READ_LOCAL_EXT_FEATURES 0x1004 +#define HCI_OP_READ_BUFFER_SIZE 0x1005 +#define HCI_OP_READ_BD_ADDR 0x1009 + +// events +#define HCI_EV_INQUIRY_COMPLETE 0x01 +#define HCI_EV_INQUIRY_RESULT 0x02 +#define HCI_EV_CONN_COMPLETE 0x03 +#define HCI_EV_CONN_REQUEST 0x04 +#define HCI_EV_DISCONN_COMPLETE 0x05 +#define HCI_EV_AUTH_COMPLETE 0x06 +#define HCI_EV_REMOTE_NAME 0x07 +#define HCI_EV_ENCRYPT_CHANGE 0x08 +#define HCI_EV_CHANGE_LINK_KEY_COMPLETE 0x09 +#define HCI_EV_REMOTE_FEATURES 0x0b +#define HCI_EV_REMOTE_VERSION 0x0c +#define HCI_EV_QOS_SETUP_COMPLETE 0x0d +#define HCI_EV_CMD_COMPLETE 0x0e +#define HCI_EV_CMD_STATUS 0x0f +#define HCI_EV_ROLE_CHANGE 0x12 +#define HCI_EV_NUM_COMP_PKTS 0x13 +#define HCI_EV_MODE_CHANGE 0x14 +#define HCI_EV_PIN_CODE_REQ 0x16 +#define HCI_EV_LINK_KEY_REQ 0x17 +#define HCI_EV_LINK_KEY_NOTIFY 0x18 +#define HCI_EV_CLOCK_OFFSET 0x1c +#define HCI_EV_PKT_TYPE_CHANGE 0x1d +#define HCI_EV_PSCAN_REP_MODE 0x20 +#define HCI_EV_INQUIRY_RESULT_WITH_RSSI 0x22 +#define HCI_EV_REMOTE_EXT_FEATURES 0x23 +#define HCI_EV_SYNC_CONN_COMPLETE 0x2c +#define HCI_EV_SYNC_CONN_CHANGED 0x2d +#define HCI_EV_SNIFF_SUBRATE 0x2e +#define HCI_EV_EXTENDED_INQUIRY_RESULT 0x2f +#define HCI_EV_IO_CAPA_REQUEST 0x31 +#define HCI_EV_SIMPLE_PAIR_COMPLETE 0x36 +#define HCI_EV_REMOTE_HOST_FEATURES 0x3d + +/* Possible error codes */ +#define HCI_UNKNOWN_HCI_COMMAND 0x01 +#define HCI_NO_CONNECTION 0x02 +#define HCI_HW_FAILURE 0x03 +#define HCI_PAGE_TIMEOUT 0x04 +#define HCI_AUTHENTICATION_FAILURE 0x05 +#define HCI_KEY_MISSING 0x06 +#define HCI_MEMORY_FULL 0x07 +#define HCI_CONN_TIMEOUT 0x08 +#define HCI_MAX_NUMBER_OF_CONNECTIONS 0x09 +#define HCI_MAX_NUMBER_OF_SCO_CONNECTIONS_TO_DEVICE 0x0A +#define HCI_ACL_CONNECTION_EXISTS 0x0B +#define HCI_COMMAND_DISSALLOWED 0x0C +#define HCI_HOST_REJECTED_DUE_TO_LIMITED_RESOURCES 0x0D +#define HCI_HOST_REJECTED_DUE_TO_SECURITY_REASONS 0x0E +#define HCI_HOST_REJECTED_DUE_TO_REMOTE_DEVICE_ONLY_PERSONAL_SERVICE 0x0F +#define HCI_HOST_TIMEOUT 0x10 +#define HCI_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE 0x11 +#define HCI_INVALID_HCI_COMMAND_PARAMETERS 0x12 +#define HCI_OTHER_END_TERMINATED_CONN_USER_ENDED 0x13 +#define HCI_OTHER_END_TERMINATED_CONN_LOW_RESOURCES 0x14 +#define HCI_OTHER_END_TERMINATED_CONN_ABOUT_TO_POWER_OFF 0x15 +#define HCI_CONN_TERMINATED_BY_LOCAL_HOST 0x16 +#define HCI_REPETED_ATTEMPTS 0x17 +#define HCI_PAIRING_NOT_ALLOWED 0x18 +#define HCI_UNKNOWN_LMP_PDU 0x19 +#define HCI_UNSUPPORTED_REMOTE_FEATURE 0x1A +#define HCI_SCO_OFFSET_REJECTED 0x1B +#define HCI_SCO_INTERVAL_REJECTED 0x1C +#define HCI_SCO_AIR_MODE_REJECTED 0x1D +#define HCI_INVALID_LMP_PARAMETERS 0x1E +#define HCI_UNSPECIFIED_ERROR 0x1F +#define HCI_UNSUPPORTED_LMP_PARAMETER_VALUE 0x20 +#define HCI_ROLE_CHANGE_NOT_ALLOWED 0x21 +#define HCI_LMP_RESPONSE_TIMEOUT 0x22 +#define HCI_LMP_ERROR_TRANSACTION_COLLISION 0x23 +#define HCI_LMP_PDU_NOT_ALLOWED 0x24 +#define HCI_ENCRYPTION_MODE_NOT_ACCEPTABLE 0x25 +#define HCI_UNIT_KEY_USED 0x26 +#define HCI_QOS_NOT_SUPPORTED 0x27 +#define HCI_INSTANT_PASSED 0x28 +#define HCI_PAIRING_UNIT_KEY_NOT_SUPPORTED 0x29 + +const char* EvtStr(int evt) +{ + switch (evt) + { + case HCI_EV_INQUIRY_COMPLETE: return "HCI_EV_INQUIRY_COMPLETE"; + case HCI_EV_INQUIRY_RESULT: return "HCI_EV_INQUIRY_RESULT"; + case HCI_EV_CONN_COMPLETE: return "HCI_EV_CONN_COMPLETE"; + case HCI_EV_CONN_REQUEST: return "HCI_EV_CONN_REQUEST"; + case HCI_EV_DISCONN_COMPLETE: return "HCI_EV_DISCONN_COMPLETE"; + case HCI_EV_AUTH_COMPLETE: return "HCI_EV_AUTH_COMPLETE"; + case HCI_EV_REMOTE_NAME: return "HCI_EV_REMOTE_NAME"; + case HCI_EV_ENCRYPT_CHANGE: return "HCI_EV_ENCRYPT_CHANGE"; + case HCI_EV_CHANGE_LINK_KEY_COMPLETE : return "HCI_EV_CHANGE_LINK_KEY_COMPLETE"; + case HCI_EV_REMOTE_FEATURES: return "HCI_EV_REMOTE_FEATURES"; + case HCI_EV_REMOTE_VERSION: return "HCI_EV_REMOTE_VERSION"; + case HCI_EV_QOS_SETUP_COMPLETE : return "HCI_EV_QOS_SETUP_COMPLETE"; + case HCI_EV_CMD_COMPLETE: return "HCI_EV_CMD_COMPLETE"; + case HCI_EV_CMD_STATUS: return "HCI_EV_CMD_STATUS"; + case HCI_EV_ROLE_CHANGE: return "HCI_EV_ROLE_CHANGE"; + case HCI_EV_NUM_COMP_PKTS: return "HCI_EV_NUM_COMP_PKTS"; + case HCI_EV_MODE_CHANGE: return "HCI_EV_MODE_CHANGE"; + case HCI_EV_PIN_CODE_REQ: return "HCI_EV_PIN_CODE_REQ"; + case HCI_EV_LINK_KEY_REQ: return "HCI_EV_LINK_KEY_REQ"; + case HCI_EV_LINK_KEY_NOTIFY: return "HCI_EV_LINK_KEY_NOTIFY"; + case HCI_EV_CLOCK_OFFSET: return "HCI_EV_CLOCK_OFFSET"; + case HCI_EV_PKT_TYPE_CHANGE: return "HCI_EV_PKT_TYPE_CHANGE"; + case HCI_EV_PSCAN_REP_MODE: return "HCI_EV_PSCAN_REP_MODE"; + case HCI_EV_INQUIRY_RESULT_WITH_RSSI : return "HCI_EV_INQUIRY_RESULT_WITH_RSSI"; + case HCI_EV_REMOTE_EXT_FEATURES: return "HCI_EV_REMOTE_EXT_FEATURES"; + case HCI_EV_SYNC_CONN_COMPLETE: return "HCI_EV_SYNC_CONN_COMPLETE"; + case HCI_EV_SYNC_CONN_CHANGED: return "HCI_EV_SYNC_CONN_CHANGED"; + case HCI_EV_SNIFF_SUBRATE: return "HCI_EV_SNIFF_SUBRATE"; + case HCI_EV_EXTENDED_INQUIRY_RESULT: return "HCI_EV_EXTENDED_INQUIRY_RESULT"; + case HCI_EV_IO_CAPA_REQUEST: return "HCI_EV_IO_CAPA_REQUEST"; + case HCI_EV_SIMPLE_PAIR_COMPLETE: return "HCI_EV_SIMPLE_PAIR_COMPLETE"; + case HCI_EV_REMOTE_HOST_FEATURES: return "HCI_EV_REMOTE_HOST_FEATURES"; + } + return "Unknown Event"; +} + +const char* CmdStr(int cmd) +{ + switch (cmd) + { + // 0x04XX + case HCI_OP_INQUIRY: return "HCI_OP_INQUIRY"; + case HCI_OP_INQUIRY_CANCEL: return "HCI_OP_INQUIRY_CANCEL"; + case HCI_OP_EXIT_PERIODIC_INQ: return "HCI_OP_EXIT_PERIODIC_INQ"; + case HCI_OP_CREATE_CONN: return "HCI_OP_CREATE_CONN"; + case HCI_OP_DISCONNECT: return "HCI_OP_DISCONNECT"; + case HCI_OP_ADD_SCO: return "HCI_OP_ADD_SCO"; + case HCI_OP_CREATE_CONN_CANCEL: return "HCI_OP_CREATE_CONN_CANCEL"; + case HCI_OP_ACCEPT_CONN_REQ: return "HCI_OP_ACCEPT_CONN_REQ"; + case HCI_OP_REJECT_CONN_REQ: return "HCI_OP_REJECT_CONN_REQ"; + case HCI_OP_LINK_KEY_REPLY: return "HCI_OP_LINK_KEY_REPLY"; + case HCI_OP_LINK_KEY_NEG_REPLY: return "HCI_OP_LINK_KEY_NEG_REPLY"; + case HCI_OP_PIN_CODE_REPLY: return "HCI_OP_PIN_CODE_REPLY"; + case HCI_OP_PIN_CODE_NEG_REPLY: return "HCI_OP_PIN_CODE_NEG_REPLY"; + case HCI_OP_CHANGE_CONN_PTYPE: return "HCI_OP_CHANGE_CONN_PTYPE"; + case HCI_OP_AUTH_REQUESTED: return "HCI_OP_AUTH_REQUESTED"; + case HCI_OP_SET_CONN_ENCRYPT: return "HCI_OP_SET_CONN_ENCRYPT"; + case HCI_OP_CHANGE_CONN_LINK_KEY: return "HCI_OP_CHANGE_CONN_LINK_KEY"; + case HCI_OP_REMOTE_NAME_REQ: return "HCI_OP_REMOTE_NAME_REQ"; + case HCI_OP_REMOTE_NAME_REQ_CANCEL: return "HCI_OP_REMOTE_NAME_REQ_CANCEL"; + case HCI_OP_READ_REMOTE_FEATURES: return "HCI_OP_READ_REMOTE_FEATURES"; + case HCI_OP_READ_REMOTE_EXT_FEATURES: return "HCI_OP_READ_REMOTE_EXT_FEATURES"; + case HCI_OP_READ_REMOTE_VERSION: return "HCI_OP_READ_REMOTE_VERSION"; + case HCI_OP_SETUP_SYNC_CONN: return "HCI_OP_SETUP_SYNC_CONN"; + case HCI_OP_ACCEPT_SYNC_CONN_REQ: return "HCI_OP_ACCEPT_SYNC_CONN_REQ"; + case HCI_OP_REJECT_SYNC_CONN_REQ: return "HCI_OP_REJECT_SYNC_CONN_REQ"; + // 0x0CXX + case HCI_OP_SET_EVENT_MASK: return "HCI_OP_SET_EVENT_MASK"; + case HCI_OP_RESET: return "HCI_OP_RESET"; + case HCI_OP_SET_EVENT_FLT: return "HCI_OP_SET_EVENT_FLT"; + case HCI_OP_WRITE_LOCAL_NAME: return "HCI_OP_WRITE_LOCAL_NAME"; + case HCI_OP_READ_LOCAL_NAME: return "HCI_OP_READ_LOCAL_NAME"; + case HCI_OP_WRITE_CA_TIMEOUT: return "HCI_OP_WRITE_CA_TIMEOUT"; + case HCI_OP_WRITE_PG_TIMEOUT: return "HCI_OP_WRITE_PG_TIMEOUT"; + case HCI_OP_WRITE_SCAN_ENABLE: return "HCI_OP_WRITE_SCAN_ENABLE"; + case HCI_OP_READ_AUTH_ENABLE: return "HCI_OP_READ_AUTH_ENABLE"; + case HCI_OP_WRITE_AUTH_ENABLE: return "HCI_OP_WRITE_AUTH_ENABLE"; + case HCI_OP_READ_ENCRYPT_MODE: return "HCI_OP_READ_ENCRYPT_MODE"; + case HCI_OP_WRITE_ENCRYPT_MODE: return "HCI_OP_WRITE_ENCRYPT_MODE"; + case HCI_OP_READ_CLASS_OF_DEV: return "HCI_OP_READ_CLASS_OF_DEV"; + case HCI_OP_WRITE_CLASS_OF_DEV: return "HCI_OP_WRITE_CLASS_OF_DEV"; + case HCI_OP_READ_VOICE_SETTING: return "HCI_OP_READ_VOICE_SETTING"; + case HCI_OP_WRITE_VOICE_SETTING: return "HCI_OP_WRITE_VOICE_SETTING"; + case HCI_OP_HOST_BUFFER_SIZE: return "HCI_OP_HOST_BUFFER_SIZE"; + case HCI_OP_READ_SSP_MODE: return "HCI_OP_READ_SSP_MODE"; + case HCI_OP_WRITE_SSP_MODE: return "HCI_OP_WRITE_SSP_MODE"; + + // 10xx + case HCI_OP_READ_LOCAL_VERSION: return "HCI_OP_READ_LOCAL_VERSION"; + case HCI_OP_READ_LOCAL_COMMANDS: return "HCI_OP_READ_LOCAL_COMMANDS"; + case HCI_OP_READ_LOCAL_FEATURES: return "HCI_OP_READ_LOCAL_FEATURES"; + case HCI_OP_READ_LOCAL_EXT_FEATURES: return "HCI_OP_READ_LOCAL_EXT_FEATURES"; + case HCI_OP_READ_BUFFER_SIZE: return "HCI_OP_READ_BUFFER_SIZE"; + case HCI_OP_READ_BD_ADDR: return "HCI_OP_READ_BD_ADDR"; + } + return "Unknown Cmd"; +} + +const char* HCIErrStr(int err) +{ + switch (err) + { + case 0: return "OK"; + case HCI_UNKNOWN_HCI_COMMAND: return "HCI_UNKNOWN_HCI_COMMAND"; + case HCI_NO_CONNECTION: return "HCI_NO_CONNECTION"; + case HCI_HW_FAILURE: return "HCI_HW_FAILURE"; + case HCI_PAGE_TIMEOUT: return "HCI_PAGE_TIMEOUT"; + case HCI_AUTHENTICATION_FAILURE: return "HCI_AUTHENTICATION_FAILURE"; + case HCI_KEY_MISSING: return "HCI_KEY_MISSING"; + case HCI_MEMORY_FULL: return "HCI_MEMORY_FULL"; + case HCI_CONN_TIMEOUT: return "HCI_CONN_TIMEOUT"; + case HCI_MAX_NUMBER_OF_CONNECTIONS: return "HCI_CONN_TIMEOUT"; + case HCI_MAX_NUMBER_OF_SCO_CONNECTIONS_TO_DEVICE: return "HCI_MAX_NUMBER_OF_SCO_CONNECTIONS_TO_DEVICE"; + case HCI_ACL_CONNECTION_EXISTS: return "HCI_ACL_CONNECTION_EXISTS"; + case HCI_COMMAND_DISSALLOWED: return "HCI_COMMAND_DISSALLOWED"; + case HCI_HOST_REJECTED_DUE_TO_LIMITED_RESOURCES: return "HCI_HOST_REJECTED_DUE_TO_LIMITED_RESOURCES"; + case HCI_HOST_REJECTED_DUE_TO_SECURITY_REASONS: return "HCI_HOST_REJECTED_DUE_TO_SECURITY_REASONS"; + case HCI_HOST_REJECTED_DUE_TO_REMOTE_DEVICE_ONLY_PERSONAL_SERVICE: return "HCI_HOST_REJECTED_DUE_TO_REMOTE_DEVICE_ONLY_PERSONAL_SERVICE"; + case HCI_HOST_TIMEOUT: return "HCI_HOST_TIMEOUT"; + case HCI_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE: return "HCI_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE"; + case HCI_INVALID_HCI_COMMAND_PARAMETERS: return "HCI_INVALID_HCI_COMMAND_PARAMETERS"; + case HCI_OTHER_END_TERMINATED_CONN_USER_ENDED: return "HCI_OTHER_END_TERMINATED_CONN_USER_ENDED"; + case HCI_OTHER_END_TERMINATED_CONN_LOW_RESOURCES: return "HCI_OTHER_END_TERMINATED_CONN_LOW_RESOURCES"; + case HCI_OTHER_END_TERMINATED_CONN_ABOUT_TO_POWER_OFF: return "HCI_OTHER_END_TERMINATED_CONN_ABOUT_TO_POWER_OFF"; + case HCI_CONN_TERMINATED_BY_LOCAL_HOST: return "HCI_CONN_TERMINATED_BY_LOCAL_HOST"; + case HCI_REPETED_ATTEMPTS: return "HCI_REPEATED_ATTEMPTS"; + case HCI_PAIRING_NOT_ALLOWED: return "HCI_PAIRING_NOT_ALLOWED"; + case HCI_UNKNOWN_LMP_PDU: return "HCI_UNKNOWN_LMP_PDU"; + case HCI_UNSUPPORTED_REMOTE_FEATURE: return "HCI_UNSUPPORTED_REMOTE_FEATURE"; + case HCI_SCO_OFFSET_REJECTED: return "HCI_SCO_OFFSET_REJECTED"; + case HCI_SCO_INTERVAL_REJECTED: return "HCI_SCO_INTERVAL_REJECTED"; + case HCI_SCO_AIR_MODE_REJECTED: return "HCI_SCO_AIR_MODE_REJECTED"; + case HCI_INVALID_LMP_PARAMETERS: return "HCI_INVALID_LMP_PARAMETERS"; + case HCI_UNSPECIFIED_ERROR: return "HCI_UNSPECIFIED_ERROR"; + case HCI_UNSUPPORTED_LMP_PARAMETER_VALUE: return "HCI_UNSUPPORTED_LMP_PARAMETER_VALUE"; + case HCI_ROLE_CHANGE_NOT_ALLOWED: return "HCI_ROLE_CHANGE_NOT_ALLOWED"; + case HCI_LMP_RESPONSE_TIMEOUT: return "HCI_LMP_RESPONSE_TIMEOUT"; + case HCI_LMP_ERROR_TRANSACTION_COLLISION: return "HCI_LMP_ERROR_TRANSACTION_COLLISION"; + case HCI_LMP_PDU_NOT_ALLOWED: return "HCI_LMP_PDU_NOT_ALLOWED"; + case HCI_ENCRYPTION_MODE_NOT_ACCEPTABLE: return "HCI_ENCRYPTION_MODE_NOT_ACCEPTABLE"; + case HCI_UNIT_KEY_USED: return "HCI_UNIT_KEY_USED"; + case HCI_QOS_NOT_SUPPORTED: return "HCI_QOS_NOT_SUPPORTED"; + case HCI_INSTANT_PASSED: return "HCI_INSTANT_PASSED"; + case HCI_PAIRING_UNIT_KEY_NOT_SUPPORTED: return "HCI_PAIRING_UNIT_KEY_NOT_SUPPORTED"; + }; + return "Unknow HCI err"; +}; + + +#endif // HCI_PRIVATE_H_INCLUDED
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/myBlueUSB/rfcomm/RFCOMM.cpp Wed Jun 15 19:12:25 2011 +0000 @@ -0,0 +1,660 @@ +#include "mbed.h" +#include "Utils.h" +#include "RFCOMM.h" + +// Control field values bit no. 1 2 3 4 5 6 7 8 +#define BT_RFCOMM_SABM 0x3F // 1 1 1 1 P/F 1 0 0 +#define BT_RFCOMM_UA 0x73 // 1 1 0 0 P/F 1 1 0 +#define BT_RFCOMM_DM 0x0F // 1 1 1 1 P/F 0 0 0 +#define BT_RFCOMM_DM_PF 0x1F +#define BT_RFCOMM_DISC 0x53 // 1 1 0 0 P/F 0 1 0 +#define BT_RFCOMM_UIH 0xEF // 1 1 1 1 P/F 1 1 1 +#define BT_RFCOMM_UIH_PF 0xFF + +// Multiplexer message types +#define BT_RFCOMM_PN_CMD 0x83 +#define BT_RFCOMM_PN_RSP 0x81 +#define BT_RFCOMM_TEST_CMD 0x23 +#define BT_RFCOMM_TEST_RSP 0x21 +#define BT_RFCOMM_FCON_CMD 0xA3 +#define BT_RFCOMM_FCON_RSP 0xA1 +#define BT_RFCOMM_FCOFF_CMD 0x63 +#define BT_RFCOMM_FCOFF_RSP 0x61 +#define BT_RFCOMM_MSC_CMD 0xE3 +#define BT_RFCOMM_MSC_RSP 0xE1 +#define BT_RFCOMM_RPN_CMD 0x93 +#define BT_RFCOMM_RPN_RSP 0x91 +#define BT_RFCOMM_RLS_CMD 0x53 +#define BT_RFCOMM_RLS_RSP 0x51 +#define BT_RFCOMM_NSC_RSP 0x11 + +// FCS calc +#define BT_RFCOMM_CODE_WORD 0xE0 // pol = x8+x2+x1+1 +#define BT_RFCOMM_CRC_CHECK_LEN 3 +#define BT_RFCOMM_UIHCRC_CHECK_LEN 2 + +#define NR_CREDITS 1 +#define INITIAL_CREDITS 1 //0...7 +#define MAX_FRAME_SIZE 350 //ACL buffer - some headroom + +#define DEBUG 0 + +// Instance +RFCOMMManager rfcomm_manager; + +//uint8_t rfcomm_out_buffer[1000];//seems a bit big as default max framesize is 127 +unsigned rfcomm::maxframesize = MAX_FRAME_SIZE; //only initial value + +//these functions are obtained from rfcomm.c on google code +void _bt_rfcomm_send_sabm(unsigned short source_cid, unsigned char initiator, unsigned char channel); +void _bt_rfcomm_send_uih_pn_command(unsigned short source_cid, unsigned char initiator, unsigned char channel, unsigned short max_frame_size); +void _bt_rfcomm_send_uih_msc_cmd(unsigned short source_cid, unsigned char initiator, unsigned char channel, unsigned char signals); +void _bt_rfcomm_send_uih_rpn_cmd(uint16_t source_cid, uint8_t initiator, uint8_t dlci, port_settings *val); +int rfcomm_send_packet(unsigned short source_cid, unsigned char address, unsigned char control, unsigned char credits, const unsigned char *data, unsigned short len); +uint8_t crc8_calc(uint8_t *data, uint16_t len); + + +//find a free socket slot for channel ch +int rfcomm::find_slot(unsigned ch) { + for (int i = 0; i < MAX_RFCOMM_SCKTS; i++) { + if (sckts[i] != 0) { //socket is in use + RFCOMMSocket *s = (RFCOMMSocket*)GetSocketInternal(sckts[i]); + if (s==0) { + printf("find_slot: socket %d not found\n", sckts[i]); + continue; + } + if (s->dlci >> 1 == ch) { + printf("Channel %d is already in use on socket %d\n", ch, sckts[i]); + return -1; + } + } else //slot is free + return i; + } + return -2; //no free slots +} + +//find the rfcomm socket for dlci +RFCOMMSocket* rfcomm::find_socket(unsigned dlci) { + for (int i = 0; i < MAX_RFCOMM_SCKTS; i++) { + if (sckts[i] != 0) { //socket is in use + RFCOMMSocket *s = (RFCOMMSocket*)GetSocketInternal(sckts[i]); + if (s==0) { + printf("find_socket: socket %d not found\n", sckts[i]); + continue; + } + if (s->dlci == dlci) { + return s; + } + } + } + printf("RFCOMMSocket for dlci %d was not found!\n", dlci); + return 0; //socket not found +} + +//send a PN command to all sockets waiting to be opened +void rfcomm::initChannels(int socket) { + for (int i = 0; i < MAX_RFCOMM_SCKTS; i++) { + if (sckts[i] != 0) { //socket is in use + RFCOMMSocket *s = (RFCOMMSocket*)GetSocketInternal(sckts[i]); + if (s==0) { + printf("initChannels: socket %d not found\n", sckts[i]); + continue; + } + if (s->State == SocketState_Opening) { + printf("Sending PN for DLCI %d on socket %d\n", s->dlci, sckts[i]); + _bt_rfcomm_send_uih_pn_command(socket, 1, s->dlci, maxframesize); + s->State = SocketState_L2CAP_Config_wait; + } + } + } +} + +unsigned rfcomm::release_channel(unsigned dlci) { + int n = 0; + for (int i = 0; i < MAX_RFCOMM_SCKTS; i++) { + if (sckts[i] != 0) { //socket is in use + RFCOMMSocket *s = (RFCOMMSocket*)GetSocketInternal(sckts[i]); + if (s==0) { + printf("Release: socket for dlci %d not found\n", dlci); + continue; + } + if (s->dlci == dlci) + sckts[i] = 0; + else + n++; + } + } + return n; +} + +int rfcomm::Send(SocketInternal *sock, const u8* data, int len) {//also see if credits need to be send + RFCOMMSocket *s = (RFCOMMSocket*)sock; + char credits = 0; + char control = BT_RFCOMM_UIH; + if (len + 14 > maxframesize) //hci/l2cap header =8, rfcomm header ~ 6 + printf("Error! packetsize = %d, maxframesize = %d\n", len, maxframesize); + if (s->peer_credits == 0) {//peer is low on credits + credits = NR_CREDITS; + control = BT_RFCOMM_UIH_PF; + s->peer_credits += NR_CREDITS;//so provide some more + } + unsigned char address = (1 << 0) | (initiator << 1) | (s->dlci << 2); + if (s->my_credits) { + s->my_credits--; + return rfcomm_send_packet(_l2cap, address, control, credits, data, len); + } else + return rfcomm_send_packet(_l2cap, address, control, credits, data, 0);//send an empty packet when credits run out +} + +int rfcomm::Close(SocketInternal* sock) { + RFCOMMSocket *s = (RFCOMMSocket*)sock; + int id = s->dlci; + printf("Closing rfcomm dlci %d state=%d\n", id, s->State); + Disconnect(s); + int n = release_channel(id); + printf("%d channels are still open\n", n); + if (n == 0) {//all rfcomm channels are closed + printf("....L2CAP must be closed as well\n"); + rfcomm_send_packet(_l2cap, (1 << 0) | (initiator << 1) /*| (!initiator << 2)*/, BT_RFCOMM_DISC, 0, 0, 0); //close dlci0 + Socket_Close(_l2cap); + _l2cap = 0; //return rfcomm to the pool + } + return 0; +} + +int rfcomm::Disconnect(RFCOMMSocket *s) { + unsigned char address = (1 << 0) | (initiator << 1) | (s->dlci << 2); + return rfcomm_send_packet(_l2cap, address, BT_RFCOMM_DISC, 0, 0, 0); +} + +//expect this to be called with socket type=SOCKET_RFCOM and addr->psm = channel and addr->bdaddr is the BT addr +//of the device to connect to. +//eg. Socket_Open(SOCKET_RFCOM, rfcommaddr(bdaddr, chan), receiver_func, appl_obj); +int rfcomm::Open(SocketInternal* sock, SocketAddrHdr* addr) { + int ch = ((L2CAPAddr*)addr)->psm;//abused psm for channel ID + RFCOMMSocket *s = (RFCOMMSocket*)sock; + int slot = find_slot(ch); + if (slot < 0) return 0; + sckts[slot] = s->ID; + s->serdevice = this; + s->State = SocketState_Opening; + + if (_l2cap == 0) { //no rfcomm -> l2cap connection yet + printf("Need to open L2CAP channel first before opening RFCOMM channel %d\n", s->dlci); + ((L2CAPAddr*)addr)->psm = L2CAP_PSM_RFCOMM;//open the l2cap channel and the rfcomm_ch channel + initiator = 1; + s->dlci = (ch<<1)|!initiator; + _l2cap = Socket_Open(SOCKET_L2CAP, addr, OnRfCommControl, this);//this is the socket between the RFCOMM and the L2CAP layer + if (_l2cap) + printf("Successfully opened L2CAP channel on socket %d\n", _l2cap); + else { + printf("Opening L2CAP channel failed\n"); + sckts[slot] = 0; + s->State = SocketState_Closed; + return 0; + } + } else {//bypass the l2cap channel creation + s->dlci = (ch<<1)|!initiator; + _bt_rfcomm_send_uih_pn_command(_l2cap, initiator, s->dlci, maxframesize); + s->State = SocketState_L2CAP_Config_wait; + } + return s->ID; //return the application unique socket nr. +} + +int rfcomm::set_remote_port_parameters(unsigned char dlci, port_settings *p) { + _bt_rfcomm_send_uih_rpn_cmd(_l2cap, initiator, dlci, p); + return 0; +} + +/* +int rfcomm::Open(BD_ADDR* bdAddr, inquiry_info* info) {//obsolete??? + _addr = *bdAddr; + L2CAPAddr sockAddr; + sockAddr.bdaddr = _addr; + //open an L2CAP socket for RFCOMM + sockAddr.psm = L2CAP_PSM_RFCOMM; + _l2cap = Socket_Open(SOCKET_L2CAP,&sockAddr.hdr,OnRfCommControl,this);//this is the socket between the RFCOMM and the L2CAP layer + + printfBytes("OPEN DEVICE CLASS",info->dev_class,3); + _devClass = (info->dev_class[0] << 16) | (info->dev_class[1] << 8) | info->dev_class[2]; + return _l2cap; +} +*/ + +//socket is an L2CAP socket and state is the state of the L2CAP socket, not the RFCOMM socket +void rfcomm::OnRfCommControl(int socket, SocketState state, const u8* data, int len, void* userData) { + int packet_processed = 0; + rfcomm* self = (rfcomm*)userData; + const u8 initiator = self->initiator; + printf("\x1B[%dm", 32); //debug: set a different colour + //printf("OnRfCommControl sock = %d, state = %d, length = %d\n", socket, state, len); + + if (len == 0) {//client only + if (state==SocketState_Open) {//callback after change to 'open', the rfcomm->l2cap channel is now open + _bt_rfcomm_send_sabm(socket, initiator, 0); //setup the rfcomm control channel dlci==0 + return; + } + return; //or other states to handle, e.g. Closing or Closed + } + //we have data, so parse the header + const u8 &addr = data[0]; + u8 dlci = addr>>2; + const u8 &control = data[1]; + u16 length = data[2]>>1; + const u8 *payload = data+3; + const u8 *pFCS = data+len-1; //expected position of the CRC + if (data[2]&1 == 0) { //two byte length + length += data[3]<<7; + payload++; + } + u8 credits = 0; + if (control == BT_RFCOMM_UIH_PF)//this packet carries credits + credits = *(payload++); + //sanity check + if (payload+length != pFCS) + printf("RFCOMM size mismatch, expected %d payload bytes, got %d\n", length, pFCS-payload); + + if (DEBUG) { + printf("RFCOMM: EA=%d, C/R=%d, D=%d, ch=%d; control=%02X (P/F=%d); length=%d\n", addr&1, (addr>>1)&1, (addr>>2)&1, (addr>>3), control, (control>>4)&1, length); + printfBytes("payload:", payload, length); + } + if (dlci == 0) { //dlci==0 control channel + L2CAPSocket *s = (L2CAPSocket*)GetSocketInternal(socket); + switch (control) { + case BT_RFCOMM_UA:// received 1. message BT_RF_COMM_UA + packet_processed++; + if (s->si.State == SocketState_Closing || s->si.State==SocketState_L2CAP_WaitDisconnect) { //Confirmation of disconnect + printf("Remote side confirmed disconnect for socket %d\n", s->si.ID); + s->si.SetState(SocketState_Closed); + break; + } + printf("Received RFCOMM unnumbered acknowledgement for channel 0 - multiplexer working\n"); + printf("Sending UIH Parameter Negotiation Command from OnRfCommControl\n"); + self->initChannels(socket); + //_bt_rfcomm_send_uih_pn_command(socket, initiator, rfcomm_ch, MAX_FRAME_SIZE); + break; + case BT_RFCOMM_UIH:// received UIH Parameter Negotiation Response + switch (payload[0]) { + case BT_RFCOMM_PN_RSP: {//client + packet_processed++; + printf("UIH Parameter Negotiation Response\n"); + printf("Sending SABM #%u\n", payload[2]); + _bt_rfcomm_send_sabm(socket, initiator, payload[2]);//was rfcomm_ch + RFCOMMSocket *r = self->find_socket(payload[2]); + if (r==0) break; + r->my_credits = payload[9]; //initial amount of credits + maxframesize = min(maxframesize, payload[6] + (payload[7]<<8)); + printf("Max Frame Size = %d, got %d initial credits\n", maxframesize, payload[9]); + } + break; + case BT_RFCOMM_PN_CMD: { //remote side send PN command, mtu and initial credits + packet_processed++; + printf("UIH Parameter Negotiation Indication\n"); + maxframesize = min(maxframesize, payload[6] + (payload[7]<<8)); + unsigned char cred = payload[9] & 7; + unsigned char _dlci = payload[2]; + + int skt = rfcomm_manager.find_socket(_dlci>>1); + if (skt == 0) { //No-one is listening + printf("No-one is Listening on channel %d\n", _dlci>>1); + rfcomm_send_packet(socket, (_dlci<<2)|1, BT_RFCOMM_DM, 0, 0, 0); + break; + } + RFCOMMSocket *r = (RFCOMMSocket*)GetSocketInternal(skt); + r->my_credits = cred; + r->peer_credits = INITIAL_CREDITS; + unsigned char reply[10]; + memcpy(reply, payload, sizeof(reply)); + reply[0] = BT_RFCOMM_PN_RSP;//[1]=len, [2]=dlci, [4]=priority, [5]=timer(must be 0), [8] retransmissions (must be 0) + reply[3] = payload[3]==0xF0 ? 0xE0 : 0; //support credit based flow control + reply[6] = maxframesize; + reply[7] = maxframesize>>8; + reply[9] = payload[3]==0xF0 ? r->peer_credits : 0; + printf("Max Frame Size = %d, give %d initial credits\n", maxframesize, reply[9]); + rfcomm_send_packet(socket, addr^2, BT_RFCOMM_UIH, 0, reply, sizeof(reply)); + } + break; + case BT_RFCOMM_MSC_CMD: + packet_processed++; + { + printf("Received BT_RFCOMM_MSC_IND\n"); + // fine with this + RFCOMMSocket *r = self->find_socket(payload[2]>>2); + if (r==0) break; + unsigned char reply[5]; + memcpy(reply, payload, 5); //keep length, dlci and value(s) + reply[0] = BT_RFCOMM_MSC_RSP; // change command into response + printf("Sending MSC_RSP (%d bytes)\n", length); + rfcomm_send_packet(socket, addr^2, BT_RFCOMM_UIH, 0, reply, (payload[1]>>1)+2); // reply is 4 or 5 bytes + switch (r->State) { + case SocketState_L2CAP_Config_wait: + r->State = SocketState_L2CAP_Config_wait_send; + printf("Sending MSC_CMD\n"); + _bt_rfcomm_send_uih_msc_cmd(socket, initiator, payload[2]>>2, 0x8d); // ea=1,fc=0,rtc(DSR/DTR)=1,rtr(RTS/CTs)=1,ic(RI)=0,dv(DCD)=1 + r->State = SocketState_L2CAP_Config_wait_rsp; + break; + case SocketState_L2CAP_Config_wait_reqrsp: + r->State = SocketState_L2CAP_Config_wait_rsp; + break; + case SocketState_L2CAP_Config_wait_req: + r->SetState(SocketState_Open); + break; + case SocketState_Open: + //inform port adaptation layer + printf("Received MSC IND in state Open for dlci 0x%02x\n", payload[2]>>2); + break; + default: + printf("Received MSC IND in state %d for dlci 0x%02x\n", r->State, payload[2]>>2); + } + } + break; + case BT_RFCOMM_MSC_RSP: + packet_processed++; + { + RFCOMMSocket *r = self->find_socket(payload[2]>>2); + if (r==0) break; + if (r->State == SocketState_L2CAP_Config_wait_reqrsp) + r->State = SocketState_L2CAP_Config_wait_req; + else if (r->State == SocketState_L2CAP_Config_wait_rsp) + r->SetState(SocketState_Open); + else + printf("Received MSC confirmation in state %d for dlci 0x%02x\n", r->State, payload[2]>>2); + } + break; + case BT_RFCOMM_RPN_CMD: + packet_processed++; + //accept and ignore all settings + unsigned char reply[10]; + memcpy(reply, payload, length); //keep length, dlci and value(s) + reply[0] = BT_RFCOMM_RPN_RSP; // change command into response + printf("Responding to RPN indication (%d bytes)\n", length); + rfcomm_send_packet(socket, addr^2, BT_RFCOMM_UIH, 0, reply, length); + break; + case BT_RFCOMM_RPN_RSP: + packet_processed++; + //ignore a response + printf("Received RPN confirmation\n"); + break; + default: + printf("Unsupported multiplexer frame, type=%02XH\n", data[3]); + } + break; + case BT_RFCOMM_DISC: + printf("Remote site actively disconnected from DLCI0\n"); + rfcomm_send_packet(socket, addr|2, BT_RFCOMM_UA, 0, 0, 0);//confirm disconnection + //intentional fall through + case BT_RFCOMM_DM: + packet_processed++; + printf("Remote side refused connection on DLCI0\n"); + self->_l2cap = Socket_Close(socket); + break; + case BT_RFCOMM_SABM: + packet_processed++; + printf("Remote site is seeking connection on DLCI0\n"); //respond with UA + rfcomm_send_packet(socket, addr|2, BT_RFCOMM_UA, 0, 0, 0);//confirm connection + break; + default: + printf("Unexpected RFCOMM cmd %02XH for address %02XH, length=%d\n", control, addr, length); + } + } else { //data is for one of the serial sockets + RFCOMMSocket *s = 0; + if (control == BT_RFCOMM_SABM) { //req. for conn on this dlci + //cannot call self->rfcomm::find_socket because it has no socket yet + int skt = rfcomm_manager.find_socket(dlci>>1); //find the server socket + s = (RFCOMMSocket*)GetSocketInternal(skt);//the listening socket + if (s) {//move the listening socket to the appropriate rfcomm + int slot = self->find_slot(dlci>>1); + if (slot < 0) { + printf("RFCOMM Channel %d is not free on rfcomm with l2cap socket %d\n", dlci>>1, self->_l2cap); + return; + } + s->serdevice = self; //bind the socket to this refcomm entity + self->sckts[slot] = skt; + rfcomm_manager.remove_socket(skt); + } else { + printf("Couln't find a listening socket for dlci %d\n", dlci); + return; + } + } else + s = self->find_socket(dlci); + if (s==0){ + printf("DLCI %d not found\n", dlci); + return; + } + switch (control) { + case BT_RFCOMM_SABM: + packet_processed++; + rfcomm_send_packet(socket, addr|2, BT_RFCOMM_UA, 0, 0, 0);//confirm connection + s->State = SocketState_L2CAP_Config_wait; //wait for msc cmd + break; + case BT_RFCOMM_UA:// received 2. message BT_RF_COMM_UA + packet_processed++; + if (s->State == SocketState_Closing) { //Confirmation of disconnect + printf("Remote side confirmed disconnect for socket %d\n", s->ID); + s->SetState(SocketState_Closed); + break; + } + printf("Received RFCOMM unnumbered acknowledgement for dlci %u - channel opened\n", dlci); + if (s->State == SocketState_L2CAP_Config_wait) { + printf("Sending MSC CMD\n"); + _bt_rfcomm_send_uih_msc_cmd(socket, initiator, dlci, 0x8d); // ea=1,fc=0,rtc(DSR/DTR)=1,rtr(RTS/CTs)=1,ic(RI)=0,dv(DCD)=1 + s->State = SocketState_L2CAP_Config_wait_reqrsp; + } + break; + case BT_RFCOMM_UIH_PF: //user data with credits + //printf("Got %u credits\n", credits); + s->my_credits += credits; + //intentional fall-through + case BT_RFCOMM_UIH: //user data + packet_processed++; + if (DEBUG) { + printf("RX: address %02x, control %02x: ", addr, control); + printHex( payload, length); + } + if (length) { + s->peer_credits--; + s->Recv(payload, length); + } + if (length == 0 || s->peer_credits == 0) {//send credits when peer runs out + //char ini = !(dlci & 1); + unsigned char address = (1 << 0) | (initiator << 1) | (dlci << 2); + //printf("send %d credits to dlci %d\n", NR_CREDITS, addr>>2); + rfcomm_send_packet(socket, address, BT_RFCOMM_UIH_PF, NR_CREDITS, NULL, 0); + s->peer_credits += NR_CREDITS; + } + break; + case BT_RFCOMM_DISC: + packet_processed++; + printf("Received DISC IND for dlci %d\n", dlci); + rfcomm_send_packet(socket, addr, BT_RFCOMM_UA, 0, 0, 0);//confirm disconnection + s->SetState(SocketState_Closed); + break; + case BT_RFCOMM_DM: + case BT_RFCOMM_DM_PF: + packet_processed++; + printf("Received DM IND (%02X) for dlci %d\n", control, dlci); + s->SetState(SocketState_Closed); + break; + default: + printf("Unexpected RFCOMM cmd %02XH for address %02XH, length=%d\n", control, addr, length); + } + } + + if (!packet_processed) { + // just dump data for now + printf("??: address %02x, control %02x: ", data[0], data[1]); + printHex( data, len ); + } + printf("\x1B[%dm", 0);//reset terminal colour +} + +/** + * @param credits - only used for RFCOMM flow control in UIH wiht P/F = 1 + */ +/* Questionable optimisation. When OFFSET==8 a buffer is (dynamically) allocated that provides space for the lower + layer headers, this reduces copying to, and allocation of, a lower layer buffer. However, all other layers using + HCI/L2CAP must do the same. +*/ +#define OFFSET 8 + +int rfcomm_send_packet(uint16_t source_cid, uint8_t address, uint8_t control, uint8_t credits, const uint8_t *data, uint16_t len) { + + uint16_t pos = OFFSET; + uint8_t crc_fields = 3; + +#if OFFSET == 8 + uint8_t* rfcomm_out_buffer = new uint8_t[OFFSET+len+6]; +#else + static uint8_t rfcomm_out_buffer[MAXFRAMESIZE+6];//seems a bit big as default max framesize is 127 +#endif + rfcomm_out_buffer[pos++] = address; + rfcomm_out_buffer[pos++] = control; + + // length field can be 1 or 2 octets + if (len < 128) { + rfcomm_out_buffer[pos++] = (len << 1)| 1; // bits 0-6 + } else { + rfcomm_out_buffer[pos++] = (len & 0x7f) << 1; // bits 0-6 + rfcomm_out_buffer[pos++] = len >> 7; // bits 7-14 + crc_fields++; + } + + // add credits for UIH frames when PF bit is set + if (control == BT_RFCOMM_UIH_PF) { + rfcomm_out_buffer[pos++] = credits; + } + + // copy actual data + memcpy(&rfcomm_out_buffer[pos], data, len); + pos += len; + + // UIH frames only calc FCS over address + control (5.1.1) + if ((control & 0xef) == BT_RFCOMM_UIH) { + crc_fields = 2; + } + rfcomm_out_buffer[pos++] = crc8_calc(rfcomm_out_buffer+OFFSET, crc_fields); // calc fcs + int retval = Socket_Send( source_cid, rfcomm_out_buffer, pos); +#if OFFSET == 8 + delete[] rfcomm_out_buffer; +#endif + if (retval <= 0) + return retval; + return len;//return the size of the payload +} + +void _bt_rfcomm_send_sabm(uint16_t source_cid, uint8_t initiator, uint8_t dlci) { + uint8_t address = (1 << 0) | (initiator << 1) | (dlci << 2); + rfcomm_send_packet(source_cid, address, BT_RFCOMM_SABM, 0, NULL, 0); +} + +void _bt_rfcomm_send_uih_pn_command(uint16_t source_cid, uint8_t initiator, uint8_t dlci, uint16_t max_frame_size) { + uint8_t payload[10]; + uint8_t address = (1 << 0) | (initiator << 1); // EA and C/R bit set - always server channel 0 + uint8_t pos = 0; + payload[pos++] = BT_RFCOMM_PN_CMD; + payload[pos++] = 8 << 1 | 1; // len + payload[pos++] = dlci; + payload[pos++] = 0xf0; // pre defined for Bluetooth, see 5.5.3 of TS 07.10 Adaption for RFCOMM + payload[pos++] = 0; // priority + payload[pos++] = 0; // max 60 seconds ack + payload[pos++] = max_frame_size & 0xff; // max framesize low + payload[pos++] = max_frame_size >> 8; // max framesize high + payload[pos++] = 0x00; // number of retransmissions + payload[pos++] = INITIAL_CREDITS; // unused error recovery window + rfcomm_send_packet(source_cid, address, BT_RFCOMM_UIH, 0, (uint8_t *) payload, pos); +} + +void _bt_rfcomm_send_uih_data(uint16_t source_cid, uint8_t initiator, uint8_t channel, uint8_t *data, uint16_t len) { + uint8_t address = (1 << 0) | (initiator << 1) | (!initiator << 2) | (channel << 3); + rfcomm_send_packet(source_cid, address, BT_RFCOMM_UIH, 0, data, len); +} + +void _bt_rfcomm_send_uih_msc_cmd(uint16_t source_cid, uint8_t initiator, uint8_t dlci, uint8_t signals) { + uint8_t address = (1 << 0) | (initiator << 1); // EA and C/R bit set - always server channel 0 + uint8_t payload[5]; + uint8_t pos = 0; + payload[pos++] = BT_RFCOMM_MSC_CMD; + payload[pos++] = 2 << 1 | 1; // len, should be adapted when adding break byte + payload[pos++] = (1 << 0) | (1 << 1) | (dlci << 2); //C/R is always 1 + payload[pos++] = signals; + // payload[pos++] = brk; + rfcomm_send_packet(source_cid, address, BT_RFCOMM_UIH, 0, (uint8_t *) payload, pos); +} + +void _bt_rfcomm_send_uih_rpn_cmd(uint16_t source_cid, uint8_t initiator, uint8_t dlci, port_settings *val) { + uint8_t address = (1 << 0) | (initiator << 1); // EA and C/R bit set - always server channel 0 + uint8_t payload[sizeof(port_settings)+3]; + uint8_t pos = 0; + payload[pos++] = BT_RFCOMM_RPN_CMD;//type + if (val) { + payload[pos++] = ((1+sizeof(port_settings)) << 1) | 1; // len + payload[pos++] = (1 << 0) | (1 << 1) | (dlci << 2); + memcpy(payload+pos, (char*)val, sizeof(port_settings)); + pos += sizeof(port_settings); + } else { + payload[pos++] = (1 << 1) | 1; // len + payload[pos++] = (1 << 0) | (1 << 1) | (dlci << 2); + } + rfcomm_send_packet(source_cid, address, BT_RFCOMM_UIH, 0, (uint8_t *) payload, pos); +} + +int set_remote_port_parameters(int socket, port_settings *p) { + RFCOMMSocket* si = (RFCOMMSocket*)GetSocketInternal(socket);//gets the RFCOMM socket + if (!si || si->ID != socket) + return ERR_SOCKET_NOT_FOUND; + return si->serdevice->set_remote_port_parameters(si->dlci, p); +} + + +/* + * CRC (reversed crc) lookup table as calculated by the table generator in ETSI TS 101 369 V6.3.0. + */ +static const uint8_t crc8table[256] = { /* reversed, 8-bit, poly=0x07 */ + 0x00, 0x91, 0xE3, 0x72, 0x07, 0x96, 0xE4, 0x75, 0x0E, 0x9F, 0xED, 0x7C, 0x09, 0x98, 0xEA, 0x7B, + 0x1C, 0x8D, 0xFF, 0x6E, 0x1B, 0x8A, 0xF8, 0x69, 0x12, 0x83, 0xF1, 0x60, 0x15, 0x84, 0xF6, 0x67, + 0x38, 0xA9, 0xDB, 0x4A, 0x3F, 0xAE, 0xDC, 0x4D, 0x36, 0xA7, 0xD5, 0x44, 0x31, 0xA0, 0xD2, 0x43, + 0x24, 0xB5, 0xC7, 0x56, 0x23, 0xB2, 0xC0, 0x51, 0x2A, 0xBB, 0xC9, 0x58, 0x2D, 0xBC, 0xCE, 0x5F, + 0x70, 0xE1, 0x93, 0x02, 0x77, 0xE6, 0x94, 0x05, 0x7E, 0xEF, 0x9D, 0x0C, 0x79, 0xE8, 0x9A, 0x0B, + 0x6C, 0xFD, 0x8F, 0x1E, 0x6B, 0xFA, 0x88, 0x19, 0x62, 0xF3, 0x81, 0x10, 0x65, 0xF4, 0x86, 0x17, + 0x48, 0xD9, 0xAB, 0x3A, 0x4F, 0xDE, 0xAC, 0x3D, 0x46, 0xD7, 0xA5, 0x34, 0x41, 0xD0, 0xA2, 0x33, + 0x54, 0xC5, 0xB7, 0x26, 0x53, 0xC2, 0xB0, 0x21, 0x5A, 0xCB, 0xB9, 0x28, 0x5D, 0xCC, 0xBE, 0x2F, + 0xE0, 0x71, 0x03, 0x92, 0xE7, 0x76, 0x04, 0x95, 0xEE, 0x7F, 0x0D, 0x9C, 0xE9, 0x78, 0x0A, 0x9B, + 0xFC, 0x6D, 0x1F, 0x8E, 0xFB, 0x6A, 0x18, 0x89, 0xF2, 0x63, 0x11, 0x80, 0xF5, 0x64, 0x16, 0x87, + 0xD8, 0x49, 0x3B, 0xAA, 0xDF, 0x4E, 0x3C, 0xAD, 0xD6, 0x47, 0x35, 0xA4, 0xD1, 0x40, 0x32, 0xA3, + 0xC4, 0x55, 0x27, 0xB6, 0xC3, 0x52, 0x20, 0xB1, 0xCA, 0x5B, 0x29, 0xB8, 0xCD, 0x5C, 0x2E, 0xBF, + 0x90, 0x01, 0x73, 0xE2, 0x97, 0x06, 0x74, 0xE5, 0x9E, 0x0F, 0x7D, 0xEC, 0x99, 0x08, 0x7A, 0xEB, + 0x8C, 0x1D, 0x6F, 0xFE, 0x8B, 0x1A, 0x68, 0xF9, 0x82, 0x13, 0x61, 0xF0, 0x85, 0x14, 0x66, 0xF7, + 0xA8, 0x39, 0x4B, 0xDA, 0xAF, 0x3E, 0x4C, 0xDD, 0xA6, 0x37, 0x45, 0xD4, 0xA1, 0x30, 0x42, 0xD3, + 0xB4, 0x25, 0x57, 0xC6, 0xB3, 0x22, 0x50, 0xC1, 0xBA, 0x2B, 0x59, 0xC8, 0xBD, 0x2C, 0x5E, 0xCF +}; + +#define CRC8_INIT 0xFF // Initial FCS value +#define CRC8_OK 0xCF // Good final FCS value +/*-----------------------------------------------------------------------------------*/ +uint8_t crc8(uint8_t *data, uint16_t len) { + uint16_t count; + uint8_t crc = CRC8_INIT; + for (count = 0; count < len; count++) + crc = crc8table[crc ^ data[count]]; + return crc; +} + +/*-----------------------------------------------------------------------------------*/ +uint8_t crc8_check(uint8_t *data, uint16_t len, uint8_t check_sum) { + uint8_t crc; + + crc = crc8(data, len); + + crc = crc8table[crc ^ check_sum]; + if (crc == CRC8_OK) + return 0; /* Valid */ + else + return 1; /* Failed */ + +} + +/*-----------------------------------------------------------------------------------*/ +uint8_t crc8_calc(uint8_t *data, uint16_t len) { + /* Ones complement */ + return 0xFF - crc8(data, len); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/myBlueUSB/rfcomm/RFCOMM.h Wed Jun 15 19:12:25 2011 +0000 @@ -0,0 +1,309 @@ +#ifndef RFCOMM_H +#define RFCOMM_H +#include "USBHost.h" +#include "hci.h" +#include "Utils.h" + +#define MAX_RFCOMM_SCKTS 4 +/* +template <class T> +T min(T a, T b) { + return a<b ? a : b; +} +*/ + +#define MASK_BITRATE 0X0001 +#define MASK_DATABITS 0X0002 +#define MASK_STOPBITS 0X0004 +#define MASK_PARITYBITS 0X0008 +#define MASK_PARITYTYPE 0X0010 +#define MASK_XONCHAR 0X0020 +#define MASK_XOFFCHAR 0X0040 +#define MASK_XONXOFFIN 0X0100 +#define MASK_XONXOFFOUT 0X0200 +#define MASK_RTRIN 0X0400 +#define MASK_RTROUT 0X0800 +#define MASK_RTCIN 0X1000 +#define MASK_RTCOUT 0X2000 + +struct port_settings { + unsigned char baud; +unsigned char bits: + 2; +unsigned char stop: + 1; +unsigned char par: + 1; +unsigned char par_t: + 2; +unsigned char : + 2; +unsigned char flow: + 6; +unsigned char : + 2; + unsigned char xon; + unsigned char xoff; + unsigned short mask; +}; + +class rfcomm; +class RFCOMMManager; +#define MAX_RFCOMM_DEVICES 8 //physical devices + +class RFCOMMSocket: public SocketInternal {//this object must not be larger than SocketInternalPad (socketinternal + 8 bytes) +public: + rfcomm* serdevice; + u8 dlci; //channel + D bit, D bit is inverted initiator bit + u8 my_credits, peer_credits; +}; + +class rfcomm: public SocketHandler { + int _l2cap; //socket to the l2cap layer + int _devClass; + BD_ADDR _addr; + u8 initiator; + u8 _pad[0]; // Struct align + char sckts[MAX_RFCOMM_SCKTS]; + static unsigned maxframesize; + int find_slot(unsigned ch); + RFCOMMSocket* find_socket(unsigned dlci); + void initChannels(int socket); + unsigned release_channel(unsigned dlci); + static void OnRfCommControl(int socket, SocketState state, const u8* data, int len, void* userData);//I guess this is called when data comes out of the socket + int Disconnect(RFCOMMSocket*); +public: + rfcomm() : _l2cap(0), _devClass(0) { + for (int i = 0; i < MAX_RFCOMM_SCKTS; i++) sckts[i] = 0; + } + + bool InUse() { + return _l2cap != 0; + } + virtual int Open(SocketInternal* sock, SocketAddrHdr* addr); + virtual int Send(SocketInternal* sock, const u8* data, int len);//wrap data in RFCOMM frame and dispatch + virtual int Close(SocketInternal* sock); + virtual char* Name() { + return "rfcomm SocketHandler"; + } + void Recv(const u8* data, int len) { + printf("rfcomm::Recv was called\n"); + } +#if 0 + int Listen(unsigned char ch=0) {//passive open, similar semantics to 'Open' but connection is only made at request of the peer + RFCOMMSocket *s = 0;//this entity may or may not be bound to a remote entity + if (ch>0) {//specific channel + s = find_socket(ch<<1); + if (s) { //socket for this channel already in use + printf("rfcomm::Listen: channel %d already in use\n", ch); + return 0; + } //else s==0, no socket for channel ch + }//else listen to any channel + int sn = find_slot(ch); + if (sn<0) { + printf("No socket could be found for channel %d\n", ch); + return 0; + } //else use slot 'sn' for the new rfcomm socket + int sock = Socket_Create(SOCKET_RFCOM, OnRfCommControl, this);//allocate an rfcomm socket + sckts[sn] = sock; //claim the socket + RFCOMMSocket *rs = (RFCOMMSocket*)GetSocketInternal(sock); + rs->serdevice = this; + rs->dlci = (ch<<1)|1;//server socket + //initiator = 0; what to do if already connected actively on different channel??? + /*l2cap is already present or is created when accepting the connection + if (_l2cap == 0) { //no rfcomm -> l2cap connection yet + printf("Need to open L2CAP channel first before opening RFCOMM channel %d\n", rs->dlci); + ((L2CAPAddr*)addr)->psm = L2CAP_PSM_RFCOMM;//open the l2cap channel and the rfcomm_ch channel + initiator = 0; + _l2cap = Socket_Create(SOCKET_L2CAP, addr, OnRfCommControl, this);//this is the socket between the RFCOMM and the L2CAP layer + if (_l2cap) + printf("Successfully opened L2CAP channel on socket %d\n", _l2cap); + else { + printf("Opening L2CAP channel failed\n"); + return 0; + } + } + */ + return sock; + } +#endif + //int Open(BD_ADDR* bdAddr, inquiry_info* info); + int set_remote_port_parameters(unsigned char dlci, port_settings *p); + friend RFCOMMManager; +}; + +class RFCOMMManager: public SocketHandler { + rfcomm _devs[MAX_RFCOMM_DEVICES]; + int serverSock; + char sckts[MAX_RFCOMM_SCKTS];//listening sockets +public: + virtual int Open(SocketInternal* sock, SocketAddrHdr* addr) { + L2CAPAddr* ad = (L2CAPAddr*)addr; + BD_ADDR* a = &ad->bdaddr; + rfcomm *r = FindRfCommDevice(a); + if (r==0) + r = NewRfCommDevice(); + if (r==0) + return 0; + return r->Open(sock, addr); + } + + int FindSocket(BTDevice* dev) {//finds the l2cap socket for a certain rfcomm-btdevice connection + for (int i = 0; i < MAX_RFCOMM_DEVICES; i++) { + rfcomm *r = _devs+i; + int l2cap = r->_l2cap; + if (l2cap) { + L2CAPSocket *p = (L2CAPSocket*)GetSocketInternal(l2cap); + if (p->btdevice == dev) + return l2cap; + } + } + return 0; + } + + rfcomm* FindDev(BTDevice* dev) {//finds the rfcomm entity for a certain rfcomm-btdevice connection + for (int i = 0; i < MAX_RFCOMM_DEVICES; i++) { + rfcomm *r = _devs+i; + int l2cap = r->_l2cap; + if (l2cap) { + L2CAPSocket *p = (L2CAPSocket*)GetSocketInternal(l2cap); + if (p->btdevice == dev) + return r; + } + } + return 0; + } + + int BindSocket(int s) { + L2CAPSocket *ls = (L2CAPSocket*)GetSocketInternal(s); + printf("Binding l2cap socket %d to a new rfcomm server entity\n", s); + rfcomm *r = NewRfCommDevice(); + r->_l2cap = s; + r->initiator = 0;//we are server + ls->si.userData = r;//was BTDevice, make rfcomm + return 0; + } + + int new_slot(unsigned ch) { + for (int i = 0; i < MAX_RFCOMM_SCKTS; i++) { + if (sckts[i] != 0) { //socket is in use + RFCOMMSocket *s = (RFCOMMSocket*)GetSocketInternal(sckts[i]); + if (s==0) { + printf("find_slot: socket %d not found\n", sckts[i]); + continue; + } + if ((s->dlci >> 1) == ch) { + printf("Channel %d is already in use on socket %d\n", ch, sckts[i]); + return -1; + } + } else //slot is free + return i; + } + return -2; //no free slots + } + + int find_socket(unsigned ch) { + for (int i = 0; i < MAX_RFCOMM_SCKTS; i++) { + if (sckts[i] != 0) { //socket is in use + RFCOMMSocket *s = (RFCOMMSocket*)GetSocketInternal(sckts[i]); + if (s==0) { + printf("find_slot: socket %d not found\n", sckts[i]); + continue; + } + if ((s->dlci >> 1) == ch) { + printf("Found Channel %d on socket %d\n", ch, sckts[i]); + return sckts[i]; + } + else + printf("slot %d has socket %d has dlci %d\n", i, sckts[i], s->dlci); + } + else + printf("Slot %d is free\n", i); + } + printf("channel %d not found\n", ch); + return 0; //channel not found + } + + int remove_socket(int sock) { + for (int i = 0; i < MAX_RFCOMM_SCKTS; i++) { + if (sckts[i] == sock) { + sckts[i] = 0; + return 0; + } + } + return -1; + } + + virtual int Listen(SocketInternal* sock, int ch) {//called by Socket_Listen(SOCKET_RFCOM, channel, callback, userData) + int slot = new_slot(ch); + switch (slot) { + case -1: + printf("There is already someone listening on ch %d\n", ch); + return ERR_SOCKET_CANT_LISTEN;//channel is occupied + case -2: + printf("All listener sockets are in use\n"); + return ERR_SOCKET_NONE_LEFT; + } + RFCOMMSocket *rs = (RFCOMMSocket*)sock; + const char dir = 0; + rs->dlci = (ch<<1)|dir; + rs->State = SocketState_Listen; + rs->serdevice = 0;//don't know yet + sckts[slot] = rs->ID; + printf("RFCOMM listener socket %d for ch %d (dlci 0x%02X) is assigned to slot %d\n", rs->ID, ch, rs->dlci, slot); + return rs->ID; + } +/* + virtual int Accept(SocketInternal *sock, int scid, int rxid) { //called indirectly from BTDevice::Control + //sock is registered as an RFCOMM sock but we use it as an L2CAP sock + //sock->type=RFCOM, meaning open/close/send/accept go to RFCOMMManager first + //sock->userData = BTDevice, necessary to make the call back to BTDevice::Accept + //Internal = L2CAPSocket, for scid, dcid + BTDevice *l2cap = (BTDevice*)sock->userData; + //sock->si.dcid = scid + //sock->si.scid = something based on sock->ID + serverSock = sock->ID; + printf("Invoking accept on %p (%s) for sock %d and scid=%d\n", l2cap, l2cap->Name(), sock->ID, scid); + return l2cap->Accept(sock, scid, rxid); //connect 'serverSock' to the remote RFCOMM client + } +*/ + virtual int Send(SocketInternal* sock, const u8* data, int len) { + RFCOMMSocket *s = (RFCOMMSocket*)sock; + return s->serdevice->Send(sock, data, len); + } + + virtual int Close(SocketInternal* sock) { + RFCOMMSocket *s = (RFCOMMSocket*)sock; + return s->serdevice->Close(sock); + } + + virtual char* Name() { + return "RFCOMMManager SocketHandler"; + } + + rfcomm* NewRfCommDevice() {//allocate a new RFCOMM device from the pool + for (int i = 0; i < MAX_RFCOMM_DEVICES; i++) + if (!_devs[i].InUse()) + return _devs+i; + return 0; + } + + rfcomm* FindRfCommDevice(BD_ADDR* ad) {//get a specific RFCOMM device from the pool + for (int i = 0; i < MAX_RFCOMM_DEVICES; i++) + if (_devs[i].InUse() && memcmp(ad, &_devs[i]._addr, 6)==0) + return _devs+i; + return 0; + } + + static void SerServer(int socket, SocketState state, const u8* data, int len, void* userData) { + printfBytes("SerServer: ", data, len); + //userData is the rfcomm + rfcomm::OnRfCommControl(socket, state, data, len, userData); + } + //friend rfcomm; +}; + +int set_remote_port_parameters(int socket, port_settings *p); +extern RFCOMMManager rfcomm_manager; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/myBlueUSB/sdp/sdp.cpp Wed Jun 15 19:12:25 2011 +0000 @@ -0,0 +1,787 @@ +#include "mbed.h" +#include "Utils.h" +#include "hci.h" +#include "sdp_data.h" +#include "sdp.h" + +SDPManager SDP; //instance +const unsigned char base_uuid[16] = { 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0, 0x07, 0x70, 0, 0x10, 0, 0}; +map<unsigned, serv_rec*> SDPManager::server; +int SDPManager::serverSock = 0; + +void attribHandler(serv_rec *r) { + printf("Service 0x%08X\n", (*r)[0x0000]->asUnsigned()); + map<unsigned short, sdp_data*>::iterator it = r->begin(); + for (;it != r->end();it++) { + printf(" 0x%04X: %s\n", (*it).first, (*it).second->asString()); + } +} + +#define BROWSEROOT 0x1002 +#define SERIALSERV 0x1101 + +SDPHandler::SDPHandler(): txid(1), tree(0) { + ErrorResponse=errorhandler; + ServiceSearchResponse=0; + ServiceAttributeResponse=attribHandler; + ServiceSearchAttributeResponse=0; + buf = l2cap_buf+OFFSET; + contBuf = 0; + byteCount = 0; + contState[0] = 0; + _state = 0; +} + +void SDPHandler::Clear() { + for (index = services.begin(); index != services.end(); index++) {//for all services + for (serv_rec::iterator it = index->second->begin(); it != index->second->end(); it++)//for all attributes + delete it->second; //delete the attribute value tree + delete (*index).second; //delete the attribute list + } + services.clear();//and empty the services list +} + +//Called as: Socket_Open(SOCKET_SDP, addr, callback, userdata(this)) from SDPManager +//never called +int SDPHandler::Open(SocketInternal* sock, SocketAddrHdr* addr) { + printf("Successfully opened SDP socket %d\n", sock->ID); + sock->SetState(SocketState_Open); + sdp_socket = sock->ID; + return sdp_socket; +} + +int SDPHandler::Send(SocketInternal* sock, const u8* data, int len) { + printf("SDPHandler::Send should not be called directly\n"); +// return Socket_Send(_l2cap, data, len); + BTDevice *l2cap = (BTDevice*)sock->userData; + return l2cap->Send(sock, data, len); +} + +int SDPHandler::Close(SocketInternal* sock) { + printf("SDPHandler::Close(%d)\n", sock->ID); + Clear(); +// printf("SDP socket %d and L2CAP socket %d closed, freemem=%d\n", sock->ID, _l2cap, AvailableMemory(1)); + int retval = 0;//Socket_Close(_l2cap);//could also keep it open for the next connection + return retval; +} + +//this function is called when the L2CAP layer receives SDP packets (see SDPHandler::Open), userdata is the sdpmanager instance +void SDPHandler::OnSdpRsp(int socket, SocketState state, const u8* data, int len, void* userData) { + printf("\x1B[%dm", 35); +// printf("OnSdpRsp(socket=%d, state=%d, len=%d)\n", socket, state, len); + printf("SDPHandler::OnSdpRsp(socket=%d, state=%d, len=%d, freemem=%d\n", socket, state, len, AvailableMemory(1)); + SDPHandler *self = (SDPHandler*)userData; + if (state == SocketState_Open) { + self->sdp_socket = socket; + self->OnSdpRsp(data, len); + } else if (state == SocketState_Closed) { + SDP.Destroy(socket); + } + printf("\x1B[%dm", 0); +} + +//this function is called when the L2CAP layer receives SDP packets (see SDPHandler::Open), userdata is the sdpmanager instance +//void SDPHandler::OnSdpRsp(int socket, SocketState state, const u8* data, int len, void* userData) { +void SDPHandler::OnSdpRsp(const u8* data, int len) { + static sdp_data list(sdp_data::SEQUENCE); + static sdp_data all(0x0000ffffU,4); + static sdp_data serviceID(0U, 2); + static sdp_data name(0x100U, 2); + static sdp_data root(sdp_data::UUID, BROWSEROOT); + static sdp_data req(sdp_data::SEQUENCE); + static bool once = true; +// printf("_state=%d first=%d ", _state, once); + if (once) { + list.add_element(&all); + //list.add_element(&serviceID); + //list.add_element(&name); + req.add_element(&root); + once = false; + } + if (data) { + parseRsp(data, len); + } + switch (_state) { + case 0: //closed + if (len==0) { //socket just opened + //'Open' cleared the services list + ServiceSearchRequest(&req, 10); + _state = 1; //wait for service handles + } + break; + case 1: //service handles arriving + if (contState[0]) {//continuation, repeat request + ServiceSearchRequest(&req, 5); + } else { + if (data[0]==3) { + index = services.begin(); + if (index != services.end()) { + unsigned handle = (*index).first; + //printf("req.: handle %#X\n", handle); + ServiceAttributeRequest(handle, 100, &list);//0x1001D + } else + printf(" - empty list - \n");//should not happen + _state = 2; //wait for attribute response + } else + printf("Expected a ServiceSearchResponse 0x03, got %#x\n", data[0]); + } + break; + case 2: + if (contState[0])//repeat request + ServiceAttributeRequest((*index).first, 100, &list); + else { + if (data[0]==5) { + index++; //move to next service + if (index != services.end()) { + //printf("req.: handle %#X\n", (*index).first); + ServiceAttributeRequest((*index).first, 100, &list); + } else { + printf(" - end of list - \n"); + Socket_Close(sdp_socket); //Note: socket=L2CAP, sdp_socket=SDP !!! + _state = 0; + } + } else + printf("Expected a ServiceAttributeResponse 0x05, got %#x\n", data[0]); + } + break; + } +} + +//this function is called when the SDP sockets receives data (see HCICallback in TestShell), +//currently does not happen because not forwarded from OnSdpRsp, can be used to handle multiple connections +void SDPHandler::OnSockCallback(int socket, SocketState state, const u8* data, int len, void* userData) { + printf("SDPHandler::OnSockCallback(socket=%d, state=%d, len=%d)\n", socket, state, len); + printfBytes("Got SDP Response from socket: ", data, len); +} + +//void SDPHandler::errorhandler(unsigned err) {//default error handler +void errorhandler(unsigned err) {//default error handler + switch (err) { + case 1: + printf("Unsupported version of SDP\n"); + break; + case 2: + printf("Invalid SDP ServiceRecordHandle\n"); + break; + case 3: + printf("SDP syntax error\n"); + break; + case 4: + printf("PDU size was invalid\n"); + break; + case 5: + printf("Continuation state was invalid\n"); + break; + case 6: + printf("SDP server has insufficient resources\n"); + break; + default: + printf("Unknown SDP error code\n"); + break; + } +} + +int SDPHandler::ServiceSearchRequest(sdp_data *sp, unsigned count, unsigned cs) { + int parlen = sp->Size() + contState[0] + 3; + buf[0] = 2; //pdu + buf[1] = txid>>8; + buf[2] = txid++; + buf[4] = parlen; + buf[3] = parlen>>8; + int p = sp->build(buf+5, 100-10); + buf[p+6] = count; + buf[p+5] = count>>8; + buf[p+7] = contState[0]; + for (int j = 1; j <= contState[0]; j++) + buf[p+j+7] = contState[j]; + //printfBytes("SDP Send: ", buf, parlen+5); + return Socket_Send(sdp_socket, l2cap_buf, parlen + 5 + OFFSET); +} + +int SDPHandler::ServiceAttributeRequest(unsigned handle, unsigned count, sdp_data* al, unsigned cs) { + int parlen = al->Size() + contState[0] + 7; + buf[0] = 4; //pdu + buf[1] = txid>>8; + buf[2] = txid++; + buf[4] = parlen; + buf[3] = parlen>>8; + for (int i = 0; i < 4; i++) + buf[i+5] = ((char*)&handle)[3-i]; + buf[9] = count>>8; + buf[10] = count; + int p = al->build(buf+11, 100-26); + buf[p+11] = contState[0]; + for (int j = 1; j <= contState[0]; j++) + buf[p+j+11] = contState[j]; + //printfBytes("SDP Send: ", buf, parlen+5); + return Socket_Send(sdp_socket, l2cap_buf, parlen + 5 + OFFSET); +} + +int SDPHandler::ServiceSearchAttributeRequest(sdp_data *sp, unsigned count, sdp_data* al, unsigned cs) { + int parlen = sp->Size() + al->Size() + contState[0] + 3; // count (2 bytes) + at least 1 cont + buf[0] = 6; //pdu + buf[1] = txid>>8; + buf[2] = txid++; + buf[4] = parlen; + buf[3] = parlen>>8; + int p = sp->build(buf+5, 30); + buf[p+6] = count; + buf[p+5] = count>>8; + p += al->build(buf+11, 100-38); + buf[p+7] = contState[0]; + for (int j = 1; j <= contState[0]; j++) + buf[p+j+7] = contState[j]; + //printfBytes("SDP Send: ", buf, parlen+5); + return Socket_Send(sdp_socket, l2cap_buf, parlen + 5 + OFFSET); +} + +int SDPManager::ServiceSearchAttributeReply(unsigned rxid, sdp_data* al, unsigned count, unsigned cs) { + unsigned size = al->Size(); + unsigned cont = 0;//outgoing continuation + unsigned char *_buf = new unsigned char[OFFSET+5+2+size+3]; + unsigned char *buf = _buf+OFFSET; + unsigned byteCount = size - cs; //remainder of data to send + unsigned parlen = 2 + byteCount + 1 ;// attributelistbytecount+payload+no_continuation + if (byteCount > count) {//still too large, need continuation + byteCount = count; //limit at maximum + cont = cs + count; //start for next iteration + parlen = 2 + byteCount + 3; //adjusted for payload and continuation + printf("Need continuation, sending bytes [%d, %d> of attributeList\n", cs, cont); + } else { + // printf("Final or only block, sending bytes [%d, %d> of attributeList\n", cs, cs+byteCount); + } + buf[0] = 7; //pdu + buf[1] = rxid>>8; + buf[2] = rxid; + buf[3] = parlen>>8; + buf[4] = parlen; + buf[5] = byteCount>>8; + buf[6] = byteCount; + int p = al->build(buf+7, size);//limited only by buffersize + //printf("'build' added %d bytes to the buffer\n", p); + if (cs == 0) { //this is not a continuation + buf[byteCount+7] = 0; + } else { //this is a continuation + memcpy(buf+7, buf+7+cs, byteCount);//move part of interrest to beginning of buffer + buf[byteCount+7] = 2; + buf[byteCount+8] = cont>>8; + buf[byteCount+9] = cont; + } + //printfBytes("SDP Send: ", buf, parlen+5); + int retval = Socket_Send(serverSock, _buf, parlen + 5 + OFFSET); + delete[] _buf; + return retval; +} + +//unsigned SDPHandler::getval(const unsigned char *p, int n) { +unsigned getval(const unsigned char *p, int n) { + unsigned ret = 0; + for (int i = 0; i < n; i++) + ret = (ret<<8) + (unsigned)p[i]; + return ret; +} + +//unsigned SDPHandler::length(const unsigned char *el, unsigned &p) { +unsigned length(const unsigned char *el, unsigned &p) { + unsigned len = 0; + switch (el[p++] & 7) {//length + case 0: + len = 1; + break; + case 1: + len = 2; + break; + case 2: + len = 4; + break; + case 3: + len = 8; + break; + case 4: + len = 16; + break; + case 7://4bytes + len= el[p++]<<24; + len += el[p++]<<16; + case 6://2bytes + len += el[p++]<<8; + case 5://1byte + len += el[p++]; + break; + } + return len; +} + +extern "C" void HardFault_Handler() { + printf("Hard Fault! %d bytes left\n", AvailableMemory(1)); + while (1); +} + +unsigned SDPHandler::parseLight (const unsigned char *el, unsigned count, sdp_data* &result, serv_rec* &record) { + unsigned p = 0; + unsigned len = length(el, p); + int end = p+len;//end is the index of the item just after the sequence + sdp_data *item = 0; + switch (el[0]>>3) {//type + case sdp_data::NULL_: + printf("NULL "); + break; + case sdp_data::UNSIGNED: + printf("UINT%d=%u ", len, (unsigned)getval(el+p, len)); + break; + case sdp_data::SIGNED: + printf("INT%d=%d ", len, (unsigned)getval(el+p, len)); + break; + case sdp_data::UUID: + if (len==16) { + printf("UUID16= "); + for (int i = 0; i < 16; i++) + printf("%02x ", el[p+i]); + } else + printf("UUID%d=%u ", len, (unsigned)getval(el+p, len)); + break; + case sdp_data::STRING: + printf("STR%d='%s' ", len, (char*)el+p); + break; + case sdp_data::BOOL: + printf("BOOL%d=%d ", len, (unsigned)getval(el+p, len)); + break; + case sdp_data::SEQUENCE: + goto skip; + case sdp_data::ALTERNATIVE: +skip: {//p points just after the length indicator, hence at the first item IN the sequence + printf("SEQ%d{%p ", len, item); + int n = 0; + unsigned short key; + serv_rec *dummy = 0; + while (p < end) { + sdp_data *elem = 0; + p += parseLight(el + p, len-p, elem, dummy);//parse each element in the sequence, the second arg is as yet unused + if (record) { + if (n & 1) { //value + record->insert(pair<unsigned short, sdp_data*>(key, elem)); + } else //key + key = n; + n++; + } + } + } + printf("}\n"); + break; + case 8: + printf("URL%d='%s' ", len, (char*)el+p); + break; + default: + printf("Parse: Unknown type %d, len=%d (code=%#02X)\n", el[0]>>3, len, el[0]); + } + result = item; + return end; +} + +unsigned SDPHandler::parse (const unsigned char *el, unsigned count, sdp_data* &result, serv_rec* &record) { + unsigned p = 0; + unsigned len = length(el, p); + int end = p+len;//end is the index of the item just after the sequence + sdp_data *item = 0; + switch (el[0]>>3) {//type + case sdp_data::NULL_: + item = new sdp_data(); + break; + case sdp_data::UNSIGNED: + item = new sdp_data((unsigned)getval(el+p, len), len); + break; + case sdp_data::SIGNED: + item = new sdp_data((int)getval(el+p, len), len); + break; + case sdp_data::UUID: + if (len==16) { + char rev[16]; + for (int i = 0; i < 16; i++) + rev[i] = el[p+15-i]; + item = new sdp_data(sdp_data::UUID, rev, len); + } else + item = new sdp_data(sdp_data::UUID, getval(el+p, len), len); + break; + case sdp_data::STRING: + item = new sdp_data((char*)el+p, len); + break; + case sdp_data::BOOL: + item = new sdp_data((bool)getval(el+p, len), len); + break; + case sdp_data::SEQUENCE: + item = new sdp_data(sdp_data::SEQUENCE); + goto skip; + case sdp_data::ALTERNATIVE: + item = new sdp_data(sdp_data::ALTERNATIVE); +skip: {//p points just after the length indicator, hence at the first item IN the sequence + //printf("SEQ%d{%p ", len, item); + int n = 0; + unsigned short key; + serv_rec *dummy = 0;//means: there is no service record to fill in for deeper levels + while (p < end) { + sdp_data *elem = 0; //this becomes the tree with attribute values + p += parse(el + p, len-p, elem, dummy);//parse each element in the sequence, the second arg is as yet unused + if (record) { //if at the level of attribute list, add elem to record as key/value pair + if (n & 1) { //value + record->insert(pair<unsigned short, sdp_data*>(key, elem)); + } else //key + key = elem->asUnsigned(); + n++; + } else //just add the elements to the value tree + item->add_element(elem); + } + } + //printf("}\n"); + break; + case 8: + item = new sdp_data(sdp_data::URL, (char*)el+p, len); + break; + default: + printf("Parse: Unknown type %d, len=%d (code=%#02X)\n", el[0]>>3, len, el[0]); + } + result = item; + return end; +} + +void SDPHandler::append(const unsigned char *payload, int len) { + unsigned char *tmp = new unsigned char[byteCount + len];//append the payload to the previous continuation buffer + if (contBuf && byteCount) { + memcpy(tmp, contBuf, byteCount); //copy the existing part + delete[] contBuf;//delete the old buffer + } + memcpy(tmp+byteCount, payload, len); //append the new part + contBuf = tmp; + byteCount += len; +} + +void SDPHandler::freeBuf() { + if (contBuf) { + delete[] contBuf; + contBuf = 0; + } + byteCount = 0; +} + + +//TODO: test case 7, add server support (cases 2, 4, 6) +//3 cases: cont==0 && contBuf==0 -> use rsp; cont!=0 -> append; cont==0 && contBuf!=0 -> append and use contBuf +int SDPHandler::parseRsp(const unsigned char*rsp, int len) { + //unsigned tid = rsp[2] + ((unsigned)rsp[1]<<8); + unsigned parlen = rsp[4] + ((unsigned)rsp[3]<<8); + //printf("ParseRsp: tid=%04X, parlen=%d ", tid, parlen); + unsigned cont = 0; + switch (rsp[0]) { + case 1: {//errorRsp + unsigned errorcode = rsp[6] + ((unsigned)rsp[5]<<8); + if (parlen > 2) { + printf("ErrorInfo (%d bytes) for error %d is available\n", parlen-2, errorcode); + } + if (ErrorResponse) + ErrorResponse(errorcode); + return errorcode; + } + //break; + case 3: { //servicesearchRsp + //unsigned total = rsp[6] + ((unsigned)rsp[5]<<8); + unsigned current = rsp[8] + ((unsigned)rsp[7]<<8); + cont = rsp[9+4*current]; + memcpy(contState, &rsp[9+4*current], cont+1);//copy the continuation state + //printf("total=%d, current=%d, cont=%d\n", total, current, cont); + if (cont) { + //no special handling here, just append the servicerecordhandles + } + //linear list of 32bit service-handles + for (int i = 0; i < current; i++) { + unsigned result = 0; + for (int j = 0; j< 4; j++) + result = (result<<8) + rsp[9 + 4*i + j]; + printf("SDP Search handle %08X\n", result); + services.insert(pair<unsigned, serv_rec*>(result, 0)); + } + if (ServiceSearchResponse) + ServiceSearchResponse(); + } + break; + case 5: { //serviceattributeRsp + unsigned count = rsp[6] + ((unsigned)rsp[5]<<8);//bytes in this part of the attribute list +// append(rsp+7, count); + cont = rsp[7+count]; + memcpy(contState, &rsp[7+count], cont+1);//copy the continuation state + if (cont) { + append(rsp+7, count); + break; + } + //printf("count=%d parsing...\n", byteCount); + serv_rec *serv = new serv_rec; + if (contBuf) { + append(rsp+7, count); + parse(contBuf, byteCount, tree, serv); + } else + parse(rsp+7, count, tree, serv); + //printf("...parsing done, "); + //get the AttributeID, make sure attribId 0 is always included in the request + unsigned key = (*serv)[0]->asUnsigned();//AttributeID '0' always refers to the serviceID + //printf("Key=%#X\n", key); //key will be 0 when not requested + services[key] = serv; //Add the attribute list to the services + freeBuf(); + if (ServiceAttributeResponse) + ServiceAttributeResponse(serv); + } + break; + //below is UNTESTED + case 7: { //servicesearchattributeRsp + unsigned count = rsp[6] + ((unsigned)rsp[5]<<8); + append(rsp+7, count); + cont = rsp[7+count]; + memcpy(contState, &rsp[7+count], cont+1); + if (cont) + break; + unsigned pos = 0; + if (contBuf[pos]>>3 != sdp_data::SEQUENCE) { + printf("Expected a sequence of attribute lists\n"); + break; + } + unsigned len = length(contBuf, pos);//get the length of the list of lists and advance pos to the first list + while (pos<len) { + printf("pos=%d, count=%d, parsing...\n", pos, len); + serv_rec *serv = new serv_rec; + pos = parse(contBuf+pos, len, tree, serv); + unsigned key = (*serv)[0]->asUnsigned(); + services[key] = serv; + } + freeBuf(); + printf("...parsing done, pos=%d\n", pos); + if (ServiceSearchAttributeResponse) + ServiceSearchAttributeResponse(); + } + break; + default: + printf("Unknown SDP response type %02X\n", rsp[0]); + break; + } + return 0; +} + +//************************ SERVER related *******************************************// + +//unsigned SDPHandler::parseUUID(const u8* data, int len, unsigned &p) { +unsigned parseUUID(const u8* data, int len, unsigned &p) { + unsigned u = 0; + if ((data[p]>>3) != sdp_data::UUID) { + printf(" UUID expected, got %d ", data[p]>>3); + return (unsigned)-1; + } + switch (data[p++] & 7) { + case 1: + u = getval(data+p, 2); + p +=2; + break; + case 2: + u = getval(data+p, 4); + p += 4; + break; + case 4: + u = getval(data+p, 4); + p += 16; + break; + default: + printf(" UUID must be 2, 4 or 16 bytes, got type %d\n", data[p-1]); + } + return u; +} + +#define SVC_HANDLE 0x0001001DU //serial service +void SDPManager::buildServer() { + static sdp_data rfcomm(sdp_data::SEQUENCE); + static sdp_data l2cap(sdp_data::SEQUENCE); + static sdp_data protocol(sdp_data::SEQUENCE); + static sdp_data serviceclass(sdp_data::SEQUENCE); + static sdp_data browsegroup(sdp_data::SEQUENCE); + static sdp_data root(sdp_data::UUID, BROWSEROOT); + static sdp_data l2capuuid(sdp_data::UUID, 0x0100); + static sdp_data rfcommuuid(sdp_data::UUID, 0x003); + static sdp_data serial(sdp_data::UUID, 0x1101); + static sdp_data chan(1U,1); + static sdp_data handle(SVC_HANDLE,4); + static sdp_data serviceID(0U, 2); + static sdp_data name("MBED BlueUSB RFCOMM Serial"); + rfcomm.add_element(&rfcommuuid); + rfcomm.add_element(&chan); + l2cap.add_element(&l2capuuid); + protocol.add_element(&l2cap); + protocol.add_element(&rfcomm); + serviceclass.add_element(&serial); + browsegroup.add_element(&root); + static serv_rec attr_list; + attr_list[0] = &handle; + attr_list[1] = &serviceclass; + attr_list[4] = &protocol; + attr_list[5] = &browsegroup; + attr_list[0x100] = &name; + server[SVC_HANDLE] = &attr_list;//server is static and this statement crashes the program when invoked from the constructor which is also invoked statically +} + +int SDPManager::findUUID(unsigned h, unsigned uuid) { + serv_rec *rec = server[h]; + for ( serv_rec::iterator it = rec->begin(); it != rec->end(); it++) { + if (it->second->findUUID(uuid)) + return it->first; + } + printf("rejected %08X because of %04Xx\n", h, uuid); + return -1; +} + +void SDPManager::match(bool elig[], unsigned uuid) { + map<unsigned, serv_rec*>::iterator idx; + int i = 0; + for (idx = server.begin(); idx != server.end(); idx++, i++) + if (findUUID(idx->first, uuid) < 0) + elig[i] = false; +} + +bool SDPManager::isInList(unsigned short id, const unsigned char* list, int end) { + int len; + for (unsigned pos = 0; pos < end; pos += len) { + len = length(list, pos); + switch (len) { + case 2: //single value + if (getval(list+pos, 2) == id) + return true; + break; + case 4: //range + if (getval(list+pos, 2) > id) break; + if (getval(list+pos+2, 2) < id) break; + return true; + default: + printf("Unexpected length %d\n", len); + } + } + return false; +} + +void SDPManager::addToReply(sdp_data *svc, serv_rec *list, const unsigned char* att, int end) { + unsigned short len, low, high; + serv_rec::iterator from, to, idx; + for (unsigned pos = 0; pos < end; pos += len) { + len = length(att, pos); + switch (len) { + case 2: //single value + low = getval(att+pos, 2); + svc->add_element(new sdp_data(low, 2)); + svc->add_element((*list)[low]); + printf("Found attrib %d\n", low); + break; + case 4: //range + low = getval(att+pos, 2); + high = getval(att+pos+2, 2); + from = list->lower_bound(low); + to = list->upper_bound(high); + for (idx = from; idx != to; idx++) { + svc->add_element(new sdp_data(idx->first, 2)); + svc->add_element(idx->second); + printf("Found attrib %d\n", idx->first); + } + break; + default: + printf("Unexpected length %d\n", len); + } + } +} + +//for continuations, just generate the entire list, truncate to desired length and append position of the remainder as continuation +//on the next iteration, generate the list again, use continuation to find remainder and reiterate +void SDPManager::SDPServer(int socket, SocketState state, const u8* data, int len, void* userData) { + unsigned tid = data[2] + ((unsigned)data[1]<<8); + unsigned parlen = data[4] + ((unsigned)data[3]<<8); + //printf("ParseReq: PDU_ID=%d, tid=%04X, parlen=%d ", data[0], tid, parlen); + unsigned pos = 5; + switch (data[0]) { + case 1: {//errorRsp + unsigned errorcode = data[6] + ((unsigned)data[5]<<8); + if (parlen > 2) { + printf("ErrorInfo (%d bytes) for error %d is available\n", parlen-2, errorcode); + } + errorhandler(errorcode); + } + break; + case 2: { //servicesearchReq + } + break; + case 4: { //serviceattributeReq + } + break; + case 6: { //servicesearchattributeReq + sdp_data reply(sdp_data::SEQUENCE);//the attributelist of the reply + + unsigned pat[12];//the received search pattern + int pn;//number of uuids in the pattern + if (data[pos]>>3 != sdp_data::SEQUENCE) {//the uuids are wrapped in a sequence + printf("Expected a sequence of UUIDs\n"); + break; + } + unsigned end = pos + length(data, pos);//get the length of the list of lists and advance pos to the first list + bool *eligible = new bool[server.size()];//marks for the services identified by the search pattern + for (int i = 0; i < server.size(); i++) eligible[i] = true; + for (pn = 0; pn < 12 && pos < end; pn++) { + pat[pn] = parseUUID(data,end, pos);//store uuid from the sequence in the pattern + match(eligible, pat[pn]);//unmark a service when it does not contain the uuid + //printf("pos=%d, count=%d, uuid=%#X\n", pos, len, pat[pn]); + } + + unsigned count = getval(data+pos, 2); //maximum length of attribute list to return + pos += 2; + + int len = length(data, pos); //get the length of the attributeID list + int cont = pos + len; + //printf("Count = %d pos=%d, data[pos]=%02x, len=%d, cont=%d\n", count, pos, data[pos], len, cont); + int i = 0; + for (map<unsigned, serv_rec*>::iterator idx = server.begin(); idx != server.end(); idx++, i++) {//foreach service + //printf("testing service handle %08X\n", idx->first); + if (!eligible[i]) continue; //skip services that don't match the pattern + sdp_data *svc = new sdp_data(sdp_data::SEQUENCE); //create a sequence for the attributes of the present service +#if 0 + for (serv_rec::iterator attr = idx->second->begin(); attr != idx->second->end(); attr++) {//foreach attrib in the service + //printf("testing attribID %u\n", attr->first); + if (isInList(attr->first, data+pos, len)) {//check if it is requested + printf("Found attribID %d\n", attr->first); + sdp_data *p = attr->second; //the attribute + svc->add_element(new sdp_data(attr->first, 2)); //add the attribute ID as an unsigned short + svc->add_element(p); //add the attribute + //printf("appending %d bytes\n", p->Size()); + } + } +#else +//alternatively use map::lower/upper_bound and equal_range, needs only one pass over the range list for each service + addToReply(svc, idx->second, data+pos, len); +#endif + reply.add_element(svc); //append the new attribute list to the reply list + } + + unsigned tail = data[cont]; + if (tail) { + tail = getval(data+cont+1, tail); + printf("requested continuation tailpos=%u, size=%u\n", tail, reply.Size()); + } + else { + //printf("No continuation requested\n"); + } + ServiceSearchAttributeReply(tid, &reply, count, tail); + + for (int j = 0; j < reply.items(); j++) { + sdp_data *al = reply.item(j); + for (int k = 0; k < al->items(); k++) { + if ((k & 1) == 0) //even hence ID + delete al->item(k); //destroy the ID + al->remove(k); //set all items to nil to prevent destruction of the DB + } + delete al; //destroy the list; + reply.remove(j); + } + delete[] eligible; + } + break; + default: + printf("Unknown SDP request type %02X\n", data[0]); + break; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/myBlueUSB/sdp/sdp.h Wed Jun 15 19:12:25 2011 +0000 @@ -0,0 +1,184 @@ +#ifndef SDP_H +#define SDP_H +#include "AvailableMemory.h" +#include "sdp_data.h" +#include <map> +#define OFFSET 8 + +class SDPManager; +extern SDPManager SDP; +typedef map<unsigned short, sdp_data*> serv_rec; + +void attribHandler(serv_rec *r); +unsigned parseUUID(const u8* data, int len, unsigned &p); +unsigned length(const unsigned char *el, unsigned &p); +unsigned getval(const unsigned char *p, int n) ; +void errorhandler(unsigned err);//default error handler + + +class SDPHandler: public SocketHandler { +// int _l2cap; + int sdp_socket; + unsigned char l2cap_buf[100+OFFSET]; + unsigned char* buf; + unsigned txid; + unsigned char contState[17];//maximum size, in practive it is 3 + unsigned char *contBuf; + unsigned byteCount; + int _state; + sdp_data *tree;//root of the entire service tree + map<unsigned, serv_rec*> services;//the set of supported services <handle, service> + map<unsigned, serv_rec*>::iterator index; +//server properties +// static map<unsigned, serv_rec*> server; +// static int serverSock; +public: + SDPHandler(); + void Clear(); + virtual int Open(SocketInternal* sock, SocketAddrHdr* addr); +// virtual int Accept(SocketInternal *sock, int scid, int rxid); //called indirectly from BTDevice::Control + virtual int Send(SocketInternal* sock, const u8* data, int len); + virtual int Close(SocketInternal* sock); + virtual char* Name() { + return "SDPHandler SocketHandler"; + } + void OnSdpRsp(const u8* data, int len); + static void OnSdpRsp(int socket, SocketState state, const u8* data, int len, void* userData); + + //this function is called when the SDP sockets receives data (see HCICallback in TestShell), + //currently does not happen because not forwarded from OnSdpRsp, can be used to handle multiple connections + static void OnSockCallback(int socket, SocketState state, const u8* data, int len, void* userData) ; + //The SDP server is stateless hence can be static +// static void SDPServer(int socket, SocketState state, const u8* data, int len, void* userData) ; + + void (*ErrorResponse)(unsigned) ; + void (*ServiceSearchResponse)() ; + void (*ServiceAttributeResponse)(serv_rec*) ; + void (*ServiceSearchAttributeResponse)() ; + int ServiceSearchRequest(sdp_data *sp, unsigned count, unsigned cs=0); + int ServiceAttributeRequest(unsigned handle, unsigned count, sdp_data* al, unsigned cs=0) ; + int ServiceSearchAttributeRequest(sdp_data *sp, unsigned count, sdp_data* al, unsigned cs=0); +//server +// static int ServiceSearchAttributeReply(unsigned rxid, sdp_data* al, unsigned count, unsigned cs=0); +private: +// static unsigned length(const unsigned char *el, unsigned &p); +// static unsigned getval(const unsigned char *p, int n) ; +// static unsigned parseUUID(const u8* data, int len, unsigned &p); + unsigned parse (const unsigned char *el, unsigned count, sdp_data* &result, serv_rec* &record) ; + unsigned parseLight (const unsigned char *el, unsigned count, sdp_data* &result, serv_rec* &record) ; + int parseRsp(const unsigned char*rsp, int len) ; + void append(const unsigned char*rsp, int len) ; + void freeBuf(); +}; +/* +class SDPClient: public SDPHandler { +}; + +class SDPServer: public SDPHandler { +}; +*/ +class SDPManager: public SocketHandler { + map<int, SDPHandler*> handlers; +//server properties +// SDPHandler *Server; + static map<unsigned, serv_rec*> server; + static int serverSock; + bool once; +public: + SDPManager() { + once = true; + } + virtual int Open(SocketInternal* sock, SocketAddrHdr* addr) { + printf("SDPManager::Open(sock (ID=%d, type=%d), addr): should not be called\n", sock->ID, sock->Type); + return sock->ID;//((SDPHandler*)sock->userData)->Open(sock, addr); + } + int Open(SocketAddrHdr* addr) { + L2CAPAddr* ad = (L2CAPAddr*)addr; + ad->psm = L2CAP_PSM_SDP;//open the l2cap channel + SDPHandler *h = new SDPHandler; + int s = Socket_Open(SOCKET_L2CAP, addr, &SDPHandler::OnSdpRsp, h); + handlers[s] = h; + return s; + } + virtual int Accept(SocketInternal *sock, int scid, int rxid) { //called indirectly from BTDevice::Control + if (once) { + once = false; + buildServer();//build the DB on the first connection + } + //sock is registered as an SDP sock but we use it as an L2CAP sock + //type=SDP + //userData = BTDevice + //Internal = L2CAPSocket + BTDevice *l2cap = (BTDevice*)sock->userData; + //sock->dcid = scid + //sock->scid = something based on sock->ID + serverSock = sock->ID; + printf("Invoking accept on %p (%s) for sock %d and scid=%d\n", l2cap, l2cap->Name(), sock->ID, scid); + return l2cap->Accept(sock, scid, rxid); + } + virtual int Send(SocketInternal* sock, const u8* data, int len) {//called by the server + BTDevice *l2cap = (BTDevice*)sock->userData; + return l2cap->Send(sock, data, len); + } + virtual int Close(SocketInternal* sock) { + printf("SDPManager::Close() closing socket %d\n", sock->ID); + SDPHandler *h = handlers[sock->ID]; + int retval = h->Close(sock); + delete h; + handlers[sock->ID] = 0; + return retval; + } + void Destroy(int s) { + printf("Deleting handler for socket %d\n", s); + delete handlers[s]; + handlers[s] = 0; + } + virtual char* Name() { + return "SDPManager SocketHandler"; + } + //void OnSdpRsp(const u8* data, int len); + static void OnSdpRsp(int socket, SocketState state, const u8* data, int len, void* userData) { + printf("SDPManager::OnSdpRsp(socket %d, state %d, len %d)\n", socket, state, len); + } + //The SDP server is (almost) stateless hence can be static + static void SDPServer(int socket, SocketState state, const u8* data, int len, void* userData) ; + static void match(bool elig[], unsigned uuid); + static bool isInList(unsigned short id, const unsigned char* list, int end); + static void addToReply(sdp_data *svc, serv_rec *list, const unsigned char* att, int end); + static int findUUID(unsigned h, unsigned uuid); + void buildServer(); + static int ServiceSearchAttributeReply(unsigned rxid, sdp_data* al, unsigned count, unsigned cs=0); + /* + //this function is called when the SDP sockets receives data (see HCICallback in TestShell), + //currently does not happen because not forwarded from OnSdpRsp, can be used to handle multiple connections + static void OnSockCallback(int socket, SocketState state, const u8* data, int len, void* userData) ; + + static void errorhandler(unsigned err); + + void (*ErrorResponse)(unsigned) ; + void (*ServiceSearchResponse)() ; + void (*ServiceAttributeResponse)(serv_rec*) ; + void (*ServiceSearchAttributeResponse)() ; + int ServiceSearchRequest(sdp_data *sp, unsigned count, unsigned cs=0); + int ServiceAttributeRequest(unsigned handle, unsigned count, sdp_data* al, unsigned cs=0) ; + int ServiceSearchAttributeRequest(sdp_data *sp, unsigned count, sdp_data* al, unsigned cs=0); + //server + private: + static unsigned length(const unsigned char *el, unsigned &p); + static unsigned getval(const unsigned char *p, int n) ; + static unsigned parseUUID(const u8* data, int len, unsigned &p); + static void addAttrib(unsigned h, unsigned short id, sdp_data *attrib); + static void addIndex(unsigned h, unsigned uuid); + static int findUUID(unsigned h, unsigned uuid); + static void match(bool elig[], unsigned uuid); + static bool isInList(unsigned short id, const unsigned char* list, int end); + void buildServer(); + unsigned parse (const unsigned char *el, unsigned count, sdp_data* &result, serv_rec* &record) ; + unsigned parseLight (const unsigned char *el, unsigned count, sdp_data* &result, serv_rec* &record) ; + int parseRsp(const unsigned char*rsp, int len) ; + void append(const unsigned char*rsp, int len) ; + void freeBuf(); + */ +}; + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/myBlueUSB/sdp/sdp_data.cpp Wed Jun 15 19:12:25 2011 +0000 @@ -0,0 +1,229 @@ +#include "mbed.h" +#include "sdp_data.h" +#include "Utils.h" + +char sdp_data::ret[12]; + +unsigned sdp_data::asUnsigned() { + switch (type) { + case NULL_: + return 0; + case UNSIGNED: + case SIGNED: + case BOOL: + return data; + case UUID: +#ifdef LONGUUID + return uuid[6] + uuid[7]<<16; +#else + return data; +#endif + default: + return 0; + } +} + +const char* sdp_data::asString(bool alt) { + char sep = ','; + switch (type) { + case NULL_: + return "NULL"; + case UNSIGNED: + if (alt) sprintf(ret, "0x%0*X", size*2, data); + else sprintf(ret, "%u", data); + return ret; + case SIGNED: + sprintf(ret, "%d", data); + return ret; + case BOOL: + return data ? "TRUE" : "FALSE"; + case STRING: + case URL: + return str; + case ALTERNATIVE: + sep = '|'; + case SEQUENCE: { + if (longstr) delete[] longstr; + int n = sprintf(ret, "SEQ %d { ", size) + 1; + longstr = new char[n]; + strcpy(longstr, ret); + for (int i = 0; i < sequence.size(); i++) { + const char *s = sequence[i]->asString(alt); + n = strlen(longstr) + strlen(s) + 2; + char *t = new char[n]; + strcpy(t, longstr); + strcat(t, s); + t[n-2] = sep; + t[n-1]='\0'; + //printf("[%s]+[%s]+%c=[%s]\n", longstr, s, sep, t); + delete[] longstr; + longstr = t; + } + longstr[n-2] = '}'; + } + return longstr; + case UUID: +#ifdef LONGUUID + switch (size) { + case 2: + sprintf(ret, "0x%04X", uuid[6]); + return ret; + case 4: + sprintf(ret, "0x%04X%04X", uuid[7],uuid[6]); + return ret; + case 16: + longstr = new char[35]; + sprintf(longstr, "%04X%04X-%04X-%04X-%04X-%04X%04X%04X", uuid[7],uuid[6],uuid[5],uuid[4],uuid[3],uuid[2],uuid[1],uuid[0]); + return longstr; + } +#else + switch (size) { + case 2: + sprintf(ret, "0x%04X", data & 0xffff); + return ret; + case 4: + sprintf(ret, "0x%08X", data); + return ret; + case 16: + longstr = new char[35]; + sprintf(longstr, "%08X-%04X-%04X-%04X-%04X%04X%04X", data,base_uuid[5],base_uuid[4],base_uuid[3],base_uuid[2],base_uuid[1],base_uuid[0]); + return longstr; + } +#endif + } + return "Unsupported"; +} + +unsigned sdp_data::Size() { + if (size==0 && type==SEQUENCE) + return 2; + if (size<3 || size==4 || size==8 || size==16) + return size+1;//include descriptor + if (size < 256) return size+2; //1 extra byte + if (size < 65536) return size+3; //2 extra bytes + return size+5; //4 extra bytes +} + +unsigned sdp_data::sizedesc(unsigned char *buf) { + int desc, extra=0; + switch (size) { + case 0: + /* should be: + if (type != NULL_) { + desc = 5; + extra = 1; + buf[1] = 0; + } + */ + case 1: + desc = 0; + break; + case 2: + desc = 1; + break; + case 4: + desc = 2; + break; + case 8: + desc = 3; + break; + case 16: + desc = 4; + break; + default: + if (size < 256) { + desc = 5; + extra = 1; + buf[1] = size; + } else if (size < 65536) { + desc = 6; + extra = 2; + *(unsigned short*)&buf[1] = size; + } else { + desc = 7; + extra = 4; + *(unsigned*)&buf[1] = size; + } + } + buf[0] |= desc; + return extra+1; +} + +void sdp_data::revcpy(unsigned char*d, const unsigned char*s, int n) { + for (int i = 0; i < n; i++) + d[i] = s[n-i-1]; +} + +unsigned sdp_data::build(unsigned char *buf, unsigned max) {//max is ignored + int p = 0; + buf[p] = type<<3; + switch (type) { + case NULL_: + p++; + break; + case UNSIGNED: + case SIGNED: + case BOOL: + p += sizedesc(buf+p); + revcpy(buf+p, (unsigned char*)&data, size); + break; + case UUID: + p += sizedesc(buf+p); +#ifdef LONGUUID + switch (size) { + case 2: + case 4: + revcpy(buf+p, (unsigned char*)&uuid[6], size); + break; + case 16: + revcpy(buf+p, (unsigned char*)uuid, size); + break; + } +#else + switch (size) { + case 2: + case 4: + revcpy(buf+p, (unsigned char*)&data, size); + break; + case 16: + revcpy(buf+p, (unsigned char*)&data, 4); + revcpy(buf+p+4, base_uuid, 12); + break; + } +#endif + break; + case STRING: + case URL: + p += sizedesc(buf+p); + memcpy(buf+p, str, size); + break; + case SEQUENCE: + case ALTERNATIVE: { + if (sequence.size()==0) {//hack: should be solved in sizedesc + buf[p++] |= 5; + buf[p++] = 0; + break; + } + int n = 0; + p += sizedesc(buf+p); + for (int i = 0; i < sequence.size(); i++) + n += sequence.at(i)->build(buf+p+n, max-p); + } + break; + } + p += size; +// printfBytes("Build:", buf, p); + return p; +} + +bool sdp_data::findUUID(unsigned uuid) { + if (type == UUID) + return asUnsigned()==uuid; + if (type==SEQUENCE || type==ALTERNATIVE) { + for (int i = 0; i < sequence.size(); i++) { + if (sequence[i]->findUUID(uuid)) + return true; + } + } + return false; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/myBlueUSB/sdp/sdp_data.h Wed Jun 15 19:12:25 2011 +0000 @@ -0,0 +1,116 @@ +#ifndef SDP_DATA_H +#define SDP_DATA_H + +#include <vector> + +extern const unsigned char base_uuid[16];// = { 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0, 0x07, 0x70, 0, 0x10, 0, 0}; + +class sdp_data { +public: + enum elements { NULL_, UNSIGNED, SIGNED, UUID, STRING, BOOL, SEQUENCE, ALTERNATIVE, URL}; +private: + enum elements type; + char size; + union { + unsigned data; + char *str; +#ifdef LONGUUID + unsigned short uuid[8]; +#endif + }; + vector<sdp_data*> sequence; //not allowed to be in union + static char ret[12]; + char *longstr; +public: + sdp_data(): type(NULL_), size(0), longstr(0) { + //printf("NULL%d ", size); + } + sdp_data(unsigned d, unsigned sz=4): type(UNSIGNED), size(sz), longstr(0) { + data=d; + //printf("UINT%d=%u ", size, data); + } + sdp_data(unsigned short d, unsigned sz=2): type(UNSIGNED), size(sz), longstr(0) { + data=d; + //printf("UINT%d=%u ", size, data); + } + sdp_data(signed d, unsigned sz=4): type(SIGNED), size(sz), longstr(0) { + data=d; + //printf("INT%d=%d ", size, data); + } + sdp_data(bool d, unsigned sz=1): type(BOOL), size(sz), longstr(0) { + data=d; + //printf("BOOL%d=%u ", size, data); + } + sdp_data(char*s, unsigned sz=0): type(STRING), longstr(0) { + if (sz) size = sz+1; + else size = strlen(s)+1; + str = new char[size]; + strncpy(str, s, size); + str[size-1] = '\0'; + //printf("STR%d='%s' ", size, str); + } + sdp_data(enum elements t, unsigned d, unsigned sz=2): type(t), size(sz), longstr(0) { + if (t==UUID) { +#ifdef LONGUUID + memcpy(uuid, base_uuid, 16); + uuid[6] = d; + uuid[7] = d>>16; + // printf("UUID%d=%04X%04X ", size, uuid[7], uuid[6]); +#else + data = d; +#endif + } else printf("Please use other constructor for type %d\n", t); + } + sdp_data(enum elements t, char *d=0, unsigned sz=0): type(t), size(sz), longstr(0) { + switch (t) { +#ifdef LONGUUID + case UUID: + memcpy(uuid, d, size); + // printf("UUID%d=%08X ", size, uuid[6]); + break; +#endif + case URL: + //size = strlen(d)+1; + str = new char[size+1]; + strcpy(str, d); + // printf("URL%d='%u' ", size, str); + break; + case SEQUENCE: + case ALTERNATIVE: + break; + default: + printf("Please use other constructor for type %d\n", t); + } + } + ~sdp_data() { + switch (type) { + case STRING: + case URL: + delete[] str; + break; + case SEQUENCE: + case ALTERNATIVE: + for (int i = 0; i < sequence.size(); i++) + delete sequence.at(i); + break; + } + if (longstr) + delete[] longstr; + } + void add_element(sdp_data *el) { + sequence.push_back(el); + size += el->Size(); + } + unsigned asUnsigned() ; + const char* asString(bool alt=false) ; + unsigned Size() ; + unsigned items() { return sequence.size();} + sdp_data* item(int i) { return sequence[i];} + void remove(int i) { sequence[i] = 0;} + unsigned sizedesc(unsigned char *buf) ; + void revcpy(unsigned char*d, const unsigned char*s, int n) ; + unsigned build(unsigned char *buf, unsigned max) ; + bool findUUID(unsigned uuid); +}; + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/myUSBHost/AutoEvents.cpp Wed Jun 15 19:12:25 2011 +0000 @@ -0,0 +1,181 @@ + +/* +Copyright (c) 2010 Peter Barrett + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "mbed.h" +#include "USBHost.h" +#include "Utils.h" +#include "ftusb.h" + +#define AUTOEVT(_class,_subclass,_protocol) (((_class) << 16) | ((_subclass) << 8) | _protocol) +#define AUTO_KEYBOARD AUTOEVT(CLASS_HID,1,1) +#define AUTO_MOUSE AUTOEVT(CLASS_HID,1,2) +#define AUTO_SERIAL AUTOEVT(CLASS_COMM_AND_CDC_CONTROL,2,1) + +u8 auto_mouse[4]; // buttons,dx,dy,scroll +u8 auto_keyboard[8]; // modifiers,reserved,keycode1..keycode6 +u8 auto_joystick[4]; // x,y,buttons,throttle +u8 auto_serial[8]; //connection speed change structure or uart state bitmap + +void AutoEventCallback(int device, int endpoint, int status, u8* data, int len, void* userData) +{ + int evt = (int)userData; + switch (evt) + { + case AUTO_KEYBOARD: + printf("AUTO_KEYBOARD "); + break; + case AUTO_MOUSE: + printf("AUTO_MOUSE "); + break; + case AUTO_SERIAL: + printf("AUTO_SERIAL %02X", status); + break; + default: + printf("HUH "); + } + printfBytes("data",data,len); + USBInterruptTransfer(device,endpoint,data,len,AutoEventCallback,userData); +} + +// Establish transfers for interrupt events +void AddAutoEvent(int device, InterfaceDescriptor* id, EndpointDescriptor* ed) +{ + if ((ed->bmAttributes & 3) != ENDPOINT_INTERRUPT || !(ed->bEndpointAddress & 0x80)) + return; + + // Make automatic interrupt enpoints for known devices + u32 evt = AUTOEVT(id->bInterfaceClass,id->bInterfaceSubClass,id->bInterfaceProtocol); + u8* dst = 0; + int len; + switch (evt) + { + case AUTO_MOUSE: + dst = auto_mouse; + len = sizeof(auto_mouse); + break; + case AUTO_KEYBOARD: + dst = auto_keyboard; + len = sizeof(auto_keyboard); + break; + case AUTO_SERIAL: + dst = auto_serial; + len = sizeof(auto_serial); + break; + default: + printf("Interrupt endpoint %02X %08X\n",ed->bEndpointAddress,evt); + break; + } + if (dst) + { + printf("Auto Event for %02X %08X\n",ed->bEndpointAddress,evt); + USBInterruptTransfer(device,ed->bEndpointAddress,dst,len,AutoEventCallback,(void*)evt); + } +} + +void PrintString(int device, int i) +{ + u8 buffer[256]; + int le = GetDescriptor(device,DESCRIPTOR_TYPE_STRING,i,buffer,255); + if (le < 0) + return; + char* dst = (char*)buffer; + for (int j = 2; j < le; j += 2) + *dst++ = buffer[j]; + *dst = 0; + printf("%d:%s\n",i,(const char*)buffer); + } + +// Walk descriptors and create endpoints for a given device +int StartAutoEvent(int device, int configuration, int interfaceNumber) +{ + u8 buffer[255]; + int err = GetDescriptor(device,DESCRIPTOR_TYPE_CONFIGURATION,0,buffer,255); + if (err < 0) + return err; + + int len = buffer[2] | (buffer[3] << 8); + u8* d = buffer; + u8* end = d + len; + while (d < end) + { + if (d[1] == DESCRIPTOR_TYPE_INTERFACE) + { InterfaceDescriptor* id = (InterfaceDescriptor*)d; + /*printf("StartAutoEvent device %d, interfaceDescriptor(T=%d, N=%d, C=%02X, S=%02X, P=%02X)\n", + device, id->bDescriptorType, id->bInterfaceNumber, id->bInterfaceClass, id->bInterfaceSubClass, id->bInterfaceProtocol); + */ + if (id->bInterfaceNumber == interfaceNumber) + { + d += d[0]; + while (d < end && d[1] != DESCRIPTOR_TYPE_INTERFACE) + { + if (d[1] == DESCRIPTOR_TYPE_ENDPOINT) + AddAutoEvent(device,id,(EndpointDescriptor*)d); + d += d[0]; + } + } + } + d += d[0]; + } + return 0; +} + +// Implemented in main.cpp +int OnDiskInsert(int device); + +void OnLoadDevice(int device, DeviceDescriptor* deviceDesc, InterfaceDescriptor* interfaceDesc) +{ + printf("LoadDevice %d %02X:%02X:%02X\n",device,interfaceDesc->bInterfaceClass,interfaceDesc->bInterfaceSubClass,interfaceDesc->bInterfaceProtocol); + char s[128]; + for (int i = 1; i < 3; i++) + { + if (GetString(device,i,s,sizeof(s)) < 0) + break; + printf("%d: %s\n",i,s); + } + + if (deviceDesc->idVendor == 0x146A || deviceDesc->idVendor == 0x221D) {//Knobloch GMBH or MSC Vertrieb + OnLoadFtDevice(device, deviceDesc, interfaceDesc); + return; + } + switch (interfaceDesc->bInterfaceClass) + { + case CLASS_MASS_STORAGE: + if (interfaceDesc->bInterfaceSubClass == 0x06 && interfaceDesc->bInterfaceProtocol == 0x50) + OnDiskInsert(device); // it's SCSI! + break; + case CLASS_COMM_AND_CDC_CONTROL: + if (interfaceDesc->bInterfaceSubClass == 0x02 && interfaceDesc->bInterfaceProtocol == 0x01){ + printf("Found serial device\n"); + //OnSerialInsert(device); + StartAutoEvent(device,1,0); + } + break; + case CLASS_WIRELESS_CONTROLLER: + if (interfaceDesc->bInterfaceSubClass == 0x01 && interfaceDesc->bInterfaceProtocol == 0x01) + OnBluetoothInsert(device); // it's bluetooth! + break; + default: + StartAutoEvent(device,1,0); + break; + } +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/myUSBHost/MassStorage.cpp Wed Jun 15 19:12:25 2011 +0000 @@ -0,0 +1,180 @@ + +/* +Copyright (c) 2010 Peter Barrett + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "stdlib.h" +#include "stdio.h" +#include "string.h" + +#include "Utils.h" +#include "USBHost.h" + + +int MassStorage_ReadCapacity(int device, u32* blockCount, u32* blockSize); +int MassStorage_ReadBlock(int device, u32 block, u8* dst); +int MassStorage_WriteBlock(int device, u32 block, const u8* dst); + + +#define ERR_BAD_CSW_SIGNATURE -200 + +#define CBW_SIGNATURE 0x43425355 +#define CSW_SIGNATURE 0x53425355 + +// Command Block +typedef struct +{ + u32 Signature; + u32 Tag; + u32 TransferLength; + u8 Flags; + u8 LUN; + u8 CBLength; + u8 CB[16]; // only 6 really +} CBW; + +// Status block +typedef struct +{ + u32 Signature; + u32 Tag; + u32 DataResidue; + u8 Status; +} CSW; + +int SCSIRequestSense(int device); + +int DoSCSI(int device, const u8* cmd, int cmdLen, int flags, u8* data, u32 transferLen) +{ + CBW cbw; + cbw.Signature = CBW_SIGNATURE; + cbw.Tag = 0; + cbw.TransferLength = transferLen; + cbw.Flags = flags; + cbw.LUN = 0; + cbw.CBLength = cmdLen; + memset(cbw.CB,0,sizeof(cbw.CB)); + memcpy(cbw.CB,cmd,cmdLen); + + int r; + r = USBBulkTransfer(device,0x01,(u8*)&cbw,31); // Send the command + if (r < 0) + return r; + + if (data) + { + r = USBBulkTransfer(device,flags | 1,data,transferLen); + if (r < 0) + return r; + } + + CSW csw; + csw.Signature = 0; + r = USBBulkTransfer(device,0x81,(u8*)&csw,13); + if (r < 0) + return r; + + if (csw.Signature != CSW_SIGNATURE) + return ERR_BAD_CSW_SIGNATURE; + + // ModeSense? + if (csw.Status == 1 && cmd[0] != 3) + return SCSIRequestSense(device); + + return csw.Status; +} + +int SCSITestUnitReady(int device) +{ + u8 cmd[6]; + memset(cmd,0,6); + return DoSCSI(device,cmd,6,DEVICE_TO_HOST,0,0); +} + +int SCSIRequestSense(int device) +{ + u8 cmd[6] = {0x03,0,0,0,18,0}; + u8 result[18]; + int r = DoSCSI(device,cmd,6,DEVICE_TO_HOST,result,18); + return r; +} + +int SCSIInquiry(int device) +{ + u8 cmd[6] = {0x12,0,0,0,36,0}; + u8 result[36+2]; + result[36] = '\n'; + result[37] = 0; + int r = DoSCSI(device,cmd,6,DEVICE_TO_HOST,result,36); + if (r == 0) + printf((const char*)result + 8); + return r; +} + +int SCSIReadCapacity(int device, u32* blockCount, u32* blockSize) +{ + u8 cmd[10] = {0x25,0,0,0,8,0,0,0,0,0}; + u8 result[8]; + *blockSize = 0; + *blockCount = 0; + int r = DoSCSI(device,cmd,10,DEVICE_TO_HOST,result,8); + if (r == 0) + { + *blockCount = BE32(result); + *blockSize = BE32(result+4); + } + return r; +} + +int SCSITransfer(int device, u32 blockAddr, u32 blockCount, u8* dst, u32 blockSize, int direction) +{ + // USB hardware will only do 4k per transfer + while (blockCount*blockSize > 4096) + { + int count = 4096/blockSize; + int r = SCSITransfer(device,blockAddr,count,dst,blockSize,direction); + dst += count*blockSize; + blockAddr += count; + blockCount -= count; + } + + u8 cmd[10]; + memset(cmd,0,10); + cmd[0] = (direction == DEVICE_TO_HOST) ? 0x28 : 0x2A; + BE32(blockAddr,cmd+2); + BE16(blockCount,cmd+7); + return DoSCSI(device,cmd,10,direction,dst,blockSize*blockCount); +} + +int MassStorage_ReadCapacity(int device, u32* blockCount, u32* blockSize) +{ + return SCSIReadCapacity(device,blockCount,blockSize); +} + +int MassStorage_Read(int device, u32 blockAddr, u32 blockCount, u8* dst, u32 blockSize = 512) +{ + return SCSITransfer(device,blockAddr,blockCount,dst,blockSize,DEVICE_TO_HOST); +} + +int MassStorage_Write(int device, u32 blockAddr, u32 blockCount, u8* dst, u32 blockSize = 512) +{ + return SCSITransfer(device,blockAddr,blockCount,dst,blockSize,HOST_TO_DEVICE); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/myUSBHost/USBHost.cpp Wed Jun 15 19:12:25 2011 +0000 @@ -0,0 +1,1076 @@ + +/* +Copyright (c) 2010 Peter Barrett + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "mbed.h" +#include "USBHost.h" + +// Config (default uses x bytes) +#define MAX_DEVICES 8 // Max number of devices +#define MAX_ENDPOINTS_TOTAL 16 // Max number of endpoints total +#define MAX_ENDPOINTS_PER_DEVICE 8 // Max number of endpoints for any one device + +#define USBLOG 1 +#if USBLOG +#define LOG(...) printf(__VA_ARGS__) +#else +#define LOG(...) do {} while(0) +#endif + +// USB host structures + +#define USB_RAM_SIZE 16*1024 // AHB SRAM block 1 TODO MACHINE DEPENDENT +#define USB_RAM_BASE 0x2007C000 + +#define TOKEN_SETUP 0 +#define TOKEN_IN 1 +#define TOKEN_OUT 2 + +// Status flags from hub +#define PORT_CONNECTION 0 +#define PORT_ENABLE 1 +#define PORT_SUSPEND 2 +#define PORT_OVER_CURRENT 3 +#define PORT_RESET 4 +#define PORT_POWER 8 +#define PORT_LOW_SPEED 9 + +#define C_PORT_CONNECTION 16 +#define C_PORT_ENABLE 17 +#define C_PORT_SUSPEND 18 +#define C_PORT_OVER_CURRENT 19 +#define C_PORT_RESET 20 + +typedef struct { + u8 bm_request_type; + u8 b_request; + u16 w_value; + u16 w_index; + u16 w_length; +} Setup; + + +// Hub stuff is kept private just to keep api simple +int SetPortFeature(int device, int feature, int index); +int ClearPortFeature(int device, int feature, int index); +int SetPortPower(int device, int port); +int SetPortReset(int device, int port); +int GetPortStatus(int device, int port, u32* status); + +//=================================================================== +//=================================================================== +// Hardware defines + +// HcControl +#define PeriodicListEnable 0x00000004 +#define IsochronousEnable 0x00000008 +#define ControlListEnable 0x00000010 +#define BulkListEnable 0x00000020 +#define OperationalMask 0x00000080 +#define HostControllerFunctionalState 0x000000C0 + +// HcCommandStatus +#define HostControllerReset 0x00000001 +#define ControlListFilled 0x00000002 +#define BulkListFilled 0x00000004 + +// HcInterruptStatus Register +#define WritebackDoneHead 0x00000002 +#define StartofFrame 0x00000004 +#define ResumeDetected 0x00000008 +#define UnrecoverableError 0x00000010 +#define FrameNumberOverflow 0x00000020 +#define RootHubStatusChange 0x00000040 +#define OwnershipChange 0x00000080 +#define MasterInterruptEnable 0x80000000 + +// HcRhStatus +#define SetGlobalPower 0x00010000 +#define DeviceRemoteWakeupEnable 0x00008000 + +// HcRhPortStatus (hub 0, port 1) +#define CurrentConnectStatus 0x00000001 +#define PortEnableStatus 0x00000002 +#define PortSuspendStatus 0x00000004 +#define PortOverCurrentIndicator 0x00000008 +#define PortResetStatus 0x00000010 + +#define PortPowerStatus 0x00000100 +#define LowspeedDevice 0x00000200 +#define HighspeedDevice 0x00000400 + +#define ConnectStatusChange (CurrentConnectStatus << 16) +#define PortResetStatusChange (PortResetStatus << 16) + + +#define TD_ROUNDING (u32)0x00040000 +#define TD_SETUP (u32)0x00000000 +#define TD_IN (u32)0x00100000 +#define TD_OUT (u32)0x00080000 +#define TD_DELAY_INT(x) (u32)((x) << 21) +#define TD_TOGGLE_0 (u32)0x02000000 +#define TD_TOGGLE_1 (u32)0x03000000 +#define TD_CC (u32)0xF0000000 + +// HostController EndPoint Descriptor +typedef struct { + volatile u32 Control; + volatile u32 TailTd; + volatile u32 HeadTd; + volatile u32 Next; +} HCED; + +// HostController Transfer Descriptor +typedef struct { + volatile u32 Control; + volatile u32 CurrBufPtr; + volatile u32 Next; + volatile u32 BufEnd; +} HCTD; + +// Host Controller Communication Area +typedef struct { + volatile u32 InterruptTable[32]; + volatile u16 FrameNumber; + volatile u16 FrameNumberPad; + volatile u32 DoneHead; + volatile u8 Reserved[120]; +} HCCA; + +//==================================================================================== +//==================================================================================== + +class HostController; +class Endpoint; +class Device; + +// must be 3*16 bytes long +class Endpoint +{ +public: + HCED EndpointDescriptor; // Pointer to EndpointDescriptor == Pointer to Endpoint + HCTD TDHead; + + enum State + { + Free, + NotQueued, + Idle, + SetupQueued, + DataQueued, + StatusQueued, + CallbackPending + }; + + volatile u8 CurrentState; + u8 Flags; // 0x80 In, 0x03 mask endpoint type + + u16 Length; + u8* Data; + USBCallback Callback; // Must be a multiple of 16 bytes long + void* UserData; + + int Address() + { + int ep = (EndpointDescriptor.Control >> 7) & 0xF; + if (ep) + ep |= Flags & 0x80; + return ep; + } + + int Device() + { + return EndpointDescriptor.Control & 0x7F; + } + + int Status() + { + return (TDHead.Control >> 28) & 0xF; + } + + u32 Enqueue(u32 head) + { + if (CurrentState == NotQueued) + { + EndpointDescriptor.Next = head; + head = (u32)&EndpointDescriptor; + CurrentState = Idle; + } + return head; + } +}; + +class Device +{ +public: + u8 _endpointMap[MAX_ENDPOINTS_PER_DEVICE*2]; + u8 Hub; + u8 Port; + u8 Addr; + u8 Pad; + + // Only if this device is a hub + u8 HubPortCount; // nonzero if this is a hub + u8 HubInterruptData; + u8 HubMap; + u8 HubMask; + + int Flags; // 1 = Disconnected + + Setup SetupBuffer; + + // Allocate endpoint zero + int Init(DeviceDescriptor* d, int hub, int port, int addr, int lowSpeed) + { + Hub = hub; + Port = port; + Addr = addr; + Flags = lowSpeed; + memset(_endpointMap,0xFF,sizeof(_endpointMap)); + return 0; + } + + int SetEndpointIndex(int ep, int endpointIndex) + { + for (int i = 0; i < MAX_ENDPOINTS_PER_DEVICE*2; i += 2) + { + if (_endpointMap[i] == 0xFF) // Add endpoint to map + { + _endpointMap[i] = ep; + _endpointMap[i+1] = endpointIndex; + return 0; + } + } + return ERR_ENDPOINT_NONE_LEFT; + } + + int GetEndpointIndex(int ep) + { + for (int i = 0; i < MAX_ENDPOINTS_PER_DEVICE*2; i += 2) + { + if (_endpointMap[i] == ep) + return _endpointMap[i+1]; + if (_endpointMap[i] == 0xFF) + break; + } + return -1; + } +}; + +class HostController +{ +public: + HCCA CommunicationArea; + Endpoint Endpoints[MAX_ENDPOINTS_TOTAL]; // Multiple of 16 + + Endpoint EndpointZero; // For device enumeration + HCTD _commonTail; + Setup _setupZero; + + Device Devices[MAX_DEVICES]; + u32 _frameNumber; // 32 bit ms counter + + u8 _callbacksPending; // Endpoints with callbacks are pending, set from ISR via ProcessDoneQueue + u8 _rootHubStatusChange; // Root hub status has changed, set from ISR + u8 _unused0; + u8 _unused1; + + u8 _connectPending; // Reset has initiated a connect + u8 _connectCountdown; // Number of ms left after reset before we can connect + u8 _connectHub; // Will connect on this hub + u8 _connectPort; // ... and this port + + u8 SRAM[0]; // Start of free SRAM + + void Loop() + { + u16 elapsed = CommunicationArea.FrameNumber - (u16)_frameNumber; // extend to 32 bits + _frameNumber += elapsed; + + // Do callbacks, if any + while (_callbacksPending) + { + for (int i = 0; i < MAX_ENDPOINTS_TOTAL; i++) + { + Endpoint* endpoint = Endpoints + i; + if (endpoint->CurrentState == Endpoint::CallbackPending) + { + _callbacksPending--; + endpoint->CurrentState = Endpoint::Idle; + endpoint->Callback(endpoint->Device(),endpoint->Address(),endpoint->Status(),endpoint->Data,endpoint->Length,endpoint->UserData); + } + } + } + + // Deal with changes on the root hub + if (_rootHubStatusChange) + { + u32 status = LPC_USB->HcRhPortStatus1; + _rootHubStatusChange = 0; + if (status >> 16) + { + HubStatusChange(0,1,status); + LPC_USB->HcRhPortStatus1 = status & 0xFFFF0000; // clear status changes + } + } + + // Connect after reset timeout + if (_connectCountdown) + { + if (elapsed >= _connectCountdown) + { + _connectCountdown = 0; + Connect(_connectHub,_connectPort & 0x7F,_connectPort & 0x80); + } else + _connectCountdown -= elapsed; + } + } + + // HubInterrupt - bitmap in dev->HubInterruptData + void HubInterrupt(int device) + { + Device* dev = &Devices[device-1]; + for (int i = 0; i < dev->HubPortCount; i++) + { + int port = i+1; + if (dev->HubInterruptData & (1 << port)) + { + u32 status = 0; + GetPortStatus(device,port,&status); + if (status >> 16) + { + if (_connectPending && (status & ConnectStatusChange)) + continue; // Don't connect again until previous device has been added and addressed + + HubStatusChange(device,port,status); + if (status & ConnectStatusChange) + ClearPortFeature(device,C_PORT_CONNECTION,port); + if (status & PortResetStatusChange) + ClearPortFeature(device,C_PORT_RESET,port); + } + } + } + } + + static void HubInterruptCallback(int device, int endpoint, int status, u8* data, int len, void* userData) + { + HostController* controller = (HostController*)userData; + if (status == 0) + controller->HubInterrupt(device); + USBInterruptTransfer(device,endpoint,data,1,HubInterruptCallback,userData); + } + + int InitHub(int device) + { + u8 buf[16]; + int r= USBControlTransfer(device,DEVICE_TO_HOST | REQUEST_TYPE_CLASS | RECIPIENT_DEVICE,GET_DESCRIPTOR,(DESCRIPTOR_TYPE_HUB << 8),0,buf,sizeof(buf)); + if (r < 0) + return ERR_HUB_INIT_FAILED; + + // turn on power on the hubs ports + Device* dev = &Devices[device-1]; + int ports = buf[2]; + dev->HubPortCount = ports; + for (int i = 0; i < ports; i++) + SetPortPower(device,i+1); + + // Enable hub change interrupts + return USBInterruptTransfer(device,0x81,&dev->HubInterruptData,1,HubInterruptCallback,this); + } + + int AddEndpoint(int device, int ep, int attributes, int maxPacketSize, int interval) + { + LOG("AddEndpoint D:%02X A:%02X T:%02X P:%04X I:%02X\n",device,ep,attributes,maxPacketSize,interval); + Device* dev = &Devices[device-1]; + Endpoint* endpoint = AllocateEndpoint(device,ep,attributes,maxPacketSize); + if (!endpoint) + return ERR_ENDPOINT_NONE_LEFT; + dev->SetEndpointIndex(ep,endpoint - Endpoints); + endpoint->EndpointDescriptor.Control |= dev->Flags; // Map in slow speed + return 0; // TODO ed->bInterval + } + + int AddEndpoint(int device, EndpointDescriptor* ed) + { + return AddEndpoint(device,ed->bEndpointAddress,ed->bmAttributes,ed->wMaxPacketSize,ed->bInterval); + } + + // allocate a endpoint + Endpoint* AllocateEndpoint(int device, int endpointAddress, int type, int maxPacketSize) + { + for (int i = 0; i < MAX_ENDPOINTS_TOTAL; i++) + { + Endpoint* ep = &Endpoints[i]; + if (ep->CurrentState == 0) + { + //LOG("Allocated endpoint %d to %02X:%02X\n",i,device,endpointAddress); + ep->Flags = (endpointAddress & 0x80) | (type & 3); + ep->CurrentState = Endpoint::NotQueued; + ep->EndpointDescriptor.Control = (maxPacketSize << 16) | ((endpointAddress & 0x7F) << 7) | device; + return ep; + } + } + return 0; + } + + Endpoint* GetEndpoint(int device, int ep) + { + if (device == 0) + { + //printf("WARNING: USING DEVICE 0\n"); + return &EndpointZero; + } + if (device > MAX_DEVICES) + return 0; + int i = Devices[device-1].GetEndpointIndex(ep); + if (i == -1) + return 0; + return Endpoints + i; + } + + int Transfer(Endpoint* endpoint, int token, u8* data, int len, int state) + { + //LOG("Transfer %02X T:%d Len:%d S:%d\n",endpoint->Address(),token,len,state); + + int toggle = 0; + if (endpoint->Address() == 0) + toggle = (token == TOKEN_SETUP) ? TD_TOGGLE_0 : TD_TOGGLE_1; + + if (token != TOKEN_SETUP) + token = (token == TOKEN_IN ? TD_IN : TD_OUT); + + HCTD* head = &endpoint->TDHead; + HCTD* tail = &_commonTail; + + head->Control = TD_ROUNDING | token | TD_DELAY_INT(0) | toggle | TD_CC; + head->CurrBufPtr = (u32)data; + head->BufEnd = (u32)(data + len - 1); + head->Next = (u32)tail; + + HCED* ed = &endpoint->EndpointDescriptor; + ed->HeadTd = (u32)head | (ed->HeadTd & 0x00000002); // carry toggle + ed->TailTd = (u32)tail; + + //HCTD* td = head; + //LOG("%04X TD %08X %08X %08X Next:%08X\n",CommunicationArea.FrameNumber,td->Control,td->CurrBufPtr,td->BufEnd,td->Next); + //LOG("%04X ED %08X %08X %08X\n",CommunicationArea.FrameNumber,ed->Control,ed->HeadTd,ed->TailTd); + + switch (endpoint->Flags & 3) + { + case ENDPOINT_CONTROL: + LPC_USB->HcControlHeadED = endpoint->Enqueue(LPC_USB->HcControlHeadED); // May change state NotQueued->Idle + endpoint->CurrentState = state; // Get in before an int + LPC_USB->HcCommandStatus = LPC_USB->HcCommandStatus | ControlListFilled; + LPC_USB->HcControl = LPC_USB->HcControl | ControlListEnable; + break; + + case ENDPOINT_BULK: + LPC_USB->HcBulkHeadED = endpoint->Enqueue(LPC_USB->HcBulkHeadED); + endpoint->CurrentState = state; + LPC_USB->HcCommandStatus = LPC_USB->HcCommandStatus | BulkListFilled; + LPC_USB->HcControl = LPC_USB->HcControl | BulkListEnable; + break; + + case ENDPOINT_INTERRUPT: + CommunicationArea.InterruptTable[0] = endpoint->Enqueue(CommunicationArea.InterruptTable[0]); + endpoint->CurrentState = state; + LPC_USB->HcControl |= PeriodicListEnable; + break; + } + return 0; + } + + // Remove an endpoint from an active queue + bool Remove(HCED* ed, volatile HCED** queue) + { + if (*queue == 0) + return false; + if (*queue == (volatile HCED*)ed) + { + *queue = (volatile HCED*)ed->Next; // At head of queue + return true; + } + + volatile HCED* head = *queue; + while (head) + { + if (head->Next == (u32)ed) + { + head->Next = ed->Next; + return true; + } + head = (volatile HCED*)head->Next; + } + return false; + } + + void Release(Endpoint* endpoint) + { + if (endpoint->CurrentState == Endpoint::NotQueued) + { + // Never event used it, nothing to do + } + else + { + HCED* ed = (HCED*)endpoint; + ed->Control |= 0x4000; // SKIP + switch (endpoint->Flags & 0x03) + { + case ENDPOINT_CONTROL: + Remove(ed,(volatile HCED**)&LPC_USB->HcControlHeadED); + break; + case ENDPOINT_BULK: + Remove(ed,(volatile HCED**)&LPC_USB->HcBulkHeadED); + break; + case ENDPOINT_INTERRUPT: + for (int i = 0; i < 32; i++) + Remove(ed,(volatile HCED**)&CommunicationArea.InterruptTable[i]); + break; + } + + u16 fn = CommunicationArea.FrameNumber; + while (fn == CommunicationArea.FrameNumber) + ; // Wait for next frame + + } + + // In theory, the endpoint is now dead. + // TODO: Will Callbacks ever be pending? BUGBUG + memset(endpoint,0,sizeof(Endpoint)); + } + + // Pop the last TD from the list + HCTD* Reverse(HCTD* current) + { + HCTD *result = NULL,*temp; + while (current) + { + temp = (HCTD*)current->Next; + current->Next = (u32)result; + result = current; + current = temp; + } + return result; + } + + // Called from interrupt... + // Control endpoints use a state machine to progress through the transfers + void ProcessDoneQueue(u32 tdList) + { + HCTD* list = Reverse((HCTD*)tdList); + while (list) + { + Endpoint* endpoint = (Endpoint*)(list-1); + list = (HCTD*)list->Next; + int ep = endpoint->Address(); + bool in = endpoint->Flags & 0x80; + int status = (endpoint->TDHead.Control >> 28) & 0xF; + + //LOG("ProcessDoneQueue %02X %08X\n",ep,endpoint->TDHead.Control); + + if (status != 0) + { + LOG("ProcessDoneQueue status %02X %d\n",ep,status); + endpoint->CurrentState = Endpoint::Idle; + } else { + switch (endpoint->CurrentState) + { + case Endpoint::SetupQueued: + if (endpoint->Length == 0) + Transfer(endpoint,in ? TOKEN_OUT : TOKEN_IN,0,0,Endpoint::StatusQueued); // Skip Data Phase + else + Transfer(endpoint,in ? TOKEN_IN : TOKEN_OUT,endpoint->Data,endpoint->Length, Endpoint::DataQueued); // Setup is done, now Data + break; + + case Endpoint::DataQueued: + if (endpoint->TDHead.CurrBufPtr) + endpoint->Length = endpoint->TDHead.CurrBufPtr - (u32)endpoint->Data; + + if (ep == 0) + Transfer(endpoint,in ? TOKEN_OUT : TOKEN_IN,0,0,Endpoint::StatusQueued); // Data is done, now Status, Control only + else + endpoint->CurrentState = Endpoint::Idle; + break; + + case Endpoint::StatusQueued: // Transaction is done + endpoint->CurrentState = Endpoint::Idle; + break; + } + } + + // Complete, flag if we need a callback + if (endpoint->Callback && endpoint->CurrentState == Endpoint::Idle) + { + endpoint->CurrentState = Endpoint::CallbackPending; + _callbacksPending++; + } + } + } + + // Hack to reset devices that don't want to connect + int AddDevice(int hub, int port, bool isLowSpeed) + { + int device = AddDeviceCore(hub,port,isLowSpeed); + if (device < 0) + { + LOG("========RETRY ADD DEVICE========\n"); // This will go for ever.. TODO power cycle root? + Disconnect(hub,port); // Could not read descriptor at assigned address, reset this port and try again + ResetPort(hub,port); // Cheap bluetooth dongles often need this on a hotplug + return -1; + } + return device; + } + + int AddDeviceCore(int hub, int port, bool isLowSpeed) + { + int lowSpeed = isLowSpeed ? 0x2000 : 0; + DeviceDescriptor desc; + EndpointZero.EndpointDescriptor.Control = (8 << 16) | lowSpeed; // MaxPacketSize == 8 + int r = GetDescriptor(0,DESCRIPTOR_TYPE_DEVICE,0,(u8*)&desc,8); + if (r < 0) + { + LOG("FAILED TO LOAD DESCRIPTOR FOR DEVICE 0\n"); + return r; + } + + EndpointZero.EndpointDescriptor.Control = (desc.bMaxPacketSize << 16) | lowSpeed; // Actual MaxPacketSize + r = GetDescriptor(0,DESCRIPTOR_TYPE_DEVICE,0,(u8*)&desc,sizeof(desc)); + if (r < 0) + return r; + + LOG("\nClass %02X found %04X:%04X\n\n",desc.bDeviceClass,desc.idVendor,desc.idProduct); + + // Now assign the device an address, move off EndpointZero + int device = 0; + for (int i = 0; i < MAX_DEVICES; i++) + { + if (Devices[i].Port == 0) + { + device = i+1; + break; + } + } + if (!device) + return ERR_DEVICE_NONE_LEFT; + + r = SetAddress(0,device); + if (r) + return r; + DelayMS(2); + + // Now at a nonzero address, create control endpoint + Device* dev = &Devices[device-1]; + dev->Init(&desc,hub,port,device,lowSpeed); + AddEndpoint(device,0,ENDPOINT_CONTROL,desc.bMaxPacketSize,0); + _connectPending = 0; + + // Verify this all works + r = GetDescriptor(device,DESCRIPTOR_TYPE_DEVICE,0,(u8*)&desc,sizeof(desc)); + if (r < 0) + return r; + + // Set to interface 0 by default + // Calls LoadDevice if interface is found + r = SetConfigurationAndInterface(device,1,0,&desc); + + if (desc.bDeviceClass == CLASS_HUB) + InitHub(device); // Handle hubs in this code + + return device; + } + + // Walk descriptors and create endpoints for a given device + // TODO configuration !=1, alternate settings etc. + int SetConfigurationAndInterface(int device, int configuration, int interfaceNumber, DeviceDescriptor* desc) + { + u8 buffer[255]; + int err = GetDescriptor(device,DESCRIPTOR_TYPE_CONFIGURATION,0,buffer,sizeof(buffer)); + if (err < 0) + return err; + + err = SetConfiguration(device,configuration); + if (err < 0) + return err; + + // Add the endpoints for this interface + int len = buffer[2] | (buffer[3] << 8); + u8* d = buffer; + u8* end = d + len; + InterfaceDescriptor* found = 0; +// for (int i = 0; i < len; i++) printf(" %02X ", *(d+i)); printf("\n"); + while (d < end) + { + if (d[1] == DESCRIPTOR_TYPE_INTERFACE) + { + InterfaceDescriptor* id = (InterfaceDescriptor*)d; + if (id->bInterfaceNumber == interfaceNumber) + { + found = id; + d += d[0]; + while (d < end && d[1] != DESCRIPTOR_TYPE_CONFIGURATION)//changed by AvdW: was INTERFACE + { + switch (d[1]) + { + case DESCRIPTOR_TYPE_ENDPOINT: + AddEndpoint(device,(EndpointDescriptor*)d); + break; + case DESCRIPTOR_TYPE_INTERFACE: + LOG("Parsing interface %d descriptor (%d bytes)\n",d[2],d[0]); + break; + default: + LOG("Skipping descriptor %02X (%d bytes)\n",d[1],d[0]); + } + d += d[0]; + } + } + } + d += d[0]; + } + + if (!found) + return ERR_INTERFACE_NOT_FOUND; + OnLoadDevice(device,desc,found); + return 0; + } + + void Init() + { + LOG("USB INIT (Controller is %d bytes)\n",sizeof(*this)); + memset(this,0,sizeof(HostController)); + EndpointZero.CurrentState = Endpoint::NotQueued; + HWInit(&CommunicationArea); + DelayMS(10); + } + + void ResetPort(int hub, int port) + { + LOG("ResetPort Hub:%d Port:%d\n",hub,port); + _connectPending++; // Only reset/add 1 device at a time + if (hub == 0) + LPC_USB->HcRhPortStatus1 = PortResetStatus; // Reset Root Hub, port 1 + else + SetPortReset(hub,port); // or reset other hub + } + + void Disconnect(int hub, int port) + { + LOG("Disconnect Hub:%d Port:%d\n",hub,port); // Mark a device for destruction + for (int i = 0; i < MAX_DEVICES; i++) + { + Device* dev = Devices + i; + if (dev->Port == port && dev->Hub == hub) + { + // Disconnect everything that is attached to this device if it is a hub + for (int p = 0; p < dev->HubPortCount; p++) + Disconnect(i+1,p+1); + + // Now release endpoints + for (int j = 1; j < MAX_ENDPOINTS_PER_DEVICE*2; j += 2) + { + u8 endpointIndex = dev->_endpointMap[j]; + if (endpointIndex != 0xFF) + Release(Endpoints + endpointIndex); + } + dev->Port = 0; // Device is now free + dev->Flags = 0; + return; + } + } + } + + // called after reset + void Connect(int hub, int port, bool lowspeed) + { + LOG("Connect Hub:%d Port:%d %s\n",hub,port,lowspeed ? "slow" : "full"); + AddDevice(hub,port,lowspeed); + } + + // Called from interrupt + void HubStatusChange(int hub, int port, u32 status) + { + LOG("HubStatusChange Hub:%d Port:%d %08X\n",hub,port,status); + if (status & ConnectStatusChange) + { + if (status & CurrentConnectStatus) // Connecting + ResetPort(hub,port); // Reset to initiate connect (state machine?) + else + Disconnect(hub,port); + } + + if (status & PortResetStatusChange) + { + if (!(status & PortResetStatus)) + { + _connectCountdown = 200; // Schedule a connection in 200ms + if (status & LowspeedDevice) + port |= 0x80; + _connectHub = hub; + _connectPort = port; + } + } + } + + #define HOST_CLK_EN (1<<0) + #define PORTSEL_CLK_EN (1<<3) + #define AHB_CLK_EN (1<<4) + #define CLOCK_MASK (HOST_CLK_EN | PORTSEL_CLK_EN | AHB_CLK_EN) + + #define FRAMEINTERVAL (12000-1) // 1ms + #define DEFAULT_FMINTERVAL ((((6 * (FRAMEINTERVAL - 210)) / 7) << 16) | FRAMEINTERVAL) + + void DelayMS(int ms) + { + u16 f = ms + CommunicationArea.FrameNumber; + while (f != CommunicationArea.FrameNumber) + ; + } + + static void HWInit(HCCA* cca) + { + NVIC_DisableIRQ(USB_IRQn); + + // turn on power for USB + LPC_SC->PCONP |= (1UL<<31); + // Enable USB host clock, port selection and AHB clock + LPC_USB->USBClkCtrl |= CLOCK_MASK; + // Wait for clocks to become available + while ((LPC_USB->USBClkSt & CLOCK_MASK) != CLOCK_MASK) + ; + + // We are a Host + LPC_USB->OTGStCtrl |= 1; + LPC_USB->USBClkCtrl &= ~PORTSEL_CLK_EN; // we don't need port selection clock until we do OTG + + // configure USB pins + LPC_PINCON->PINSEL1 &= ~((3<<26)|(3<<28)); + LPC_PINCON->PINSEL1 |= ((1<<26)|(1<<28)); // USB D+/D- + + LPC_PINCON->PINSEL3 &= ~((3 << 6) | (3 << 22)); // USB_PPWR, USB_OVRCR + LPC_PINCON->PINSEL3 |= ((2 << 6) | (2 << 22)); + + LPC_PINCON->PINSEL4 &= ~(3 << 18); // USB_CONNECT + LPC_PINCON->PINSEL4 |= (1 << 18); + + // Reset OHCI block + LPC_USB->HcControl = 0; + LPC_USB->HcControlHeadED = 0; + LPC_USB->HcBulkHeadED = 0; + + LPC_USB->HcCommandStatus = HostControllerReset; + LPC_USB->HcFmInterval = DEFAULT_FMINTERVAL; + LPC_USB->HcPeriodicStart = FRAMEINTERVAL*90/100; + + LPC_USB->HcControl = (LPC_USB->HcControl & (~HostControllerFunctionalState)) | OperationalMask; + LPC_USB->HcRhStatus = SetGlobalPower; + + LPC_USB->HcHCCA = (u32)cca; + LPC_USB->HcInterruptStatus |= LPC_USB->HcInterruptStatus; + LPC_USB->HcInterruptEnable = MasterInterruptEnable | WritebackDoneHead | RootHubStatusChange | FrameNumberOverflow; + + NVIC_SetPriority(USB_IRQn, 0); + NVIC_EnableIRQ(USB_IRQn); + while (cca->FrameNumber < 10) + ; // 10ms delay before diving in + } +}; + +//==================================================================================== +//==================================================================================== +// Host controller instance and Interrupt handler + +static HostController _controller __attribute__((at(USB_RAM_BASE))); + +extern "C" void USB_IRQHandler(void) __irq; +void USB_IRQHandler (void) __irq +{ + u32 int_status = LPC_USB->HcInterruptStatus; + + if (int_status & RootHubStatusChange) // Root hub status change + _controller._rootHubStatusChange++; // Just flag the controller, will be processed in USBLoop + + u32 head = 0; + if (int_status & WritebackDoneHead) + { + head = _controller.CommunicationArea.DoneHead; // Writeback Done + _controller.CommunicationArea.DoneHead = 0; + } + LPC_USB->HcInterruptStatus = int_status; + + if (head) + _controller.ProcessDoneQueue(head); // TODO - low bit can be set BUGBUG +} + +//==================================================================================== +//==================================================================================== +// API Methods + +void USBInit() +{ + return _controller.Init(); +} + +void USBLoop() +{ + return _controller.Loop(); +} + +u8* USBGetBuffer(u32* len) +{ + *len = USB_RAM_SIZE - sizeof(HostController); + return _controller.SRAM; +} + +static Setup* GetSetup(int device) +{ + if (device == 0) + return &_controller._setupZero; + + if (device < 1 || device > MAX_DEVICES) + return 0; + return &_controller.Devices[device-1].SetupBuffer; +} + +// Loop until IO on endpoint is complete +static int WaitIODone(Endpoint* endpoint) +{ + if (endpoint->CurrentState == Endpoint::NotQueued) + return 0; + while (endpoint->CurrentState != Endpoint::Idle) + USBLoop(); // May generate callbacks, mount or unmount devices etc + int status = endpoint->Status(); + if (status == 0) + return endpoint->Length; + return -status; +} + +int USBTransfer(int device, int ep, u8 flags, u8* data, int length, USBCallback callback, void* userData) +{ + Endpoint* endpoint = _controller.GetEndpoint(device,ep); + if (!endpoint) + return ERR_ENDPOINT_NOT_FOUND; + + WaitIODone(endpoint); + endpoint->Flags = flags; + endpoint->Data = data; + endpoint->Length = length; + endpoint->Callback = callback; + endpoint->UserData = userData; + if (ep == 0) + _controller.Transfer(endpoint,TOKEN_SETUP,(u8*)GetSetup(device),8,Endpoint::SetupQueued); + else + _controller.Transfer(endpoint,flags & 0x80 ? TOKEN_IN : TOKEN_OUT,data,length,Endpoint::DataQueued); + if (callback) + return IO_PENDING; + return WaitIODone(endpoint); +} + +int USBControlTransfer(int device, int request_type, int request, int value, int index, u8* data, int length, USBCallback callback, void * userData) +{ + Setup* setup = GetSetup(device); + if (!setup) + return ERR_DEVICE_NOT_FOUND; + + // Async control calls may overwrite setup buffer of previous call, so we need to wait before setting up next call + WaitIODone(_controller.GetEndpoint(device,0)); + + setup->bm_request_type = request_type; + setup->b_request = request; + setup->w_value = value; + setup->w_index = index; + setup->w_length = length; + return USBTransfer(device,0,request_type & DEVICE_TO_HOST,data,length,callback,userData); +} + +int USBInterruptTransfer(int device, int ep, u8* data, int length, USBCallback callback, void* userData) +{ + return USBTransfer(device,ep,(ep & 0x80) | ENDPOINT_INTERRUPT,data,length,callback,userData); +} + +int USBBulkTransfer(int device, int ep, u8* data, int length, USBCallback callback, void* userData) +{ + return USBTransfer(device,ep,(ep & 0x80) | ENDPOINT_BULK,data,length,callback,userData); +} + +int GetDescriptor(int device, int descType,int descIndex, u8* data, int length) +{ + return USBControlTransfer(device,DEVICE_TO_HOST | RECIPIENT_DEVICE, GET_DESCRIPTOR,(descType << 8)|(descIndex), 0, data, length, 0); +} + +int GetString(int device, int index, char* dst, int length) +{ + u8 buffer[255]; + int le = GetDescriptor(device,DESCRIPTOR_TYPE_STRING,index,buffer,sizeof(buffer)); + if (le < 0) + return le; + if (length < 1) + return -1; + length <<= 1; + if (le > length) + le = length; + for (int j = 2; j < le; j += 2) + *dst++ = buffer[j]; + *dst = 0; + return (le>>1)-1; +} + +int SetAddress(int device, int new_addr) +{ + return USBControlTransfer(device,HOST_TO_DEVICE | RECIPIENT_DEVICE, SET_ADDRESS, new_addr, 0, 0, 0, 0); +} + +int SetConfiguration(int device, int configNum) +{ + return USBControlTransfer(device,HOST_TO_DEVICE | RECIPIENT_DEVICE, SET_CONFIGURATION, configNum, 0, 0, 0, 0); +} + +int SetInterface(int device, int ifNum, int altNum) +{ + return USBControlTransfer(device,HOST_TO_DEVICE | RECIPIENT_INTERFACE, SET_INTERFACE, altNum, ifNum, 0, 0, 0); +} + +// HUB stuff +int SetPortFeature(int device, int feature, int index) +{ + return USBControlTransfer(device,HOST_TO_DEVICE | REQUEST_TYPE_CLASS | RECIPIENT_OTHER,SET_FEATURE,feature,index,0,0); +} + +int ClearPortFeature(int device, int feature, int index) +{ + return USBControlTransfer(device,HOST_TO_DEVICE | REQUEST_TYPE_CLASS | RECIPIENT_OTHER,CLEAR_FEATURE,feature,index,0,0); +} + +int SetPortPower(int device, int port) +{ + int r = SetPortFeature(device,PORT_POWER,port); + _controller.DelayMS(20); // 80ms to turn on a hubs power... DESCRIPTOR? todo + return r; +} + +int SetPortReset(int device, int port) +{ + return SetPortFeature(device,PORT_RESET,port); +} + +int GetPortStatus(int device, int port, u32* status) +{ + return USBControlTransfer(device,DEVICE_TO_HOST | REQUEST_TYPE_CLASS | RECIPIENT_OTHER,GET_STATUS,0,port,(u8*)status,4); +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/myUSBHost/USBHost.h Wed Jun 15 19:12:25 2011 +0000 @@ -0,0 +1,200 @@ + +/* +Copyright (c) 2010 Peter Barrett + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef USBHOST_H +#define USBHOST_H + +#ifndef u8 +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned long u32; + +typedef char s8; +typedef short s16; +typedef char s32; +#endif + +#define ENDPOINT_CONTROL 0 +#define ENDPOINT_ISOCRONOUS 1 +#define ENDPOINT_BULK 2 +#define ENDPOINT_INTERRUPT 3 + +#define DESCRIPTOR_TYPE_DEVICE 1 +#define DESCRIPTOR_TYPE_CONFIGURATION 2 +#define DESCRIPTOR_TYPE_STRING 3 +#define DESCRIPTOR_TYPE_INTERFACE 4 +#define DESCRIPTOR_TYPE_ENDPOINT 5 + +#define DESCRIPTOR_TYPE_HID 0x21 +#define DESCRIPTOR_TYPE_REPORT 0x22 +#define DESCRIPTOR_TYPE_PHYSICAL 0x23 +#define DESCRIPTOR_TYPE_HUB 0x29 + +enum USB_CLASS_CODE +{ + CLASS_DEVICE, + CLASS_AUDIO, + CLASS_COMM_AND_CDC_CONTROL, + CLASS_HID, + CLASS_PHYSICAL = 0x05, + CLASS_STILL_IMAGING, + CLASS_PRINTER, + CLASS_MASS_STORAGE, + CLASS_HUB, + CLASS_CDC_DATA, + CLASS_SMART_CARD, + CLASS_CONTENT_SECURITY = 0x0D, + CLASS_VIDEO = 0x0E, + CLASS_DIAGNOSTIC_DEVICE = 0xDC, + CLASS_WIRELESS_CONTROLLER = 0xE0, + CLASS_MISCELLANEOUS = 0xEF, + CLASS_APP_SPECIFIC = 0xFE, + CLASS_VENDOR_SPECIFIC = 0xFF +}; + +#define DEVICE_TO_HOST 0x80 +#define HOST_TO_DEVICE 0x00 +#define REQUEST_TYPE_CLASS 0x20 +#define RECIPIENT_DEVICE 0x00 +#define RECIPIENT_INTERFACE 0x01 +#define RECIPIENT_ENDPOINT 0x02 +#define RECIPIENT_OTHER 0x03 + +#define GET_STATUS 0 +#define CLEAR_FEATURE 1 +#define SET_FEATURE 3 +#define SET_ADDRESS 5 +#define GET_DESCRIPTOR 6 +#define SET_DESCRIPTOR 7 +#define GET_CONFIGURATION 8 +#define SET_CONFIGURATION 9 +#define GET_INTERFACE 10 +#define SET_INTERFACE 11 +#define SYNCH_FRAME 11 + +// -5 is nak +/* +0010 ACK Handshake +1010 NAK Handshake +1110 STALL Handshake +0110 NYET (No Response Yet) +*/ + +#define IO_PENDING -100 +#define ERR_ENDPOINT_NONE_LEFT -101 +#define ERR_ENDPOINT_NOT_FOUND -102 +#define ERR_DEVICE_NOT_FOUND -103 +#define ERR_DEVICE_NONE_LEFT -104 +#define ERR_HUB_INIT_FAILED -105 +#define ERR_INTERFACE_NOT_FOUND -106 + +typedef struct +{ + u8 bLength; + u8 bDescriptorType; + u16 bcdUSB; + u8 bDeviceClass; + u8 bDeviceSubClass; + u8 bDeviceProtocol; + u8 bMaxPacketSize; + u16 idVendor; + u16 idProduct; + u16 bcdDevice; // version + u8 iManufacturer; + u8 iProduct; + u8 iSerialNumber; + u8 bNumConfigurations; +} DeviceDescriptor; // 16 bytes + +typedef struct +{ + u8 bLength; + u8 bDescriptorType; + u16 wTotalLength; + u8 bNumInterfaces; + u8 bConfigurationValue; // Value to use as an argument to select this configuration + u8 iConfiguration; // Index of String Descriptor describing this configuration + u8 bmAttributes; // Bitmap D7 Reserved, set to 1. (USB 1.0 Bus Powered),D6 Self Powered,D5 Remote Wakeup,D4..0 = 0 + u8 bMaxPower; // Maximum Power Consumption in 2mA units +} ConfigurationDescriptor; + +typedef struct +{ + u8 bLength; + u8 bDescriptorType; + u8 bInterfaceNumber; + u8 bAlternateSetting; + u8 bNumEndpoints; + u8 bInterfaceClass; + u8 bInterfaceSubClass; + u8 bInterfaceProtocol; + u8 iInterface; // Index of String Descriptor Describing this interface +} InterfaceDescriptor; + +typedef struct +{ + u8 bLength; + u8 bDescriptorType; + u8 bEndpointAddress; // Bits 0:3 endpoint, Bits 7 Direction 0 = Out, 1 = In (Ignored for Control Endpoints) + u8 bmAttributes; // Bits 0:1 00 = Control, 01 = Isochronous, 10 = Bulk, 11 = Interrupt + u16 wMaxPacketSize; + u8 bInterval; // Interval for polling endpoint data transfers. +} EndpointDescriptor; + +typedef struct { + u8 bLength; + u8 bDescriptorType; + u16 bcdHID; + u8 bCountryCode; + u8 bNumDescriptors; + u8 bDescriptorType2; + u16 wDescriptorLength; +} HIDDescriptor; + +//============================================================================ +//============================================================================ + + +void USBInit(); +void USBLoop(); +u8* USBGetBuffer(u32* len); + +// Optional callback for transfers, called at interrupt time +typedef void (*USBCallback)(int device, int endpoint, int status, u8* data, int len, void* userData); + +// Transfers +int USBControlTransfer(int device, int request_type, int request, int value, int index, u8* data, int length, USBCallback callback = 0, void* userData = 0); +int USBInterruptTransfer(int device, int ep, u8* data, int length, USBCallback callback = 0, void* userData = 0); +int USBBulkTransfer(int device, int ep, u8* data, int length, USBCallback callback = 0, void* userData = 0); + +// Standard Device methods +int GetDescriptor(int device, int descType, int descIndex, u8* data, int length); +int GetString(int device, int index, char* dst, int length); +int SetAddress(int device, int new_addr); +int SetConfiguration(int device, int configNum); +int SetInterface(int device, int ifNum, int altNum); + +// Implemented to notify app of the arrival of a device +void OnLoadDevice(int device, DeviceDescriptor* deviceDesc, InterfaceDescriptor* interfaceDesc); + +#endif \ No newline at end of file