Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Revision 0:6ce9c65992e5, committed 2015-04-15
- Comitter:
- dylancachan
- Date:
- Wed Apr 15 06:23:18 2015 +0000
- Commit message:
- telemetre
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/CAN_FIFO/can.cpp Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,206 @@
+#include "all_includes.h"
+
+
+// FIFO CAN
+unsigned char FIFO_ecriture=0;
+int COD_valeur;
+unsigned char JOG_valeur,mise_a_jour_JOG=0,mise_a_jour_COD=0,flag_mbed_reset=0;
+//extern USBHostSerial serial;
+
+
+void can_ISR_Reader(void)
+{
+ if (can.read(can_MsgRx[FIFO_ecriture]))
+ {
+ if(can_MsgRx[FIFO_ecriture].id==RESET_TELEMETRE)
+ {
+ flag_mbed_reset=1;
+ }
+ else
+ {
+ FIFO_ecriture=(FIFO_ecriture+1)%SIZE_FIFO;// FIFO gestion
+ FIFO_ecriture=(FIFO_ecriture+1)%SIZE_FIFO;
+ myled[0] = !myled[0];
+ }
+ }
+}
+
+
+
+void CAN_automate_reception(void)
+{
+
+ static signed char FIFO_lecture=0,FIFO_occupation=0,FIFO_max_occupation=0;
+ FIFO_occupation=FIFO_ecriture-FIFO_lecture;
+ if(FIFO_occupation<0)
+ FIFO_occupation=FIFO_occupation+SIZE_FIFO;
+ if(FIFO_max_occupation<FIFO_occupation)
+ FIFO_max_occupation=FIFO_occupation;
+ if(FIFO_occupation>SIZE_FIFO)
+ while(!can.write(CANMessage(LCD_OVERFLOW,CANStandard)));
+ if(FIFO_occupation!=0)
+ {
+ switch(can_MsgRx[FIFO_lecture].id)
+ {
+
+ case JOG_DATA: JOG_valeur=can_MsgRx[FIFO_lecture].data[0];
+ mise_a_jour_JOG=1;
+ break;
+
+ case COD_DATA: COD_valeur=can_MsgRx[FIFO_lecture].data[0];
+ mise_a_jour_COD=1;
+ break;
+
+
+ case TELEMETRE_RTR_CARTO:
+ angle_cartographie = can_MsgRx[FIFO_lecture].data[0];
+ cooX_demande = (((unsigned short)can_MsgRx[FIFO_lecture].data[1])<<8)+(can_MsgRx[FIFO_lecture].data[2]);
+ cooY_demande = (((unsigned short)can_MsgRx[FIFO_lecture].data[3])<<8)+(can_MsgRx[FIFO_lecture].data[4]);
+
+ DEBUG_PRINTF("coordonne actuelles : x=%d\ty=%d\n",cooX_actuelle,cooY_actuelle);
+ DEBUG_PRINTF("coordonne demandees : x=%d\ty=%d\tangle=%d\n",cooX_demande,cooY_demande,angle_cartographie);
+
+ teta_actuelle_rad=teta_actuelle*M_PI/180;
+
+ x_telemetre = (cooX_demande - cooX_actuelle)*cos(teta_actuelle_rad) + (cooY_demande - cooY_actuelle)*sin(teta_actuelle_rad);
+ y_telemetre = (-1)*(cooX_demande - cooX_actuelle)*sin(teta_actuelle_rad) + (cooY_demande - cooY_actuelle)*cos(teta_actuelle_rad);
+
+ if(y_telemetre==0)
+ {
+ if(x_telemetre>0)
+ teta = M_PI/2;
+ else if(x_telemetre<0)
+ teta = -M_PI/2;
+ }
+ else
+ teta = atan(((double)x_telemetre)/((double)y_telemetre));
+
+
+ DEBUG_PRINTF("x tel = %d\ty tel = %d\tteta tel = %lf",x_telemetre,y_telemetre,teta*180./M_PI);
+ wait(10);
+
+
+
+ /* if(angle_cartographie == 0)
+ {
+ //La commande doit varier en fonction du x, y donn� et creer un d�but/fin en fonction de teta
+ //create_command(&MS_one);
+ //MS_center = MS_one;
+
+ }
+
+ else
+ {
+ //MS_one.debut =
+ //create_command(&MS_one);
+ //MS_center = MS_one;
+
+ }*/
+
+// etat_connection = MS;
+
+ break;
+
+
+
+
+ case TELEMETRE_PRINT_REQUEST: etat_connection = ENVOI_CAN_ECRAN;
+
+ break;
+
+ case RECEIVE_ODOMETRIE: cooX_actuelle = (((unsigned short)can_MsgRx[FIFO_lecture].data[0])<<8)+(can_MsgRx[FIFO_lecture].data[1]);
+ cooY_actuelle = (((unsigned short)can_MsgRx[FIFO_lecture].data[2])<<8)+(can_MsgRx[FIFO_lecture].data[3]);
+ teta_actuelle=(((short)can_MsgRx[FIFO_lecture].data[4])<<8)+((short)(can_MsgRx[FIFO_lecture].data[5]));
+ teta_actuelle_rad=teta_actuelle*M_PI/180;
+ DEBUG_PRINTF("x odo = %d\ty odo = %d\tteta odo = %d en rad=%f\t",cooX_actuelle,cooY_actuelle,teta_actuelle,teta_actuelle_rad);
+ wait(10);
+
+ break;
+ }
+ FIFO_lecture=(FIFO_lecture+1)%SIZE_FIFO;
+ }
+
+}
+
+void CAN2_wrFilter (uint32_t id) {
+ static int CAN_std_cnt = 0;
+ uint32_t buf0, buf1;
+ int cnt1, cnt2, bound1;
+
+ /* Acceptance Filter Memory full */
+ if (((CAN_std_cnt + 1) >> 1) >= 512)
+ return; /* error: objects full */
+
+ /* Setup Acceptance Filter Configuration
+ Acceptance Filter Mode Register = Off */
+ LPC_CANAF->AFMR = 0x00000001;
+
+ id |= 1 << 13; /* Add controller number(2) */
+ id &= 0x0000F7FF; /* Mask out 16-bits of ID */
+
+ if (CAN_std_cnt == 0) { /* For entering first ID */
+ LPC_CANAF_RAM->mask[0] = 0x0000FFFF | (id << 16);
+ } else if (CAN_std_cnt == 1) { /* For entering second ID */
+ if ((LPC_CANAF_RAM->mask[0] >> 16) > id)
+ LPC_CANAF_RAM->mask[0] = (LPC_CANAF_RAM->mask[0] >> 16) | (id << 16);
+ else
+ LPC_CANAF_RAM->mask[0] = (LPC_CANAF_RAM->mask[0] & 0xFFFF0000) | id;
+ } else {
+ /* Find where to insert new ID */
+ cnt1 = 0;
+ cnt2 = CAN_std_cnt;
+ bound1 = (CAN_std_cnt - 1) >> 1;
+ while (cnt1 <= bound1) { /* Loop through standard existing IDs */
+ if ((LPC_CANAF_RAM->mask[cnt1] >> 16) > id) {
+ cnt2 = cnt1 * 2;
+ break;
+ }
+ if ((LPC_CANAF_RAM->mask[cnt1] & 0x0000FFFF) > id) {
+ cnt2 = cnt1 * 2 + 1;
+ break;
+ }
+ cnt1++; /* cnt1 = U32 where to insert new ID */
+ } /* cnt2 = U16 where to insert new ID */
+
+ if (cnt1 > bound1) { /* Adding ID as last entry */
+ if ((CAN_std_cnt & 0x0001) == 0) /* Even number of IDs exists */
+ LPC_CANAF_RAM->mask[cnt1] = 0x0000FFFF | (id << 16);
+ else /* Odd number of IDs exists */
+ LPC_CANAF_RAM->mask[cnt1] = (LPC_CANAF_RAM->mask[cnt1] & 0xFFFF0000) | id;
+ } else {
+ buf0 = LPC_CANAF_RAM->mask[cnt1]; /* Remember current entry */
+ if ((cnt2 & 0x0001) == 0) /* Insert new mask to even address */
+ buf1 = (id << 16) | (buf0 >> 16);
+ else /* Insert new mask to odd address */
+ buf1 = (buf0 & 0xFFFF0000) | id;
+
+ LPC_CANAF_RAM->mask[cnt1] = buf1; /* Insert mask */
+
+ bound1 = CAN_std_cnt >> 1;
+ /* Move all remaining standard mask entries one place up */
+ while (cnt1 < bound1) {
+ cnt1++;
+ buf1 = LPC_CANAF_RAM->mask[cnt1];
+ LPC_CANAF_RAM->mask[cnt1] = (buf1 >> 16) | (buf0 << 16);
+ buf0 = buf1;
+ }
+
+ if ((CAN_std_cnt & 0x0001) == 0) /* Even number of IDs exists */
+ LPC_CANAF_RAM->mask[cnt1] = (LPC_CANAF_RAM->mask[cnt1] & 0xFFFF0000) | (0x0000FFFF);
+ }
+ }
+ CAN_std_cnt++;
+
+ /* Calculate std ID start address (buf0) and ext ID start address <- none (buf1) */
+ buf0 = ((CAN_std_cnt + 1) >> 1) << 2;
+ buf1 = buf0;
+
+ /* Setup acceptance filter pointers */
+ LPC_CANAF->SFF_sa = 0;
+ LPC_CANAF->SFF_GRP_sa = buf0;
+ LPC_CANAF->EFF_sa = buf0;
+ LPC_CANAF->EFF_GRP_sa = buf1;
+ LPC_CANAF->ENDofTable = buf1;
+
+ LPC_CANAF->AFMR = 0x00000000; /* Use acceptance filter */
+} // CAN2_wrFilter
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CAN_FIFO/can.h Wed Apr 15 06:23:18 2015 +0000 @@ -0,0 +1,14 @@ + +#define SIZE_FIFO 5 + +extern unsigned char FIFO_ecriture; +extern CAN can; /*Configuration des ports du CAN : rd p30 td p29*/ +extern CANMessage can_MsgRx[SIZE_FIFO]; +extern DigitalOut myled[4]; + + +void can_ISR_Reader(void); + +void CAN_automate_reception(void); + +void CAN2_wrFilter (uint32_t id);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CAN_FIFO/ident.h Wed Apr 15 06:23:18 2015 +0000 @@ -0,0 +1,58 @@ +#ifndef _IDENT_H +#define _IDENT_H + +/* FILE: ident.h */ +/****************************************************************************************/ +/* MODULE NAME: MC9S12XS128 - MSCAN => Motorola�s Scalable Controller Area Network */ +/* (BUS CAN) */ +/* */ +/* AUTHOR : BRUNO LARNAUDIE */ +/* */ +/* EMAIL : bruno.larnaudie@u-psud.fr */ +/* */ +/* INSTITUTION: IUT de CACHAN - 9 av. de la div. Leclerc - 94230 CACHAN */ +/* */ +/* DATE : 03/07/2012 */ +/* CPU : FREESCALE MC9S12XS128MAA */ +/* BOARD : CACHAN Xboard+MicroB12 */ +/* OS : None */ +/* */ +/* DESCRIPTION: Identifiants utilis�s sur le bus CAN */ +/****************************************************************************************/ + +// NOM ID |Flag |Sens |Data | Fonction | Data | +// |Mess |(I/O)|Req | | nb | Type | contenu (dans l'ordre) | +//------------------------------------------------------------------------------------------------------------------------| +// Carte IHM 0x700-0x7FF | | | | | | | | +//------------------------------------------------------------------------------------------------------------------------| +// //| | | | | | | | +// Module LCD 16x2 //| | | | | | | | +#define LCD_CHAR0 0x700 //| M | O | D |char 0 � 7 sur LCD | 8 | U8 | C00|C01|C02|C03|C04|C05|C06|C07 | +#define LCD_CHAR1 0x701 //| M | O | D |char 8 � 15 sur LCD | 8 | U8 | C08|C09|C10|C11|C12|C13|C14|C15 | +#define LCD_CHAR2 0x702 //| M | O | D |char 16 � 23 sur LCD| 8 | U8 | C16|C17|C18|C19|C20|C21|C22|C23 | +#define LCD_CHAR3 0x703 //| M | O | D |char 24 � 31 sur LCD| 8 | U8 | C24|C25|C26|C27|C28|C29|C30|C31 | +// //| | | | | | | | +// 0x704 //| | | | | | | R�serv� pour un �ventuel LCD | +// R�serv� ... //| | | | | | | plus grand ou tactile | +// 0x77D //| | | | | | | | +// //| | | | | | | | +#define LCD_OVERFLOW 0x77E //| M | O | R |Flag d'Overflow LCD | 0 | | | +#define LCD_CLEAR 0x77F //| M | O | D | | 0 | | Efface l'ecran LCD | + //| | | | | | | | +// JOG //| | | | | | | | +#define JOG_REQ 0x790 //| M | I | R | Demande valeur JOG | 0 | | | +#define JOG_DATA 0x791 //| M | O | D | Valeur JOG | 1 | U8 | STATUS_JOG=PTP | +// CODEUR | | | | | | | | +#define COD_REQ 0x7A0 //| M | I | R | Demande valeur COD | 0 | | | +#define COD_DATA 0x7A1 //| M | O | D | Valeur COD | 1 | S8 | OFFSET du CODEUR entre -128 et 127| +// BARGRAPH | | | | | | | | +#define BAR_SET 0x7B0 //| M | I | D | valeur bargraph | 2 | U16 | Les bits � allumer | + //------------------------------------------------------------------------------------------ +/* L�gende : I = Consigne pour la carte + O = Etat donn� par la carte + + D = Trame de donn�es + R = Trame de requ�te */ + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CAN_FIFO/ident_crac.h Wed Apr 15 06:23:18 2015 +0000 @@ -0,0 +1,187 @@ +#define STOP 0x001 +#define START 0x002 + +#define BALISE_STOP 0x003 + +#define BALISE_DANGER 0x00A +#define BALISE_FIN_ALERTE 0x00B + +#define MOTEUR_PWM 0x020 +#define MOTEUR_VITESSE 0x021 +#define MOTEUR_POSITION 0x022 +#define MOTEUR_XYT 0x023 +#define MOTEUR_VITESSE_THETA 0x024 +#define MOTEUR_BEND_RADIUS 0x025 +#define MOTEUR_PARAM 0x026 +#define MOTEUR_CALIBR 0x027 +#define MOTEUR_ROTATION 0x028 + +#define OVERFLOW_ODOMETRIE 0x040 +#define OVERFLOW_ASSERVISSEMENT 0x041 + +#define RESET_BALISE 0x030 +#define RESET_MOTEUR 0x031 +#define RESET_RTC 0x032 +#define RESET_TELEMETRE 0x033 +#define RESET_CAPTEURS 0x034 +#define RESET_SERVO 0x035 +#define RESET_ZIGBEE 0x036 + +#define CHECK_BALISE 0x060 +#define CHECK_MOTEUR 0x061 +#define CHECK_RTC 0x062 +#define CHECK_TELEMETRE 0x063 +#define CHECK_CAPTEURS 0x064 +#define CHECK_SERVO 0x065 +#define CHECK_ZIGBEE 0x066 + +#define ALIVE_BALISE 0x070 +#define ALIVE_MOTEUR 0x071 +#define ALIVE_RTC 0x072 +#define ALIVE_TELEMETRE 0x073 +#define ALIVE_CAPTEURS 0x074 +#define ALIVE_SERVO 0x075 +#define ALIVE_ZIGBEE 0x076 + +#define CHECK_OK_BALISE 0x080 +#define CHECK_OK_MOTEUR 0x081 +#define CHECK_OK_RTC 0x082 +#define CHECK_OK_TELEMETRE 0x083 +#define CHECK_OK_CAPTEURS 0x084 +#define CHECK_OK_SERVO 0x085 +#define CHECK_OK_ZIGBEE 0x086 + +#define ACK_STOP 0x100 +#define ACK_ASSERVISSEMENT 0x101 +#define FIN_CONSIGNE 0x102 +#define ACK_CONSIGNE 0x103 +#define ACK_ODOMETRIE 0x104 +#define ACK_CALIBRAGE 0x105 + +#define ACK_BALISE 0x106 + +#define RAMASSAGE_GOBELET 0x200 +#define ACK_RAMASSER_GOBELET 0x2F0 +#define DEPOSE_GOBELET 0x201 +#define ACK_DEPOSER_GOBELET 0x2F1 +#define RECUPERATION_POPCORN 0x202 +#define ACK_RECUPERER_POPCORN 0x2F2 +#define LACHE_POPCORN 0x203 +#define ACK_LACHER_POPCORN 0x2F3 +#define RAMASSAGE_SPOT 0x204 +#define ACK_RAMASSER_SPOT 0x2F4 +#define DEPOSE_SPOT 0x205 +#define ACK_DEPOSER_SPOT 0x2F5 +#define FERMETURE_CLAP 0x206 +#define ACK_FERMER_CLAP 0x2F6 +#define MONTER_ESCALIERS 0x207 +#define ACK_MONTER_ESCALIERS 0x2F7 +#define DEROULAGE_TAPIS 0x208 +#define ACK_DEROULER_TAPIS 0x2F8 + +#define RANGER_CROCHET_AV 0x210 +#define OUVRIR_CROCHET_AV 0x211 +#define GRAB_CROCHET_AV 0x212 +#define ANGLE_CROCHET_AV 0x213 + +#define ACK_CROCHET_AV 0x21E +#define ORDRE_FINI_CROCHET_AV 0x21F + +#define RANGER_CROCHET_AR 0x220 +#define OUVRIR_CROCHET_AR 0x221 +#define GRAB_CROCHET_AR 0x222 +#define ANGLE_CROCHET_AR 0x223 + +#define ACK_CROCHET_AR 0x22E +#define ORDRE_FINI_CROCHET_AR 0x22F + +#define RANGER_CROCHET_G 0x230 +#define OUVRIR_CROCHET_G 0x231 +#define GRAB_CROCHET_G 0x232 +#define ANGLE_CROCHET_G 0x233 + +#define ACK_CROCHET_G 0x23E +#define ORDRE_FINI_CROCHET_G 0x23F + +#define RANGER_CROCHET_D 0x240 +#define OUVRIR_CROCHET_D 0x241 +#define GRAB_CROCHET_D 0x242 +#define ANGLE_CROCHET_D 0x243 + +#define ACK_CROCHET_D 0x24E +#define ORDRE_FINI_CROCHET_D 0x24F + +#define RANGER_ANCRE 0x250 +#define GAUCHE_ANCRE 0x251 +#define DROITE_ANCRE 0x252 +#define ANGLE_ANCRE 0x253 + +#define ACK_ANCRE 0x25E +#define ORDRE_FINI_ANCRE 0x25F + +#define GAUCHE_AIGUILLEUR_G 0x260 +#define DROITE_AIGUILLEUR_G 0x261 +#define ANGLE_AIGUILLEUR_G 0x262 + +#define ACK_AIGUILLEUR_G 0x26E +#define ORDRE_FINI_AIGUILLEUR_G 0x26F + +#define GAUCHE_AIGUILLEUR_D 0x270 +#define DROITE_AIGUILLEUR_D 0x271 +#define ANGLE_AIGUILLEUR_D 0x272 + +#define ACK_AIGUILLEUR_D 0x27E +#define ORDRE_FINI_AIGUILLEUR_D 0x27F + +#define RANGER_BLOQUEUR_G 0x280 +#define OUVRIR_BLOQUEUR_G 0x281 +#define FERMER_BLOQUEUR_G 0x282 +#define ANGLE_BLOQUEUR_G 0x283 + +#define ACK_BLOQUEUR_G 0x28E +#define ORDRE_FINI_BLOQUEUR_G 0x28F + +#define RANGER_BLOQUEUR_D 0x290 +#define OUVRIR_BLOQUEUR_D 0x291 +#define FERMER_BLOQUEUR_D 0x292 +#define ANGLE_BLOQUEUR_D 0x293 + +#define ACK_BLOQUEUR_D 0x29E +#define ORDRE_FINI_BLOQUEUR_D 0x29F + +#define BALISE_3615 0x300 + +#define TELEMETRE 0x301 +#define TELEMETRE_OVER 0x302 +#define TELEMETRE_RTR_CARTO 0x303 +#define TELEMETRE_ACK_RTR 0x304 +#define TELEMETRE_PRINT_CARTO 0x305 +#define TELEMETRE_ACK_PRINT 0x306 +#define TELEMETRE_PRINT_REQUEST 0x307 + +#define ACK_TELEMETRE 0x311 + +#define OUBLI_CLE 0x401 + +#define RECEIVE_ODOMETRIE 0x500 +#define SET_ODOMETRIE 0x501 +#define RAZ_ODOMETRIE 0x502 + +#define ZIGBEE 0x550 + +#define TOUCH_SCREEN_STRATEGY 0x601 +#define TOUCH_SCREEN_COLOR 0x602 +#define TOUCH_SCREEN_STRAT_OVER 0x603 + +#define ACK_STRATEGY 0x611 +#define ACK_COLOR 0x612 + +#define BALISE_BUG 0x785 +#define RTC_BUG 0x786 +#define MOTEUR_BUG 0x787 +#define TELEMETRE_BUG 0x788 +#define STRATEGIE_BUG 0x789 + +#define TACTILE_PRINTF 0x7C0 +#define TACTILE_PRINTF_OVER 0x7CF +#define RESET_TOUCH_SCREEN 0x7C1
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/IHM/IHM.cpp Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,224 @@
+/* FILE: IHM.c */
+/****************************************************************************************/
+/* MODULE NAME: IHM 16x2 */
+/* */
+/* AUTHOR : Jacques-Olivier KLEIN */
+/* Bruno LARNAUDIE */
+/* */
+/* EMAIL : jacques-olivier.klein@u-psud.fr */
+/* bruno.larnaudie@u-psud.fr */
+/* */
+/* INSTITUTION: IUT de CACHAN - 9 av. de la div. Leclerc - 94230 CACHAN */
+/* */
+/* DATE : 12/07/2012 */
+/* CPU : FREESCALE MC9S12XS128MAA */
+/* BOARD : CACHAN Xboard + IHM16x2 */
+/* OS : None */
+/* */
+/* DESCRIPTION: Fonctions d'accès au Lcd émulé passant par le bus CAN */
+/****************************************************************************************/
+
+#include <stdarg.h> // Pour va_list ... dans IHM_printf
+#include <stdio.h> // Pour vprintf et setprintf
+#include "all_includes.h"
+
+extern DigitalOut myled[4];
+extern unsigned char Reception_CAN;
+CANMessage trame_Tx;
+extern CANMessage can_MsgRx[SIZE_FIFO];
+extern CAN can; /*Configuration des ports du CAN : rd p30 td p29*/
+
+/****************************************************************************************/
+/* Variables globales */
+/****************************************************************************************/
+UINT8 curseur=0;
+static char tableau_ecran[32]={32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32};
+UINT8 IHM_is_running = 0;
+
+/****************************************************************************************/
+/* FUNCTION NAME: IHM_init */
+/* DESCRIPTION : Initialise l'afficheur IHM */
+/* RETURN : VOID */
+/****************************************************************************************/
+void IHM_init(void)
+{
+}
+
+
+/****************************************************************************************/
+/* FUNCTION NAME: IHM_gotoxy */
+/* DESCRIPTION : Modifie la position du curseur sur l'afficheur LCD de la carte IHM */
+/* RETURN : VOID */
+/* PARAMETER 1 : UINT8 x : indice de la ligne (0 à 1) */
+/* PARAMETER 2 : UINT8 y : indice de la colonne (0 à 15) */
+/****************************************************************************************/
+void IHM_gotoxy (UINT8 x, UINT8 y)
+{
+ curseur=(x*16+y)%32;
+}
+
+
+/****************************************************************************************/
+/* FUNCTION NAME: IHM_sendchar */
+/* DESCRIPTION : Envoie un caractere à afficher au controleur de l'afficheur LCD */
+/* RETURN : VOID */
+/* PARAMETER 1 : char data : caractère à afficher */
+/****************************************************************************************/
+void IHM_sendchar (char data)
+{
+ tableau_ecran[curseur]=data;
+ curseur=(curseur+1)%32;
+}
+
+
+/****************************************************************************************/
+/* FUNCTION NAME: IHM_printf */
+/* DESCRIPTION : Affichage formaté de type "printf" sur un afficheur LCD */
+/* RETURN : VOID */
+/* PARAMETER 1 : char* format : format d'affichage de printf */
+/* PARAMETER 2 : ... : parametres à afficher */
+/* Attention : le nouvel affichage doit recouvrir le précédent. */
+/*********************** NOTE concernant la commande IHM_printf *************************/
+/* Les appels melangés à printf, LCD_printf et IHM_printf peuvent donner des resutlats */
+/* imprevisibles */
+/* */
+/* L'IHM doit etre initialise par la fonction IHM_init */
+/****************************************************************************************/
+void IHM_printf(const char* format, ...)
+{
+ //oldcurseur=curseur;
+ unsigned char i,j;
+ va_list args;
+ //sprintf(
+ //set_printf(IHM_sendchar); /* Placement des datas dans le tableau */
+ //vputc(IHM_sendchar);
+ va_start(args, format);
+ vsprintf(tableau_ecran+curseur,format, args);
+ va_end(args);
+ // envoi sur le bus can du tableau complet de l'ecran
+ for(j=0;j<4;j++)
+ {
+ trame_Tx.id=LCD_CHAR0+j;
+ trame_Tx.type=CANData;
+ trame_Tx.len=8;
+ for(i=0;i<8;i++)
+ trame_Tx.data[i]=tableau_ecran[i+j*8];
+ while(!can.write(trame_Tx));
+ }
+}
+/****************************************************************************************/
+/* FUNCTION NAME: IHM_sendstring */
+/* DESCRIPTION : Affiche une chaine sur l'IHM */
+/* RETURN : VOID */
+/* PARAMETER 1 : char* message : chaine de caractere a afficher */
+/****************************************************************************************/
+void IHM_sendstring (char* message)
+{
+ unsigned char i,j;
+ sprintf(tableau_ecran+curseur,message);
+
+ for(j=0;j<4;j++)
+ {
+ trame_Tx.id=LCD_CHAR0+j;
+ trame_Tx.type=CANData;
+ trame_Tx.len=8;
+ for(i=0;i<8;i++)
+ trame_Tx.data[i]=tableau_ecran[i+j*8];
+ while(!can.write(trame_Tx));
+ }
+}
+/****************************************************************************************/
+/* FUNCTION NAME: IHM_clear */
+/* DESCRIPTION : Efface le LCD */
+/* RETURN : VOID */
+/****************************************************************************************/
+void IHM_clear(void)
+{
+ UINT8 i;
+ curseur=0;
+ for(i=0;i<32;i++)
+ tableau_ecran[i]=32;
+ while(!can.write(CANMessage(LCD_CLEAR,CANStandard)));
+
+}
+/****************************************************************************************/
+/* FUNCTION NAME: BAR_set */
+/* DESCRIPTION : commande les 10 LED du bargraph */
+/* PARAMETER 1 : UINT16 valeur : ordre d'allumage, exprimé sur les 10 bits de droite.
+ Le bit k doit valoir 0 pour allumer la LED k, 1 pour l'éteindre.
+ Exemple : ~(1<<9) allume la LED 9, ~0x00F allume les 4 LED 0 à 3 */
+/****************************************************************************************/
+void BAR_set(UINT16 valeur)
+{
+ trame_Tx.id=BAR_SET;
+ trame_Tx.type=CANData;
+ trame_Tx.len=2;
+ trame_Tx.data[0]=valeur>>8;
+ trame_Tx.data[1]=(UINT8)valeur;
+ while(!can.write(trame_Tx));
+}
+
+
+/****************************************************************************************/
+/* FUNCTION NAME: JOG_read */
+/* DESCRIPTION : indique la position (parmi les 8 possibles) et l'enfoncement du Jog. */
+/* RETURN : un octet UINT8 qui indique la position (RIGHT, LEFT, UP, DOWN + 4 combinaisons)
+ et l'enfoncement (PUSH) du Jog, exprimés sur 5 bits utiles.*/
+
+ /* - Si le Jog est au repos : la fonction renvoie 0 (0x00).
+ - si le Jog n'est pas au repos : 1 à 3 bits peuvent être mis à 1 dans l'octet renvoyé.
+ Il est intéressant d'utiliser les masques définis en constantes.
+ La signification des 8 bits de la valeur renvoyée est:
+ 0 0 0 RIGHT UP PUSH LEFT DOWN
+ Plusieurs bits peuvent être à 1 en même temps. Par exemple : RIGHT + UP + PUSH
+ à 1 indiquent que le Jog est en position "Nord Est " (UP+RIGHT) et qu'il est enfoncé.
+ Si le Jog est simultanément enfoncé et positionné à droite, la fonction renvoie
+ (0001 0100) en binaire, soit 0x14. Exprimée avec les masques, la valeur renvoyée vaut
+ JOG_MSK_RIGHT | JOG_MSK_PUSH (0x14). */
+/**************************************************************************************************/
+/**************************************************************************************************/
+/* utiliser les Constantes symboliques de IHM.h pour interpréter la valeur renvoyée par le jog... */
+/**************************************************************************************************/
+
+UINT8 JOG_read(void)
+{
+ while(!can.write(CANMessage(JOG_REQ,CANStandard)));
+ while(mise_a_jour_JOG==0)
+ CAN_automate_reception();
+ mise_a_jour_JOG=0;
+ return JOG_valeur;
+
+}
+
+
+/***************************************************************************************************/
+/* FUNCTION NAME: COD_read */
+/* DESCRIPTION : indique la rotation effectuée par le codeur incrémental. */
+/* RETURN : un octet UINT8 dont la valeur entre 0 et 255 indique la rotation du
+ codeur incrémental depuis l'initialisation du codeur (cad de la carte IHM),
+ exprimée en douzièmes de tours. Le codeur dispose en effet de 12 positions
+ et la valeur retournée s'incrémente/se décrémente à chaque 12e de tour.
+ Par exemple, si le codeur a été tourné de 2 tours et demi, la valeur
+ retournée vaut 12+12+6 = 30 = 0x1E (le codeur a effectué 30 douzièmes de tour) */
+/***************************************************************************************************/
+
+SINT8 COD_read(void)
+{
+ while(!can.write(CANMessage(COD_REQ,CANStandard)));
+ while(mise_a_jour_COD==0)
+ CAN_automate_reception();
+ mise_a_jour_COD=0;
+ return COD_valeur;
+
+}
+
+
+
+
+
+
+
+
+
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/IHM/IHM.h Wed Apr 15 06:23:18 2015 +0000 @@ -0,0 +1,151 @@ +#ifndef _IHM_H +#define _IHM_H + +/* FILE: IHM.h */ +/****************************************************************************************/ +/* MODULE NAME: IHM 16x2 */ +/* */ +/* AUTHOR : Jacques-Olivier KLEIN */ +/* Bruno LARNAUDIE */ +/* */ +/* EMAIL : jacques-olivier.klein@u-psud.fr */ +/* bruno.larnaudie@u-psud.fr */ +/* */ +/* INSTITUTION: IUT de CACHAN - 9 av. de la div. Leclerc - 94230 CACHAN */ +/* */ +/* DATE : 12/07/2012 */ +/* CPU : FREESCALE MC9S12XS128MAA */ +/* BOARD : CACHAN Xboard + IHM16x2 */ +/* OS : None */ +/* */ +/* DESCRIPTION: Fonctions d'acc�s au Lcd �mul� passant par le bus CAN */ +/****************************************************************************************/ + +extern int COD_valeur; +extern unsigned char JOG_valeur,mise_a_jour_JOG,mise_a_jour_COD; + +/****************************************************************************************/ +/* Variables globales */ +/****************************************************************************************/ +extern UINT8 curseur; +extern UINT8 IHM_is_running; + +/****************************************************************************************/ +/* Prototypes */ +/****************************************************************************************/ + +/****************************************************************************************/ +/* FUNCTION NAME: IHM_init */ +/* DESCRIPTION : Initialise l'afficheur IHM */ +/* RETURN : VOID */ +/****************************************************************************************/ +void IHM_init(void); + + +/****************************************************************************************/ +/* FUNCTION NAME: IHM_clear */ +/* DESCRIPTION : Efface le LCD */ +/* RETURN : VOID */ +/****************************************************************************************/ +void IHM_clear(void); + +/****************************************************************************************/ +/* FUNCTION NAME: IHM_gotoxy */ +/* DESCRIPTION : Modifie la position du curseur sur l'afficheur LCD de la carte IHM */ +/* RETURN : VOID */ +/* PARAMETER 1 : UINT8 x : indice de la ligne (0 � 1) */ +/* PARAMETER 2 : UINT8 y : indice de la colonne (0 � 15) */ +/****************************************************************************************/ +void IHM_gotoxy (UINT8 x, UINT8 y); + +/****************************************************************************************/ +/* FUNCTION NAME: IHM_printf */ +/* DESCRIPTION : Affichage format� de type "printf" sur un afficheur LCD de l'IHM */ +/* RETURN : VOID */ +/* PARAMETER 1 : char* format : format d'affichage de printf */ +/* PARAMETER 2 : ... : parametres � afficher */ +/* Attention : le nouvel affichage doit recouvrir le pr�c�dent. */ +/*********************** NOTE concernant la commande IHM_printf *************************/ +/* Les appels melang�s � printf, LCD_printf et IHM_printf peuvent donner des resultats */ +/* imprevisibles */ +/* */ +/* L'IHM doit etre initialise par la fonction IHM_init */ +/****************************************************************************************/ +void IHM_printf(const char* format,...) ; + + +/****************************************************************************************/ +/* FUNCTION NAME: IHM_sendchar */ +/* DESCRIPTION : Envoie un caractere � afficher au controleur de l'afficheur LCD */ +/* RETURN : VOID */ +/* PARAMETER 1 : char data : caract�re � afficher */ +/****************************************************************************************/ +void IHM_sendchar (char data); + + +/****************************************************************************************/ +/* FUNCTION NAME: IHM_sendstring */ +/* DESCRIPTION : Affiche une chaine sur l'IHM */ +/* RETURN : VOID */ +/* PARAMETER 1 : char* message : chaine de caractere a afficher */ +/****************************************************************************************/ +void IHM_sendstring (char * message); + + +/****************************************************************************************/ +/* FUNCTION NAME: BAR_set */ +/* DESCRIPTION : commande les 10 LED du bargraph */ +/* PARAMETER 1 : UINT16 valeur : ordre d'allumage, exprim� sur les 10 bits de poids faibles. + Le bit k doit valoir 0 pour allumer la LED k, 1 pour l'�teindre. + Exemple : ~(1<<9) allume la LED 9, ~0x00F allume les 4 LED 0 � 3 */ +/****************************************************************************************/ +void BAR_set(UINT16 valeur); + + +/****************************************************************************************/ +/* FUNCTION NAME: JOG_read */ +/* DESCRIPTION : indique la position (parmi les 8 possibles) et l'enfoncement du Jog. */ +/* RETURN : un octet UINT8 qui indique la position (RIGHT, LEFT, UP, DOWN + 4 combinaisons) + et l'enfoncement (PUSH) du Jog, exprim�s sur 5 bits utiles. + + - Si le Jog est au repos : la fonction renvoie 0 (0x00). + - si le Jog n'est pas au repos : 1 � 3 bits peuvent �tre mis � 1 dans l'octet renvoy�. + Il est int�ressant d'utiliser les masques d�finis en constantes. + La signification des 8 bits de la valeur renvoy�e est: + 0 0 0 RIGHT UP PUSH LEFT DOWN + Plusieurs bits peuvent �tre � 1 en m�me temps. Par exemple : RIGHT + UP + PUSH + � 1 indiquent que le Jog est en position "Nord Est " (UP+RIGHT) et qu'il est enfonc�. + Si le Jog est simultan�ment enfonc� et positionn� � droite, la fonction renvoie + (0001 0100) en binaire, soit 0x14. Exprim�e avec les masques, la valeur renvoy�e vaut + JOG_MSK_RIGHT | JOG_MSK_PUSH (0x14). */ +/**************************************************************************************************/ +UINT8 JOG_read(void); + +/***************************************************************************/ +/* Constantes symboliques pour interpr�ter la valeur renvoy�e par le jog :*/ +/***************************************************************************/ +// les valeurs suivantes peuvent se combiner dans la valeur envoy�e (exemple JOG_MSK_UP | JOG_MSK_PUSH) : + +#define JOG_MSK_PUSH (1<<2) // valeur renvoy�e si le Jog est enfonc� (en position de repos) +#define JOG_MSK_RIGHT (1<<4) // valeur renvoy�e si le Jog est pouss� vers la droite (non enfonc�). +#define JOG_MSK_UP (1<<3) // valeur renvoy�e si le Jog est pouss� vers le haut (non enfonc�). +#define JOG_MSK_LEFT (1<<1) // valeur renvoy�e si le Jog est pouss� vers la gauche (non enfonc�). +#define JOG_MSK_DOWN 1 // valeur renvoy�e si le Jog est pouss� vers le bas (non enfonc�). + + + +/***************************************************************************************************/ +/* FUNCTION NAME: COD_read */ +/* DESCRIPTION : indique la rotation effectu�e par le codeur incr�mental. */ +/* RETURN : un octet UINT8 dont la valeur entre 0 et 255 indique la rotation du + codeur incr�mental depuis l'initialisation du codeur (cad de la carte IHM), + exprim�e en douzi�mes de tours. Le codeur dispose en effet de 12 positions + et la valeur retourn�e s'incr�mente/se d�cr�mente � chaque 12e de tour. + Par exemple, si le codeur a �t� tourn� de 2 tours et demi, la valeur + retourn�e vaut 12+12+6 = 30 = 0x1E (le codeur a effectu� 30 douzi�mes de tour) */ +/***************************************************************************************************/ +SINT8 COD_read(void); + + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/FATFileSystem/ChaN/ccsbcs.cpp Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,540 @@
+/*------------------------------------------------------------------------*/
+/* Unicode - Local code bidirectional converter (C)ChaN, 2009 */
+/* (SBCS code pages) */
+/*------------------------------------------------------------------------*/
+/* 437 U.S. (OEM)
+/ 720 Arabic (OEM)
+/ 1256 Arabic (Windows)
+/ 737 Greek (OEM)
+/ 1253 Greek (Windows)
+/ 1250 Central Europe (Windows)
+/ 775 Baltic (OEM)
+/ 1257 Baltic (Windows)
+/ 850 Multilingual Latin 1 (OEM)
+/ 852 Latin 2 (OEM)
+/ 1252 Latin 1 (Windows)
+/ 855 Cyrillic (OEM)
+/ 1251 Cyrillic (Windows)
+/ 866 Russian (OEM)
+/ 857 Turkish (OEM)
+/ 1254 Turkish (Windows)
+/ 858 Multilingual Latin 1 + Euro (OEM)
+/ 862 Hebrew (OEM)
+/ 1255 Hebrew (Windows)
+/ 874 Thai (OEM, Windows)
+/ 1258 Vietnam (OEM, Windows)
+*/
+
+#include "ff.h"
+
+
+#if _CODE_PAGE == 437
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = { /* CP437(0x80-0xFF) to Unicode conversion table */
+ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7,
+ 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
+ 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9,
+ 0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192,
+ 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA,
+ 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
+ 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
+ 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
+ 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
+ 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
+ 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
+ 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4,
+ 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
+ 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248,
+ 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 720
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = { /* CP720(0x80-0xFF) to Unicode conversion table */
+ 0x0000, 0x0000, 0x00E9, 0x00E2, 0x0000, 0x00E0, 0x0000, 0x00E7,
+ 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0651, 0x0652, 0x00F4, 0x00A4, 0x0640, 0x00FB, 0x00F9,
+ 0x0621, 0x0622, 0x0623, 0x0624, 0x00A3, 0x0625, 0x0626, 0x0627,
+ 0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F,
+ 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x00AB, 0x00BB,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
+ 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
+ 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
+ 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
+ 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
+ 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
+ 0x0636, 0x0637, 0x0638, 0x0639, 0x063A, 0x0641, 0x00B5, 0x0642,
+ 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, 0x0648, 0x0649, 0x064A,
+ 0x2261, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F, 0xO650, 0x2248,
+ 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 737
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = { /* CP737(0x80-0xFF) to Unicode conversion table */
+ 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398,
+ 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, 0x03A0,
+ 0x03A1, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9,
+ 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8,
+ 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0,
+ 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
+ 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
+ 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
+ 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
+ 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
+ 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
+ 0x03C9, 0x03AC, 0x03AD, 0x03AE, 0x03CA, 0x03AF, 0x03CC, 0x03CD,
+ 0x03CB, 0x03CE, 0x0386, 0x0388, 0x0389, 0x038A, 0x038C, 0x038E,
+ 0x038F, 0x00B1, 0x2265, 0x2264, 0x03AA, 0x03AB, 0x00F7, 0x2248,
+ 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 775
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = { /* CP775(0x80-0xFF) to Unicode conversion table */
+ 0x0106, 0x00FC, 0x00E9, 0x0101, 0x00E4, 0x0123, 0x00E5, 0x0107,
+ 0x0142, 0x0113, 0x0156, 0x0157, 0x012B, 0x0179, 0x00C4, 0x00C5,
+ 0x00C9, 0x00E6, 0x00C6, 0x014D, 0x00F6, 0x0122, 0x00A2, 0x015A,
+ 0x015B, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x00A4,
+ 0x0100, 0x012A, 0x00F3, 0x017B, 0x017C, 0x017A, 0x201D, 0x00A6,
+ 0x00A9, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x0141, 0x00AB, 0x00BB,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0104, 0x010C, 0x0118,
+ 0x0116, 0x2563, 0x2551, 0x2557, 0x255D, 0x012E, 0x0160, 0x2510,
+ 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0172, 0x016A,
+ 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x017D,
+ 0x0105, 0x010D, 0x0119, 0x0117, 0x012F, 0x0161, 0x0173, 0x016B,
+ 0x017E, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
+ 0x00D3, 0x00DF, 0x014C, 0x0143, 0x00F5, 0x00D5, 0x00B5, 0x0144,
+ 0x0136, 0x0137, 0x013B, 0x013C, 0x0146, 0x0112, 0x0145, 0x2019,
+ 0x00AD, 0x00B1, 0x201C, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x201E,
+ 0x00B0, 0x2219, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 850
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = { /* CP850(0x80-0xFF) to Unicode conversion table */
+ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7,
+ 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
+ 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9,
+ 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192,
+ 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA,
+ 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0,
+ 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510,
+ 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3,
+ 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
+ 0x00F0, 0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x0131, 0x00CD, 0x00CE,
+ 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580,
+ 0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE,
+ 0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4,
+ 0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8,
+ 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 852
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = { /* CP852(0x80-0xFF) to Unicode conversion table */
+ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x016F, 0x0107, 0x00E7,
+ 0x0142, 0x00EB, 0x0150, 0x0151, 0x00EE, 0x0179, 0x00C4, 0x0106,
+ 0x00C9, 0x0139, 0x013A, 0x00F4, 0x00F6, 0x013D, 0x013E, 0x015A,
+ 0x015B, 0x00D6, 0x00DC, 0x0164, 0x0165, 0x0141, 0x00D7, 0x010D,
+ 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x0104, 0x0105, 0x017D, 0x017E,
+ 0x0118, 0x0119, 0x00AC, 0x017A, 0x010C, 0x015F, 0x00AB, 0x00BB,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x011A,
+ 0x015E, 0x2563, 0x2551, 0x2557, 0x255D, 0x017B, 0x017C, 0x2510,
+ 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0102, 0x0103,
+ 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
+ 0x0111, 0x0110, 0x010E, 0x00CB, 0x010F, 0x0147, 0x00CD, 0x00CE,
+ 0x011B, 0x2518, 0x250C, 0x2588, 0x2584, 0x0162, 0x016E, 0x2580,
+ 0x00D3, 0x00DF, 0x00D4, 0x0143, 0x0144, 0x0148, 0x0160, 0x0161,
+ 0x0154, 0x00DA, 0x0155, 0x0170, 0x00FD, 0x00DD, 0x0163, 0x00B4,
+ 0x00AD, 0x02DD, 0x02DB, 0x02C7, 0x02D8, 0x00A7, 0x00F7, 0x00B8,
+ 0x00B0, 0x00A8, 0x02D9, 0x0171, 0x0158, 0x0159, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 855
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = { /* CP855(0x80-0xFF) to Unicode conversion table */
+ 0x0452, 0x0402, 0x0453, 0x0403, 0x0451, 0x0401, 0x0454, 0x0404,
+ 0x0455, 0x0405, 0x0456, 0x0406, 0x0457, 0x0407, 0x0458, 0x0408,
+ 0x0459, 0x0409, 0x045A, 0x040A, 0x045B, 0x040B, 0x045C, 0x040C,
+ 0x045E, 0x040E, 0x045F, 0x040F, 0x044E, 0x042E, 0x044A, 0x042A,
+ 0x0430, 0x0410, 0x0431, 0x0411, 0x0446, 0x0426, 0x0434, 0x0414,
+ 0x0435, 0x0415, 0x0444, 0x0424, 0x0433, 0x0413, 0x00AB, 0x00BB,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0445, 0x0425, 0x0438,
+ 0x0418, 0x2563, 0x2551, 0x2557, 0x255D, 0x0439, 0x0419, 0x2510,
+ 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x043A, 0x041A,
+ 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
+ 0x043B, 0x041B, 0x043C, 0x041C, 0x043D, 0x041D, 0x043E, 0x041E,
+ 0x043F, 0x2518, 0x250C, 0x2588, 0x2584, 0x041F, 0x044F, 0x2580,
+ 0x042F, 0x0440, 0x0420, 0x0441, 0x0421, 0x0442, 0x0422, 0x0443,
+ 0x0423, 0x0436, 0x0416, 0x0432, 0x0412, 0x044C, 0x042C, 0x2116,
+ 0x00AD, 0x044B, 0x042B, 0x0437, 0x0417, 0x0448, 0x0428, 0x044D,
+ 0x042D, 0x0449, 0x0429, 0x0447, 0x0427, 0x00A7, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 857
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = { /* CP857(0x80-0xFF) to Unicode conversion table */
+ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7,
+ 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0131, 0x00C4, 0x00C5,
+ 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9,
+ 0x0130, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x015E, 0x015F,
+ 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x011E, 0x011F,
+ 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0,
+ 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510,
+ 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3,
+ 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
+ 0x00BA, 0x00AA, 0x00CA, 0x00CB, 0x00C8, 0x0000, 0x00CD, 0x00CE,
+ 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580,
+ 0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x0000,
+ 0x00D7, 0x00DA, 0x00DB, 0x00D9, 0x00EC, 0x00FF, 0x00AF, 0x00B4,
+ 0x00AD, 0x00B1, 0x0000, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8,
+ 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 858
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = { /* CP858(0x80-0xFF) to Unicode conversion table */
+ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7,
+ 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
+ 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9,
+ 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192,
+ 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA,
+ 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0,
+ 0x00A9, 0x2563, 0x2551, 0x2557, 0x2550, 0x00A2, 0x00A5, 0x2510,
+ 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3,
+ 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
+ 0x00F0, 0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x20AC, 0x00CD, 0x00CE,
+ 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00C6, 0x00CC, 0x2580,
+ 0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE,
+ 0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4,
+ 0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8,
+ 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 862
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = { /* CP862(0x80-0xFF) to Unicode conversion table */
+ 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7,
+ 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,
+ 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7,
+ 0x05E8, 0x05E9, 0x05EA, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192,
+ 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA,
+ 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
+ 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
+ 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
+ 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
+ 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
+ 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
+ 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4,
+ 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
+ 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248,
+ 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 866
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = { /* CP866(0x80-0xFF) to Unicode conversion table */
+ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417,
+ 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
+ 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427,
+ 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
+ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
+ 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
+ 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
+ 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
+ 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
+ 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
+ 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
+ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
+ 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
+ 0x0401, 0x0451, 0x0404, 0x0454, 0x0407, 0x0457, 0x040E, 0x045E,
+ 0x00B0, 0x2219, 0x00B7, 0x221A, 0x2116, 0x00A4, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 874
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = { /* CP874(0x80-0xFF) to Unicode conversion table */
+ 0x20AC, 0x0000, 0x0000, 0x0000, 0x0000, 0x2026, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x00A0, 0x0E01, 0x0E02, 0x0E03, 0x0E04, 0x0E05, 0x0E06, 0x0E07,
+ 0x0E08, 0x0E09, 0x0E0A, 0x0E0B, 0x0E0C, 0x0E0D, 0x0E0E, 0x0E0F,
+ 0x0E10, 0x0E11, 0x0E12, 0x0E13, 0x0E14, 0x0E15, 0x0E16, 0x0E17,
+ 0x0E18, 0x0E19, 0x0E1A, 0x0E1B, 0x0E1C, 0x0E1D, 0x0E1E, 0x0E1F,
+ 0x0E20, 0x0E21, 0x0E22, 0x0E23, 0x0E24, 0x0E25, 0x0E26, 0x0E27,
+ 0x0E28, 0x0E29, 0x0E2A, 0x0E2B, 0x0E2C, 0x0E2D, 0x0E2E, 0x0E2F,
+ 0x0E30, 0x0E31, 0x0E32, 0x0E33, 0x0E34, 0x0E35, 0x0E36, 0x0E37,
+ 0x0E38, 0x0E39, 0x0E3A, 0x0000, 0x0000, 0x0000, 0x0000, 0x0E3F,
+ 0x0E40, 0x0E41, 0x0E42, 0x0E43, 0x0E44, 0x0E45, 0x0E46, 0x0E47,
+ 0x0E48, 0x0E49, 0x0E4A, 0x0E4B, 0x0E4C, 0x0E4D, 0x0E4E, 0x0E4F,
+ 0x0E50, 0x0E51, 0x0E52, 0x0E53, 0x0E54, 0x0E55, 0x0E56, 0x0E57,
+ 0x0E58, 0x0E59, 0x0E5A, 0x0E5B, 0x0000, 0x0000, 0x0000, 0x0000
+};
+
+#elif _CODE_PAGE == 1250
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = { /* CP1250(0x80-0xFF) to Unicode conversion table */
+ 0x20AC, 0x0000, 0x201A, 0x0000, 0x201E, 0x2026, 0x2020, 0x2021,
+ 0x0000, 0x2030, 0x0160, 0x2039, 0x015A, 0x0164, 0x017D, 0x0179,
+ 0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+ 0x0000, 0x2122, 0x0161, 0x203A, 0x015B, 0x0165, 0x017E, 0x017A,
+ 0x00A0, 0x02C7, 0x02D8, 0x0141, 0x00A4, 0x0104, 0x00A6, 0x00A7,
+ 0x00A8, 0x00A9, 0x015E, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x017B,
+ 0x00B0, 0x00B1, 0x02DB, 0x0142, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+ 0x00B8, 0x0105, 0x015F, 0x00BB, 0x013D, 0x02DD, 0x013E, 0x017C,
+ 0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7,
+ 0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E,
+ 0x0110, 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7,
+ 0x0158, 0x016E, 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162, 0x00DF,
+ 0x0155, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x013A, 0x0107, 0x00E7,
+ 0x010D, 0x00E9, 0x0119, 0x00EB, 0x011B, 0x00ED, 0x00EE, 0x010F,
+ 0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x00F7,
+ 0x0159, 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD, 0x0163, 0x02D9
+};
+
+#elif _CODE_PAGE == 1251
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = { /* CP1251(0x80-0xFF) to Unicode conversion table */
+ 0x0402, 0x0403, 0x201A, 0x0453, 0x201E, 0x2026, 0x2020, 0x2021,
+ 0x20AC, 0x2030, 0x0409, 0x2039, 0x040A, 0x040C, 0x040B, 0x040F,
+ 0x0452, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+ 0x0000, 0x2111, 0x0459, 0x203A, 0x045A, 0x045C, 0x045B, 0x045F,
+ 0x00A0, 0x040E, 0x045E, 0x0408, 0x00A4, 0x0490, 0x00A6, 0x00A7,
+ 0x0401, 0x00A9, 0x0404, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x0407,
+ 0x00B0, 0x00B1, 0x0406, 0x0456, 0x0491, 0x00B5, 0x00B6, 0x00B7,
+ 0x0451, 0x2116, 0x0454, 0x00BB, 0x0458, 0x0405, 0x0455, 0x0457,
+ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417,
+ 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
+ 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427,
+ 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
+ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
+ 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
+ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
+ 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F
+};
+
+#elif _CODE_PAGE == 1252
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = { /* CP1252(0x80-0xFF) to Unicode conversion table */
+ 0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
+ 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0x0000, 0x017D, 0x0000,
+ 0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+ 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0x0000, 0x017E, 0x0178,
+ 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+ 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+ 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
+ 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
+ 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
+ 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7,
+ 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF,
+ 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
+ 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
+ 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7,
+ 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF
+};
+
+#elif _CODE_PAGE == 1253
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = { /* CP1253(0x80-0xFF) to Unicode conversion table */
+ 0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
+ 0x0000, 0x2030, 0x0000, 0x2039, 0x000C, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+ 0x0000, 0x2122, 0x0000, 0x203A, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x00A0, 0x0385, 0x0386, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+ 0x00A8, 0x00A9, 0x0000, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x2015,
+ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x0384, 0x00B5, 0x00B6, 0x00B7,
+ 0x0388, 0x0389, 0x038A, 0x00BB, 0x038C, 0x00BD, 0x038E, 0x038F,
+ 0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397,
+ 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F,
+ 0x03A0, 0x03A1, 0x0000, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7,
+ 0x03A8, 0x03A9, 0x03AA, 0x03AD, 0x03AC, 0x03AD, 0x03AE, 0x03AF,
+ 0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7,
+ 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
+ 0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7,
+ 0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0x0000
+};
+
+#elif _CODE_PAGE == 1254
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = { /* CP1254(0x80-0xFF) to Unicode conversion table */
+ 0x20AC, 0x0000, 0x210A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
+ 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+ 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0x0000, 0x0000, 0x0178,
+ 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+ 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+ 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
+ 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
+ 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
+ 0x011E, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7,
+ 0x00D8, 0x00D9, 0x00DA, 0x00BD, 0x00DC, 0x0130, 0x015E, 0x00DF,
+ 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
+ 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
+ 0x011F, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7,
+ 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x0131, 0x015F, 0x00FF
+};
+
+#elif _CODE_PAGE == 1255
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = { /* CP1255(0x80-0xFF) to Unicode conversion table */
+ 0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
+ 0x02C6, 0x2030, 0x0000, 0x2039, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+ 0x02DC, 0x2122, 0x0000, 0x203A, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+ 0x00A8, 0x00A9, 0x00D7, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+ 0x00B8, 0x00B9, 0x00F7, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
+ 0x05B0, 0x05B1, 0x05B2, 0x05B3, 0x05B4, 0x05B5, 0x05B6, 0x05B7,
+ 0x05B8, 0x05B9, 0x0000, 0x05BB, 0x05BC, 0x05BD, 0x05BE, 0x05BF,
+ 0x05C0, 0x05C1, 0x05C2, 0x05C3, 0x05F0, 0x05F1, 0x05F2, 0x05F3,
+ 0x05F4, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7,
+ 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,
+ 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7,
+ 0x05E8, 0x05E9, 0x05EA, 0x0000, 0x0000, 0x200E, 0x200F, 0x0000
+};
+
+#elif _CODE_PAGE == 1256
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = { /* CP1256(0x80-0xFF) to Unicode conversion table */
+ 0x20AC, 0x067E, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
+ 0x02C6, 0x2030, 0x0679, 0x2039, 0x0152, 0x0686, 0x0698, 0x0688,
+ 0x06AF, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+ 0x06A9, 0x2122, 0x0691, 0x203A, 0x0153, 0x200C, 0x200D, 0x06BA,
+ 0x00A0, 0x060C, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+ 0x00A8, 0x00A9, 0x06BE, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+ 0x00B8, 0x00B9, 0x061B, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x061F,
+ 0x06C1, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627,
+ 0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F,
+ 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x00D7,
+ 0x0637, 0x0638, 0x0639, 0x063A, 0x0640, 0x0640, 0x0642, 0x0643,
+ 0x00E0, 0x0644, 0x00E2, 0x0645, 0x0646, 0x0647, 0x0648, 0x00E7,
+ 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x0649, 0x064A, 0x00EE, 0x00EF,
+ 0x064B, 0x064C, 0x064D, 0x064E, 0x00F4, 0x064F, 0x0650, 0x00F7,
+ 0x0651, 0x00F9, 0x0652, 0x00FB, 0x00FC, 0x200E, 0x200F, 0x06D2
+}
+
+#elif _CODE_PAGE == 1257
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = { /* CP1257(0x80-0xFF) to Unicode conversion table */
+ 0x20AC, 0x0000, 0x201A, 0x0000, 0x201E, 0x2026, 0x2020, 0x2021,
+ 0x0000, 0x2030, 0x0000, 0x2039, 0x0000, 0x00A8, 0x02C7, 0x00B8,
+ 0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+ 0x0000, 0x2122, 0x0000, 0x203A, 0x0000, 0x00AF, 0x02DB, 0x0000,
+ 0x00A0, 0x0000, 0x00A2, 0x00A3, 0x00A4, 0x0000, 0x00A6, 0x00A7,
+ 0x00D8, 0x00A9, 0x0156, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+ 0x00B8, 0x00B9, 0x0157, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00E6,
+ 0x0104, 0x012E, 0x0100, 0x0106, 0x00C4, 0x00C5, 0x0118, 0x0112,
+ 0x010C, 0x00C9, 0x0179, 0x0116, 0x0122, 0x0136, 0x012A, 0x013B,
+ 0x0160, 0x0143, 0x0145, 0x00D3, 0x014C, 0x00D5, 0x00D6, 0x00D7,
+ 0x0172, 0x0141, 0x015A, 0x016A, 0x00DC, 0x017B, 0x017D, 0x00DF,
+ 0x0105, 0x012F, 0x0101, 0x0107, 0x00E4, 0x00E5, 0x0119, 0x0113,
+ 0x010D, 0x00E9, 0x017A, 0x0117, 0x0123, 0x0137, 0x012B, 0x013C,
+ 0x0161, 0x0144, 0x0146, 0x00F3, 0x014D, 0x00F5, 0x00F6, 0x00F7,
+ 0x0173, 0x014E, 0x015B, 0x016B, 0x00FC, 0x017C, 0x017E, 0x02D9
+};
+
+#elif _CODE_PAGE == 1258
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = { /* CP1258(0x80-0xFF) to Unicode conversion table */
+ 0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
+ 0x02C6, 0x2030, 0x0000, 0x2039, 0x0152, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+ 0x02DC, 0x2122, 0x0000, 0x203A, 0x0153, 0x0000, 0x0000, 0x0178,
+ 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+ 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+ 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
+ 0x00C0, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
+ 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x0300, 0x00CD, 0x00CE, 0x00CF,
+ 0x0110, 0x00D1, 0x0309, 0x00D3, 0x00D4, 0x01A0, 0x00D6, 0x00D7,
+ 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x01AF, 0x0303, 0x00DF,
+ 0x00E0, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
+ 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x0301, 0x00ED, 0x00EE, 0x00EF,
+ 0x0111, 0x00F1, 0x0323, 0x00F3, 0x00F4, 0x01A1, 0x00F6, 0x00F7,
+ 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x01B0, 0x20AB, 0x00FF
+};
+
+#endif
+
+
+#if !_TBLDEF || !_USE_LFN
+#error This file is not needed in current configuration. Remove from the project.
+#endif
+
+
+WCHAR ff_convert ( /* Converted character, Returns zero on error */
+ WCHAR src, /* Character code to be converted */
+ UINT dir /* 0: Unicode to OEMCP, 1: OEMCP to Unicode */
+)
+{
+ WCHAR c;
+
+
+ if (src < 0x80) { /* ASCII */
+ c = src;
+
+ } else {
+ if (dir) { /* OEMCP to Unicode */
+ c = (src >= 0x100) ? 0 : Tbl[src - 0x80];
+
+ } else { /* Unicode to OEMCP */
+ for (c = 0; c < 0x80; c++) {
+ if (src == Tbl[c]) break;
+ }
+ c = (c + 0x80) & 0xFF;
+ }
+ }
+
+ return c;
+}
+
+
+WCHAR ff_wtoupper ( /* Upper converted character */
+ WCHAR chr /* Input character */
+)
+{
+ static const WCHAR tbl_lower[] = { 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0xA1, 0x00A2, 0x00A3, 0x00A5, 0x00AC, 0x00AF, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0x0FF, 0x101, 0x103, 0x105, 0x107, 0x109, 0x10B, 0x10D, 0x10F, 0x111, 0x113, 0x115, 0x117, 0x119, 0x11B, 0x11D, 0x11F, 0x121, 0x123, 0x125, 0x127, 0x129, 0x12B, 0x12D, 0x12F, 0x131, 0x133, 0x135, 0x137, 0x13A, 0x13C, 0x13E, 0x140, 0x142, 0x144, 0x146, 0x148, 0x14B, 0x14D, 0x14F, 0x151, 0x153, 0x155, 0x157, 0x159, 0x15B, 0x15D, 0x15F, 0x161, 0x163, 0x165, 0x167, 0x169, 0x16B, 0x16D, 0x16F, 0x171, 0x173, 0x175, 0x177, 0x17A, 0x17C, 0x17E, 0x192, 0x3B1, 0x3B2, 0x3B3, 0x3B4, 0x3B5, 0x3B6, 0x3B7, 0x3B8, 0x3B9, 0x3BA, 0x3BB, 0x3BC, 0x3BD, 0x3BE, 0x3BF, 0x3C0, 0x3C1, 0x3C3, 0x3C4, 0x3C5, 0x3C6, 0x3C7, 0x3C8, 0x3C9, 0x3CA, 0x430, 0x431, 0x432, 0x433, 0x434, 0x435, 0x436, 0x437, 0x438, 0x439, 0x43A, 0x43B, 0x43C, 0x43D, 0x43E, 0x43F, 0x440, 0x441, 0x442, 0x443, 0x444, 0x445, 0x446, 0x447, 0x448, 0x449, 0x44A, 0x44B, 0x44C, 0x44D, 0x44E, 0x44F, 0x451, 0x452, 0x453, 0x454, 0x455, 0x456, 0x457, 0x458, 0x459, 0x45A, 0x45B, 0x45C, 0x45E, 0x45F, 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177, 0x2178, 0x2179, 0x217A, 0x217B, 0x217C, 0x217D, 0x217E, 0x217F, 0xFF41, 0xFF42, 0xFF43, 0xFF44, 0xFF45, 0xFF46, 0xFF47, 0xFF48, 0xFF49, 0xFF4A, 0xFF4B, 0xFF4C, 0xFF4D, 0xFF4E, 0xFF4F, 0xFF50, 0xFF51, 0xFF52, 0xFF53, 0xFF54, 0xFF55, 0xFF56, 0xFF57, 0xFF58, 0xFF59, 0xFF5A, 0 };
+ static const WCHAR tbl_upper[] = { 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x21, 0xFFE0, 0xFFE1, 0xFFE5, 0xFFE2, 0xFFE3, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0x178, 0x100, 0x102, 0x104, 0x106, 0x108, 0x10A, 0x10C, 0x10E, 0x110, 0x112, 0x114, 0x116, 0x118, 0x11A, 0x11C, 0x11E, 0x120, 0x122, 0x124, 0x126, 0x128, 0x12A, 0x12C, 0x12E, 0x130, 0x132, 0x134, 0x136, 0x139, 0x13B, 0x13D, 0x13F, 0x141, 0x143, 0x145, 0x147, 0x14A, 0x14C, 0x14E, 0x150, 0x152, 0x154, 0x156, 0x158, 0x15A, 0x15C, 0x15E, 0x160, 0x162, 0x164, 0x166, 0x168, 0x16A, 0x16C, 0x16E, 0x170, 0x172, 0x174, 0x176, 0x179, 0x17B, 0x17D, 0x191, 0x391, 0x392, 0x393, 0x394, 0x395, 0x396, 0x397, 0x398, 0x399, 0x39A, 0x39B, 0x39C, 0x39D, 0x39E, 0x39F, 0x3A0, 0x3A1, 0x3A3, 0x3A4, 0x3A5, 0x3A6, 0x3A7, 0x3A8, 0x3A9, 0x3AA, 0x410, 0x411, 0x412, 0x413, 0x414, 0x415, 0x416, 0x417, 0x418, 0x419, 0x41A, 0x41B, 0x41C, 0x41D, 0x41E, 0x41F, 0x420, 0x421, 0x422, 0x423, 0x424, 0x425, 0x426, 0x427, 0x428, 0x429, 0x42A, 0x42B, 0x42C, 0x42D, 0x42E, 0x42F, 0x401, 0x402, 0x403, 0x404, 0x405, 0x406, 0x407, 0x408, 0x409, 0x40A, 0x40B, 0x40C, 0x40E, 0x40F, 0x2160, 0x2161, 0x2162, 0x2163, 0x2164, 0x2165, 0x2166, 0x2167, 0x2168, 0x2169, 0x216A, 0x216B, 0x216C, 0x216D, 0x216E, 0x216F, 0xFF21, 0xFF22, 0xFF23, 0xFF24, 0xFF25, 0xFF26, 0xFF27, 0xFF28, 0xFF29, 0xFF2A, 0xFF2B, 0xFF2C, 0xFF2D, 0xFF2E, 0xFF2F, 0xFF30, 0xFF31, 0xFF32, 0xFF33, 0xFF34, 0xFF35, 0xFF36, 0xFF37, 0xFF38, 0xFF39, 0xFF3A, 0 };
+ int i;
+
+
+ for (i = 0; tbl_lower[i] && chr != tbl_lower[i]; i++) ;
+
+ return tbl_lower[i] ? tbl_upper[i] : chr;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/FATFileSystem/ChaN/diskio.cpp Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,94 @@
+/*-----------------------------------------------------------------------*/
+/* Low level disk I/O module skeleton for FatFs (C)ChaN, 2007 */
+/*-----------------------------------------------------------------------*/
+/* This is a stub disk I/O module that acts as front end of the existing */
+/* disk I/O modules and attach it to FatFs module with common interface. */
+/*-----------------------------------------------------------------------*/
+#include "ffconf.h"
+#include "diskio.h"
+
+#include "mbed_debug.h"
+#include "FATFileSystem.h"
+
+using namespace mbed;
+
+DSTATUS disk_initialize (
+ BYTE drv /* Physical drive nmuber (0..) */
+)
+{
+ debug_if(FFS_DBG, "disk_initialize on drv [%d]\n", drv);
+ return (DSTATUS)FATFileSystem::_ffs[drv]->disk_initialize();
+}
+
+DSTATUS disk_status (
+ BYTE drv /* Physical drive nmuber (0..) */
+)
+{
+ debug_if(FFS_DBG, "disk_status on drv [%d]\n", drv);
+ return (DSTATUS)FATFileSystem::_ffs[drv]->disk_status();
+}
+
+DRESULT disk_read (
+ BYTE drv, /* Physical drive nmuber (0..) */
+ BYTE *buff, /* Data buffer to store read data */
+ DWORD sector, /* Sector address (LBA) */
+ BYTE count /* Number of sectors to read (1..255) */
+)
+{
+ debug_if(FFS_DBG, "disk_read(sector %d, count %d) on drv [%d]\n", sector, count, drv);
+ if (FATFileSystem::_ffs[drv]->disk_read((uint8_t*)buff, sector, count))
+ return RES_PARERR;
+ else
+ return RES_OK;
+}
+
+#if _READONLY == 0
+DRESULT disk_write (
+ BYTE drv, /* Physical drive nmuber (0..) */
+ const BYTE *buff, /* Data to be written */
+ DWORD sector, /* Sector address (LBA) */
+ BYTE count /* Number of sectors to write (1..255) */
+)
+{
+ debug_if(FFS_DBG, "disk_write(sector %d, count %d) on drv [%d]\n", sector, count, drv);
+ if (FATFileSystem::_ffs[drv]->disk_write((uint8_t*)buff, sector, count))
+ return RES_PARERR;
+ else
+ return RES_OK;
+}
+#endif /* _READONLY */
+
+DRESULT disk_ioctl (
+ BYTE drv, /* Physical drive nmuber (0..) */
+ BYTE ctrl, /* Control code */
+ void *buff /* Buffer to send/receive control data */
+)
+{
+ debug_if(FFS_DBG, "disk_ioctl(%d)\n", ctrl);
+ switch(ctrl) {
+ case CTRL_SYNC:
+ if(FATFileSystem::_ffs[drv] == NULL) {
+ return RES_NOTRDY;
+ } else if(FATFileSystem::_ffs[drv]->disk_sync()) {
+ return RES_ERROR;
+ }
+ return RES_OK;
+ case GET_SECTOR_COUNT:
+ if(FATFileSystem::_ffs[drv] == NULL) {
+ return RES_NOTRDY;
+ } else {
+ DWORD res = FATFileSystem::_ffs[drv]->disk_sectors();
+ if(res > 0) {
+ *((DWORD*)buff) = res; // minimum allowed
+ return RES_OK;
+ } else {
+ return RES_ERROR;
+ }
+ }
+ case GET_BLOCK_SIZE:
+ *((DWORD*)buff) = 1; // default when not known
+ return RES_OK;
+
+ }
+ return RES_PARERR;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/FATFileSystem/ChaN/diskio.h Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,76 @@
+//-----------------------------------------------------------------------
+// Low level disk interface modlue include file
+//-----------------------------------------------------------------------
+
+#ifndef _DISKIO
+
+#define _READONLY 0 // 1: Remove write functions
+#define _USE_IOCTL 1 // 1: Use disk_ioctl fucntion
+
+#include "integer.h"
+
+
+// Status of Disk Functions
+typedef BYTE DSTATUS;
+
+// Results of Disk Functions
+typedef enum {
+ RES_OK = 0, // 0: Successful
+ RES_ERROR, // 1: R/W Error
+ RES_WRPRT, // 2: Write Protected
+ RES_NOTRDY, // 3: Not Ready
+ RES_PARERR // 4: Invalid Parameter
+} DRESULT;
+
+
+// Prototypes for disk control functions
+
+int assign_drives (int, int);
+DSTATUS disk_initialize (BYTE);
+DSTATUS disk_status (BYTE);
+DRESULT disk_read (BYTE, BYTE*, DWORD, BYTE);
+#if _READONLY == 0
+DRESULT disk_write (BYTE, const BYTE*, DWORD, BYTE);
+#endif
+DRESULT disk_ioctl (BYTE, BYTE, void*);
+
+
+
+// Disk Status Bits (DSTATUS)
+#define STA_NOINIT 0x01 // Drive not initialized
+#define STA_NODISK 0x02 // No medium in the drive
+#define STA_PROTECT 0x04 // Write protected
+
+
+// Command code for disk_ioctrl fucntion
+
+// Generic command (defined for FatFs)
+#define CTRL_SYNC 0 // Flush disk cache (for write functions)
+#define GET_SECTOR_COUNT 1 // Get media size (for only f_mkfs())
+#define GET_SECTOR_SIZE 2 // Get sector size (for multiple sector size (_MAX_SS >= 1024))
+#define GET_BLOCK_SIZE 3 // Get erase block size (for only f_mkfs())
+#define CTRL_ERASE_SECTOR 4 // Force erased a block of sectors (for only _USE_ERASE)
+
+// Generic command
+#define CTRL_POWER 5 // Get/Set power status
+#define CTRL_LOCK 6 // Lock/Unlock media removal
+#define CTRL_EJECT 7 // Eject media
+
+// MMC/SDC specific ioctl command
+#define MMC_GET_TYPE 10 // Get card type
+#define MMC_GET_CSD 11 // Get CSD
+#define MMC_GET_CID 12 // Get CID
+#define MMC_GET_OCR 13 // Get OCR
+#define MMC_GET_SDSTAT 14 // Get SD status
+
+// ATA/CF specific ioctl command
+#define ATA_GET_REV 20 // Get F/W revision
+#define ATA_GET_MODEL 21 // Get model name
+#define ATA_GET_SN 22 // Get serial number
+
+// NAND specific ioctl command
+#define NAND_FORMAT 30 // Create physical format
+
+
+#define _DISKIO
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/FATFileSystem/ChaN/ff.cpp Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,4153 @@
+/*----------------------------------------------------------------------------/
+/ FatFs - FAT file system module R0.09a (C)ChaN, 2012
+/-----------------------------------------------------------------------------/
+/ FatFs module is a generic FAT file system module for small embedded systems.
+/ This is a free software that opened for education, research and commercial
+/ developments under license policy of following terms.
+/
+/ Copyright (C) 2012, ChaN, all right reserved.
+/
+/ * The FatFs module is a free software and there is NO WARRANTY.
+/ * No restriction on use. You can use, modify and redistribute it for
+/ personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY.
+/ * Redistributions of source code must retain the above copyright notice.
+/
+/-----------------------------------------------------------------------------/
+/ Feb 26,'06 R0.00 Prototype.
+/
+/ Apr 29,'06 R0.01 First stable version.
+/
+/ Jun 01,'06 R0.02 Added FAT12 support.
+/ Removed unbuffered mode.
+/ Fixed a problem on small (<32M) partition.
+/ Jun 10,'06 R0.02a Added a configuration option (_FS_MINIMUM).
+/
+/ Sep 22,'06 R0.03 Added f_rename().
+/ Changed option _FS_MINIMUM to _FS_MINIMIZE.
+/ Dec 11,'06 R0.03a Improved cluster scan algorithm to write files fast.
+/ Fixed f_mkdir() creates incorrect directory on FAT32.
+/
+/ Feb 04,'07 R0.04 Supported multiple drive system.
+/ Changed some interfaces for multiple drive system.
+/ Changed f_mountdrv() to f_mount().
+/ Added f_mkfs().
+/ Apr 01,'07 R0.04a Supported multiple partitions on a physical drive.
+/ Added a capability of extending file size to f_lseek().
+/ Added minimization level 3.
+/ Fixed an endian sensitive code in f_mkfs().
+/ May 05,'07 R0.04b Added a configuration option _USE_NTFLAG.
+/ Added FSInfo support.
+/ Fixed DBCS name can result FR_INVALID_NAME.
+/ Fixed short seek (<= csize) collapses the file object.
+/
+/ Aug 25,'07 R0.05 Changed arguments of f_read(), f_write() and f_mkfs().
+/ Fixed f_mkfs() on FAT32 creates incorrect FSInfo.
+/ Fixed f_mkdir() on FAT32 creates incorrect directory.
+/ Feb 03,'08 R0.05a Added f_truncate() and f_utime().
+/ Fixed off by one error at FAT sub-type determination.
+/ Fixed btr in f_read() can be mistruncated.
+/ Fixed cached sector is not flushed when create and close without write.
+/
+/ Apr 01,'08 R0.06 Added fputc(), fputs(), fprintf() and fgets().
+/ Improved performance of f_lseek() on moving to the same or following cluster.
+/
+/ Apr 01,'09 R0.07 Merged Tiny-FatFs as a configuration option. (_FS_TINY)
+/ Added long file name feature.
+/ Added multiple code page feature.
+/ Added re-entrancy for multitask operation.
+/ Added auto cluster size selection to f_mkfs().
+/ Added rewind option to f_readdir().
+/ Changed result code of critical errors.
+/ Renamed string functions to avoid name collision.
+/ Apr 14,'09 R0.07a Separated out OS dependent code on reentrant cfg.
+/ Added multiple sector size feature.
+/ Jun 21,'09 R0.07c Fixed f_unlink() can return FR_OK on error.
+/ Fixed wrong cache control in f_lseek().
+/ Added relative path feature.
+/ Added f_chdir() and f_chdrive().
+/ Added proper case conversion to extended char.
+/ Nov 03,'09 R0.07e Separated out configuration options from ff.h to ffconf.h.
+/ Fixed f_unlink() fails to remove a sub-dir on _FS_RPATH.
+/ Fixed name matching error on the 13 char boundary.
+/ Added a configuration option, _LFN_UNICODE.
+/ Changed f_readdir() to return the SFN with always upper case on non-LFN cfg.
+/
+/ May 15,'10 R0.08 Added a memory configuration option. (_USE_LFN = 3)
+/ Added file lock feature. (_FS_SHARE)
+/ Added fast seek feature. (_USE_FASTSEEK)
+/ Changed some types on the API, XCHAR->TCHAR.
+/ Changed fname member in the FILINFO structure on Unicode cfg.
+/ String functions support UTF-8 encoding files on Unicode cfg.
+/ Aug 16,'10 R0.08a Added f_getcwd(). (_FS_RPATH = 2)
+/ Added sector erase feature. (_USE_ERASE)
+/ Moved file lock semaphore table from fs object to the bss.
+/ Fixed a wrong directory entry is created on non-LFN cfg when the given name contains ';'.
+/ Fixed f_mkfs() creates wrong FAT32 volume.
+/ Jan 15,'11 R0.08b Fast seek feature is also applied to f_read() and f_write().
+/ f_lseek() reports required table size on creating CLMP.
+/ Extended format syntax of f_printf function.
+/ Ignores duplicated directory separators in given path name.
+/
+/ Sep 06,'11 R0.09 f_mkfs() supports multiple partition to finish the multiple partition feature.
+/ Added f_fdisk(). (_MULTI_PARTITION = 2)
+/ Aug 27,'12 R0.09a Fixed assertion failure due to OS/2 EA on FAT12/16 volume.
+/ Changed f_open() and f_opendir reject null object pointer to avoid crash.
+/ Changed option name _FS_SHARE to _FS_LOCK.
+/---------------------------------------------------------------------------*/
+
+#include "ff.h" /* FatFs configurations and declarations */
+#include "diskio.h" /* Declarations of low level disk I/O functions */
+
+
+/*--------------------------------------------------------------------------
+
+ Module Private Definitions
+
+---------------------------------------------------------------------------*/
+
+#if _FATFS != 4004 /* Revision ID */
+#error Wrong include file (ff.h).
+#endif
+
+
+/* Definitions on sector size */
+#if _MAX_SS != 512 && _MAX_SS != 1024 && _MAX_SS != 2048 && _MAX_SS != 4096
+#error Wrong sector size.
+#endif
+#if _MAX_SS != 512
+#define SS(fs) ((fs)->ssize) /* Variable sector size */
+#else
+#define SS(fs) 512U /* Fixed sector size */
+#endif
+
+
+/* Reentrancy related */
+#if _FS_REENTRANT
+#if _USE_LFN == 1
+#error Static LFN work area must not be used in re-entrant configuration.
+#endif
+#define ENTER_FF(fs) { if (!lock_fs(fs)) return FR_TIMEOUT; }
+#define LEAVE_FF(fs, res) { unlock_fs(fs, res); return res; }
+#else
+#define ENTER_FF(fs)
+#define LEAVE_FF(fs, res) return res
+#endif
+
+#define ABORT(fs, res) { fp->flag |= FA__ERROR; LEAVE_FF(fs, res); }
+
+
+/* File access control feature */
+#if _FS_LOCK
+#if _FS_READONLY
+#error _FS_LOCK must be 0 on read-only cfg.
+#endif
+typedef struct {
+ FATFS *fs; /* File ID 1, volume (NULL:blank entry) */
+ DWORD clu; /* File ID 2, directory */
+ WORD idx; /* File ID 3, directory index */
+ WORD ctr; /* File open counter, 0:none, 0x01..0xFF:read open count, 0x100:write mode */
+} FILESEM;
+#endif
+
+
+
+/* DBCS code ranges and SBCS extend char conversion table */
+
+#if _CODE_PAGE == 932 /* Japanese Shift-JIS */
+#define _DF1S 0x81 /* DBC 1st byte range 1 start */
+#define _DF1E 0x9F /* DBC 1st byte range 1 end */
+#define _DF2S 0xE0 /* DBC 1st byte range 2 start */
+#define _DF2E 0xFC /* DBC 1st byte range 2 end */
+#define _DS1S 0x40 /* DBC 2nd byte range 1 start */
+#define _DS1E 0x7E /* DBC 2nd byte range 1 end */
+#define _DS2S 0x80 /* DBC 2nd byte range 2 start */
+#define _DS2E 0xFC /* DBC 2nd byte range 2 end */
+
+#elif _CODE_PAGE == 936 /* Simplified Chinese GBK */
+#define _DF1S 0x81
+#define _DF1E 0xFE
+#define _DS1S 0x40
+#define _DS1E 0x7E
+#define _DS2S 0x80
+#define _DS2E 0xFE
+
+#elif _CODE_PAGE == 949 /* Korean */
+#define _DF1S 0x81
+#define _DF1E 0xFE
+#define _DS1S 0x41
+#define _DS1E 0x5A
+#define _DS2S 0x61
+#define _DS2E 0x7A
+#define _DS3S 0x81
+#define _DS3E 0xFE
+
+#elif _CODE_PAGE == 950 /* Traditional Chinese Big5 */
+#define _DF1S 0x81
+#define _DF1E 0xFE
+#define _DS1S 0x40
+#define _DS1E 0x7E
+#define _DS2S 0xA1
+#define _DS2E 0xFE
+
+#elif _CODE_PAGE == 437 /* U.S. (OEM) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F,0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+ 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 720 /* Arabic (OEM) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x45,0x41,0x84,0x41,0x86,0x43,0x45,0x45,0x45,0x49,0x49,0x8D,0x8E,0x8F,0x90,0x92,0x92,0x93,0x94,0x95,0x49,0x49,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+ 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 737 /* Greek (OEM) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x92,0x92,0x93,0x94,0x95,0x96,0x97,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87, \
+ 0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0xAA,0x92,0x93,0x94,0x95,0x96,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0x97,0xEA,0xEB,0xEC,0xE4,0xED,0xEE,0xE7,0xE8,0xF1,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 775 /* Baltic (OEM) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x9A,0x91,0xA0,0x8E,0x95,0x8F,0x80,0xAD,0xED,0x8A,0x8A,0xA1,0x8D,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0x95,0x96,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \
+ 0xA0,0xA1,0xE0,0xA3,0xA3,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xA5,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE3,0xE8,0xE8,0xEA,0xEA,0xEE,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 850 /* Multilingual Latin 1 (OEM) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0xDE,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x59,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \
+ 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE7,0xE9,0xEA,0xEB,0xED,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 852 /* Latin 2 (OEM) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xDE,0x8F,0x80,0x9D,0xD3,0x8A,0x8A,0xD7,0x8D,0x8E,0x8F,0x90,0x91,0x91,0xE2,0x99,0x95,0x95,0x97,0x97,0x99,0x9A,0x9B,0x9B,0x9D,0x9E,0x9F, \
+ 0xB5,0xD6,0xE0,0xE9,0xA4,0xA4,0xA6,0xA6,0xA8,0xA8,0xAA,0x8D,0xAC,0xB8,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBD,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC6,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD2,0xD3,0xD2,0xD5,0xD6,0xD7,0xB7,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xE0,0xE1,0xE2,0xE3,0xE3,0xD5,0xE6,0xE6,0xE8,0xE9,0xE8,0xEB,0xED,0xED,0xDD,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xEB,0xFC,0xFC,0xFE,0xFF}
+
+#elif _CODE_PAGE == 855 /* Cyrillic (OEM) */
+#define _DF1S 0
+#define _EXCVT {0x81,0x81,0x83,0x83,0x85,0x85,0x87,0x87,0x89,0x89,0x8B,0x8B,0x8D,0x8D,0x8F,0x8F,0x91,0x91,0x93,0x93,0x95,0x95,0x97,0x97,0x99,0x99,0x9B,0x9B,0x9D,0x9D,0x9F,0x9F, \
+ 0xA1,0xA1,0xA3,0xA3,0xA5,0xA5,0xA7,0xA7,0xA9,0xA9,0xAB,0xAB,0xAD,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB6,0xB6,0xB8,0xB8,0xB9,0xBA,0xBB,0xBC,0xBE,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD3,0xD3,0xD5,0xD5,0xD7,0xD7,0xDD,0xD9,0xDA,0xDB,0xDC,0xDD,0xE0,0xDF, \
+ 0xE0,0xE2,0xE2,0xE4,0xE4,0xE6,0xE6,0xE8,0xE8,0xEA,0xEA,0xEC,0xEC,0xEE,0xEE,0xEF,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 857 /* Turkish (OEM) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0x98,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x98,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9E, \
+ 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA6,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xDE,0x59,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 858 /* Multilingual Latin 1 + Euro (OEM) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0xDE,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x59,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \
+ 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE7,0xE9,0xEA,0xEB,0xED,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 862 /* Hebrew (OEM) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+ 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 866 /* Russian (OEM) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0x90,0x91,0x92,0x93,0x9d,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 874 /* Thai (OEM, Windows) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+ 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 1250 /* Central Europe (Windows) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x8D,0x8E,0x8F, \
+ 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xA3,0xB4,0xB5,0xB6,0xB7,0xB8,0xA5,0xAA,0xBB,0xBC,0xBD,0xBC,0xAF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xFF}
+
+#elif _CODE_PAGE == 1251 /* Cyrillic (Windows) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x82,0x82,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x80,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x8D,0x8E,0x8F, \
+ 0xA0,0xA2,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB2,0xA5,0xB5,0xB6,0xB7,0xA8,0xB9,0xAA,0xBB,0xA3,0xBD,0xBD,0xAF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF}
+
+#elif _CODE_PAGE == 1252 /* Latin 1 (Windows) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0xAd,0x9B,0x8C,0x9D,0xAE,0x9F, \
+ 0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x9F}
+
+#elif _CODE_PAGE == 1253 /* Greek (Windows) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+ 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xA2,0xB8,0xB9,0xBA, \
+ 0xE0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xF2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xFB,0xBC,0xFD,0xBF,0xFF}
+
+#elif _CODE_PAGE == 1254 /* Turkish (Windows) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x9D,0x9E,0x9F, \
+ 0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x9F}
+
+#elif _CODE_PAGE == 1255 /* Hebrew (Windows) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+ 0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 1256 /* Arabic (Windows) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x8C,0x9D,0x9E,0x9F, \
+ 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0x41,0xE1,0x41,0xE3,0xE4,0xE5,0xE6,0x43,0x45,0x45,0x45,0x45,0xEC,0xED,0x49,0x49,0xF0,0xF1,0xF2,0xF3,0x4F,0xF5,0xF6,0xF7,0xF8,0x55,0xFA,0x55,0x55,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 1257 /* Baltic (Windows) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+ 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xA8,0xB9,0xAA,0xBB,0xBC,0xBD,0xBE,0xAF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xFF}
+
+#elif _CODE_PAGE == 1258 /* Vietnam (OEM, Windows) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0xAC,0x9D,0x9E,0x9F, \
+ 0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xEC,0xCD,0xCE,0xCF,0xD0,0xD1,0xF2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xFE,0x9F}
+
+#elif _CODE_PAGE == 1 /* ASCII (for only non-LFN cfg) */
+#if _USE_LFN
+#error Cannot use LFN feature without valid code page.
+#endif
+#define _DF1S 0
+
+#else
+#error Unknown code page
+
+#endif
+
+
+/* Character code support macros */
+#define IsUpper(c) (((c)>='A')&&((c)<='Z'))
+#define IsLower(c) (((c)>='a')&&((c)<='z'))
+#define IsDigit(c) (((c)>='0')&&((c)<='9'))
+
+#if _DF1S /* Code page is DBCS */
+
+#ifdef _DF2S /* Two 1st byte areas */
+#define IsDBCS1(c) (((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E) || ((BYTE)(c) >= _DF2S && (BYTE)(c) <= _DF2E))
+#else /* One 1st byte area */
+#define IsDBCS1(c) ((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E)
+#endif
+
+#ifdef _DS3S /* Three 2nd byte areas */
+#define IsDBCS2(c) (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E) || ((BYTE)(c) >= _DS3S && (BYTE)(c) <= _DS3E))
+#else /* Two 2nd byte areas */
+#define IsDBCS2(c) (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E))
+#endif
+
+#else /* Code page is SBCS */
+
+#define IsDBCS1(c) 0
+#define IsDBCS2(c) 0
+
+#endif /* _DF1S */
+
+
+/* Name status flags */
+#define NS 11 /* Index of name status byte in fn[] */
+#define NS_LOSS 0x01 /* Out of 8.3 format */
+#define NS_LFN 0x02 /* Force to create LFN entry */
+#define NS_LAST 0x04 /* Last segment */
+#define NS_BODY 0x08 /* Lower case flag (body) */
+#define NS_EXT 0x10 /* Lower case flag (ext) */
+#define NS_DOT 0x20 /* Dot entry */
+
+
+/* FAT sub-type boundaries */
+/* Note that the FAT spec by Microsoft says 4085 but Windows works with 4087! */
+#define MIN_FAT16 4086 /* Minimum number of clusters for FAT16 */
+#define MIN_FAT32 65526 /* Minimum number of clusters for FAT32 */
+
+
+/* FatFs refers the members in the FAT structures as byte array instead of
+/ structure member because the structure is not binary compatible between
+/ different platforms */
+
+#define BS_jmpBoot 0 /* Jump instruction (3) */
+#define BS_OEMName 3 /* OEM name (8) */
+#define BPB_BytsPerSec 11 /* Sector size [byte] (2) */
+#define BPB_SecPerClus 13 /* Cluster size [sector] (1) */
+#define BPB_RsvdSecCnt 14 /* Size of reserved area [sector] (2) */
+#define BPB_NumFATs 16 /* Number of FAT copies (1) */
+#define BPB_RootEntCnt 17 /* Number of root dir entries for FAT12/16 (2) */
+#define BPB_TotSec16 19 /* Volume size [sector] (2) */
+#define BPB_Media 21 /* Media descriptor (1) */
+#define BPB_FATSz16 22 /* FAT size [sector] (2) */
+#define BPB_SecPerTrk 24 /* Track size [sector] (2) */
+#define BPB_NumHeads 26 /* Number of heads (2) */
+#define BPB_HiddSec 28 /* Number of special hidden sectors (4) */
+#define BPB_TotSec32 32 /* Volume size [sector] (4) */
+#define BS_DrvNum 36 /* Physical drive number (2) */
+#define BS_BootSig 38 /* Extended boot signature (1) */
+#define BS_VolID 39 /* Volume serial number (4) */
+#define BS_VolLab 43 /* Volume label (8) */
+#define BS_FilSysType 54 /* File system type (1) */
+#define BPB_FATSz32 36 /* FAT size [sector] (4) */
+#define BPB_ExtFlags 40 /* Extended flags (2) */
+#define BPB_FSVer 42 /* File system version (2) */
+#define BPB_RootClus 44 /* Root dir first cluster (4) */
+#define BPB_FSInfo 48 /* Offset of FSInfo sector (2) */
+#define BPB_BkBootSec 50 /* Offset of backup boot sector (2) */
+#define BS_DrvNum32 64 /* Physical drive number (2) */
+#define BS_BootSig32 66 /* Extended boot signature (1) */
+#define BS_VolID32 67 /* Volume serial number (4) */
+#define BS_VolLab32 71 /* Volume label (8) */
+#define BS_FilSysType32 82 /* File system type (1) */
+#define FSI_LeadSig 0 /* FSI: Leading signature (4) */
+#define FSI_StrucSig 484 /* FSI: Structure signature (4) */
+#define FSI_Free_Count 488 /* FSI: Number of free clusters (4) */
+#define FSI_Nxt_Free 492 /* FSI: Last allocated cluster (4) */
+#define MBR_Table 446 /* MBR: Partition table offset (2) */
+#define SZ_PTE 16 /* MBR: Size of a partition table entry */
+#define BS_55AA 510 /* Boot sector signature (2) */
+
+#define DIR_Name 0 /* Short file name (11) */
+#define DIR_Attr 11 /* Attribute (1) */
+#define DIR_NTres 12 /* NT flag (1) */
+#define DIR_CrtTimeTenth 13 /* Created time sub-second (1) */
+#define DIR_CrtTime 14 /* Created time (2) */
+#define DIR_CrtDate 16 /* Created date (2) */
+#define DIR_LstAccDate 18 /* Last accessed date (2) */
+#define DIR_FstClusHI 20 /* Higher 16-bit of first cluster (2) */
+#define DIR_WrtTime 22 /* Modified time (2) */
+#define DIR_WrtDate 24 /* Modified date (2) */
+#define DIR_FstClusLO 26 /* Lower 16-bit of first cluster (2) */
+#define DIR_FileSize 28 /* File size (4) */
+#define LDIR_Ord 0 /* LFN entry order and LLE flag (1) */
+#define LDIR_Attr 11 /* LFN attribute (1) */
+#define LDIR_Type 12 /* LFN type (1) */
+#define LDIR_Chksum 13 /* Sum of corresponding SFN entry */
+#define LDIR_FstClusLO 26 /* Filled by zero (0) */
+#define SZ_DIR 32 /* Size of a directory entry */
+#define LLE 0x40 /* Last long entry flag in LDIR_Ord */
+#define DDE 0xE5 /* Deleted directory entry mark in DIR_Name[0] */
+#define NDDE 0x05 /* Replacement of the character collides with DDE */
+
+
+/*------------------------------------------------------------*/
+/* Module private work area */
+/*------------------------------------------------------------*/
+/* Note that uninitialized variables with static duration are
+/ zeroed/nulled at start-up. If not, the compiler or start-up
+/ routine is out of ANSI-C standard.
+*/
+
+#if _VOLUMES
+static
+FATFS *FatFs[_VOLUMES]; /* Pointer to the file system objects (logical drives) */
+#else
+#error Number of volumes must not be 0.
+#endif
+
+static
+WORD Fsid; /* File system mount ID */
+
+#if _FS_RPATH
+static
+BYTE CurrVol; /* Current drive */
+#endif
+
+#if _FS_LOCK
+static
+FILESEM Files[_FS_LOCK]; /* File lock semaphores */
+#endif
+
+#if _USE_LFN == 0 /* No LFN feature */
+#define DEF_NAMEBUF BYTE sfn[12]
+#define INIT_BUF(dobj) (dobj).fn = sfn
+#define FREE_BUF()
+
+#elif _USE_LFN == 1 /* LFN feature with static working buffer */
+static WCHAR LfnBuf[_MAX_LFN+1];
+#define DEF_NAMEBUF BYTE sfn[12]
+#define INIT_BUF(dobj) { (dobj).fn = sfn; (dobj).lfn = LfnBuf; }
+#define FREE_BUF()
+
+#elif _USE_LFN == 2 /* LFN feature with dynamic working buffer on the stack */
+#define DEF_NAMEBUF BYTE sfn[12]; WCHAR lbuf[_MAX_LFN+1]
+#define INIT_BUF(dobj) { (dobj).fn = sfn; (dobj).lfn = lbuf; }
+#define FREE_BUF()
+
+#elif _USE_LFN == 3 /* LFN feature with dynamic working buffer on the heap */
+#define DEF_NAMEBUF BYTE sfn[12]; WCHAR *lfn
+#define INIT_BUF(dobj) { lfn = ff_memalloc((_MAX_LFN + 1) * 2); \
+ if (!lfn) LEAVE_FF((dobj).fs, FR_NOT_ENOUGH_CORE); \
+ (dobj).lfn = lfn; (dobj).fn = sfn; }
+#define FREE_BUF() ff_memfree(lfn)
+
+#else
+#error Wrong LFN configuration.
+#endif
+
+
+
+
+/*--------------------------------------------------------------------------
+
+ Module Private Functions
+
+---------------------------------------------------------------------------*/
+
+
+/*-----------------------------------------------------------------------*/
+/* String functions */
+/*-----------------------------------------------------------------------*/
+
+/* Copy memory to memory */
+static
+void mem_cpy (void* dst, const void* src, UINT cnt) {
+ BYTE *d = (BYTE*)dst;
+ const BYTE *s = (const BYTE*)src;
+
+#if _WORD_ACCESS == 1
+ while (cnt >= sizeof (int)) {
+ *(int*)d = *(int*)s;
+ d += sizeof (int); s += sizeof (int);
+ cnt -= sizeof (int);
+ }
+#endif
+ while (cnt--)
+ *d++ = *s++;
+}
+
+/* Fill memory */
+static
+void mem_set (void* dst, int val, UINT cnt) {
+ BYTE *d = (BYTE*)dst;
+
+ while (cnt--)
+ *d++ = (BYTE)val;
+}
+
+/* Compare memory to memory */
+static
+int mem_cmp (const void* dst, const void* src, UINT cnt) {
+ const BYTE *d = (const BYTE *)dst, *s = (const BYTE *)src;
+ int r = 0;
+
+ while (cnt-- && (r = *d++ - *s++) == 0) ;
+ return r;
+}
+
+/* Check if chr is contained in the string */
+static
+int chk_chr (const char* str, int chr) {
+ while (*str && *str != chr) str++;
+ return *str;
+}
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Request/Release grant to access the volume */
+/*-----------------------------------------------------------------------*/
+#if _FS_REENTRANT
+
+static
+int lock_fs (
+ FATFS *fs /* File system object */
+)
+{
+ return ff_req_grant(fs->sobj);
+}
+
+
+static
+void unlock_fs (
+ FATFS *fs, /* File system object */
+ FRESULT res /* Result code to be returned */
+)
+{
+ if (fs &&
+ res != FR_NOT_ENABLED &&
+ res != FR_INVALID_DRIVE &&
+ res != FR_INVALID_OBJECT &&
+ res != FR_TIMEOUT) {
+ ff_rel_grant(fs->sobj);
+ }
+}
+#endif
+
+
+
+/*-----------------------------------------------------------------------*/
+/* File lock control functions */
+/*-----------------------------------------------------------------------*/
+#if _FS_LOCK
+
+static
+FRESULT chk_lock ( /* Check if the file can be accessed */
+ DIR* dj, /* Directory object pointing the file to be checked */
+ int acc /* Desired access (0:Read, 1:Write, 2:Delete/Rename) */
+)
+{
+ UINT i, be;
+
+ /* Search file semaphore table */
+ for (i = be = 0; i < _FS_LOCK; i++) {
+ if (Files[i].fs) { /* Existing entry */
+ if (Files[i].fs == dj->fs && /* Check if the file matched with an open file */
+ Files[i].clu == dj->sclust &&
+ Files[i].idx == dj->index) break;
+ } else { /* Blank entry */
+ be++;
+ }
+ }
+ if (i == _FS_LOCK) /* The file is not opened */
+ return (be || acc == 2) ? FR_OK : FR_TOO_MANY_OPEN_FILES; /* Is there a blank entry for new file? */
+
+ /* The file has been opened. Reject any open against writing file and all write mode open */
+ return (acc || Files[i].ctr == 0x100) ? FR_LOCKED : FR_OK;
+}
+
+
+static
+int enq_lock (void) /* Check if an entry is available for a new file */
+{
+ UINT i;
+
+ for (i = 0; i < _FS_LOCK && Files[i].fs; i++) ;
+ return (i == _FS_LOCK) ? 0 : 1;
+}
+
+
+static
+UINT inc_lock ( /* Increment file open counter and returns its index (0:int error) */
+ DIR* dj, /* Directory object pointing the file to register or increment */
+ int acc /* Desired access mode (0:Read, !0:Write) */
+)
+{
+ UINT i;
+
+
+ for (i = 0; i < _FS_LOCK; i++) { /* Find the file */
+ if (Files[i].fs == dj->fs &&
+ Files[i].clu == dj->sclust &&
+ Files[i].idx == dj->index) break;
+ }
+
+ if (i == _FS_LOCK) { /* Not opened. Register it as new. */
+ for (i = 0; i < _FS_LOCK && Files[i].fs; i++) ;
+ if (i == _FS_LOCK) return 0; /* No space to register (int err) */
+ Files[i].fs = dj->fs;
+ Files[i].clu = dj->sclust;
+ Files[i].idx = dj->index;
+ Files[i].ctr = 0;
+ }
+
+ if (acc && Files[i].ctr) return 0; /* Access violation (int err) */
+
+ Files[i].ctr = acc ? 0x100 : Files[i].ctr + 1; /* Set semaphore value */
+
+ return i + 1;
+}
+
+
+static
+FRESULT dec_lock ( /* Decrement file open counter */
+ UINT i /* Semaphore index */
+)
+{
+ WORD n;
+ FRESULT res;
+
+
+ if (--i < _FS_LOCK) {
+ n = Files[i].ctr;
+ if (n == 0x100) n = 0;
+ if (n) n--;
+ Files[i].ctr = n;
+ if (!n) Files[i].fs = 0;
+ res = FR_OK;
+ } else {
+ res = FR_INT_ERR;
+ }
+ return res;
+}
+
+
+static
+void clear_lock ( /* Clear lock entries of the volume */
+ FATFS *fs
+)
+{
+ UINT i;
+
+ for (i = 0; i < _FS_LOCK; i++) {
+ if (Files[i].fs == fs) Files[i].fs = 0;
+ }
+}
+#endif
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Change window offset */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT move_window (
+ FATFS *fs, /* File system object */
+ DWORD sector /* Sector number to make appearance in the fs->win[] */
+) /* Move to zero only writes back dirty window */
+{
+ DWORD wsect;
+
+
+ wsect = fs->winsect;
+ if (wsect != sector) { /* Changed current window */
+#if !_FS_READONLY
+ if (fs->wflag) { /* Write back dirty window if needed */
+ if (disk_write(fs->drv, fs->win, wsect, 1) != RES_OK)
+ return FR_DISK_ERR;
+ fs->wflag = 0;
+ if (wsect < (fs->fatbase + fs->fsize)) { /* In FAT area */
+ BYTE nf;
+ for (nf = fs->n_fats; nf > 1; nf--) { /* Reflect the change to all FAT copies */
+ wsect += fs->fsize;
+ disk_write(fs->drv, fs->win, wsect, 1);
+ }
+ }
+ }
+#endif
+ if (sector) {
+ if (disk_read(fs->drv, fs->win, sector, 1) != RES_OK)
+ return FR_DISK_ERR;
+ fs->winsect = sector;
+ }
+ }
+
+ return FR_OK;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Clean-up cached data */
+/*-----------------------------------------------------------------------*/
+#if !_FS_READONLY
+static
+FRESULT sync ( /* FR_OK: successful, FR_DISK_ERR: failed */
+ FATFS *fs /* File system object */
+)
+{
+ FRESULT res;
+
+
+ res = move_window(fs, 0);
+ if (res == FR_OK) {
+ /* Update FSInfo sector if needed */
+ if (fs->fs_type == FS_FAT32 && fs->fsi_flag) {
+ fs->winsect = 0;
+ /* Create FSInfo structure */
+ mem_set(fs->win, 0, 512);
+ ST_WORD(fs->win+BS_55AA, 0xAA55);
+ ST_DWORD(fs->win+FSI_LeadSig, 0x41615252);
+ ST_DWORD(fs->win+FSI_StrucSig, 0x61417272);
+ ST_DWORD(fs->win+FSI_Free_Count, fs->free_clust);
+ ST_DWORD(fs->win+FSI_Nxt_Free, fs->last_clust);
+ /* Write it into the FSInfo sector */
+ disk_write(fs->drv, fs->win, fs->fsi_sector, 1);
+ fs->fsi_flag = 0;
+ }
+ /* Make sure that no pending write process in the physical drive */
+ if (disk_ioctl(fs->drv, CTRL_SYNC, 0) != RES_OK)
+ res = FR_DISK_ERR;
+ }
+
+ return res;
+}
+#endif
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Get sector# from cluster# */
+/*-----------------------------------------------------------------------*/
+
+
+DWORD clust2sect ( /* !=0: Sector number, 0: Failed - invalid cluster# */
+ FATFS *fs, /* File system object */
+ DWORD clst /* Cluster# to be converted */
+)
+{
+ clst -= 2;
+ if (clst >= (fs->n_fatent - 2)) return 0; /* Invalid cluster# */
+ return clst * fs->csize + fs->database;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* FAT access - Read value of a FAT entry */
+/*-----------------------------------------------------------------------*/
+
+
+DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, Else:Cluster status */
+ FATFS *fs, /* File system object */
+ DWORD clst /* Cluster# to get the link information */
+)
+{
+ UINT wc, bc;
+ BYTE *p;
+
+
+ if (clst < 2 || clst >= fs->n_fatent) /* Check range */
+ return 1;
+
+ switch (fs->fs_type) {
+ case FS_FAT12 :
+ bc = (UINT)clst; bc += bc / 2;
+ if (move_window(fs, fs->fatbase + (bc / SS(fs)))) break;
+ wc = fs->win[bc % SS(fs)]; bc++;
+ if (move_window(fs, fs->fatbase + (bc / SS(fs)))) break;
+ wc |= fs->win[bc % SS(fs)] << 8;
+ return (clst & 1) ? (wc >> 4) : (wc & 0xFFF);
+
+ case FS_FAT16 :
+ if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 2)))) break;
+ p = &fs->win[clst * 2 % SS(fs)];
+ return LD_WORD(p);
+
+ case FS_FAT32 :
+ if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4)))) break;
+ p = &fs->win[clst * 4 % SS(fs)];
+ return LD_DWORD(p) & 0x0FFFFFFF;
+ }
+
+ return 0xFFFFFFFF; /* An error occurred at the disk I/O layer */
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* FAT access - Change value of a FAT entry */
+/*-----------------------------------------------------------------------*/
+#if !_FS_READONLY
+
+FRESULT put_fat (
+ FATFS *fs, /* File system object */
+ DWORD clst, /* Cluster# to be changed in range of 2 to fs->n_fatent - 1 */
+ DWORD val /* New value to mark the cluster */
+)
+{
+ UINT bc;
+ BYTE *p;
+ FRESULT res;
+
+
+ if (clst < 2 || clst >= fs->n_fatent) { /* Check range */
+ res = FR_INT_ERR;
+
+ } else {
+ switch (fs->fs_type) {
+ case FS_FAT12 :
+ bc = (UINT)clst; bc += bc / 2;
+ res = move_window(fs, fs->fatbase + (bc / SS(fs)));
+ if (res != FR_OK) break;
+ p = &fs->win[bc % SS(fs)];
+ *p = (clst & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val;
+ bc++;
+ fs->wflag = 1;
+ res = move_window(fs, fs->fatbase + (bc / SS(fs)));
+ if (res != FR_OK) break;
+ p = &fs->win[bc % SS(fs)];
+ *p = (clst & 1) ? (BYTE)(val >> 4) : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F));
+ break;
+
+ case FS_FAT16 :
+ res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 2)));
+ if (res != FR_OK) break;
+ p = &fs->win[clst * 2 % SS(fs)];
+ ST_WORD(p, (WORD)val);
+ break;
+
+ case FS_FAT32 :
+ res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 4)));
+ if (res != FR_OK) break;
+ p = &fs->win[clst * 4 % SS(fs)];
+ val |= LD_DWORD(p) & 0xF0000000;
+ ST_DWORD(p, val);
+ break;
+
+ default :
+ res = FR_INT_ERR;
+ }
+ fs->wflag = 1;
+ }
+
+ return res;
+}
+#endif /* !_FS_READONLY */
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* FAT handling - Remove a cluster chain */
+/*-----------------------------------------------------------------------*/
+#if !_FS_READONLY
+static
+FRESULT remove_chain (
+ FATFS *fs, /* File system object */
+ DWORD clst /* Cluster# to remove a chain from */
+)
+{
+ FRESULT res;
+ DWORD nxt;
+#if _USE_ERASE
+ DWORD scl = clst, ecl = clst, rt[2];
+#endif
+
+ if (clst < 2 || clst >= fs->n_fatent) { /* Check range */
+ res = FR_INT_ERR;
+
+ } else {
+ res = FR_OK;
+ while (clst < fs->n_fatent) { /* Not a last link? */
+ nxt = get_fat(fs, clst); /* Get cluster status */
+ if (nxt == 0) break; /* Empty cluster? */
+ if (nxt == 1) { res = FR_INT_ERR; break; } /* Internal error? */
+ if (nxt == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } /* Disk error? */
+ res = put_fat(fs, clst, 0); /* Mark the cluster "empty" */
+ if (res != FR_OK) break;
+ if (fs->free_clust != 0xFFFFFFFF) { /* Update FSInfo */
+ fs->free_clust++;
+ fs->fsi_flag = 1;
+ }
+#if _USE_ERASE
+ if (ecl + 1 == nxt) { /* Is next cluster contiguous? */
+ ecl = nxt;
+ } else { /* End of contiguous clusters */
+ rt[0] = clust2sect(fs, scl); /* Start sector */
+ rt[1] = clust2sect(fs, ecl) + fs->csize - 1; /* End sector */
+ disk_ioctl(fs->drv, CTRL_ERASE_SECTOR, rt); /* Erase the block */
+ scl = ecl = nxt;
+ }
+#endif
+ clst = nxt; /* Next cluster */
+ }
+ }
+
+ return res;
+}
+#endif
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* FAT handling - Stretch or Create a cluster chain */
+/*-----------------------------------------------------------------------*/
+#if !_FS_READONLY
+static
+DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */
+ FATFS *fs, /* File system object */
+ DWORD clst /* Cluster# to stretch. 0 means create a new chain. */
+)
+{
+ DWORD cs, ncl, scl;
+ FRESULT res;
+
+
+ if (clst == 0) { /* Create a new chain */
+ scl = fs->last_clust; /* Get suggested start point */
+ if (!scl || scl >= fs->n_fatent) scl = 1;
+ }
+ else { /* Stretch the current chain */
+ cs = get_fat(fs, clst); /* Check the cluster status */
+ if (cs < 2) return 1; /* It is an invalid cluster */
+ if (cs < fs->n_fatent) return cs; /* It is already followed by next cluster */
+ scl = clst;
+ }
+
+ ncl = scl; /* Start cluster */
+ for (;;) {
+ ncl++; /* Next cluster */
+ if (ncl >= fs->n_fatent) { /* Wrap around */
+ ncl = 2;
+ if (ncl > scl) return 0; /* No free cluster */
+ }
+ cs = get_fat(fs, ncl); /* Get the cluster status */
+ if (cs == 0) break; /* Found a free cluster */
+ if (cs == 0xFFFFFFFF || cs == 1)/* An error occurred */
+ return cs;
+ if (ncl == scl) return 0; /* No free cluster */
+ }
+
+ res = put_fat(fs, ncl, 0x0FFFFFFF); /* Mark the new cluster "last link" */
+ if (res == FR_OK && clst != 0) {
+ res = put_fat(fs, clst, ncl); /* Link it to the previous one if needed */
+ }
+ if (res == FR_OK) {
+ fs->last_clust = ncl; /* Update FSINFO */
+ if (fs->free_clust != 0xFFFFFFFF) {
+ fs->free_clust--;
+ fs->fsi_flag = 1;
+ }
+ } else {
+ ncl = (res == FR_DISK_ERR) ? 0xFFFFFFFF : 1;
+ }
+
+ return ncl; /* Return new cluster number or error code */
+}
+#endif /* !_FS_READONLY */
+
+
+
+/*-----------------------------------------------------------------------*/
+/* FAT handling - Convert offset into cluster with link map table */
+/*-----------------------------------------------------------------------*/
+
+#if _USE_FASTSEEK
+static
+DWORD clmt_clust ( /* <2:Error, >=2:Cluster number */
+ FIL* fp, /* Pointer to the file object */
+ DWORD ofs /* File offset to be converted to cluster# */
+)
+{
+ DWORD cl, ncl, *tbl;
+
+
+ tbl = fp->cltbl + 1; /* Top of CLMT */
+ cl = ofs / SS(fp->fs) / fp->fs->csize; /* Cluster order from top of the file */
+ for (;;) {
+ ncl = *tbl++; /* Number of cluters in the fragment */
+ if (!ncl) return 0; /* End of table? (error) */
+ if (cl < ncl) break; /* In this fragment? */
+ cl -= ncl; tbl++; /* Next fragment */
+ }
+ return cl + *tbl; /* Return the cluster number */
+}
+#endif /* _USE_FASTSEEK */
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Directory handling - Set directory index */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT dir_sdi (
+ FATFS_DIR *dj, /* Pointer to directory object */
+ WORD idx /* Index of directory table */
+)
+{
+ DWORD clst;
+ WORD ic;
+
+
+ dj->index = idx;
+ clst = dj->sclust;
+ if (clst == 1 || clst >= dj->fs->n_fatent) /* Check start cluster range */
+ return FR_INT_ERR;
+ if (!clst && dj->fs->fs_type == FS_FAT32) /* Replace cluster# 0 with root cluster# if in FAT32 */
+ clst = dj->fs->dirbase;
+
+ if (clst == 0) { /* Static table (root-dir in FAT12/16) */
+ dj->clust = clst;
+ if (idx >= dj->fs->n_rootdir) /* Index is out of range */
+ return FR_INT_ERR;
+ dj->sect = dj->fs->dirbase + idx / (SS(dj->fs) / SZ_DIR); /* Sector# */
+ }
+ else { /* Dynamic table (sub-dirs or root-dir in FAT32) */
+ ic = SS(dj->fs) / SZ_DIR * dj->fs->csize; /* Entries per cluster */
+ while (idx >= ic) { /* Follow cluster chain */
+ clst = get_fat(dj->fs, clst); /* Get next cluster */
+ if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */
+ if (clst < 2 || clst >= dj->fs->n_fatent) /* Reached to end of table or int error */
+ return FR_INT_ERR;
+ idx -= ic;
+ }
+ dj->clust = clst;
+ dj->sect = clust2sect(dj->fs, clst) + idx / (SS(dj->fs) / SZ_DIR); /* Sector# */
+ }
+
+ dj->dir = dj->fs->win + (idx % (SS(dj->fs) / SZ_DIR)) * SZ_DIR; /* Ptr to the entry in the sector */
+
+ return FR_OK; /* Seek succeeded */
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Directory handling - Move directory table index next */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT dir_next ( /* FR_OK:Succeeded, FR_NO_FILE:End of table, FR_DENIED:EOT and could not stretch */
+ FATFS_DIR *dj, /* Pointer to directory object */
+ int stretch /* 0: Do not stretch table, 1: Stretch table if needed */
+)
+{
+ DWORD clst;
+ WORD i;
+
+
+ stretch = stretch; /* To suppress warning on read-only cfg. */
+ i = dj->index + 1;
+ if (!i || !dj->sect) /* Report EOT when index has reached 65535 */
+ return FR_NO_FILE;
+
+ if (!(i % (SS(dj->fs) / SZ_DIR))) { /* Sector changed? */
+ dj->sect++; /* Next sector */
+
+ if (dj->clust == 0) { /* Static table */
+ if (i >= dj->fs->n_rootdir) /* Report EOT when end of table */
+ return FR_NO_FILE;
+ }
+ else { /* Dynamic table */
+ if (((i / (SS(dj->fs) / SZ_DIR)) & (dj->fs->csize - 1)) == 0) { /* Cluster changed? */
+ clst = get_fat(dj->fs, dj->clust); /* Get next cluster */
+ if (clst <= 1) return FR_INT_ERR;
+ if (clst == 0xFFFFFFFF) return FR_DISK_ERR;
+ if (clst >= dj->fs->n_fatent) { /* When it reached end of dynamic table */
+#if !_FS_READONLY
+ BYTE c;
+ if (!stretch) return FR_NO_FILE; /* When do not stretch, report EOT */
+ clst = create_chain(dj->fs, dj->clust); /* Stretch cluster chain */
+ if (clst == 0) return FR_DENIED; /* No free cluster */
+ if (clst == 1) return FR_INT_ERR;
+ if (clst == 0xFFFFFFFF) return FR_DISK_ERR;
+ /* Clean-up stretched table */
+ if (move_window(dj->fs, 0)) return FR_DISK_ERR; /* Flush active window */
+ mem_set(dj->fs->win, 0, SS(dj->fs)); /* Clear window buffer */
+ dj->fs->winsect = clust2sect(dj->fs, clst); /* Cluster start sector */
+ for (c = 0; c < dj->fs->csize; c++) { /* Fill the new cluster with 0 */
+ dj->fs->wflag = 1;
+ if (move_window(dj->fs, 0)) return FR_DISK_ERR;
+ dj->fs->winsect++;
+ }
+ dj->fs->winsect -= c; /* Rewind window address */
+#else
+ return FR_NO_FILE; /* Report EOT */
+#endif
+ }
+ dj->clust = clst; /* Initialize data for new cluster */
+ dj->sect = clust2sect(dj->fs, clst);
+ }
+ }
+ }
+
+ dj->index = i;
+ dj->dir = dj->fs->win + (i % (SS(dj->fs) / SZ_DIR)) * SZ_DIR;
+
+ return FR_OK;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Directory handling - Load/Store start cluster number */
+/*-----------------------------------------------------------------------*/
+
+static
+DWORD ld_clust (
+ FATFS *fs, /* Pointer to the fs object */
+ BYTE *dir /* Pointer to the directory entry */
+)
+{
+ DWORD cl;
+
+ cl = LD_WORD(dir+DIR_FstClusLO);
+ if (fs->fs_type == FS_FAT32)
+ cl |= (DWORD)LD_WORD(dir+DIR_FstClusHI) << 16;
+
+ return cl;
+}
+
+
+#if !_FS_READONLY
+static
+void st_clust (
+ BYTE *dir, /* Pointer to the directory entry */
+ DWORD cl /* Value to be set */
+)
+{
+ ST_WORD(dir+DIR_FstClusLO, cl);
+ ST_WORD(dir+DIR_FstClusHI, cl >> 16);
+}
+#endif
+
+
+
+/*-----------------------------------------------------------------------*/
+/* LFN handling - Test/Pick/Fit an LFN segment from/to directory entry */
+/*-----------------------------------------------------------------------*/
+#if _USE_LFN
+static
+const BYTE LfnOfs[] = {1,3,5,7,9,14,16,18,20,22,24,28,30}; /* Offset of LFN chars in the directory entry */
+
+
+static
+int cmp_lfn ( /* 1:Matched, 0:Not matched */
+ WCHAR *lfnbuf, /* Pointer to the LFN to be compared */
+ BYTE *dir /* Pointer to the directory entry containing a part of LFN */
+)
+{
+ UINT i, s;
+ WCHAR wc, uc;
+
+
+ i = ((dir[LDIR_Ord] & ~LLE) - 1) * 13; /* Get offset in the LFN buffer */
+ s = 0; wc = 1;
+ do {
+ uc = LD_WORD(dir+LfnOfs[s]); /* Pick an LFN character from the entry */
+ if (wc) { /* Last char has not been processed */
+ wc = ff_wtoupper(uc); /* Convert it to upper case */
+ if (i >= _MAX_LFN || wc != ff_wtoupper(lfnbuf[i++])) /* Compare it */
+ return 0; /* Not matched */
+ } else {
+ if (uc != 0xFFFF) return 0; /* Check filler */
+ }
+ } while (++s < 13); /* Repeat until all chars in the entry are checked */
+
+ if ((dir[LDIR_Ord] & LLE) && wc && lfnbuf[i]) /* Last segment matched but different length */
+ return 0;
+
+ return 1; /* The part of LFN matched */
+}
+
+
+
+static
+int pick_lfn ( /* 1:Succeeded, 0:Buffer overflow */
+ WCHAR *lfnbuf, /* Pointer to the Unicode-LFN buffer */
+ BYTE *dir /* Pointer to the directory entry */
+)
+{
+ UINT i, s;
+ WCHAR wc, uc;
+
+
+ i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13; /* Offset in the LFN buffer */
+
+ s = 0; wc = 1;
+ do {
+ uc = LD_WORD(dir+LfnOfs[s]); /* Pick an LFN character from the entry */
+ if (wc) { /* Last char has not been processed */
+ if (i >= _MAX_LFN) return 0; /* Buffer overflow? */
+ lfnbuf[i++] = wc = uc; /* Store it */
+ } else {
+ if (uc != 0xFFFF) return 0; /* Check filler */
+ }
+ } while (++s < 13); /* Read all character in the entry */
+
+ if (dir[LDIR_Ord] & LLE) { /* Put terminator if it is the last LFN part */
+ if (i >= _MAX_LFN) return 0; /* Buffer overflow? */
+ lfnbuf[i] = 0;
+ }
+
+ return 1;
+}
+
+
+#if !_FS_READONLY
+static
+void fit_lfn (
+ const WCHAR *lfnbuf, /* Pointer to the LFN buffer */
+ BYTE *dir, /* Pointer to the directory entry */
+ BYTE ord, /* LFN order (1-20) */
+ BYTE sum /* SFN sum */
+)
+{
+ UINT i, s;
+ WCHAR wc;
+
+
+ dir[LDIR_Chksum] = sum; /* Set check sum */
+ dir[LDIR_Attr] = AM_LFN; /* Set attribute. LFN entry */
+ dir[LDIR_Type] = 0;
+ ST_WORD(dir+LDIR_FstClusLO, 0);
+
+ i = (ord - 1) * 13; /* Get offset in the LFN buffer */
+ s = wc = 0;
+ do {
+ if (wc != 0xFFFF) wc = lfnbuf[i++]; /* Get an effective char */
+ ST_WORD(dir+LfnOfs[s], wc); /* Put it */
+ if (!wc) wc = 0xFFFF; /* Padding chars following last char */
+ } while (++s < 13);
+ if (wc == 0xFFFF || !lfnbuf[i]) ord |= LLE; /* Bottom LFN part is the start of LFN sequence */
+ dir[LDIR_Ord] = ord; /* Set the LFN order */
+}
+
+#endif
+#endif
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Create numbered name */
+/*-----------------------------------------------------------------------*/
+#if _USE_LFN
+void gen_numname (
+ BYTE *dst, /* Pointer to generated SFN */
+ const BYTE *src, /* Pointer to source SFN to be modified */
+ const WCHAR *lfn, /* Pointer to LFN */
+ WORD seq /* Sequence number */
+)
+{
+ BYTE ns[8], c;
+ UINT i, j;
+
+
+ mem_cpy(dst, src, 11);
+
+ if (seq > 5) { /* On many collisions, generate a hash number instead of sequential number */
+ do seq = (seq >> 1) + (seq << 15) + (WORD)*lfn++; while (*lfn);
+ }
+
+ /* itoa (hexdecimal) */
+ i = 7;
+ do {
+ c = (seq % 16) + '0';
+ if (c > '9') c += 7;
+ ns[i--] = c;
+ seq /= 16;
+ } while (seq);
+ ns[i] = '~';
+
+ /* Append the number */
+ for (j = 0; j < i && dst[j] != ' '; j++) {
+ if (IsDBCS1(dst[j])) {
+ if (j == i - 1) break;
+ j++;
+ }
+ }
+ do {
+ dst[j++] = (i < 8) ? ns[i++] : ' ';
+ } while (j < 8);
+}
+#endif
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Calculate sum of an SFN */
+/*-----------------------------------------------------------------------*/
+#if _USE_LFN
+static
+BYTE sum_sfn (
+ const BYTE *dir /* Ptr to directory entry */
+)
+{
+ BYTE sum = 0;
+ UINT n = 11;
+
+ do sum = (sum >> 1) + (sum << 7) + *dir++; while (--n);
+ return sum;
+}
+#endif
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Directory handling - Find an object in the directory */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT dir_find (
+ FATFS_DIR *dj /* Pointer to the directory object linked to the file name */
+)
+{
+ FRESULT res;
+ BYTE c, *dir;
+#if _USE_LFN
+ BYTE a, ord, sum;
+#endif
+
+ res = dir_sdi(dj, 0); /* Rewind directory object */
+ if (res != FR_OK) return res;
+
+#if _USE_LFN
+ ord = sum = 0xFF;
+#endif
+ do {
+ res = move_window(dj->fs, dj->sect);
+ if (res != FR_OK) break;
+ dir = dj->dir; /* Ptr to the directory entry of current index */
+ c = dir[DIR_Name];
+ if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */
+#if _USE_LFN /* LFN configuration */
+ a = dir[DIR_Attr] & AM_MASK;
+ if (c == DDE || ((a & AM_VOL) && a != AM_LFN)) { /* An entry without valid data */
+ ord = 0xFF;
+ } else {
+ if (a == AM_LFN) { /* An LFN entry is found */
+ if (dj->lfn) {
+ if (c & LLE) { /* Is it start of LFN sequence? */
+ sum = dir[LDIR_Chksum];
+ c &= ~LLE; ord = c; /* LFN start order */
+ dj->lfn_idx = dj->index;
+ }
+ /* Check validity of the LFN entry and compare it with given name */
+ ord = (c == ord && sum == dir[LDIR_Chksum] && cmp_lfn(dj->lfn, dir)) ? ord - 1 : 0xFF;
+ }
+ } else { /* An SFN entry is found */
+ if (!ord && sum == sum_sfn(dir)) break; /* LFN matched? */
+ ord = 0xFF; dj->lfn_idx = 0xFFFF; /* Reset LFN sequence */
+ if (!(dj->fn[NS] & NS_LOSS) && !mem_cmp(dir, dj->fn, 11)) break; /* SFN matched? */
+ }
+ }
+#else /* Non LFN configuration */
+ if (!(dir[DIR_Attr] & AM_VOL) && !mem_cmp(dir, dj->fn, 11)) /* Is it a valid entry? */
+ break;
+#endif
+ res = dir_next(dj, 0); /* Next entry */
+ } while (res == FR_OK);
+
+ return res;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Read an object from the directory */
+/*-----------------------------------------------------------------------*/
+#if _FS_MINIMIZE <= 1
+static
+FRESULT dir_read (
+ FATFS_DIR *dj /* Pointer to the directory object that pointing the entry to be read */
+)
+{
+ FRESULT res;
+ BYTE c, *dir;
+#if _USE_LFN
+ BYTE a, ord = 0xFF, sum = 0xFF;
+#endif
+
+ res = FR_NO_FILE;
+ while (dj->sect) {
+ res = move_window(dj->fs, dj->sect);
+ if (res != FR_OK) break;
+ dir = dj->dir; /* Ptr to the directory entry of current index */
+ c = dir[DIR_Name];
+ if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */
+#if _USE_LFN /* LFN configuration */
+ a = dir[DIR_Attr] & AM_MASK;
+ if (c == DDE || (!_FS_RPATH && c == '.') || ((a & AM_VOL) && a != AM_LFN)) { /* An entry without valid data */
+ ord = 0xFF;
+ } else {
+ if (a == AM_LFN) { /* An LFN entry is found */
+ if (c & LLE) { /* Is it start of LFN sequence? */
+ sum = dir[LDIR_Chksum];
+ c &= ~LLE; ord = c;
+ dj->lfn_idx = dj->index;
+ }
+ /* Check LFN validity and capture it */
+ ord = (c == ord && sum == dir[LDIR_Chksum] && pick_lfn(dj->lfn, dir)) ? ord - 1 : 0xFF;
+ } else { /* An SFN entry is found */
+ if (ord || sum != sum_sfn(dir)) /* Is there a valid LFN? */
+ dj->lfn_idx = 0xFFFF; /* It has no LFN. */
+ break;
+ }
+ }
+#else /* Non LFN configuration */
+ if (c != DDE && (_FS_RPATH || c != '.') && !(dir[DIR_Attr] & AM_VOL)) /* Is it a valid entry? */
+ break;
+#endif
+ res = dir_next(dj, 0); /* Next entry */
+ if (res != FR_OK) break;
+ }
+
+ if (res != FR_OK) dj->sect = 0;
+
+ return res;
+}
+#endif
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Register an object to the directory */
+/*-----------------------------------------------------------------------*/
+#if !_FS_READONLY
+static
+FRESULT dir_register ( /* FR_OK:Successful, FR_DENIED:No free entry or too many SFN collision, FR_DISK_ERR:Disk error */
+ FATFS_DIR *dj /* Target directory with object name to be created */
+)
+{
+ FRESULT res;
+ BYTE c, *dir;
+#if _USE_LFN /* LFN configuration */
+ WORD n, ne, is;
+ BYTE sn[12], *fn, sum;
+ WCHAR *lfn;
+
+
+ fn = dj->fn; lfn = dj->lfn;
+ mem_cpy(sn, fn, 12);
+
+ if (_FS_RPATH && (sn[NS] & NS_DOT)) /* Cannot create dot entry */
+ return FR_INVALID_NAME;
+
+ if (sn[NS] & NS_LOSS) { /* When LFN is out of 8.3 format, generate a numbered name */
+ fn[NS] = 0; dj->lfn = 0; /* Find only SFN */
+ for (n = 1; n < 100; n++) {
+ gen_numname(fn, sn, lfn, n); /* Generate a numbered name */
+ res = dir_find(dj); /* Check if the name collides with existing SFN */
+ if (res != FR_OK) break;
+ }
+ if (n == 100) return FR_DENIED; /* Abort if too many collisions */
+ if (res != FR_NO_FILE) return res; /* Abort if the result is other than 'not collided' */
+ fn[NS] = sn[NS]; dj->lfn = lfn;
+ }
+
+ if (sn[NS] & NS_LFN) { /* When LFN is to be created, reserve an SFN + LFN entries. */
+ for (ne = 0; lfn[ne]; ne++) ;
+ ne = (ne + 25) / 13;
+ } else { /* Otherwise reserve only an SFN entry. */
+ ne = 1;
+ }
+
+ /* Reserve contiguous entries */
+ res = dir_sdi(dj, 0);
+ if (res != FR_OK) return res;
+ n = is = 0;
+ do {
+ res = move_window(dj->fs, dj->sect);
+ if (res != FR_OK) break;
+ c = *dj->dir; /* Check the entry status */
+ if (c == DDE || c == 0) { /* Is it a blank entry? */
+ if (n == 0) is = dj->index; /* First index of the contiguous entry */
+ if (++n == ne) break; /* A contiguous entry that required count is found */
+ } else {
+ n = 0; /* Not a blank entry. Restart to search */
+ }
+ res = dir_next(dj, 1); /* Next entry with table stretch */
+ } while (res == FR_OK);
+
+ if (res == FR_OK && ne > 1) { /* Initialize LFN entry if needed */
+ res = dir_sdi(dj, is);
+ if (res == FR_OK) {
+ sum = sum_sfn(dj->fn); /* Sum of the SFN tied to the LFN */
+ ne--;
+ do { /* Store LFN entries in bottom first */
+ res = move_window(dj->fs, dj->sect);
+ if (res != FR_OK) break;
+ fit_lfn(dj->lfn, dj->dir, (BYTE)ne, sum);
+ dj->fs->wflag = 1;
+ res = dir_next(dj, 0); /* Next entry */
+ } while (res == FR_OK && --ne);
+ }
+ }
+
+#else /* Non LFN configuration */
+ res = dir_sdi(dj, 0);
+ if (res == FR_OK) {
+ do { /* Find a blank entry for the SFN */
+ res = move_window(dj->fs, dj->sect);
+ if (res != FR_OK) break;
+ c = *dj->dir;
+ if (c == DDE || c == 0) break; /* Is it a blank entry? */
+ res = dir_next(dj, 1); /* Next entry with table stretch */
+ } while (res == FR_OK);
+ }
+#endif
+
+ if (res == FR_OK) { /* Initialize the SFN entry */
+ res = move_window(dj->fs, dj->sect);
+ if (res == FR_OK) {
+ dir = dj->dir;
+ mem_set(dir, 0, SZ_DIR); /* Clean the entry */
+ mem_cpy(dir, dj->fn, 11); /* Put SFN */
+#if _USE_LFN
+ dir[DIR_NTres] = *(dj->fn+NS) & (NS_BODY | NS_EXT); /* Put NT flag */
+#endif
+ dj->fs->wflag = 1;
+ }
+ }
+
+ return res;
+}
+#endif /* !_FS_READONLY */
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Remove an object from the directory */
+/*-----------------------------------------------------------------------*/
+#if !_FS_READONLY && !_FS_MINIMIZE
+static
+FRESULT dir_remove ( /* FR_OK: Successful, FR_DISK_ERR: A disk error */
+ FATFS_DIR *dj /* Directory object pointing the entry to be removed */
+)
+{
+ FRESULT res;
+#if _USE_LFN /* LFN configuration */
+ WORD i;
+
+ i = dj->index; /* SFN index */
+ res = dir_sdi(dj, (WORD)((dj->lfn_idx == 0xFFFF) ? i : dj->lfn_idx)); /* Goto the SFN or top of the LFN entries */
+ if (res == FR_OK) {
+ do {
+ res = move_window(dj->fs, dj->sect);
+ if (res != FR_OK) break;
+ *dj->dir = DDE; /* Mark the entry "deleted" */
+ dj->fs->wflag = 1;
+ if (dj->index >= i) break; /* When reached SFN, all entries of the object has been deleted. */
+ res = dir_next(dj, 0); /* Next entry */
+ } while (res == FR_OK);
+ if (res == FR_NO_FILE) res = FR_INT_ERR;
+ }
+
+#else /* Non LFN configuration */
+ res = dir_sdi(dj, dj->index);
+ if (res == FR_OK) {
+ res = move_window(dj->fs, dj->sect);
+ if (res == FR_OK) {
+ *dj->dir = DDE; /* Mark the entry "deleted" */
+ dj->fs->wflag = 1;
+ }
+ }
+#endif
+
+ return res;
+}
+#endif /* !_FS_READONLY */
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Pick a segment and create the object name in directory form */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT create_name (
+ FATFS_DIR *dj, /* Pointer to the directory object */
+ const TCHAR **path /* Pointer to pointer to the segment in the path string */
+)
+{
+#ifdef _EXCVT
+ static const BYTE excvt[] = _EXCVT; /* Upper conversion table for extended chars */
+#endif
+
+#if _USE_LFN /* LFN configuration */
+ BYTE b, cf;
+ WCHAR w, *lfn;
+ UINT i, ni, si, di;
+ const TCHAR *p;
+
+ /* Create LFN in Unicode */
+ for (p = *path; *p == '/' || *p == '\\'; p++) ; /* Strip duplicated separator */
+ lfn = dj->lfn;
+ si = di = 0;
+ for (;;) {
+ w = p[si++]; /* Get a character */
+ if (w < ' ' || w == '/' || w == '\\') break; /* Break on end of segment */
+ if (di >= _MAX_LFN) /* Reject too long name */
+ return FR_INVALID_NAME;
+#if !_LFN_UNICODE
+ w &= 0xFF;
+ if (IsDBCS1(w)) { /* Check if it is a DBC 1st byte (always false on SBCS cfg) */
+ b = (BYTE)p[si++]; /* Get 2nd byte */
+ if (!IsDBCS2(b))
+ return FR_INVALID_NAME; /* Reject invalid sequence */
+ w = (w << 8) + b; /* Create a DBC */
+ }
+ w = ff_convert(w, 1); /* Convert ANSI/OEM to Unicode */
+ if (!w) return FR_INVALID_NAME; /* Reject invalid code */
+#endif
+ if (w < 0x80 && chk_chr("\"*:<>\?|\x7F", w)) /* Reject illegal chars for LFN */
+ return FR_INVALID_NAME;
+ lfn[di++] = w; /* Store the Unicode char */
+ }
+ *path = &p[si]; /* Return pointer to the next segment */
+ cf = (w < ' ') ? NS_LAST : 0; /* Set last segment flag if end of path */
+#if _FS_RPATH
+ if ((di == 1 && lfn[di-1] == '.') || /* Is this a dot entry? */
+ (di == 2 && lfn[di-1] == '.' && lfn[di-2] == '.')) {
+ lfn[di] = 0;
+ for (i = 0; i < 11; i++)
+ dj->fn[i] = (i < di) ? '.' : ' ';
+ dj->fn[i] = cf | NS_DOT; /* This is a dot entry */
+ return FR_OK;
+ }
+#endif
+ while (di) { /* Strip trailing spaces and dots */
+ w = lfn[di-1];
+ if (w != ' ' && w != '.') break;
+ di--;
+ }
+ if (!di) return FR_INVALID_NAME; /* Reject nul string */
+
+ lfn[di] = 0; /* LFN is created */
+
+ /* Create SFN in directory form */
+ mem_set(dj->fn, ' ', 11);
+ for (si = 0; lfn[si] == ' ' || lfn[si] == '.'; si++) ; /* Strip leading spaces and dots */
+ if (si) cf |= NS_LOSS | NS_LFN;
+ while (di && lfn[di - 1] != '.') di--; /* Find extension (di<=si: no extension) */
+
+ b = i = 0; ni = 8;
+ for (;;) {
+ w = lfn[si++]; /* Get an LFN char */
+ if (!w) break; /* Break on end of the LFN */
+ if (w == ' ' || (w == '.' && si != di)) { /* Remove spaces and dots */
+ cf |= NS_LOSS | NS_LFN; continue;
+ }
+
+ if (i >= ni || si == di) { /* Extension or end of SFN */
+ if (ni == 11) { /* Long extension */
+ cf |= NS_LOSS | NS_LFN; break;
+ }
+ if (si != di) cf |= NS_LOSS | NS_LFN; /* Out of 8.3 format */
+ if (si > di) break; /* No extension */
+ si = di; i = 8; ni = 11; /* Enter extension section */
+ b <<= 2; continue;
+ }
+
+ if (w >= 0x80) { /* Non ASCII char */
+#ifdef _EXCVT
+ w = ff_convert(w, 0); /* Unicode -> OEM code */
+ if (w) w = excvt[w - 0x80]; /* Convert extended char to upper (SBCS) */
+#else
+ w = ff_convert(ff_wtoupper(w), 0); /* Upper converted Unicode -> OEM code */
+#endif
+ cf |= NS_LFN; /* Force create LFN entry */
+ }
+
+ if (_DF1S && w >= 0x100) { /* Double byte char (always false on SBCS cfg) */
+ if (i >= ni - 1) {
+ cf |= NS_LOSS | NS_LFN; i = ni; continue;
+ }
+ dj->fn[i++] = (BYTE)(w >> 8);
+ } else { /* Single byte char */
+ if (!w || chk_chr("+,;=[]", w)) { /* Replace illegal chars for SFN */
+ w = '_'; cf |= NS_LOSS | NS_LFN;/* Lossy conversion */
+ } else {
+ if (IsUpper(w)) { /* ASCII large capital */
+ b |= 2;
+ } else {
+ if (IsLower(w)) { /* ASCII small capital */
+ b |= 1; w -= 0x20;
+ }
+ }
+ }
+ }
+ dj->fn[i++] = (BYTE)w;
+ }
+
+ if (dj->fn[0] == DDE) dj->fn[0] = NDDE; /* If the first char collides with deleted mark, replace it with 0x05 */
+
+ if (ni == 8) b <<= 2;
+ if ((b & 0x0C) == 0x0C || (b & 0x03) == 0x03) /* Create LFN entry when there are composite capitals */
+ cf |= NS_LFN;
+ if (!(cf & NS_LFN)) { /* When LFN is in 8.3 format without extended char, NT flags are created */
+ if ((b & 0x03) == 0x01) cf |= NS_EXT; /* NT flag (Extension has only small capital) */
+ if ((b & 0x0C) == 0x04) cf |= NS_BODY; /* NT flag (Filename has only small capital) */
+ }
+
+ dj->fn[NS] = cf; /* SFN is created */
+
+ return FR_OK;
+
+
+#else /* Non-LFN configuration */
+ BYTE b, c, d, *sfn;
+ UINT ni, si, i;
+ const char *p;
+
+ /* Create file name in directory form */
+ for (p = *path; *p == '/' || *p == '\\'; p++) ; /* Strip duplicated separator */
+ sfn = dj->fn;
+ mem_set(sfn, ' ', 11);
+ si = i = b = 0; ni = 8;
+#if _FS_RPATH
+ if (p[si] == '.') { /* Is this a dot entry? */
+ for (;;) {
+ c = (BYTE)p[si++];
+ if (c != '.' || si >= 3) break;
+ sfn[i++] = c;
+ }
+ if (c != '/' && c != '\\' && c > ' ') return FR_INVALID_NAME;
+ *path = &p[si]; /* Return pointer to the next segment */
+ sfn[NS] = (c <= ' ') ? NS_LAST | NS_DOT : NS_DOT; /* Set last segment flag if end of path */
+ return FR_OK;
+ }
+#endif
+ for (;;) {
+ c = (BYTE)p[si++];
+ if (c <= ' ' || c == '/' || c == '\\') break; /* Break on end of segment */
+ if (c == '.' || i >= ni) {
+ if (ni != 8 || c != '.') return FR_INVALID_NAME;
+ i = 8; ni = 11;
+ b <<= 2; continue;
+ }
+ if (c >= 0x80) { /* Extended char? */
+ b |= 3; /* Eliminate NT flag */
+#ifdef _EXCVT
+ c = excvt[c - 0x80]; /* Upper conversion (SBCS) */
+#else
+#if !_DF1S /* ASCII only cfg */
+ return FR_INVALID_NAME;
+#endif
+#endif
+ }
+ if (IsDBCS1(c)) { /* Check if it is a DBC 1st byte (always false on SBCS cfg) */
+ d = (BYTE)p[si++]; /* Get 2nd byte */
+ if (!IsDBCS2(d) || i >= ni - 1) /* Reject invalid DBC */
+ return FR_INVALID_NAME;
+ sfn[i++] = c;
+ sfn[i++] = d;
+ } else { /* Single byte code */
+ if (chk_chr("\"*+,:;<=>\?[]|\x7F", c)) /* Reject illegal chrs for SFN */
+ return FR_INVALID_NAME;
+ if (IsUpper(c)) { /* ASCII large capital? */
+ b |= 2;
+ } else {
+ if (IsLower(c)) { /* ASCII small capital? */
+ b |= 1; c -= 0x20;
+ }
+ }
+ sfn[i++] = c;
+ }
+ }
+ *path = &p[si]; /* Return pointer to the next segment */
+ c = (c <= ' ') ? NS_LAST : 0; /* Set last segment flag if end of path */
+
+ if (!i) return FR_INVALID_NAME; /* Reject nul string */
+ if (sfn[0] == DDE) sfn[0] = NDDE; /* When first char collides with DDE, replace it with 0x05 */
+
+ if (ni == 8) b <<= 2;
+ if ((b & 0x03) == 0x01) c |= NS_EXT; /* NT flag (Name extension has only small capital) */
+ if ((b & 0x0C) == 0x04) c |= NS_BODY; /* NT flag (Name body has only small capital) */
+
+ sfn[NS] = c; /* Store NT flag, File name is created */
+
+ return FR_OK;
+#endif
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Get file information from directory entry */
+/*-----------------------------------------------------------------------*/
+#if _FS_MINIMIZE <= 1
+static
+void get_fileinfo ( /* No return code */
+ FATFS_DIR *dj, /* Pointer to the directory object */
+ FILINFO *fno /* Pointer to the file information to be filled */
+)
+{
+ UINT i;
+ BYTE nt, *dir;
+ TCHAR *p, c;
+
+
+ p = fno->fname;
+ if (dj->sect) {
+ dir = dj->dir;
+ nt = dir[DIR_NTres]; /* NT flag */
+ for (i = 0; i < 8; i++) { /* Copy name body */
+ c = dir[i];
+ if (c == ' ') break;
+ if (c == NDDE) c = (TCHAR)DDE;
+ if (_USE_LFN && (nt & NS_BODY) && IsUpper(c)) c += 0x20;
+#if _LFN_UNICODE
+ if (IsDBCS1(c) && i < 7 && IsDBCS2(dir[i+1]))
+ c = (c << 8) | dir[++i];
+ c = ff_convert(c, 1);
+ if (!c) c = '?';
+#endif
+ *p++ = c;
+ }
+ if (dir[8] != ' ') { /* Copy name extension */
+ *p++ = '.';
+ for (i = 8; i < 11; i++) {
+ c = dir[i];
+ if (c == ' ') break;
+ if (_USE_LFN && (nt & NS_EXT) && IsUpper(c)) c += 0x20;
+#if _LFN_UNICODE
+ if (IsDBCS1(c) && i < 10 && IsDBCS2(dir[i+1]))
+ c = (c << 8) | dir[++i];
+ c = ff_convert(c, 1);
+ if (!c) c = '?';
+#endif
+ *p++ = c;
+ }
+ }
+ fno->fattrib = dir[DIR_Attr]; /* Attribute */
+ fno->fsize = LD_DWORD(dir+DIR_FileSize); /* Size */
+ fno->fdate = LD_WORD(dir+DIR_WrtDate); /* Date */
+ fno->ftime = LD_WORD(dir+DIR_WrtTime); /* Time */
+ }
+ *p = 0; /* Terminate SFN str by a \0 */
+
+#if _USE_LFN
+ if (fno->lfname && fno->lfsize) {
+ TCHAR *tp = fno->lfname;
+ WCHAR w, *lfn;
+
+ i = 0;
+ if (dj->sect && dj->lfn_idx != 0xFFFF) {/* Get LFN if available */
+ lfn = dj->lfn;
+ while ((w = *lfn++) != 0) { /* Get an LFN char */
+#if !_LFN_UNICODE
+ w = ff_convert(w, 0); /* Unicode -> OEM conversion */
+ if (!w) { i = 0; break; } /* Could not convert, no LFN */
+ if (_DF1S && w >= 0x100) /* Put 1st byte if it is a DBC (always false on SBCS cfg) */
+ tp[i++] = (TCHAR)(w >> 8);
+#endif
+ if (i >= fno->lfsize - 1) { i = 0; break; } /* Buffer overflow, no LFN */
+ tp[i++] = (TCHAR)w;
+ }
+ }
+ tp[i] = 0; /* Terminate the LFN str by a \0 */
+ }
+#endif
+}
+#endif /* _FS_MINIMIZE <= 1 */
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Follow a file path */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */
+ FATFS_DIR *dj, /* Directory object to return last directory and found object */
+ const TCHAR *path /* Full-path string to find a file or directory */
+)
+{
+ FRESULT res;
+ BYTE *dir, ns;
+
+
+#if _FS_RPATH
+ if (*path == '/' || *path == '\\') { /* There is a heading separator */
+ path++; dj->sclust = 0; /* Strip it and start from the root dir */
+ } else { /* No heading separator */
+ dj->sclust = dj->fs->cdir; /* Start from the current dir */
+ }
+#else
+ if (*path == '/' || *path == '\\') /* Strip heading separator if exist */
+ path++;
+ dj->sclust = 0; /* Start from the root dir */
+#endif
+
+ if ((UINT)*path < ' ') { /* Nul path means the start directory itself */
+ res = dir_sdi(dj, 0);
+ dj->dir = 0;
+ } else { /* Follow path */
+ for (;;) {
+ res = create_name(dj, &path); /* Get a segment */
+ if (res != FR_OK) break;
+ res = dir_find(dj); /* Find it */
+ ns = *(dj->fn+NS);
+ if (res != FR_OK) { /* Failed to find the object */
+ if (res != FR_NO_FILE) break; /* Abort if any hard error occurred */
+ /* Object not found */
+ if (_FS_RPATH && (ns & NS_DOT)) { /* If dot entry is not exit */
+ dj->sclust = 0; dj->dir = 0; /* It is the root dir */
+ res = FR_OK;
+ if (!(ns & NS_LAST)) continue;
+ } else { /* Could not find the object */
+ if (!(ns & NS_LAST)) res = FR_NO_PATH;
+ }
+ break;
+ }
+ if (ns & NS_LAST) break; /* Last segment match. Function completed. */
+ dir = dj->dir; /* There is next segment. Follow the sub directory */
+ if (!(dir[DIR_Attr] & AM_DIR)) { /* Cannot follow because it is a file */
+ res = FR_NO_PATH; break;
+ }
+ dj->sclust = ld_clust(dj->fs, dir);
+ }
+ }
+
+ return res;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Load a sector and check if it is an FAT Volume Boot Record */
+/*-----------------------------------------------------------------------*/
+
+static
+BYTE check_fs ( /* 0:FAT-VBR, 1:Any BR but not FAT, 2:Not a BR, 3:Disk error */
+ FATFS *fs, /* File system object */
+ DWORD sect /* Sector# (lba) to check if it is an FAT boot record or not */
+)
+{
+ if (disk_read(fs->drv, fs->win, sect, 1) != RES_OK) /* Load boot record */
+ return 3;
+ if (LD_WORD(&fs->win[BS_55AA]) != 0xAA55) /* Check record signature (always placed at offset 510 even if the sector size is >512) */
+ return 2;
+
+ if ((LD_DWORD(&fs->win[BS_FilSysType]) & 0xFFFFFF) == 0x544146) /* Check "FAT" string */
+ return 0;
+ if ((LD_DWORD(&fs->win[BS_FilSysType32]) & 0xFFFFFF) == 0x544146)
+ return 0;
+
+ return 1;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Check if the file system object is valid or not */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT chk_mounted ( /* FR_OK(0): successful, !=0: any error occurred */
+ const TCHAR **path, /* Pointer to pointer to the path name (drive number) */
+ FATFS **rfs, /* Pointer to pointer to the found file system object */
+ BYTE wmode /* !=0: Check write protection for write access */
+)
+{
+ BYTE fmt, b, pi, *tbl;
+ UINT vol;
+ DSTATUS stat;
+ DWORD bsect, fasize, tsect, sysect, nclst, szbfat;
+ WORD nrsv;
+ const TCHAR *p = *path;
+ FATFS *fs;
+
+
+ /* Get logical drive number from the path name */
+ vol = p[0] - '0'; /* Is there a drive number? */
+ if (vol <= 9 && p[1] == ':') { /* Found a drive number, get and strip it */
+ p += 2; *path = p; /* Return pointer to the path name */
+ } else { /* No drive number is given */
+#if _FS_RPATH
+ vol = CurrVol; /* Use current drive */
+#else
+ vol = 0; /* Use drive 0 */
+#endif
+ }
+
+ /* Check if the file system object is valid or not */
+ *rfs = 0;
+ if (vol >= _VOLUMES) /* Is the drive number valid? */
+ return FR_INVALID_DRIVE;
+ fs = FatFs[vol]; /* Get corresponding file system object */
+ if (!fs) return FR_NOT_ENABLED; /* Is the file system object available? */
+
+ ENTER_FF(fs); /* Lock file system */
+
+ *rfs = fs; /* Return pointer to the corresponding file system object */
+ if (fs->fs_type) { /* If the volume has been mounted */
+ stat = disk_status(fs->drv);
+ if (!(stat & STA_NOINIT)) { /* and the physical drive is kept initialized (has not been changed), */
+ if (!_FS_READONLY && wmode && (stat & STA_PROTECT)) /* Check write protection if needed */
+ return FR_WRITE_PROTECTED;
+ return FR_OK; /* The file system object is valid */
+ }
+ }
+
+ /* The file system object is not valid. */
+ /* Following code attempts to mount the volume. (analyze BPB and initialize the fs object) */
+
+ fs->fs_type = 0; /* Clear the file system object */
+ fs->drv = LD2PD(vol); /* Bind the logical drive and a physical drive */
+ stat = disk_initialize(fs->drv); /* Initialize the physical drive */
+ if (stat & STA_NOINIT) /* Check if the initialization succeeded */
+ return FR_NOT_READY; /* Failed to initialize due to no medium or hard error */
+ if (!_FS_READONLY && wmode && (stat & STA_PROTECT)) /* Check disk write protection if needed */
+ return FR_WRITE_PROTECTED;
+#if _MAX_SS != 512 /* Get disk sector size (variable sector size cfg only) */
+ if (disk_ioctl(fs->drv, GET_SECTOR_SIZE, &fs->ssize) != RES_OK)
+ return FR_DISK_ERR;
+#endif
+ /* Search FAT partition on the drive. Supports only generic partitions, FDISK and SFD. */
+ fmt = check_fs(fs, bsect = 0); /* Load sector 0 and check if it is an FAT-VBR (in SFD) */
+ if (LD2PT(vol) && !fmt) fmt = 1; /* Force non-SFD if the volume is forced partition */
+ if (fmt == 1) { /* Not an FAT-VBR, the physical drive can be partitioned */
+ /* Check the partition listed in the partition table */
+ pi = LD2PT(vol);
+ if (pi) pi--;
+ tbl = &fs->win[MBR_Table + pi * SZ_PTE];/* Partition table */
+ if (tbl[4]) { /* Is the partition existing? */
+ bsect = LD_DWORD(&tbl[8]); /* Partition offset in LBA */
+ fmt = check_fs(fs, bsect); /* Check the partition */
+ }
+ }
+ if (fmt == 3) return FR_DISK_ERR;
+ if (fmt) return FR_NO_FILESYSTEM; /* No FAT volume is found */
+
+ /* An FAT volume is found. Following code initializes the file system object */
+
+ if (LD_WORD(fs->win+BPB_BytsPerSec) != SS(fs)) /* (BPB_BytsPerSec must be equal to the physical sector size) */
+ return FR_NO_FILESYSTEM;
+
+ fasize = LD_WORD(fs->win+BPB_FATSz16); /* Number of sectors per FAT */
+ if (!fasize) fasize = LD_DWORD(fs->win+BPB_FATSz32);
+ fs->fsize = fasize;
+
+ fs->n_fats = b = fs->win[BPB_NumFATs]; /* Number of FAT copies */
+ if (b != 1 && b != 2) return FR_NO_FILESYSTEM; /* (Must be 1 or 2) */
+ fasize *= b; /* Number of sectors for FAT area */
+
+ fs->csize = b = fs->win[BPB_SecPerClus]; /* Number of sectors per cluster */
+ if (!b || (b & (b - 1))) return FR_NO_FILESYSTEM; /* (Must be power of 2) */
+
+ fs->n_rootdir = LD_WORD(fs->win+BPB_RootEntCnt); /* Number of root directory entries */
+ if (fs->n_rootdir % (SS(fs) / SZ_DIR)) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be sector aligned) */
+
+ tsect = LD_WORD(fs->win+BPB_TotSec16); /* Number of sectors on the volume */
+ if (!tsect) tsect = LD_DWORD(fs->win+BPB_TotSec32);
+
+ nrsv = LD_WORD(fs->win+BPB_RsvdSecCnt); /* Number of reserved sectors */
+ if (!nrsv) return FR_NO_FILESYSTEM; /* (BPB_RsvdSecCnt must not be 0) */
+
+ /* Determine the FAT sub type */
+ sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZ_DIR); /* RSV+FAT+DIR */
+ if (tsect < sysect) return FR_NO_FILESYSTEM; /* (Invalid volume size) */
+ nclst = (tsect - sysect) / fs->csize; /* Number of clusters */
+ if (!nclst) return FR_NO_FILESYSTEM; /* (Invalid volume size) */
+ fmt = FS_FAT12;
+ if (nclst >= MIN_FAT16) fmt = FS_FAT16;
+ if (nclst >= MIN_FAT32) fmt = FS_FAT32;
+
+ /* Boundaries and Limits */
+ fs->n_fatent = nclst + 2; /* Number of FAT entries */
+ fs->database = bsect + sysect; /* Data start sector */
+ fs->fatbase = bsect + nrsv; /* FAT start sector */
+ if (fmt == FS_FAT32) {
+ if (fs->n_rootdir) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be 0) */
+ fs->dirbase = LD_DWORD(fs->win+BPB_RootClus); /* Root directory start cluster */
+ szbfat = fs->n_fatent * 4; /* (Required FAT size) */
+ } else {
+ if (!fs->n_rootdir) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must not be 0) */
+ fs->dirbase = fs->fatbase + fasize; /* Root directory start sector */
+ szbfat = (fmt == FS_FAT16) ? /* (Required FAT size) */
+ fs->n_fatent * 2 : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1);
+ }
+ if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs)) /* (BPB_FATSz must not be less than required) */
+ return FR_NO_FILESYSTEM;
+
+#if !_FS_READONLY
+ /* Initialize cluster allocation information */
+ fs->free_clust = 0xFFFFFFFF;
+ fs->last_clust = 0;
+
+ /* Get fsinfo if available */
+ if (fmt == FS_FAT32) {
+ fs->fsi_flag = 0;
+ fs->fsi_sector = bsect + LD_WORD(fs->win+BPB_FSInfo);
+ if (disk_read(fs->drv, fs->win, fs->fsi_sector, 1) == RES_OK &&
+ LD_WORD(fs->win+BS_55AA) == 0xAA55 &&
+ LD_DWORD(fs->win+FSI_LeadSig) == 0x41615252 &&
+ LD_DWORD(fs->win+FSI_StrucSig) == 0x61417272) {
+ fs->last_clust = LD_DWORD(fs->win+FSI_Nxt_Free);
+ fs->free_clust = LD_DWORD(fs->win+FSI_Free_Count);
+ }
+ }
+#endif
+ fs->fs_type = fmt; /* FAT sub-type */
+ fs->id = ++Fsid; /* File system mount ID */
+ fs->winsect = 0; /* Invalidate sector cache */
+ fs->wflag = 0;
+#if _FS_RPATH
+ fs->cdir = 0; /* Current directory (root dir) */
+#endif
+#if _FS_LOCK /* Clear file lock semaphores */
+ clear_lock(fs);
+#endif
+
+ return FR_OK;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Check if the file/dir object is valid or not */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT validate ( /* FR_OK(0): The object is valid, !=0: Invalid */
+ void* obj /* Pointer to the object FIL/DIR to check validity */
+)
+{
+ FIL *fil;
+
+
+ fil = (FIL*)obj; /* Assuming offset of fs and id in the FIL/DIR is identical */
+ if (!fil->fs || !fil->fs->fs_type || fil->fs->id != fil->id)
+ return FR_INVALID_OBJECT;
+
+ ENTER_FF(fil->fs); /* Lock file system */
+
+ if (disk_status(fil->fs->drv) & STA_NOINIT)
+ return FR_NOT_READY;
+
+ return FR_OK;
+}
+
+
+
+
+/*--------------------------------------------------------------------------
+
+ Public Functions
+
+--------------------------------------------------------------------------*/
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Mount/Unmount a Logical Drive */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_mount (
+ BYTE vol, /* Logical drive number to be mounted/unmounted */
+ FATFS *fs /* Pointer to new file system object (NULL for unmount)*/
+)
+{
+ FATFS *rfs;
+
+
+ if (vol >= _VOLUMES) /* Check if the drive number is valid */
+ return FR_INVALID_DRIVE;
+ rfs = FatFs[vol]; /* Get current fs object */
+
+ if (rfs) {
+#if _FS_LOCK
+ clear_lock(rfs);
+#endif
+#if _FS_REENTRANT /* Discard sync object of the current volume */
+ if (!ff_del_syncobj(rfs->sobj)) return FR_INT_ERR;
+#endif
+ rfs->fs_type = 0; /* Clear old fs object */
+ }
+
+ if (fs) {
+ fs->fs_type = 0; /* Clear new fs object */
+#if _FS_REENTRANT /* Create sync object for the new volume */
+ if (!ff_cre_syncobj(vol, &fs->sobj)) return FR_INT_ERR;
+#endif
+ }
+ FatFs[vol] = fs; /* Register new fs object */
+
+ return FR_OK;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Open or Create a File */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_open (
+ FIL *fp, /* Pointer to the blank file object */
+ const TCHAR *path, /* Pointer to the file name */
+ BYTE mode /* Access mode and file open mode flags */
+)
+{
+ FRESULT res;
+ FATFS_DIR dj;
+ BYTE *dir;
+ DEF_NAMEBUF;
+
+
+ if (!fp) return FR_INVALID_OBJECT;
+ fp->fs = 0; /* Clear file object */
+
+#if !_FS_READONLY
+ mode &= FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW;
+ res = chk_mounted(&path, &dj.fs, (BYTE)(mode & ~FA_READ));
+#else
+ mode &= FA_READ;
+ res = chk_mounted(&path, &dj.fs, 0);
+#endif
+ if (res == FR_OK) {
+ INIT_BUF(dj);
+ res = follow_path(&dj, path); /* Follow the file path */
+ dir = dj.dir;
+#if !_FS_READONLY /* R/W configuration */
+ if (res == FR_OK) {
+ if (!dir) /* Current dir itself */
+ res = FR_INVALID_NAME;
+#if _FS_LOCK
+ else
+ res = chk_lock(&dj, (mode & ~FA_READ) ? 1 : 0);
+#endif
+ }
+ /* Create or Open a file */
+ if (mode & (FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)) {
+ DWORD dw, cl;
+
+ if (res != FR_OK) { /* No file, create new */
+ if (res == FR_NO_FILE) /* There is no file to open, create a new entry */
+#if _FS_LOCK
+ res = enq_lock() ? dir_register(&dj) : FR_TOO_MANY_OPEN_FILES;
+#else
+ res = dir_register(&dj);
+#endif
+ mode |= FA_CREATE_ALWAYS; /* File is created */
+ dir = dj.dir; /* New entry */
+ }
+ else { /* Any object is already existing */
+ if (dir[DIR_Attr] & (AM_RDO | AM_DIR)) { /* Cannot overwrite it (R/O or DIR) */
+ res = FR_DENIED;
+ } else {
+ if (mode & FA_CREATE_NEW) /* Cannot create as new file */
+ res = FR_EXIST;
+ }
+ }
+ if (res == FR_OK && (mode & FA_CREATE_ALWAYS)) { /* Truncate it if overwrite mode */
+ dw = get_fattime(); /* Created time */
+ ST_DWORD(dir+DIR_CrtTime, dw);
+ dir[DIR_Attr] = 0; /* Reset attribute */
+ ST_DWORD(dir+DIR_FileSize, 0); /* size = 0 */
+ cl = ld_clust(dj.fs, dir); /* Get start cluster */
+ st_clust(dir, 0); /* cluster = 0 */
+ dj.fs->wflag = 1;
+ if (cl) { /* Remove the cluster chain if exist */
+ dw = dj.fs->winsect;
+ res = remove_chain(dj.fs, cl);
+ if (res == FR_OK) {
+ dj.fs->last_clust = cl - 1; /* Reuse the cluster hole */
+ res = move_window(dj.fs, dw);
+ }
+ }
+ }
+ }
+ else { /* Open an existing file */
+ if (res == FR_OK) { /* Follow succeeded */
+ if (dir[DIR_Attr] & AM_DIR) { /* It is a directory */
+ res = FR_NO_FILE;
+ } else {
+ if ((mode & FA_WRITE) && (dir[DIR_Attr] & AM_RDO)) /* R/O violation */
+ res = FR_DENIED;
+ }
+ }
+ }
+ if (res == FR_OK) {
+ if (mode & FA_CREATE_ALWAYS) /* Set file change flag if created or overwritten */
+ mode |= FA__WRITTEN;
+ fp->dir_sect = dj.fs->winsect; /* Pointer to the directory entry */
+ fp->dir_ptr = dir;
+#if _FS_LOCK
+ fp->lockid = inc_lock(&dj, (mode & ~FA_READ) ? 1 : 0);
+ if (!fp->lockid) res = FR_INT_ERR;
+#endif
+ }
+
+#else /* R/O configuration */
+ if (res == FR_OK) { /* Follow succeeded */
+ dir = dj.dir;
+ if (!dir) { /* Current dir itself */
+ res = FR_INVALID_NAME;
+ } else {
+ if (dir[DIR_Attr] & AM_DIR) /* It is a directory */
+ res = FR_NO_FILE;
+ }
+ }
+#endif
+ FREE_BUF();
+
+ if (res == FR_OK) {
+ fp->flag = mode; /* File access mode */
+ fp->sclust = ld_clust(dj.fs, dir); /* File start cluster */
+ fp->fsize = LD_DWORD(dir+DIR_FileSize); /* File size */
+ fp->fptr = 0; /* File pointer */
+ fp->dsect = 0;
+#if _USE_FASTSEEK
+ fp->cltbl = 0; /* Normal seek mode */
+#endif
+ fp->fs = dj.fs; fp->id = dj.fs->id; /* Validate file object */
+ }
+ }
+
+ LEAVE_FF(dj.fs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Read File */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_read (
+ FIL *fp, /* Pointer to the file object */
+ void *buff, /* Pointer to data buffer */
+ UINT btr, /* Number of bytes to read */
+ UINT *br /* Pointer to number of bytes read */
+)
+{
+ FRESULT res;
+ DWORD clst, sect, remain;
+ UINT rcnt, cc;
+ BYTE csect, *rbuff = (BYTE *)buff;
+
+
+ *br = 0; /* Clear read byte counter */
+
+ res = validate(fp); /* Check validity */
+ if (res != FR_OK) LEAVE_FF(fp->fs, res);
+ if (fp->flag & FA__ERROR) /* Aborted file? */
+ LEAVE_FF(fp->fs, FR_INT_ERR);
+ if (!(fp->flag & FA_READ)) /* Check access mode */
+ LEAVE_FF(fp->fs, FR_DENIED);
+ remain = fp->fsize - fp->fptr;
+ if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */
+
+ for ( ; btr; /* Repeat until all data read */
+ rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) {
+ if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */
+ csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */
+ if (!csect) { /* On the cluster boundary? */
+ if (fp->fptr == 0) { /* On the top of the file? */
+ clst = fp->sclust; /* Follow from the origin */
+ } else { /* Middle or end of the file */
+#if _USE_FASTSEEK
+ if (fp->cltbl)
+ clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */
+ else
+#endif
+ clst = get_fat(fp->fs, fp->clust); /* Follow cluster chain on the FAT */
+ }
+ if (clst < 2) ABORT(fp->fs, FR_INT_ERR);
+ if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
+ fp->clust = clst; /* Update current cluster */
+ }
+ sect = clust2sect(fp->fs, fp->clust); /* Get current sector */
+ if (!sect) ABORT(fp->fs, FR_INT_ERR);
+ sect += csect;
+ cc = btr / SS(fp->fs); /* When remaining bytes >= sector size, */
+ if (cc) { /* Read maximum contiguous sectors directly */
+ if (csect + cc > fp->fs->csize) /* Clip at cluster boundary */
+ cc = fp->fs->csize - csect;
+ if (disk_read(fp->fs->drv, rbuff, sect, (BYTE)cc) != RES_OK)
+ ABORT(fp->fs, FR_DISK_ERR);
+#if !_FS_READONLY && _FS_MINIMIZE <= 2 /* Replace one of the read sectors with cached data if it contains a dirty sector */
+#if _FS_TINY
+ if (fp->fs->wflag && fp->fs->winsect - sect < cc)
+ mem_cpy(rbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), fp->fs->win, SS(fp->fs));
+#else
+ if ((fp->flag & FA__DIRTY) && fp->dsect - sect < cc)
+ mem_cpy(rbuff + ((fp->dsect - sect) * SS(fp->fs)), fp->buf, SS(fp->fs));
+#endif
+#endif
+ rcnt = SS(fp->fs) * cc; /* Number of bytes transferred */
+ continue;
+ }
+#if !_FS_TINY
+ if (fp->dsect != sect) { /* Load data sector if not in cache */
+#if !_FS_READONLY
+ if (fp->flag & FA__DIRTY) { /* Write-back dirty sector cache */
+ if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
+ ABORT(fp->fs, FR_DISK_ERR);
+ fp->flag &= ~FA__DIRTY;
+ }
+#endif
+ if (disk_read(fp->fs->drv, fp->buf, sect, 1) != RES_OK) /* Fill sector cache */
+ ABORT(fp->fs, FR_DISK_ERR);
+ }
+#endif
+ fp->dsect = sect;
+ }
+ rcnt = SS(fp->fs) - ((UINT)fp->fptr % SS(fp->fs)); /* Get partial sector data from sector buffer */
+ if (rcnt > btr) rcnt = btr;
+#if _FS_TINY
+ if (move_window(fp->fs, fp->dsect)) /* Move sector window */
+ ABORT(fp->fs, FR_DISK_ERR);
+ mem_cpy(rbuff, &fp->fs->win[fp->fptr % SS(fp->fs)], rcnt); /* Pick partial sector */
+#else
+ mem_cpy(rbuff, &fp->buf[fp->fptr % SS(fp->fs)], rcnt); /* Pick partial sector */
+#endif
+ }
+
+ LEAVE_FF(fp->fs, FR_OK);
+}
+
+
+
+
+#if !_FS_READONLY
+/*-----------------------------------------------------------------------*/
+/* Write File */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_write (
+ FIL *fp, /* Pointer to the file object */
+ const void *buff, /* Pointer to the data to be written */
+ UINT btw, /* Number of bytes to write */
+ UINT *bw /* Pointer to number of bytes written */
+)
+{
+ FRESULT res;
+ DWORD clst, sect;
+ UINT wcnt, cc;
+ const BYTE *wbuff = (const BYTE *)buff;
+ BYTE csect;
+ bool need_sync = false;
+
+ *bw = 0; /* Clear write byte counter */
+
+ res = validate(fp); /* Check validity */
+ if (res != FR_OK) LEAVE_FF(fp->fs, res);
+ if (fp->flag & FA__ERROR) /* Aborted file? */
+ LEAVE_FF(fp->fs, FR_INT_ERR);
+ if (!(fp->flag & FA_WRITE)) /* Check access mode */
+ LEAVE_FF(fp->fs, FR_DENIED);
+ if ((DWORD)(fp->fsize + btw) < fp->fsize) btw = 0; /* File size cannot reach 4GB */
+
+ for ( ; btw; /* Repeat until all data written */
+ wbuff += wcnt, fp->fptr += wcnt, *bw += wcnt, btw -= wcnt) {
+ if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */
+ csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */
+ if (!csect) { /* On the cluster boundary? */
+ if (fp->fptr == 0) { /* On the top of the file? */
+ clst = fp->sclust; /* Follow from the origin */
+ if (clst == 0) /* When no cluster is allocated, */
+ fp->sclust = clst = create_chain(fp->fs, 0); /* Create a new cluster chain */
+ } else { /* Middle or end of the file */
+#if _USE_FASTSEEK
+ if (fp->cltbl)
+ clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */
+ else
+#endif
+ clst = create_chain(fp->fs, fp->clust); /* Follow or stretch cluster chain on the FAT */
+ }
+ if (clst == 0) break; /* Could not allocate a new cluster (disk full) */
+ if (clst == 1) ABORT(fp->fs, FR_INT_ERR);
+ if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
+ fp->clust = clst; /* Update current cluster */
+
+#ifdef FLUSH_ON_NEW_CLUSTER
+ // We do not need to flush for the first cluster
+ if (fp->fptr != 0) {
+ need_sync = true;
+ }
+#endif
+ }
+#if _FS_TINY
+ if (fp->fs->winsect == fp->dsect && move_window(fp->fs, 0)) /* Write-back sector cache */
+ ABORT(fp->fs, FR_DISK_ERR);
+#else
+ if (fp->flag & FA__DIRTY) { /* Write-back sector cache */
+ if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
+ ABORT(fp->fs, FR_DISK_ERR);
+ fp->flag &= ~FA__DIRTY;
+ }
+#endif
+ sect = clust2sect(fp->fs, fp->clust); /* Get current sector */
+ if (!sect) ABORT(fp->fs, FR_INT_ERR);
+ sect += csect;
+ cc = btw / SS(fp->fs); /* When remaining bytes >= sector size, */
+ if (cc) { /* Write maximum contiguous sectors directly */
+ if (csect + cc > fp->fs->csize) /* Clip at cluster boundary */
+ cc = fp->fs->csize - csect;
+ if (disk_write(fp->fs->drv, wbuff, sect, (BYTE)cc) != RES_OK)
+ ABORT(fp->fs, FR_DISK_ERR);
+#if _FS_TINY
+ if (fp->fs->winsect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */
+ mem_cpy(fp->fs->win, wbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), SS(fp->fs));
+ fp->fs->wflag = 0;
+ }
+#else
+ if (fp->dsect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */
+ mem_cpy(fp->buf, wbuff + ((fp->dsect - sect) * SS(fp->fs)), SS(fp->fs));
+ fp->flag &= ~FA__DIRTY;
+ }
+#endif
+ wcnt = SS(fp->fs) * cc; /* Number of bytes transferred */
+#ifdef FLUSH_ON_NEW_SECTOR
+ need_sync = true;
+#endif
+ continue;
+ }
+#if _FS_TINY
+ if (fp->fptr >= fp->fsize) { /* Avoid silly cache filling at growing edge */
+ if (move_window(fp->fs, 0)) ABORT(fp->fs, FR_DISK_ERR);
+ fp->fs->winsect = sect;
+ }
+#else
+ if (fp->dsect != sect) { /* Fill sector cache with file data */
+ if (fp->fptr < fp->fsize &&
+ disk_read(fp->fs->drv, fp->buf, sect, 1) != RES_OK)
+ ABORT(fp->fs, FR_DISK_ERR);
+ }
+#endif
+ fp->dsect = sect;
+ }
+ wcnt = SS(fp->fs) - ((UINT)fp->fptr % SS(fp->fs));/* Put partial sector into file I/O buffer */
+ if (wcnt > btw) wcnt = btw;
+#if _FS_TINY
+ if (move_window(fp->fs, fp->dsect)) /* Move sector window */
+ ABORT(fp->fs, FR_DISK_ERR);
+ mem_cpy(&fp->fs->win[fp->fptr % SS(fp->fs)], wbuff, wcnt); /* Fit partial sector */
+ fp->fs->wflag = 1;
+#else
+ mem_cpy(&fp->buf[fp->fptr % SS(fp->fs)], wbuff, wcnt); /* Fit partial sector */
+ fp->flag |= FA__DIRTY;
+#endif
+ }
+
+ if (fp->fptr > fp->fsize) fp->fsize = fp->fptr; /* Update file size if needed */
+ fp->flag |= FA__WRITTEN; /* Set file change flag */
+
+ if (need_sync) {
+ f_sync (fp);
+ }
+
+ LEAVE_FF(fp->fs, FR_OK);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Synchronize the File Object */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_sync (
+ FIL *fp /* Pointer to the file object */
+)
+{
+ FRESULT res;
+ DWORD tim;
+ BYTE *dir;
+
+
+ res = validate(fp); /* Check validity of the object */
+ if (res == FR_OK) {
+ if (fp->flag & FA__WRITTEN) { /* Has the file been written? */
+#if !_FS_TINY /* Write-back dirty buffer */
+ if (fp->flag & FA__DIRTY) {
+ if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
+ LEAVE_FF(fp->fs, FR_DISK_ERR);
+ fp->flag &= ~FA__DIRTY;
+ }
+#endif
+ /* Update the directory entry */
+ res = move_window(fp->fs, fp->dir_sect);
+ if (res == FR_OK) {
+ dir = fp->dir_ptr;
+ dir[DIR_Attr] |= AM_ARC; /* Set archive bit */
+ ST_DWORD(dir+DIR_FileSize, fp->fsize); /* Update file size */
+ st_clust(dir, fp->sclust); /* Update start cluster */
+ tim = get_fattime(); /* Update updated time */
+ ST_DWORD(dir+DIR_WrtTime, tim);
+ ST_WORD(dir+DIR_LstAccDate, 0);
+ fp->flag &= ~FA__WRITTEN;
+ fp->fs->wflag = 1;
+ res = sync(fp->fs);
+ }
+ }
+ }
+
+ LEAVE_FF(fp->fs, res);
+}
+
+#endif /* !_FS_READONLY */
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Close File */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_close (
+ FIL *fp /* Pointer to the file object to be closed */
+)
+{
+ FRESULT res;
+
+
+#if _FS_READONLY
+ res = validate(fp);
+ {
+#if _FS_REENTRANT
+ FATFS *fs = fp->fs;
+#endif
+ if (res == FR_OK) fp->fs = 0; /* Discard file object */
+ LEAVE_FF(fs, res);
+ }
+#else
+ res = f_sync(fp); /* Flush cached data */
+#if _FS_LOCK
+ if (res == FR_OK) { /* Decrement open counter */
+#if _FS_REENTRANT
+ FATFS *fs = fp->fs;;
+ res = validate(fp);
+ if (res == FR_OK) {
+ res = dec_lock(fp->lockid);
+ unlock_fs(fs, FR_OK);
+ }
+#else
+ res = dec_lock(fp->lockid);
+#endif
+ }
+#endif
+ if (res == FR_OK) fp->fs = 0; /* Discard file object */
+ return res;
+#endif
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Current Drive/Directory Handlings */
+/*-----------------------------------------------------------------------*/
+
+#if _FS_RPATH >= 1
+
+FRESULT f_chdrive (
+ BYTE drv /* Drive number */
+)
+{
+ if (drv >= _VOLUMES) return FR_INVALID_DRIVE;
+
+ CurrVol = drv;
+
+ return FR_OK;
+}
+
+
+
+FRESULT f_chdir (
+ const TCHAR *path /* Pointer to the directory path */
+)
+{
+ FRESULT res;
+ DIR dj;
+ DEF_NAMEBUF;
+
+
+ res = chk_mounted(&path, &dj.fs, 0);
+ if (res == FR_OK) {
+ INIT_BUF(dj);
+ res = follow_path(&dj, path); /* Follow the path */
+ FREE_BUF();
+ if (res == FR_OK) { /* Follow completed */
+ if (!dj.dir) {
+ dj.fs->cdir = dj.sclust; /* Start directory itself */
+ } else {
+ if (dj.dir[DIR_Attr] & AM_DIR) /* Reached to the directory */
+ dj.fs->cdir = ld_clust(dj.fs, dj.dir);
+ else
+ res = FR_NO_PATH; /* Reached but a file */
+ }
+ }
+ if (res == FR_NO_FILE) res = FR_NO_PATH;
+ }
+
+ LEAVE_FF(dj.fs, res);
+}
+
+
+#if _FS_RPATH >= 2
+FRESULT f_getcwd (
+ TCHAR *path, /* Pointer to the directory path */
+ UINT sz_path /* Size of path */
+)
+{
+ FRESULT res;
+ DIR dj;
+ UINT i, n;
+ DWORD ccl;
+ TCHAR *tp;
+ FILINFO fno;
+ DEF_NAMEBUF;
+
+
+ *path = 0;
+ res = chk_mounted((const TCHAR**)&path, &dj.fs, 0); /* Get current volume */
+ if (res == FR_OK) {
+ INIT_BUF(dj);
+ i = sz_path; /* Bottom of buffer (dir stack base) */
+ dj.sclust = dj.fs->cdir; /* Start to follow upper dir from current dir */
+ while ((ccl = dj.sclust) != 0) { /* Repeat while current dir is a sub-dir */
+ res = dir_sdi(&dj, 1); /* Get parent dir */
+ if (res != FR_OK) break;
+ res = dir_read(&dj);
+ if (res != FR_OK) break;
+ dj.sclust = ld_clust(dj.fs, dj.dir); /* Goto parent dir */
+ res = dir_sdi(&dj, 0);
+ if (res != FR_OK) break;
+ do { /* Find the entry links to the child dir */
+ res = dir_read(&dj);
+ if (res != FR_OK) break;
+ if (ccl == ld_clust(dj.fs, dj.dir)) break; /* Found the entry */
+ res = dir_next(&dj, 0);
+ } while (res == FR_OK);
+ if (res == FR_NO_FILE) res = FR_INT_ERR;/* It cannot be 'not found'. */
+ if (res != FR_OK) break;
+#if _USE_LFN
+ fno.lfname = path;
+ fno.lfsize = i;
+#endif
+ get_fileinfo(&dj, &fno); /* Get the dir name and push it to the buffer */
+ tp = fno.fname;
+ if (_USE_LFN && *path) tp = path;
+ for (n = 0; tp[n]; n++) ;
+ if (i < n + 3) {
+ res = FR_NOT_ENOUGH_CORE; break;
+ }
+ while (n) path[--i] = tp[--n];
+ path[--i] = '/';
+ }
+ tp = path;
+ if (res == FR_OK) {
+ *tp++ = '0' + CurrVol; /* Put drive number */
+ *tp++ = ':';
+ if (i == sz_path) { /* Root-dir */
+ *tp++ = '/';
+ } else { /* Sub-dir */
+ do /* Add stacked path str */
+ *tp++ = path[i++];
+ while (i < sz_path);
+ }
+ }
+ *tp = 0;
+ FREE_BUF();
+ }
+
+ LEAVE_FF(dj.fs, res);
+}
+#endif /* _FS_RPATH >= 2 */
+#endif /* _FS_RPATH >= 1 */
+
+
+
+#if _FS_MINIMIZE <= 2
+/*-----------------------------------------------------------------------*/
+/* Seek File R/W Pointer */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_lseek (
+ FIL *fp, /* Pointer to the file object */
+ DWORD ofs /* File pointer from top of file */
+)
+{
+ FRESULT res;
+
+
+ res = validate(fp); /* Check validity of the object */
+ if (res != FR_OK) LEAVE_FF(fp->fs, res);
+ if (fp->flag & FA__ERROR) /* Check abort flag */
+ LEAVE_FF(fp->fs, FR_INT_ERR);
+
+#if _USE_FASTSEEK
+ if (fp->cltbl) { /* Fast seek */
+ DWORD cl, pcl, ncl, tcl, dsc, tlen, ulen, *tbl;
+
+ if (ofs == CREATE_LINKMAP) { /* Create CLMT */
+ tbl = fp->cltbl;
+ tlen = *tbl++; ulen = 2; /* Given table size and required table size */
+ cl = fp->sclust; /* Top of the chain */
+ if (cl) {
+ do {
+ /* Get a fragment */
+ tcl = cl; ncl = 0; ulen += 2; /* Top, length and used items */
+ do {
+ pcl = cl; ncl++;
+ cl = get_fat(fp->fs, cl);
+ if (cl <= 1) ABORT(fp->fs, FR_INT_ERR);
+ if (cl == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
+ } while (cl == pcl + 1);
+ if (ulen <= tlen) { /* Store the length and top of the fragment */
+ *tbl++ = ncl; *tbl++ = tcl;
+ }
+ } while (cl < fp->fs->n_fatent); /* Repeat until end of chain */
+ }
+ *fp->cltbl = ulen; /* Number of items used */
+ if (ulen <= tlen)
+ *tbl = 0; /* Terminate table */
+ else
+ res = FR_NOT_ENOUGH_CORE; /* Given table size is smaller than required */
+
+ } else { /* Fast seek */
+ if (ofs > fp->fsize) /* Clip offset at the file size */
+ ofs = fp->fsize;
+ fp->fptr = ofs; /* Set file pointer */
+ if (ofs) {
+ fp->clust = clmt_clust(fp, ofs - 1);
+ dsc = clust2sect(fp->fs, fp->clust);
+ if (!dsc) ABORT(fp->fs, FR_INT_ERR);
+ dsc += (ofs - 1) / SS(fp->fs) & (fp->fs->csize - 1);
+ if (fp->fptr % SS(fp->fs) && dsc != fp->dsect) { /* Refill sector cache if needed */
+#if !_FS_TINY
+#if !_FS_READONLY
+ if (fp->flag & FA__DIRTY) { /* Write-back dirty sector cache */
+ if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
+ ABORT(fp->fs, FR_DISK_ERR);
+ fp->flag &= ~FA__DIRTY;
+ }
+#endif
+ if (disk_read(fp->fs->drv, fp->buf, dsc, 1) != RES_OK) /* Load current sector */
+ ABORT(fp->fs, FR_DISK_ERR);
+#endif
+ fp->dsect = dsc;
+ }
+ }
+ }
+ } else
+#endif
+
+ /* Normal Seek */
+ {
+ DWORD clst, bcs, nsect, ifptr;
+
+ if (ofs > fp->fsize /* In read-only mode, clip offset with the file size */
+#if !_FS_READONLY
+ && !(fp->flag & FA_WRITE)
+#endif
+ ) ofs = fp->fsize;
+
+ ifptr = fp->fptr;
+ fp->fptr = nsect = 0;
+ if (ofs) {
+ bcs = (DWORD)fp->fs->csize * SS(fp->fs); /* Cluster size (byte) */
+ if (ifptr > 0 &&
+ (ofs - 1) / bcs >= (ifptr - 1) / bcs) { /* When seek to same or following cluster, */
+ fp->fptr = (ifptr - 1) & ~(bcs - 1); /* start from the current cluster */
+ ofs -= fp->fptr;
+ clst = fp->clust;
+ } else { /* When seek to back cluster, */
+ clst = fp->sclust; /* start from the first cluster */
+#if !_FS_READONLY
+ if (clst == 0) { /* If no cluster chain, create a new chain */
+ clst = create_chain(fp->fs, 0);
+ if (clst == 1) ABORT(fp->fs, FR_INT_ERR);
+ if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
+ fp->sclust = clst;
+ }
+#endif
+ fp->clust = clst;
+ }
+ if (clst != 0) {
+ while (ofs > bcs) { /* Cluster following loop */
+#if !_FS_READONLY
+ if (fp->flag & FA_WRITE) { /* Check if in write mode or not */
+ clst = create_chain(fp->fs, clst); /* Force stretch if in write mode */
+ if (clst == 0) { /* When disk gets full, clip file size */
+ ofs = bcs; break;
+ }
+ } else
+#endif
+ clst = get_fat(fp->fs, clst); /* Follow cluster chain if not in write mode */
+ if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
+ if (clst <= 1 || clst >= fp->fs->n_fatent) ABORT(fp->fs, FR_INT_ERR);
+ fp->clust = clst;
+ fp->fptr += bcs;
+ ofs -= bcs;
+ }
+ fp->fptr += ofs;
+ if (ofs % SS(fp->fs)) {
+ nsect = clust2sect(fp->fs, clst); /* Current sector */
+ if (!nsect) ABORT(fp->fs, FR_INT_ERR);
+ nsect += ofs / SS(fp->fs);
+ }
+ }
+ }
+ if (fp->fptr % SS(fp->fs) && nsect != fp->dsect) { /* Fill sector cache if needed */
+#if !_FS_TINY
+#if !_FS_READONLY
+ if (fp->flag & FA__DIRTY) { /* Write-back dirty sector cache */
+ if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
+ ABORT(fp->fs, FR_DISK_ERR);
+ fp->flag &= ~FA__DIRTY;
+ }
+#endif
+ if (disk_read(fp->fs->drv, fp->buf, nsect, 1) != RES_OK) /* Fill sector cache */
+ ABORT(fp->fs, FR_DISK_ERR);
+#endif
+ fp->dsect = nsect;
+ }
+#if !_FS_READONLY
+ if (fp->fptr > fp->fsize) { /* Set file change flag if the file size is extended */
+ fp->fsize = fp->fptr;
+ fp->flag |= FA__WRITTEN;
+ }
+#endif
+ }
+
+ LEAVE_FF(fp->fs, res);
+}
+
+
+
+#if _FS_MINIMIZE <= 1
+/*-----------------------------------------------------------------------*/
+/* Create a Directory Object */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_opendir (
+ FATFS_DIR *dj, /* Pointer to directory object to create */
+ const TCHAR *path /* Pointer to the directory path */
+)
+{
+ FRESULT res;
+ FATFS *fs;
+ DEF_NAMEBUF;
+
+
+ if (!dj) return FR_INVALID_OBJECT;
+
+ res = chk_mounted(&path, &dj->fs, 0);
+ fs = dj->fs;
+ if (res == FR_OK) {
+ INIT_BUF(*dj);
+ res = follow_path(dj, path); /* Follow the path to the directory */
+ FREE_BUF();
+ if (res == FR_OK) { /* Follow completed */
+ if (dj->dir) { /* It is not the root dir */
+ if (dj->dir[DIR_Attr] & AM_DIR) { /* The object is a directory */
+ dj->sclust = ld_clust(fs, dj->dir);
+ } else { /* The object is not a directory */
+ res = FR_NO_PATH;
+ }
+ }
+ if (res == FR_OK) {
+ dj->id = fs->id;
+ res = dir_sdi(dj, 0); /* Rewind dir */
+ }
+ }
+ if (res == FR_NO_FILE) res = FR_NO_PATH;
+ if (res != FR_OK) dj->fs = 0; /* Invalidate the dir object if function faild */
+ } else {
+ dj->fs = 0;
+ }
+
+ LEAVE_FF(fs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Read Directory Entry in Sequence */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_readdir (
+ FATFS_DIR *dj, /* Pointer to the open directory object */
+ FILINFO *fno /* Pointer to file information to return */
+)
+{
+ FRESULT res;
+ DEF_NAMEBUF;
+
+
+ res = validate(dj); /* Check validity of the object */
+ if (res == FR_OK) {
+ if (!fno) {
+ res = dir_sdi(dj, 0); /* Rewind the directory object */
+ } else {
+ INIT_BUF(*dj);
+ res = dir_read(dj); /* Read an directory item */
+ if (res == FR_NO_FILE) { /* Reached end of dir */
+ dj->sect = 0;
+ res = FR_OK;
+ }
+ if (res == FR_OK) { /* A valid entry is found */
+ get_fileinfo(dj, fno); /* Get the object information */
+ res = dir_next(dj, 0); /* Increment index for next */
+ if (res == FR_NO_FILE) {
+ dj->sect = 0;
+ res = FR_OK;
+ }
+ }
+ FREE_BUF();
+ }
+ }
+
+ LEAVE_FF(dj->fs, res);
+}
+
+
+
+#if _FS_MINIMIZE == 0
+/*-----------------------------------------------------------------------*/
+/* Get File Status */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_stat (
+ const TCHAR *path, /* Pointer to the file path */
+ FILINFO *fno /* Pointer to file information to return */
+)
+{
+ FRESULT res;
+ FATFS_DIR dj;
+ DEF_NAMEBUF;
+
+
+ res = chk_mounted(&path, &dj.fs, 0);
+ if (res == FR_OK) {
+ INIT_BUF(dj);
+ res = follow_path(&dj, path); /* Follow the file path */
+ if (res == FR_OK) { /* Follow completed */
+ if (dj.dir) /* Found an object */
+ get_fileinfo(&dj, fno);
+ else /* It is root dir */
+ res = FR_INVALID_NAME;
+ }
+ FREE_BUF();
+ }
+
+ LEAVE_FF(dj.fs, res);
+}
+
+
+
+#if !_FS_READONLY
+/*-----------------------------------------------------------------------*/
+/* Get Number of Free Clusters */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_getfree (
+ const TCHAR *path, /* Pointer to the logical drive number (root dir) */
+ DWORD *nclst, /* Pointer to the variable to return number of free clusters */
+ FATFS **fatfs /* Pointer to pointer to corresponding file system object to return */
+)
+{
+ FRESULT res;
+ FATFS *fs;
+ DWORD n, clst, sect, stat;
+ UINT i;
+ BYTE fat, *p;
+
+
+ /* Get drive number */
+ res = chk_mounted(&path, fatfs, 0);
+ fs = *fatfs;
+ if (res == FR_OK) {
+ /* If free_clust is valid, return it without full cluster scan */
+ if (fs->free_clust <= fs->n_fatent - 2) {
+ *nclst = fs->free_clust;
+ } else {
+ /* Get number of free clusters */
+ fat = fs->fs_type;
+ n = 0;
+ if (fat == FS_FAT12) {
+ clst = 2;
+ do {
+ stat = get_fat(fs, clst);
+ if (stat == 0xFFFFFFFF) { res = FR_DISK_ERR; break; }
+ if (stat == 1) { res = FR_INT_ERR; break; }
+ if (stat == 0) n++;
+ } while (++clst < fs->n_fatent);
+ } else {
+ clst = fs->n_fatent;
+ sect = fs->fatbase;
+ i = 0; p = 0;
+ do {
+ if (!i) {
+ res = move_window(fs, sect++);
+ if (res != FR_OK) break;
+ p = fs->win;
+ i = SS(fs);
+ }
+ if (fat == FS_FAT16) {
+ if (LD_WORD(p) == 0) n++;
+ p += 2; i -= 2;
+ } else {
+ if ((LD_DWORD(p) & 0x0FFFFFFF) == 0) n++;
+ p += 4; i -= 4;
+ }
+ } while (--clst);
+ }
+ fs->free_clust = n;
+ if (fat == FS_FAT32) fs->fsi_flag = 1;
+ *nclst = n;
+ }
+ }
+ LEAVE_FF(fs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Truncate File */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_truncate (
+ FIL *fp /* Pointer to the file object */
+)
+{
+ FRESULT res;
+ DWORD ncl;
+
+
+ if (!fp) return FR_INVALID_OBJECT;
+
+ res = validate(fp); /* Check validity of the object */
+ if (res == FR_OK) {
+ if (fp->flag & FA__ERROR) { /* Check abort flag */
+ res = FR_INT_ERR;
+ } else {
+ if (!(fp->flag & FA_WRITE)) /* Check access mode */
+ res = FR_DENIED;
+ }
+ }
+ if (res == FR_OK) {
+ if (fp->fsize > fp->fptr) {
+ fp->fsize = fp->fptr; /* Set file size to current R/W point */
+ fp->flag |= FA__WRITTEN;
+ if (fp->fptr == 0) { /* When set file size to zero, remove entire cluster chain */
+ res = remove_chain(fp->fs, fp->sclust);
+ fp->sclust = 0;
+ } else { /* When truncate a part of the file, remove remaining clusters */
+ ncl = get_fat(fp->fs, fp->clust);
+ res = FR_OK;
+ if (ncl == 0xFFFFFFFF) res = FR_DISK_ERR;
+ if (ncl == 1) res = FR_INT_ERR;
+ if (res == FR_OK && ncl < fp->fs->n_fatent) {
+ res = put_fat(fp->fs, fp->clust, 0x0FFFFFFF);
+ if (res == FR_OK) res = remove_chain(fp->fs, ncl);
+ }
+ }
+ }
+ if (res != FR_OK) fp->flag |= FA__ERROR;
+ }
+
+ LEAVE_FF(fp->fs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Delete a File or Directory */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_unlink (
+ const TCHAR *path /* Pointer to the file or directory path */
+)
+{
+ FRESULT res;
+ FATFS_DIR dj, sdj;
+ BYTE *dir;
+ DWORD dclst;
+ DEF_NAMEBUF;
+
+
+ res = chk_mounted(&path, &dj.fs, 1);
+ if (res == FR_OK) {
+ INIT_BUF(dj);
+ res = follow_path(&dj, path); /* Follow the file path */
+ if (_FS_RPATH && res == FR_OK && (dj.fn[NS] & NS_DOT))
+ res = FR_INVALID_NAME; /* Cannot remove dot entry */
+#if _FS_LOCK
+ if (res == FR_OK) res = chk_lock(&dj, 2); /* Cannot remove open file */
+#endif
+ if (res == FR_OK) { /* The object is accessible */
+ dir = dj.dir;
+ if (!dir) {
+ res = FR_INVALID_NAME; /* Cannot remove the start directory */
+ } else {
+ if (dir[DIR_Attr] & AM_RDO)
+ res = FR_DENIED; /* Cannot remove R/O object */
+ }
+ dclst = ld_clust(dj.fs, dir);
+ if (res == FR_OK && (dir[DIR_Attr] & AM_DIR)) { /* Is it a sub-dir? */
+ if (dclst < 2) {
+ res = FR_INT_ERR;
+ } else {
+ mem_cpy(&sdj, &dj, sizeof (FATFS_DIR)); /* Check if the sub-dir is empty or not */
+ sdj.sclust = dclst;
+ res = dir_sdi(&sdj, 2); /* Exclude dot entries */
+ if (res == FR_OK) {
+ res = dir_read(&sdj);
+ if (res == FR_OK /* Not empty dir */
+#if _FS_RPATH
+ || dclst == dj.fs->cdir /* Current dir */
+#endif
+ ) res = FR_DENIED;
+ if (res == FR_NO_FILE) res = FR_OK; /* Empty */
+ }
+ }
+ }
+ if (res == FR_OK) {
+ res = dir_remove(&dj); /* Remove the directory entry */
+ if (res == FR_OK) {
+ if (dclst) /* Remove the cluster chain if exist */
+ res = remove_chain(dj.fs, dclst);
+ if (res == FR_OK) res = sync(dj.fs);
+ }
+ }
+ }
+ FREE_BUF();
+ }
+ LEAVE_FF(dj.fs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Create a Directory */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_mkdir (
+ const TCHAR *path /* Pointer to the directory path */
+)
+{
+ FRESULT res;
+ FATFS_DIR dj;
+ BYTE *dir, n;
+ DWORD dsc, dcl, pcl, tim = get_fattime();
+ DEF_NAMEBUF;
+
+
+ res = chk_mounted(&path, &dj.fs, 1);
+ if (res == FR_OK) {
+ INIT_BUF(dj);
+ res = follow_path(&dj, path); /* Follow the file path */
+ if (res == FR_OK) res = FR_EXIST; /* Any object with same name is already existing */
+ if (_FS_RPATH && res == FR_NO_FILE && (dj.fn[NS] & NS_DOT))
+ res = FR_INVALID_NAME;
+ if (res == FR_NO_FILE) { /* Can create a new directory */
+ dcl = create_chain(dj.fs, 0); /* Allocate a cluster for the new directory table */
+ res = FR_OK;
+ if (dcl == 0) res = FR_DENIED; /* No space to allocate a new cluster */
+ if (dcl == 1) res = FR_INT_ERR;
+ if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR;
+ if (res == FR_OK) /* Flush FAT */
+ res = move_window(dj.fs, 0);
+ if (res == FR_OK) { /* Initialize the new directory table */
+ dsc = clust2sect(dj.fs, dcl);
+ dir = dj.fs->win;
+ mem_set(dir, 0, SS(dj.fs));
+ mem_set(dir+DIR_Name, ' ', 8+3); /* Create "." entry */
+ dir[DIR_Name] = '.';
+ dir[DIR_Attr] = AM_DIR;
+ ST_DWORD(dir+DIR_WrtTime, tim);
+ st_clust(dir, dcl);
+ mem_cpy(dir+SZ_DIR, dir, SZ_DIR); /* Create ".." entry */
+ dir[33] = '.'; pcl = dj.sclust;
+ if (dj.fs->fs_type == FS_FAT32 && pcl == dj.fs->dirbase)
+ pcl = 0;
+ st_clust(dir+SZ_DIR, pcl);
+ for (n = dj.fs->csize; n; n--) { /* Write dot entries and clear following sectors */
+ dj.fs->winsect = dsc++;
+ dj.fs->wflag = 1;
+ res = move_window(dj.fs, 0);
+ if (res != FR_OK) break;
+ mem_set(dir, 0, SS(dj.fs));
+ }
+ }
+ if (res == FR_OK) res = dir_register(&dj); /* Register the object to the directoy */
+ if (res != FR_OK) {
+ remove_chain(dj.fs, dcl); /* Could not register, remove cluster chain */
+ } else {
+ dir = dj.dir;
+ dir[DIR_Attr] = AM_DIR; /* Attribute */
+ ST_DWORD(dir+DIR_WrtTime, tim); /* Created time */
+ st_clust(dir, dcl); /* Table start cluster */
+ dj.fs->wflag = 1;
+ res = sync(dj.fs);
+ }
+ }
+ FREE_BUF();
+ }
+
+ LEAVE_FF(dj.fs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Change Attribute */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_chmod (
+ const TCHAR *path, /* Pointer to the file path */
+ BYTE value, /* Attribute bits */
+ BYTE mask /* Attribute mask to change */
+)
+{
+ FRESULT res;
+ FATFS_DIR dj;
+ BYTE *dir;
+ DEF_NAMEBUF;
+
+
+ res = chk_mounted(&path, &dj.fs, 1);
+ if (res == FR_OK) {
+ INIT_BUF(dj);
+ res = follow_path(&dj, path); /* Follow the file path */
+ FREE_BUF();
+ if (_FS_RPATH && res == FR_OK && (dj.fn[NS] & NS_DOT))
+ res = FR_INVALID_NAME;
+ if (res == FR_OK) {
+ dir = dj.dir;
+ if (!dir) { /* Is it a root directory? */
+ res = FR_INVALID_NAME;
+ } else { /* File or sub directory */
+ mask &= AM_RDO|AM_HID|AM_SYS|AM_ARC; /* Valid attribute mask */
+ dir[DIR_Attr] = (value & mask) | (dir[DIR_Attr] & (BYTE)~mask); /* Apply attribute change */
+ dj.fs->wflag = 1;
+ res = sync(dj.fs);
+ }
+ }
+ }
+
+ LEAVE_FF(dj.fs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Change Timestamp */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_utime (
+ const TCHAR *path, /* Pointer to the file/directory name */
+ const FILINFO *fno /* Pointer to the time stamp to be set */
+)
+{
+ FRESULT res;
+ FATFS_DIR dj;
+ BYTE *dir;
+ DEF_NAMEBUF;
+
+
+ res = chk_mounted(&path, &dj.fs, 1);
+ if (res == FR_OK) {
+ INIT_BUF(dj);
+ res = follow_path(&dj, path); /* Follow the file path */
+ FREE_BUF();
+ if (_FS_RPATH && res == FR_OK && (dj.fn[NS] & NS_DOT))
+ res = FR_INVALID_NAME;
+ if (res == FR_OK) {
+ dir = dj.dir;
+ if (!dir) { /* Root directory */
+ res = FR_INVALID_NAME;
+ } else { /* File or sub-directory */
+ ST_WORD(dir+DIR_WrtTime, fno->ftime);
+ ST_WORD(dir+DIR_WrtDate, fno->fdate);
+ dj.fs->wflag = 1;
+ res = sync(dj.fs);
+ }
+ }
+ }
+
+ LEAVE_FF(dj.fs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Rename File/Directory */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_rename (
+ const TCHAR *path_old, /* Pointer to the old name */
+ const TCHAR *path_new /* Pointer to the new name */
+)
+{
+ FRESULT res;
+ FATFS_DIR djo, djn;
+ BYTE buf[21], *dir;
+ DWORD dw;
+ DEF_NAMEBUF;
+
+
+ res = chk_mounted(&path_old, &djo.fs, 1);
+ if (res == FR_OK) {
+ djn.fs = djo.fs;
+ INIT_BUF(djo);
+ res = follow_path(&djo, path_old); /* Check old object */
+ if (_FS_RPATH && res == FR_OK && (djo.fn[NS] & NS_DOT))
+ res = FR_INVALID_NAME;
+#if _FS_LOCK
+ if (res == FR_OK) res = chk_lock(&djo, 2);
+#endif
+ if (res == FR_OK) { /* Old object is found */
+ if (!djo.dir) { /* Is root dir? */
+ res = FR_NO_FILE;
+ } else {
+ mem_cpy(buf, djo.dir+DIR_Attr, 21); /* Save the object information except for name */
+ mem_cpy(&djn, &djo, sizeof (FATFS_DIR)); /* Check new object */
+ res = follow_path(&djn, path_new);
+ if (res == FR_OK) res = FR_EXIST; /* The new object name is already existing */
+ if (res == FR_NO_FILE) { /* Is it a valid path and no name collision? */
+/* Start critical section that an interruption or error can cause cross-link */
+ res = dir_register(&djn); /* Register the new entry */
+ if (res == FR_OK) {
+ dir = djn.dir; /* Copy object information except for name */
+ mem_cpy(dir+13, buf+2, 19);
+ dir[DIR_Attr] = buf[0] | AM_ARC;
+ djo.fs->wflag = 1;
+ if (djo.sclust != djn.sclust && (dir[DIR_Attr] & AM_DIR)) { /* Update .. entry in the directory if needed */
+ dw = clust2sect(djo.fs, ld_clust(djo.fs, dir));
+ if (!dw) {
+ res = FR_INT_ERR;
+ } else {
+ res = move_window(djo.fs, dw);
+ dir = djo.fs->win+SZ_DIR; /* .. entry */
+ if (res == FR_OK && dir[1] == '.') {
+ dw = (djo.fs->fs_type == FS_FAT32 && djn.sclust == djo.fs->dirbase) ? 0 : djn.sclust;
+ st_clust(dir, dw);
+ djo.fs->wflag = 1;
+ }
+ }
+ }
+ if (res == FR_OK) {
+ res = dir_remove(&djo); /* Remove old entry */
+ if (res == FR_OK)
+ res = sync(djo.fs);
+ }
+ }
+/* End critical section */
+ }
+ }
+ }
+ FREE_BUF();
+ }
+ LEAVE_FF(djo.fs, res);
+}
+
+#endif /* !_FS_READONLY */
+#endif /* _FS_MINIMIZE == 0 */
+#endif /* _FS_MINIMIZE <= 1 */
+#endif /* _FS_MINIMIZE <= 2 */
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Forward data to the stream directly (available on only tiny cfg) */
+/*-----------------------------------------------------------------------*/
+#if _USE_FORWARD && _FS_TINY
+
+FRESULT f_forward (
+ FIL *fp, /* Pointer to the file object */
+ UINT (*func)(const BYTE*,UINT), /* Pointer to the streaming function */
+ UINT btr, /* Number of bytes to forward */
+ UINT *bf /* Pointer to number of bytes forwarded */
+)
+{
+ FRESULT res;
+ DWORD remain, clst, sect;
+ UINT rcnt;
+ BYTE csect;
+
+
+ *bf = 0; /* Clear transfer byte counter */
+
+ if (!fp) return FR_INVALID_OBJECT;
+
+ res = validate(fp); /* Check validity of the object */
+ if (res != FR_OK) LEAVE_FF(fp->fs, res);
+ if (fp->flag & FA__ERROR) /* Check error flag */
+ LEAVE_FF(fp->fs, FR_INT_ERR);
+ if (!(fp->flag & FA_READ)) /* Check access mode */
+ LEAVE_FF(fp->fs, FR_DENIED);
+
+ remain = fp->fsize - fp->fptr;
+ if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */
+
+ for ( ; btr && (*func)(0, 0); /* Repeat until all data transferred or stream becomes busy */
+ fp->fptr += rcnt, *bf += rcnt, btr -= rcnt) {
+ csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */
+ if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */
+ if (!csect) { /* On the cluster boundary? */
+ clst = (fp->fptr == 0) ? /* On the top of the file? */
+ fp->sclust : get_fat(fp->fs, fp->clust);
+ if (clst <= 1) ABORT(fp->fs, FR_INT_ERR);
+ if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
+ fp->clust = clst; /* Update current cluster */
+ }
+ }
+ sect = clust2sect(fp->fs, fp->clust); /* Get current data sector */
+ if (!sect) ABORT(fp->fs, FR_INT_ERR);
+ sect += csect;
+ if (move_window(fp->fs, sect)) /* Move sector window */
+ ABORT(fp->fs, FR_DISK_ERR);
+ fp->dsect = sect;
+ rcnt = SS(fp->fs) - (WORD)(fp->fptr % SS(fp->fs)); /* Forward data from sector window */
+ if (rcnt > btr) rcnt = btr;
+ rcnt = (*func)(&fp->fs->win[(WORD)fp->fptr % SS(fp->fs)], rcnt);
+ if (!rcnt) ABORT(fp->fs, FR_INT_ERR);
+ }
+
+ LEAVE_FF(fp->fs, FR_OK);
+}
+#endif /* _USE_FORWARD */
+
+
+
+#if _USE_MKFS && !_FS_READONLY
+/*-----------------------------------------------------------------------*/
+/* Create File System on the Drive */
+/*-----------------------------------------------------------------------*/
+#define N_ROOTDIR 512 /* Number of root dir entries for FAT12/16 */
+#define N_FATS 1 /* Number of FAT copies (1 or 2) */
+
+
+FRESULT f_mkfs (
+ BYTE drv, /* Logical drive number */
+ BYTE sfd, /* Partitioning rule 0:FDISK, 1:SFD */
+ UINT au /* Allocation unit size [bytes] */
+)
+{
+ static const WORD vst[] = { 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 0};
+ static const WORD cst[] = {32768, 16384, 8192, 4096, 2048, 16384, 8192, 4096, 2048, 1024, 512};
+ BYTE fmt, md, sys, *tbl, pdrv, part;
+ DWORD n_clst, vs, n, wsect;
+ UINT i;
+ DWORD b_vol, b_fat, b_dir, b_data; /* LBA */
+ DWORD n_vol, n_rsv, n_fat, n_dir; /* Size */
+ FATFS *fs;
+ DSTATUS stat;
+
+
+ /* Check mounted drive and clear work area */
+ if (drv >= _VOLUMES) return FR_INVALID_DRIVE;
+ if (sfd > 1) return FR_INVALID_PARAMETER;
+ if (au & (au - 1)) return FR_INVALID_PARAMETER;
+ fs = FatFs[drv];
+ if (!fs) return FR_NOT_ENABLED;
+ fs->fs_type = 0;
+ pdrv = LD2PD(drv); /* Physical drive */
+ part = LD2PT(drv); /* Partition (0:auto detect, 1-4:get from partition table)*/
+
+ /* Get disk statics */
+ stat = disk_initialize(pdrv);
+ if (stat & STA_NOINIT) return FR_NOT_READY;
+ if (stat & STA_PROTECT) return FR_WRITE_PROTECTED;
+#if _MAX_SS != 512 /* Get disk sector size */
+ if (disk_ioctl(pdrv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK || SS(fs) > _MAX_SS)
+ return FR_DISK_ERR;
+#endif
+ if (_MULTI_PARTITION && part) {
+ /* Get partition information from partition table in the MBR */
+ if (disk_read(pdrv, fs->win, 0, 1) != RES_OK) return FR_DISK_ERR;
+ if (LD_WORD(fs->win+BS_55AA) != 0xAA55) return FR_MKFS_ABORTED;
+ tbl = &fs->win[MBR_Table + (part - 1) * SZ_PTE];
+ if (!tbl[4]) return FR_MKFS_ABORTED; /* No partition? */
+ b_vol = LD_DWORD(tbl+8); /* Volume start sector */
+ n_vol = LD_DWORD(tbl+12); /* Volume size */
+ } else {
+ /* Create a partition in this function */
+ if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &n_vol) != RES_OK || n_vol < 128)
+ return FR_DISK_ERR;
+ b_vol = (sfd) ? 0 : 63; /* Volume start sector */
+ n_vol -= b_vol; /* Volume size */
+ }
+
+ if (!au) { /* AU auto selection */
+ vs = n_vol / (2000 / (SS(fs) / 512));
+ for (i = 0; vs < vst[i]; i++) ;
+ au = cst[i];
+ }
+ au /= SS(fs); /* Number of sectors per cluster */
+ if (au == 0) au = 1;
+ if (au > 128) au = 128;
+
+ /* Pre-compute number of clusters and FAT sub-type */
+ n_clst = n_vol / au;
+ fmt = FS_FAT12;
+ if (n_clst >= MIN_FAT16) fmt = FS_FAT16;
+ if (n_clst >= MIN_FAT32) fmt = FS_FAT32;
+
+ /* Determine offset and size of FAT structure */
+ if (fmt == FS_FAT32) {
+ n_fat = ((n_clst * 4) + 8 + SS(fs) - 1) / SS(fs);
+ n_rsv = 32;
+ n_dir = 0;
+ } else {
+ n_fat = (fmt == FS_FAT12) ? (n_clst * 3 + 1) / 2 + 3 : (n_clst * 2) + 4;
+ n_fat = (n_fat + SS(fs) - 1) / SS(fs);
+ n_rsv = 1;
+ n_dir = (DWORD)N_ROOTDIR * SZ_DIR / SS(fs);
+ }
+ b_fat = b_vol + n_rsv; /* FAT area start sector */
+ b_dir = b_fat + n_fat * N_FATS; /* Directory area start sector */
+ b_data = b_dir + n_dir; /* Data area start sector */
+ if (n_vol < b_data + au - b_vol) return FR_MKFS_ABORTED; /* Too small volume */
+
+ /* Align data start sector to erase block boundary (for flash memory media) */
+ if (disk_ioctl(pdrv, GET_BLOCK_SIZE, &n) != RES_OK || !n || n > 32768) n = 1;
+ n = (b_data + n - 1) & ~(n - 1); /* Next nearest erase block from current data start */
+ n = (n - b_data) / N_FATS;
+ if (fmt == FS_FAT32) { /* FAT32: Move FAT offset */
+ n_rsv += n;
+ b_fat += n;
+ } else { /* FAT12/16: Expand FAT size */
+ n_fat += n;
+ }
+
+ /* Determine number of clusters and final check of validity of the FAT sub-type */
+ n_clst = (n_vol - n_rsv - n_fat * N_FATS - n_dir) / au;
+ if ( (fmt == FS_FAT16 && n_clst < MIN_FAT16)
+ || (fmt == FS_FAT32 && n_clst < MIN_FAT32))
+ return FR_MKFS_ABORTED;
+
+ switch (fmt) { /* Determine system ID for partition table */
+ case FS_FAT12: sys = 0x01; break;
+ case FS_FAT16: sys = (n_vol < 0x10000) ? 0x04 : 0x06; break;
+ default: sys = 0x0C;
+ }
+
+ if (_MULTI_PARTITION && part) {
+ /* Update system ID in the partition table */
+ tbl = &fs->win[MBR_Table + (part - 1) * SZ_PTE];
+ tbl[4] = sys;
+ if (disk_write(pdrv, fs->win, 0, 1) != RES_OK) return FR_DISK_ERR;
+ md = 0xF8;
+ } else {
+ if (sfd) { /* No partition table (SFD) */
+ md = 0xF0;
+ } else { /* Create partition table (FDISK) */
+ mem_set(fs->win, 0, SS(fs));
+ tbl = fs->win+MBR_Table; /* Create partition table for single partition in the drive */
+ tbl[1] = 1; /* Partition start head */
+ tbl[2] = 1; /* Partition start sector */
+ tbl[3] = 0; /* Partition start cylinder */
+ tbl[4] = sys; /* System type */
+ tbl[5] = 254; /* Partition end head */
+ n = (b_vol + n_vol) / 63 / 255;
+ tbl[6] = (BYTE)((n >> 2) | 63); /* Partition end sector */
+ tbl[7] = (BYTE)n; /* End cylinder */
+ ST_DWORD(tbl+8, 63); /* Partition start in LBA */
+ ST_DWORD(tbl+12, n_vol); /* Partition size in LBA */
+ ST_WORD(fs->win+BS_55AA, 0xAA55); /* MBR signature */
+ if (disk_write(pdrv, fs->win, 0, 1) != RES_OK) /* Write it to the MBR sector */
+ return FR_DISK_ERR;
+ md = 0xF8;
+ }
+ }
+
+ /* Create BPB in the VBR */
+ tbl = fs->win; /* Clear sector */
+ mem_set(tbl, 0, SS(fs));
+ mem_cpy(tbl, "\xEB\xFE\x90" "MSDOS5.0", 11);/* Boot jump code, OEM name */
+ i = SS(fs); /* Sector size */
+ ST_WORD(tbl+BPB_BytsPerSec, i);
+ tbl[BPB_SecPerClus] = (BYTE)au; /* Sectors per cluster */
+ ST_WORD(tbl+BPB_RsvdSecCnt, n_rsv); /* Reserved sectors */
+ tbl[BPB_NumFATs] = N_FATS; /* Number of FATs */
+ i = (fmt == FS_FAT32) ? 0 : N_ROOTDIR; /* Number of rootdir entries */
+ ST_WORD(tbl+BPB_RootEntCnt, i);
+ if (n_vol < 0x10000) { /* Number of total sectors */
+ ST_WORD(tbl+BPB_TotSec16, n_vol);
+ } else {
+ ST_DWORD(tbl+BPB_TotSec32, n_vol);
+ }
+ tbl[BPB_Media] = md; /* Media descriptor */
+ ST_WORD(tbl+BPB_SecPerTrk, 63); /* Number of sectors per track */
+ ST_WORD(tbl+BPB_NumHeads, 255); /* Number of heads */
+ ST_DWORD(tbl+BPB_HiddSec, b_vol); /* Hidden sectors */
+ n = get_fattime(); /* Use current time as VSN */
+ if (fmt == FS_FAT32) {
+ ST_DWORD(tbl+BS_VolID32, n); /* VSN */
+ ST_DWORD(tbl+BPB_FATSz32, n_fat); /* Number of sectors per FAT */
+ ST_DWORD(tbl+BPB_RootClus, 2); /* Root directory start cluster (2) */
+ ST_WORD(tbl+BPB_FSInfo, 1); /* FSInfo record offset (VBR+1) */
+ ST_WORD(tbl+BPB_BkBootSec, 6); /* Backup boot record offset (VBR+6) */
+ tbl[BS_DrvNum32] = 0x80; /* Drive number */
+ tbl[BS_BootSig32] = 0x29; /* Extended boot signature */
+ mem_cpy(tbl+BS_VolLab32, "NO NAME " "FAT32 ", 19); /* Volume label, FAT signature */
+ } else {
+ ST_DWORD(tbl+BS_VolID, n); /* VSN */
+ ST_WORD(tbl+BPB_FATSz16, n_fat); /* Number of sectors per FAT */
+ tbl[BS_DrvNum] = 0x80; /* Drive number */
+ tbl[BS_BootSig] = 0x29; /* Extended boot signature */
+ mem_cpy(tbl+BS_VolLab, "NO NAME " "FAT ", 19); /* Volume label, FAT signature */
+ }
+ ST_WORD(tbl+BS_55AA, 0xAA55); /* Signature (Offset is fixed here regardless of sector size) */
+ if (disk_write(pdrv, tbl, b_vol, 1) != RES_OK) /* Write it to the VBR sector */
+ return FR_DISK_ERR;
+ if (fmt == FS_FAT32) /* Write backup VBR if needed (VBR+6) */
+ disk_write(pdrv, tbl, b_vol + 6, 1);
+
+ /* Initialize FAT area */
+ wsect = b_fat;
+ for (i = 0; i < N_FATS; i++) { /* Initialize each FAT copy */
+ mem_set(tbl, 0, SS(fs)); /* 1st sector of the FAT */
+ n = md; /* Media descriptor byte */
+ if (fmt != FS_FAT32) {
+ n |= (fmt == FS_FAT12) ? 0x00FFFF00 : 0xFFFFFF00;
+ ST_DWORD(tbl+0, n); /* Reserve cluster #0-1 (FAT12/16) */
+ } else {
+ n |= 0xFFFFFF00;
+ ST_DWORD(tbl+0, n); /* Reserve cluster #0-1 (FAT32) */
+ ST_DWORD(tbl+4, 0xFFFFFFFF);
+ ST_DWORD(tbl+8, 0x0FFFFFFF); /* Reserve cluster #2 for root dir */
+ }
+ if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK)
+ return FR_DISK_ERR;
+ mem_set(tbl, 0, SS(fs)); /* Fill following FAT entries with zero */
+ for (n = 1; n < n_fat; n++) { /* This loop may take a time on FAT32 volume due to many single sector writes */
+ if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK)
+ return FR_DISK_ERR;
+ }
+ }
+
+ /* Initialize root directory */
+ i = (fmt == FS_FAT32) ? au : n_dir;
+ do {
+ if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK)
+ return FR_DISK_ERR;
+ } while (--i);
+
+#if _USE_ERASE /* Erase data area if needed */
+ {
+ DWORD eb[2];
+
+ eb[0] = wsect; eb[1] = wsect + (n_clst - ((fmt == FS_FAT32) ? 1 : 0)) * au - 1;
+ disk_ioctl(pdrv, CTRL_ERASE_SECTOR, eb);
+ }
+#endif
+
+ /* Create FSInfo if needed */
+ if (fmt == FS_FAT32) {
+ ST_DWORD(tbl+FSI_LeadSig, 0x41615252);
+ ST_DWORD(tbl+FSI_StrucSig, 0x61417272);
+ ST_DWORD(tbl+FSI_Free_Count, n_clst - 1); /* Number of free clusters */
+ ST_DWORD(tbl+FSI_Nxt_Free, 2); /* Last allocated cluster# */
+ ST_WORD(tbl+BS_55AA, 0xAA55);
+ disk_write(pdrv, tbl, b_vol + 1, 1); /* Write original (VBR+1) */
+ disk_write(pdrv, tbl, b_vol + 7, 1); /* Write backup (VBR+7) */
+ }
+
+ return (disk_ioctl(pdrv, CTRL_SYNC, 0) == RES_OK) ? FR_OK : FR_DISK_ERR;
+}
+
+
+#if _MULTI_PARTITION == 2
+/*-----------------------------------------------------------------------*/
+/* Divide Physical Drive */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_fdisk (
+ BYTE pdrv, /* Physical drive number */
+ const DWORD szt[], /* Pointer to the size table for each partitions */
+ void* work /* Pointer to the working buffer */
+)
+{
+ UINT i, n, sz_cyl, tot_cyl, b_cyl, e_cyl, p_cyl;
+ BYTE s_hd, e_hd, *p, *buf = (BYTE*)work;
+ DSTATUS stat;
+ DWORD sz_disk, sz_part, s_part;
+
+
+ stat = disk_initialize(pdrv);
+ if (stat & STA_NOINIT) return FR_NOT_READY;
+ if (stat & STA_PROTECT) return FR_WRITE_PROTECTED;
+ if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_disk)) return FR_DISK_ERR;
+
+ /* Determine CHS in the table regardless of the drive geometry */
+ for (n = 16; n < 256 && sz_disk / n / 63 > 1024; n *= 2) ;
+ if (n == 256) n--;
+ e_hd = n - 1;
+ sz_cyl = 63 * n;
+ tot_cyl = sz_disk / sz_cyl;
+
+ /* Create partition table */
+ mem_set(buf, 0, _MAX_SS);
+ p = buf + MBR_Table; b_cyl = 0;
+ for (i = 0; i < 4; i++, p += SZ_PTE) {
+ p_cyl = (szt[i] <= 100) ? (DWORD)tot_cyl * szt[i] / 100 : szt[i] / sz_cyl;
+ if (!p_cyl) continue;
+ s_part = (DWORD)sz_cyl * b_cyl;
+ sz_part = (DWORD)sz_cyl * p_cyl;
+ if (i == 0) { /* Exclude first track of cylinder 0 */
+ s_hd = 1;
+ s_part += 63; sz_part -= 63;
+ } else {
+ s_hd = 0;
+ }
+ e_cyl = b_cyl + p_cyl - 1;
+ if (e_cyl >= tot_cyl) return FR_INVALID_PARAMETER;
+
+ /* Set partition table */
+ p[1] = s_hd; /* Start head */
+ p[2] = (BYTE)((b_cyl >> 2) + 1); /* Start sector */
+ p[3] = (BYTE)b_cyl; /* Start cylinder */
+ p[4] = 0x06; /* System type (temporary setting) */
+ p[5] = e_hd; /* End head */
+ p[6] = (BYTE)((e_cyl >> 2) + 63); /* End sector */
+ p[7] = (BYTE)e_cyl; /* End cylinder */
+ ST_DWORD(p + 8, s_part); /* Start sector in LBA */
+ ST_DWORD(p + 12, sz_part); /* Partition size */
+
+ /* Next partition */
+ b_cyl += p_cyl;
+ }
+ ST_WORD(p, 0xAA55);
+
+ /* Write it to the MBR */
+ return (disk_write(pdrv, buf, 0, 1) || disk_ioctl(pdrv, CTRL_SYNC, 0)) ? FR_DISK_ERR : FR_OK;
+}
+
+
+#endif /* _MULTI_PARTITION == 2 */
+#endif /* _USE_MKFS && !_FS_READONLY */
+
+
+
+
+#if _USE_STRFUNC
+/*-----------------------------------------------------------------------*/
+/* Get a string from the file */
+/*-----------------------------------------------------------------------*/
+TCHAR* f_gets (
+ TCHAR* buff, /* Pointer to the string buffer to read */
+ int len, /* Size of string buffer (characters) */
+ FIL* fil /* Pointer to the file object */
+)
+{
+ int n = 0;
+ TCHAR c, *p = buff;
+ BYTE s[2];
+ UINT rc;
+
+
+ while (n < len - 1) { /* Read bytes until buffer gets filled */
+ f_read(fil, s, 1, &rc);
+ if (rc != 1) break; /* Break on EOF or error */
+ c = s[0];
+#if _LFN_UNICODE /* Read a character in UTF-8 encoding */
+ if (c >= 0x80) {
+ if (c < 0xC0) continue; /* Skip stray trailer */
+ if (c < 0xE0) { /* Two-byte sequence */
+ f_read(fil, s, 1, &rc);
+ if (rc != 1) break;
+ c = ((c & 0x1F) << 6) | (s[0] & 0x3F);
+ if (c < 0x80) c = '?';
+ } else {
+ if (c < 0xF0) { /* Three-byte sequence */
+ f_read(fil, s, 2, &rc);
+ if (rc != 2) break;
+ c = (c << 12) | ((s[0] & 0x3F) << 6) | (s[1] & 0x3F);
+ if (c < 0x800) c = '?';
+ } else { /* Reject four-byte sequence */
+ c = '?';
+ }
+ }
+ }
+#endif
+#if _USE_STRFUNC >= 2
+ if (c == '\r') continue; /* Strip '\r' */
+#endif
+ *p++ = c;
+ n++;
+ if (c == '\n') break; /* Break on EOL */
+ }
+ *p = 0;
+ return n ? buff : 0; /* When no data read (eof or error), return with error. */
+}
+
+
+
+#if !_FS_READONLY
+#include <stdarg.h>
+/*-----------------------------------------------------------------------*/
+/* Put a character to the file */
+/*-----------------------------------------------------------------------*/
+int f_putc (
+ TCHAR c, /* A character to be output */
+ FIL* fil /* Pointer to the file object */
+)
+{
+ UINT bw, btw;
+ BYTE s[3];
+
+
+#if _USE_STRFUNC >= 2
+ if (c == '\n') f_putc ('\r', fil); /* LF -> CRLF conversion */
+#endif
+
+#if _LFN_UNICODE /* Write the character in UTF-8 encoding */
+ if (c < 0x80) { /* 7-bit */
+ s[0] = (BYTE)c;
+ btw = 1;
+ } else {
+ if (c < 0x800) { /* 11-bit */
+ s[0] = (BYTE)(0xC0 | (c >> 6));
+ s[1] = (BYTE)(0x80 | (c & 0x3F));
+ btw = 2;
+ } else { /* 16-bit */
+ s[0] = (BYTE)(0xE0 | (c >> 12));
+ s[1] = (BYTE)(0x80 | ((c >> 6) & 0x3F));
+ s[2] = (BYTE)(0x80 | (c & 0x3F));
+ btw = 3;
+ }
+ }
+#else /* Write the character without conversion */
+ s[0] = (BYTE)c;
+ btw = 1;
+#endif
+ f_write(fil, s, btw, &bw); /* Write the char to the file */
+ return (bw == btw) ? 1 : EOF; /* Return the result */
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Put a string to the file */
+/*-----------------------------------------------------------------------*/
+int f_puts (
+ const TCHAR* str, /* Pointer to the string to be output */
+ FIL* fil /* Pointer to the file object */
+)
+{
+ int n;
+
+
+ for (n = 0; *str; str++, n++) {
+ if (f_putc(*str, fil) == EOF) return EOF;
+ }
+ return n;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Put a formatted string to the file */
+/*-----------------------------------------------------------------------*/
+int f_printf (
+ FIL* fil, /* Pointer to the file object */
+ const TCHAR* str, /* Pointer to the format string */
+ ... /* Optional arguments... */
+)
+{
+ va_list arp;
+ BYTE f, r;
+ UINT i, j, w;
+ ULONG v;
+ TCHAR c, d, s[16], *p;
+ int res, chc, cc;
+
+
+ va_start(arp, str);
+
+ for (cc = res = 0; cc != EOF; res += cc) {
+ c = *str++;
+ if (c == 0) break; /* End of string */
+ if (c != '%') { /* Non escape character */
+ cc = f_putc(c, fil);
+ if (cc != EOF) cc = 1;
+ continue;
+ }
+ w = f = 0;
+ c = *str++;
+ if (c == '0') { /* Flag: '0' padding */
+ f = 1; c = *str++;
+ } else {
+ if (c == '-') { /* Flag: left justified */
+ f = 2; c = *str++;
+ }
+ }
+ while (IsDigit(c)) { /* Precision */
+ w = w * 10 + c - '0';
+ c = *str++;
+ }
+ if (c == 'l' || c == 'L') { /* Prefix: Size is long int */
+ f |= 4; c = *str++;
+ }
+ if (!c) break;
+ d = c;
+ if (IsLower(d)) d -= 0x20;
+ switch (d) { /* Type is... */
+ case 'S' : /* String */
+ p = va_arg(arp, TCHAR*);
+ for (j = 0; p[j]; j++) ;
+ chc = 0;
+ if (!(f & 2)) {
+ while (j++ < w) chc += (cc = f_putc(' ', fil));
+ }
+ chc += (cc = f_puts(p, fil));
+ while (j++ < w) chc += (cc = f_putc(' ', fil));
+ if (cc != EOF) cc = chc;
+ continue;
+ case 'C' : /* Character */
+ cc = f_putc((TCHAR)va_arg(arp, int), fil); continue;
+ case 'B' : /* Binary */
+ r = 2; break;
+ case 'O' : /* Octal */
+ r = 8; break;
+ case 'D' : /* Signed decimal */
+ case 'U' : /* Unsigned decimal */
+ r = 10; break;
+ case 'X' : /* Hexdecimal */
+ r = 16; break;
+ default: /* Unknown type (pass-through) */
+ cc = f_putc(c, fil); continue;
+ }
+
+ /* Get an argument and put it in numeral */
+ v = (f & 4) ? (ULONG)va_arg(arp, long) : ((d == 'D') ? (ULONG)(long)va_arg(arp, int) : (ULONG)va_arg(arp, unsigned int));
+ if (d == 'D' && (v & 0x80000000)) {
+ v = 0 - v;
+ f |= 8;
+ }
+ i = 0;
+ do {
+ d = (TCHAR)(v % r); v /= r;
+ if (d > 9) d += (c == 'x') ? 0x27 : 0x07;
+ s[i++] = d + '0';
+ } while (v && i < sizeof s / sizeof s[0]);
+ if (f & 8) s[i++] = '-';
+ j = i; d = (f & 1) ? '0' : ' ';
+ res = 0;
+ while (!(f & 2) && j++ < w) res += (cc = f_putc(d, fil));
+ do res += (cc = f_putc(s[--i], fil)); while(i);
+ while (j++ < w) res += (cc = f_putc(' ', fil));
+ if (cc != EOF) cc = res;
+ }
+
+ va_end(arp);
+ return (cc == EOF) ? cc : res;
+}
+
+#endif /* !_FS_READONLY */
+#endif /* _USE_STRFUNC */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/FATFileSystem/ChaN/ff.h Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,337 @@
+/*---------------------------------------------------------------------------/
+/ FatFs - FAT file system module include file R0.09a (C)ChaN, 2012
+/----------------------------------------------------------------------------/
+/ FatFs module is a generic FAT file system module for small embedded systems.
+/ This is a free software that opened for education, research and commercial
+/ developments under license policy of following terms.
+/
+/ Copyright (C) 2012, ChaN, all right reserved.
+/
+/ * The FatFs module is a free software and there is NO WARRANTY.
+/ * No restriction on use. You can use, modify and redistribute it for
+/ personal, non-profit or commercial product UNDER YOUR RESPONSIBILITY.
+/ * Redistributions of source code must retain the above copyright notice.
+/
+/----------------------------------------------------------------------------*/
+
+#ifndef _FATFS
+#define _FATFS 4004 /* Revision ID */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "integer.h" /* Basic integer types */
+#include "ffconf.h" /* FatFs configuration options */
+
+#if _FATFS != _FFCONF
+#error Wrong configuration file (ffconf.h).
+#endif
+
+
+
+/* Definitions of volume management */
+
+#if _MULTI_PARTITION /* Multiple partition configuration */
+typedef struct {
+ BYTE pd; /* Physical drive number */
+ BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */
+} PARTITION;
+extern PARTITION VolToPart[]; /* Volume - Partition resolution table */
+#define LD2PD(vol) (VolToPart[vol].pd) /* Get physical drive number */
+#define LD2PT(vol) (VolToPart[vol].pt) /* Get partition index */
+
+#else /* Single partition configuration */
+#define LD2PD(vol) (BYTE)(vol) /* Each logical drive is bound to the same physical drive number */
+#define LD2PT(vol) 0 /* Always mounts the 1st partition or in SFD */
+
+#endif
+
+
+
+/* Type of path name strings on FatFs API */
+
+#if _LFN_UNICODE /* Unicode string */
+#if !_USE_LFN
+#error _LFN_UNICODE must be 0 in non-LFN cfg.
+#endif
+#ifndef _INC_TCHAR
+typedef WCHAR TCHAR;
+#define _T(x) L ## x
+#define _TEXT(x) L ## x
+#endif
+
+#else /* ANSI/OEM string */
+#ifndef _INC_TCHAR
+typedef char TCHAR;
+#define _T(x) x
+#define _TEXT(x) x
+#endif
+
+#endif
+
+
+
+/* File system object structure (FATFS) */
+
+typedef struct {
+ BYTE fs_type; /* FAT sub-type (0:Not mounted) */
+ BYTE drv; /* Physical drive number */
+ BYTE csize; /* Sectors per cluster (1,2,4...128) */
+ BYTE n_fats; /* Number of FAT copies (1,2) */
+ BYTE wflag; /* win[] dirty flag (1:must be written back) */
+ BYTE fsi_flag; /* fsinfo dirty flag (1:must be written back) */
+ WORD id; /* File system mount ID */
+ WORD n_rootdir; /* Number of root directory entries (FAT12/16) */
+#if _MAX_SS != 512
+ WORD ssize; /* Bytes per sector (512, 1024, 2048 or 4096) */
+#endif
+#if _FS_REENTRANT
+ _SYNC_t sobj; /* Identifier of sync object */
+#endif
+#if !_FS_READONLY
+ DWORD last_clust; /* Last allocated cluster */
+ DWORD free_clust; /* Number of free clusters */
+ DWORD fsi_sector; /* fsinfo sector (FAT32) */
+#endif
+#if _FS_RPATH
+ DWORD cdir; /* Current directory start cluster (0:root) */
+#endif
+ DWORD n_fatent; /* Number of FAT entries (= number of clusters + 2) */
+ DWORD fsize; /* Sectors per FAT */
+ DWORD fatbase; /* FAT start sector */
+ DWORD dirbase; /* Root directory start sector (FAT32:Cluster#) */
+ DWORD database; /* Data start sector */
+ DWORD winsect; /* Current sector appearing in the win[] */
+ BYTE win[_MAX_SS]; /* Disk access window for Directory, FAT (and Data on tiny cfg) */
+} FATFS;
+
+
+
+/* File object structure (FIL) */
+
+typedef struct {
+ FATFS* fs; /* Pointer to the related file system object */
+ WORD id; /* File system mount ID of the related file system object */
+ BYTE flag; /* File status flags */
+ BYTE pad1;
+ DWORD fptr; /* File read/write pointer (0ed on file open) */
+ DWORD fsize; /* File size */
+ DWORD sclust; /* File data start cluster (0:no data cluster, always 0 when fsize is 0) */
+ DWORD clust; /* Current cluster of fpter */
+ DWORD dsect; /* Current data sector of fpter */
+#if !_FS_READONLY
+ DWORD dir_sect; /* Sector containing the directory entry */
+ BYTE* dir_ptr; /* Pointer to the directory entry in the window */
+#endif
+#if _USE_FASTSEEK
+ DWORD* cltbl; /* Pointer to the cluster link map table (null on file open) */
+#endif
+#if _FS_LOCK
+ UINT lockid; /* File lock ID (index of file semaphore table Files[]) */
+#endif
+#if !_FS_TINY
+ BYTE buf[_MAX_SS]; /* File data read/write buffer */
+#endif
+} FIL;
+
+
+
+/* Directory object structure (DIR) */
+
+typedef struct {
+ FATFS* fs; /* Pointer to the owner file system object */
+ WORD id; /* Owner file system mount ID */
+ WORD index; /* Current read/write index number */
+ DWORD sclust; /* Table start cluster (0:Root dir) */
+ DWORD clust; /* Current cluster */
+ DWORD sect; /* Current sector */
+ BYTE* dir; /* Pointer to the current SFN entry in the win[] */
+ BYTE* fn; /* Pointer to the SFN (in/out) {file[8],ext[3],status[1]} */
+#if _USE_LFN
+ WCHAR* lfn; /* Pointer to the LFN working buffer */
+ WORD lfn_idx; /* Last matched LFN index number (0xFFFF:No LFN) */
+#endif
+} FATFS_DIR;
+
+
+
+/* File status structure (FILINFO) */
+
+typedef struct {
+ DWORD fsize; /* File size */
+ WORD fdate; /* Last modified date */
+ WORD ftime; /* Last modified time */
+ BYTE fattrib; /* Attribute */
+ TCHAR fname[13]; /* Short file name (8.3 format) */
+#if _USE_LFN
+ TCHAR* lfname; /* Pointer to the LFN buffer */
+ UINT lfsize; /* Size of LFN buffer in TCHAR */
+#endif
+} FILINFO;
+
+
+
+/* File function return code (FRESULT) */
+
+typedef enum {
+ FR_OK = 0, /* (0) Succeeded */
+ FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */
+ FR_INT_ERR, /* (2) Assertion failed */
+ FR_NOT_READY, /* (3) The physical drive cannot work */
+ FR_NO_FILE, /* (4) Could not find the file */
+ FR_NO_PATH, /* (5) Could not find the path */
+ FR_INVALID_NAME, /* (6) The path name format is invalid */
+ FR_DENIED, /* (7) Access denied due to prohibited access or directory full */
+ FR_EXIST, /* (8) Access denied due to prohibited access */
+ FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */
+ FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */
+ FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */
+ FR_NOT_ENABLED, /* (12) The volume has no work area */
+ FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */
+ FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any parameter error */
+ FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */
+ FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
+ FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
+ FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > _FS_SHARE */
+ FR_INVALID_PARAMETER /* (19) Given parameter is invalid */
+} FRESULT;
+
+
+
+/*--------------------------------------------------------------*/
+/* FatFs module application interface */
+
+FRESULT f_mount (BYTE, FATFS*); /* Mount/Unmount a logical drive */
+FRESULT f_open (FIL*, const TCHAR*, BYTE); /* Open or create a file */
+FRESULT f_read (FIL*, void*, UINT, UINT*); /* Read data from a file */
+FRESULT f_lseek (FIL*, DWORD); /* Move file pointer of a file object */
+FRESULT f_close (FIL*); /* Close an open file object */
+FRESULT f_opendir (FATFS_DIR*, const TCHAR*); /* Open an existing directory */
+FRESULT f_readdir (FATFS_DIR*, FILINFO*); /* Read a directory item */
+FRESULT f_stat (const TCHAR*, FILINFO*); /* Get file status */
+FRESULT f_write (FIL*, const void*, UINT, UINT*); /* Write data to a file */
+FRESULT f_getfree (const TCHAR*, DWORD*, FATFS**); /* Get number of free clusters on the drive */
+FRESULT f_truncate (FIL*); /* Truncate file */
+FRESULT f_sync (FIL*); /* Flush cached data of a writing file */
+FRESULT f_unlink (const TCHAR*); /* Delete an existing file or directory */
+FRESULT f_mkdir (const TCHAR*); /* Create a new directory */
+FRESULT f_chmod (const TCHAR*, BYTE, BYTE); /* Change attribute of the file/dir */
+FRESULT f_utime (const TCHAR*, const FILINFO*); /* Change times-tamp of the file/dir */
+FRESULT f_rename (const TCHAR*, const TCHAR*); /* Rename/Move a file or directory */
+FRESULT f_chdrive (BYTE); /* Change current drive */
+FRESULT f_chdir (const TCHAR*); /* Change current directory */
+FRESULT f_getcwd (TCHAR*, UINT); /* Get current directory */
+FRESULT f_forward (FIL*, UINT(*)(const BYTE*,UINT), UINT, UINT*); /* Forward data to the stream */
+FRESULT f_mkfs (BYTE, BYTE, UINT); /* Create a file system on the drive */
+FRESULT f_fdisk (BYTE, const DWORD[], void*); /* Divide a physical drive into some partitions */
+int f_putc (TCHAR, FIL*); /* Put a character to the file */
+int f_puts (const TCHAR*, FIL*); /* Put a string to the file */
+int f_printf (FIL*, const TCHAR*, ...); /* Put a formatted string to the file */
+TCHAR* f_gets (TCHAR*, int, FIL*); /* Get a string from the file */
+
+#define f_eof(fp) (((fp)->fptr == (fp)->fsize) ? 1 : 0)
+#define f_error(fp) (((fp)->flag & FA__ERROR) ? 1 : 0)
+#define f_tell(fp) ((fp)->fptr)
+#define f_size(fp) ((fp)->fsize)
+
+#ifndef EOF
+#define EOF (-1)
+#endif
+
+
+
+
+/*--------------------------------------------------------------*/
+/* Additional user defined functions */
+
+/* RTC function */
+#if !_FS_READONLY
+DWORD get_fattime (void);
+#endif
+
+/* Unicode support functions */
+#if _USE_LFN /* Unicode - OEM code conversion */
+WCHAR ff_convert (WCHAR, UINT); /* OEM-Unicode bidirectional conversion */
+WCHAR ff_wtoupper (WCHAR); /* Unicode upper-case conversion */
+#if _USE_LFN == 3 /* Memory functions */
+void* ff_memalloc (UINT); /* Allocate memory block */
+void ff_memfree (void*); /* Free memory block */
+#endif
+#endif
+
+/* Sync functions */
+#if _FS_REENTRANT
+int ff_cre_syncobj (BYTE, _SYNC_t*);/* Create a sync object */
+int ff_req_grant (_SYNC_t); /* Lock sync object */
+void ff_rel_grant (_SYNC_t); /* Unlock sync object */
+int ff_del_syncobj (_SYNC_t); /* Delete a sync object */
+#endif
+
+
+
+
+/*--------------------------------------------------------------*/
+/* Flags and offset address */
+
+
+/* File access control and file status flags (FIL.flag) */
+
+#define FA_READ 0x01
+#define FA_OPEN_EXISTING 0x00
+#define FA__ERROR 0x80
+
+#if !_FS_READONLY
+#define FA_WRITE 0x02
+#define FA_CREATE_NEW 0x04
+#define FA_CREATE_ALWAYS 0x08
+#define FA_OPEN_ALWAYS 0x10
+#define FA__WRITTEN 0x20
+#define FA__DIRTY 0x40
+#endif
+
+
+/* FAT sub type (FATFS.fs_type) */
+
+#define FS_FAT12 1
+#define FS_FAT16 2
+#define FS_FAT32 3
+
+
+/* File attribute bits for directory entry */
+
+#define AM_RDO 0x01 /* Read only */
+#define AM_HID 0x02 /* Hidden */
+#define AM_SYS 0x04 /* System */
+#define AM_VOL 0x08 /* Volume label */
+#define AM_LFN 0x0F /* LFN entry */
+#define AM_DIR 0x10 /* Directory */
+#define AM_ARC 0x20 /* Archive */
+#define AM_MASK 0x3F /* Mask of defined bits */
+
+
+/* Fast seek feature */
+#define CREATE_LINKMAP 0xFFFFFFFF
+
+
+
+/*--------------------------------*/
+/* Multi-byte word access macros */
+
+#if _WORD_ACCESS == 1 /* Enable word access to the FAT structure */
+#define LD_WORD(ptr) (WORD)(*(WORD*)(BYTE*)(ptr))
+#define LD_DWORD(ptr) (DWORD)(*(DWORD*)(BYTE*)(ptr))
+#define ST_WORD(ptr,val) *(WORD*)(BYTE*)(ptr)=(WORD)(val)
+#define ST_DWORD(ptr,val) *(DWORD*)(BYTE*)(ptr)=(DWORD)(val)
+#else /* Use byte-by-byte access to the FAT structure */
+#define LD_WORD(ptr) (WORD)(((WORD)*((BYTE*)(ptr)+1)<<8)|(WORD)*(BYTE*)(ptr))
+#define LD_DWORD(ptr) (DWORD)(((DWORD)*((BYTE*)(ptr)+3)<<24)|((DWORD)*((BYTE*)(ptr)+2)<<16)|((WORD)*((BYTE*)(ptr)+1)<<8)|*(BYTE*)(ptr))
+#define ST_WORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8)
+#define ST_DWORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8); *((BYTE*)(ptr)+2)=(BYTE)((DWORD)(val)>>16); *((BYTE*)(ptr)+3)=(BYTE)((DWORD)(val)>>24)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _FATFS */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/FATFileSystem/ChaN/ffconf.h Wed Apr 15 06:23:18 2015 +0000 @@ -0,0 +1,198 @@ +/*---------------------------------------------------------------------------/ +/ FatFs - FAT file system module configuration file R0.09a (C)ChaN, 2012 +/----------------------------------------------------------------------------/ +/ +/ CAUTION! Do not forget to make clean the project after any changes to +/ the configuration options. +/ +/----------------------------------------------------------------------------*/ +#ifndef _FFCONF +#define _FFCONF 4004 /* Revision ID */ + +#define FFS_DBG 0 + +/*---------------------------------------------------------------------------/ +/ Functions and Buffer Configurations +/----------------------------------------------------------------------------*/ + +#define _FS_TINY 0 /* 0:Normal or 1:Tiny */ +/* When _FS_TINY is set to 1, FatFs uses the sector buffer in the file system +/ object instead of the sector buffer in the individual file object for file +/ data transfer. This reduces memory consumption 512 bytes each file object. */ + + +#define _FS_READONLY 0 /* 0:Read/Write or 1:Read only */ +/* Setting _FS_READONLY to 1 defines read only configuration. This removes +/ writing functions, f_write, f_sync, f_unlink, f_mkdir, f_chmod, f_rename, +/ f_truncate and useless f_getfree. */ + + +#define _FS_MINIMIZE 0 /* 0 to 3 */ +/* The _FS_MINIMIZE option defines minimization level to remove some functions. +/ +/ 0: Full function. +/ 1: f_stat, f_getfree, f_unlink, f_mkdir, f_chmod, f_truncate and f_rename +/ are removed. +/ 2: f_opendir and f_readdir are removed in addition to 1. +/ 3: f_lseek is removed in addition to 2. */ + + +#define _USE_STRFUNC 0 /* 0:Disable or 1-2:Enable */ +/* To enable string functions, set _USE_STRFUNC to 1 or 2. */ + + +#define _USE_MKFS 1 /* 0:Disable or 1:Enable */ +/* To enable f_mkfs function, set _USE_MKFS to 1 and set _FS_READONLY to 0 */ + + +#define _USE_FORWARD 0 /* 0:Disable or 1:Enable */ +/* To enable f_forward function, set _USE_FORWARD to 1 and set _FS_TINY to 1. */ + + +#define _USE_FASTSEEK 0 /* 0:Disable or 1:Enable */ +/* To enable fast seek feature, set _USE_FASTSEEK to 1. */ + + + +/*---------------------------------------------------------------------------/ +/ Locale and Namespace Configurations +/----------------------------------------------------------------------------*/ + +#define _CODE_PAGE 858 +/* The _CODE_PAGE specifies the OEM code page to be used on the target system. +/ Incorrect setting of the code page can cause a file open failure. +/ +/ 932 - Japanese Shift-JIS (DBCS, OEM, Windows) +/ 936 - Simplified Chinese GBK (DBCS, OEM, Windows) +/ 949 - Korean (DBCS, OEM, Windows) +/ 950 - Traditional Chinese Big5 (DBCS, OEM, Windows) +/ 1250 - Central Europe (Windows) +/ 1251 - Cyrillic (Windows) +/ 1252 - Latin 1 (Windows) +/ 1253 - Greek (Windows) +/ 1254 - Turkish (Windows) +/ 1255 - Hebrew (Windows) +/ 1256 - Arabic (Windows) +/ 1257 - Baltic (Windows) +/ 1258 - Vietnam (OEM, Windows) +/ 437 - U.S. (OEM) +/ 720 - Arabic (OEM) +/ 737 - Greek (OEM) +/ 775 - Baltic (OEM) +/ 850 - Multilingual Latin 1 (OEM) +/ 858 - Multilingual Latin 1 + Euro (OEM) +/ 852 - Latin 2 (OEM) +/ 855 - Cyrillic (OEM) +/ 866 - Russian (OEM) +/ 857 - Turkish (OEM) +/ 862 - Hebrew (OEM) +/ 874 - Thai (OEM, Windows) +/ 1 - ASCII only (Valid for non LFN cfg.) +*/ + + +#define _USE_LFN 1 /* 0 to 3 */ +#define _MAX_LFN 255 /* Maximum LFN length to handle (12 to 255) */ +/* The _USE_LFN option switches the LFN support. +/ +/ 0: Disable LFN feature. _MAX_LFN and _LFN_UNICODE have no effect. +/ 1: Enable LFN with static working buffer on the BSS. Always NOT reentrant. +/ 2: Enable LFN with dynamic working buffer on the STACK. +/ 3: Enable LFN with dynamic working buffer on the HEAP. +/ +/ The LFN working buffer occupies (_MAX_LFN + 1) * 2 bytes. To enable LFN, +/ Unicode handling functions ff_convert() and ff_wtoupper() must be added +/ to the project. When enable to use heap, memory control functions +/ ff_memalloc() and ff_memfree() must be added to the project. */ + + +#define _LFN_UNICODE 0 /* 0:ANSI/OEM or 1:Unicode */ +/* To switch the character code set on FatFs API to Unicode, +/ enable LFN feature and set _LFN_UNICODE to 1. */ + + +#define _FS_RPATH 0 /* 0 to 2 */ +/* The _FS_RPATH option configures relative path feature. +/ +/ 0: Disable relative path feature and remove related functions. +/ 1: Enable relative path. f_chdrive() and f_chdir() are available. +/ 2: f_getcwd() is available in addition to 1. +/ +/ Note that output of the f_readdir fnction is affected by this option. */ + + + +/*---------------------------------------------------------------------------/ +/ Physical Drive Configurations +/----------------------------------------------------------------------------*/ + +#define _VOLUMES 1 +/* Number of volumes (logical drives) to be used. */ + + +#define _MAX_SS 512 /* 512, 1024, 2048 or 4096 */ +/* Maximum sector size to be handled. +/ Always set 512 for memory card and hard disk but a larger value may be +/ required for on-board flash memory, floppy disk and optical disk. +/ When _MAX_SS is larger than 512, it configures FatFs to variable sector size +/ and GET_SECTOR_SIZE command must be implememted to the disk_ioctl function. */ + + +#define _MULTI_PARTITION 0 /* 0:Single partition, 1/2:Enable multiple partition */ +/* When set to 0, each volume is bound to the same physical drive number and +/ it can mount only first primaly partition. When it is set to 1, each volume +/ is tied to the partitions listed in VolToPart[]. */ + + +#define _USE_ERASE 0 /* 0:Disable or 1:Enable */ +/* To enable sector erase feature, set _USE_ERASE to 1. CTRL_ERASE_SECTOR command +/ should be added to the disk_ioctl functio. */ + + + +/*---------------------------------------------------------------------------/ +/ System Configurations +/----------------------------------------------------------------------------*/ + +#define _WORD_ACCESS 0 /* 0 or 1 */ +/* Set 0 first and it is always compatible with all platforms. The _WORD_ACCESS +/ option defines which access method is used to the word data on the FAT volume. +/ +/ 0: Byte-by-byte access. +/ 1: Word access. Do not choose this unless following condition is met. +/ +/ When the byte order on the memory is big-endian or address miss-aligned word +/ access results incorrect behavior, the _WORD_ACCESS must be set to 0. +/ If it is not the case, the value can also be set to 1 to improve the +/ performance and code size. +*/ + + +/* A header file that defines sync object types on the O/S, such as +/ windows.h, ucos_ii.h and semphr.h, must be included prior to ff.h. */ + +#define _FS_REENTRANT 0 /* 0:Disable or 1:Enable */ +#define _FS_TIMEOUT 1000 /* Timeout period in unit of time ticks */ +#define _SYNC_t HANDLE /* O/S dependent type of sync object. e.g. HANDLE, OS_EVENT*, ID and etc.. */ + +/* The _FS_REENTRANT option switches the reentrancy (thread safe) of the FatFs module. +/ +/ 0: Disable reentrancy. _SYNC_t and _FS_TIMEOUT have no effect. +/ 1: Enable reentrancy. Also user provided synchronization handlers, +/ ff_req_grant, ff_rel_grant, ff_del_syncobj and ff_cre_syncobj +/ function must be added to the project. */ + + +#define _FS_LOCK 0 /* 0:Disable or >=1:Enable */ +/* To enable file lock control feature, set _FS_LOCK to 1 or greater. + The value defines how many files can be opened simultaneously. */ + +#define FLUSH_ON_NEW_CLUSTER 0 /* Sync the file on every new cluster */ +#define FLUSH_ON_NEW_SECTOR 1 /* Sync the file on every new sector */ +/* Only one of these two defines needs to be set to 1. If both are set to 0 + the file is only sync when closed. + Clusters are group of sectors (eg: 8 sectors). Flushing on new cluster means + it would be less often than flushing on new sector. Sectors are generally + 512 Bytes long. */ + +#endif /* _FFCONFIG */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/FATFileSystem/ChaN/integer.h Wed Apr 15 06:23:18 2015 +0000 @@ -0,0 +1,37 @@ +/*-------------------------------------------*/ +/* Integer type definitions for FatFs module */ +/*-------------------------------------------*/ + +#ifndef _INTEGER +#define _INTEGER + +#ifdef _WIN32 /* FatFs development platform */ + +#include <windows.h> +#include <tchar.h> + +#else /* Embedded platform */ + +/* These types must be 16-bit, 32-bit or larger integer */ +typedef int INT; +typedef unsigned int UINT; + +/* These types must be 8-bit integer */ +typedef char CHAR; +typedef unsigned char UCHAR; +typedef unsigned char BYTE; + +/* These types must be 16-bit integer */ +typedef short SHORT; +typedef unsigned short USHORT; +typedef unsigned short WORD; +typedef unsigned short WCHAR; + +/* These types must be 32-bit integer */ +typedef long LONG; +typedef unsigned long ULONG; +typedef unsigned long DWORD; + +#endif + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/FATFileSystem/FATDirHandle.cpp Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,78 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2012 ARM Limited
+ *
+ * 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 <string.h>
+#include "ff.h"
+#include "FATDirHandle.h"
+
+using namespace mbed;
+
+FATDirHandle::FATDirHandle(const FATFS_DIR &the_dir) {
+ dir = the_dir;
+}
+
+int FATDirHandle::closedir() {
+ delete this;
+ return 0;
+}
+
+struct dirent *FATDirHandle::readdir() {
+ FILINFO finfo;
+
+#if _USE_LFN
+ finfo.lfname = cur_entry.d_name;
+ finfo.lfsize = sizeof(cur_entry.d_name);
+#endif // _USE_LFN
+
+ FRESULT res = f_readdir(&dir, &finfo);
+
+#if _USE_LFN
+ if(res != 0 || finfo.fname[0]==0) {
+ return NULL;
+ } else {
+ if(cur_entry.d_name[0]==0) {
+ // No long filename so use short filename.
+ memcpy(cur_entry.d_name, finfo.fname, sizeof(finfo.fname));
+ }
+ return &cur_entry;
+ }
+#else
+ if(res != 0 || finfo.fname[0]==0) {
+ return NULL;
+ } else {
+ memcpy(cur_entry.d_name, finfo.fname, sizeof(finfo.fname));
+ return &cur_entry;
+ }
+#endif /* _USE_LFN */
+}
+
+void FATDirHandle::rewinddir() {
+ dir.index = 0;
+}
+
+off_t FATDirHandle::telldir() {
+ return dir.index;
+}
+
+void FATDirHandle::seekdir(off_t location) {
+ dir.index = location;
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/FATFileSystem/FATDirHandle.h Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,45 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2012 ARM Limited
+ *
+ * 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 MBED_FATDIRHANDLE_H
+#define MBED_FATDIRHANDLE_H
+
+#include "DirHandle.h"
+
+using namespace mbed;
+
+class FATDirHandle : public DirHandle {
+
+ public:
+ FATDirHandle(const FATFS_DIR &the_dir);
+ virtual int closedir();
+ virtual struct dirent *readdir();
+ virtual void rewinddir();
+ virtual off_t telldir();
+ virtual void seekdir(off_t location);
+
+ private:
+ FATFS_DIR dir;
+ struct dirent cur_entry;
+
+};
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/FATFileSystem/FATFileHandle.cpp Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,90 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2012 ARM Limited
+ *
+ * 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 "ff.h"
+#include "ffconf.h"
+#include "mbed_debug.h"
+
+#include "FATFileHandle.h"
+
+FATFileHandle::FATFileHandle(FIL fh) {
+ _fh = fh;
+}
+
+int FATFileHandle::close() {
+ int retval = f_close(&_fh);
+ delete this;
+ return retval;
+}
+
+ssize_t FATFileHandle::write(const void* buffer, size_t length) {
+ UINT n;
+ FRESULT res = f_write(&_fh, buffer, length, &n);
+ if (res) {
+ debug_if(FFS_DBG, "f_write() failed: %d", res);
+ return -1;
+ }
+ return n;
+}
+
+ssize_t FATFileHandle::read(void* buffer, size_t length) {
+ debug_if(FFS_DBG, "read(%d)\n", length);
+ UINT n;
+ FRESULT res = f_read(&_fh, buffer, length, &n);
+ if (res) {
+ debug_if(FFS_DBG, "f_read() failed: %d\n", res);
+ return -1;
+ }
+ return n;
+}
+
+int FATFileHandle::isatty() {
+ return 0;
+}
+
+off_t FATFileHandle::lseek(off_t position, int whence) {
+ if (whence == SEEK_END) {
+ position += _fh.fsize;
+ } else if(whence==SEEK_CUR) {
+ position += _fh.fptr;
+ }
+ FRESULT res = f_lseek(&_fh, position);
+ if (res) {
+ debug_if(FFS_DBG, "lseek failed: %d\n", res);
+ return -1;
+ } else {
+ debug_if(FFS_DBG, "lseek OK, returning %i\n", _fh.fptr);
+ return _fh.fptr;
+ }
+}
+
+int FATFileHandle::fsync() {
+ FRESULT res = f_sync(&_fh);
+ if (res) {
+ debug_if(FFS_DBG, "f_sync() failed: %d\n", res);
+ return -1;
+ }
+ return 0;
+}
+
+off_t FATFileHandle::flen() {
+ return _fh.fsize;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/FATFileSystem/FATFileHandle.h Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,47 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2012 ARM Limited
+ *
+ * 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 MBED_FATFILEHANDLE_H
+#define MBED_FATFILEHANDLE_H
+
+#include "FileHandle.h"
+
+using namespace mbed;
+
+class FATFileHandle : public FileHandle {
+public:
+
+ FATFileHandle(FIL fh);
+ virtual int close();
+ virtual ssize_t write(const void* buffer, size_t length);
+ virtual ssize_t read(void* buffer, size_t length);
+ virtual int isatty();
+ virtual off_t lseek(off_t position, int whence);
+ virtual int fsync();
+ virtual off_t flen();
+
+protected:
+
+ FIL _fh;
+
+};
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/FATFileSystem/FATFileSystem.cpp Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,153 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2012 ARM Limited
+ *
+ * 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 "ffconf.h"
+#include "mbed_debug.h"
+
+#include "FATFileSystem.h"
+#include "FATFileHandle.h"
+#include "FATDirHandle.h"
+
+DWORD get_fattime(void) {
+ time_t rawtime;
+ time(&rawtime);
+ struct tm *ptm = localtime(&rawtime);
+ return (DWORD)(ptm->tm_year - 80) << 25
+ | (DWORD)(ptm->tm_mon + 1 ) << 21
+ | (DWORD)(ptm->tm_mday ) << 16
+ | (DWORD)(ptm->tm_hour ) << 11
+ | (DWORD)(ptm->tm_min ) << 5
+ | (DWORD)(ptm->tm_sec/2 );
+}
+
+FATFileSystem *FATFileSystem::_ffs[_VOLUMES] = {0};
+
+FATFileSystem::FATFileSystem(const char* n) : FileSystemLike(n) {
+ debug_if(FFS_DBG, "FATFileSystem(%s)\n", n);
+ for(int i=0; i<_VOLUMES; i++) {
+ if(_ffs[i] == 0) {
+ _ffs[i] = this;
+ _fsid = i;
+ debug_if(FFS_DBG, "Mounting [%s] on ffs drive [%d]\n", _name, _fsid);
+ f_mount(i, &_fs);
+ return;
+ }
+ }
+ error("Couldn't create %s in FATFileSystem::FATFileSystem\n", n);
+}
+
+FATFileSystem::~FATFileSystem() {
+ for (int i=0; i<_VOLUMES; i++) {
+ if (_ffs[i] == this) {
+ _ffs[i] = 0;
+ f_mount(i, NULL);
+ }
+ }
+}
+
+FileHandle *FATFileSystem::open(const char* name, int flags) {
+ debug_if(FFS_DBG, "open(%s) on filesystem [%s], drv [%d]\n", name, _name, _fsid);
+ char n[64];
+ sprintf(n, "%d:/%s", _fsid, name);
+
+ /* POSIX flags -> FatFS open mode */
+ BYTE openmode;
+ if (flags & O_RDWR) {
+ openmode = FA_READ|FA_WRITE;
+ } else if(flags & O_WRONLY) {
+ openmode = FA_WRITE;
+ } else {
+ openmode = FA_READ;
+ }
+ if(flags & O_CREAT) {
+ if(flags & O_TRUNC) {
+ openmode |= FA_CREATE_ALWAYS;
+ } else {
+ openmode |= FA_OPEN_ALWAYS;
+ }
+ }
+
+ FIL fh;
+ FRESULT res = f_open(&fh, n, openmode);
+ if (res) {
+ debug_if(FFS_DBG, "f_open('w') failed: %d\n", res);
+ return NULL;
+ }
+ if (flags & O_APPEND) {
+ f_lseek(&fh, fh.fsize);
+ }
+ return new FATFileHandle(fh);
+}
+
+int FATFileSystem::remove(const char *filename) {
+ FRESULT res = f_unlink(filename);
+ if (res) {
+ debug_if(FFS_DBG, "f_unlink() failed: %d\n", res);
+ return -1;
+ }
+ return 0;
+}
+
+int FATFileSystem::rename(const char *oldname, const char *newname) {
+ FRESULT res = f_rename(oldname, newname);
+ if (res) {
+ debug_if(FFS_DBG, "f_rename() failed: %d\n", res);
+ return -1;
+ }
+ return 0;
+}
+
+int FATFileSystem::format() {
+ FRESULT res = f_mkfs(_fsid, 0, 512); // Logical drive number, Partitioning rule, Allocation unit size (bytes per cluster)
+ if (res) {
+ debug_if(FFS_DBG, "f_mkfs() failed: %d\n", res);
+ return -1;
+ }
+ return 0;
+}
+
+DirHandle *FATFileSystem::opendir(const char *name) {
+ FATFS_DIR dir;
+ FRESULT res = f_opendir(&dir, name);
+ if (res != 0) {
+ return NULL;
+ }
+ return new FATDirHandle(dir);
+}
+
+int FATFileSystem::mkdir(const char *name, mode_t mode) {
+ FRESULT res = f_mkdir(name);
+ return res == 0 ? 0 : -1;
+}
+
+int FATFileSystem::mount() {
+ FRESULT res = f_mount(_fsid, &_fs);
+ return res == 0 ? 0 : -1;
+}
+
+int FATFileSystem::unmount() {
+ if (disk_sync())
+ return -1;
+ FRESULT res = f_mount(_fsid, NULL);
+ return res == 0 ? 0 : -1;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/FATFileSystem/FATFileSystem.h Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,94 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2012 ARM Limited
+ *
+ * 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 MBED_FATFILESYSTEM_H
+#define MBED_FATFILESYSTEM_H
+
+#include "FileSystemLike.h"
+#include "FileHandle.h"
+#include "ff.h"
+#include <stdint.h>
+
+using namespace mbed;
+
+/**
+ * FATFileSystem based on ChaN's Fat Filesystem library v0.8
+ */
+class FATFileSystem : public FileSystemLike {
+public:
+
+ FATFileSystem(const char* n);
+ virtual ~FATFileSystem();
+
+ static FATFileSystem * _ffs[_VOLUMES]; // FATFileSystem objects, as parallel to FatFs drives array
+ FATFS _fs; // Work area (file system object) for logical drive
+ int _fsid;
+
+ /**
+ * Opens a file on the filesystem
+ */
+ virtual FileHandle *open(const char* name, int flags);
+
+ /**
+ * Removes a file path
+ */
+ virtual int remove(const char *filename);
+
+ /**
+ * Renames a file
+ */
+ virtual int rename(const char *oldname, const char *newname);
+
+ /**
+ * Formats a logical drive, FDISK artitioning rule, 512 bytes per cluster
+ */
+ virtual int format();
+
+ /**
+ * Opens a directory on the filesystem
+ */
+ virtual DirHandle *opendir(const char *name);
+
+ /**
+ * Creates a directory path
+ */
+ virtual int mkdir(const char *name, mode_t mode);
+
+ /**
+ * Mounts the filesystem
+ */
+ virtual int mount();
+
+ /**
+ * Unmounts the filesystem
+ */
+ virtual int unmount();
+
+ virtual int disk_initialize() { return 0; }
+ virtual int disk_status() { return 0; }
+ virtual int disk_read(uint8_t * buffer, uint64_t sector, uint8_t count) = 0;
+ virtual int disk_write(const uint8_t * buffer, uint64_t sector, uint8_t count) = 0;
+ virtual int disk_sync() { return 0; }
+ virtual uint64_t disk_sectors() = 0;
+
+};
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/FATFileSystem/MemFileSystem.h Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,77 @@
+/* mbed Microcontroller Library - MemFileSystem
+ * Copyright (c) 2008, sford
+ */
+
+
+#ifndef MBED_MEMFILESYSTEM_H
+#define MBED_MEMFILESYSTEM_H
+
+#include "FATFileSystem.h"
+
+namespace mbed
+{
+
+ class MemFileSystem : public FATFileSystem
+ {
+ public:
+
+ // 2000 sectors, each 512 bytes (malloced as required)
+ char *sectors[2000];
+
+ MemFileSystem(const char* name) : FATFileSystem(name) {
+ memset(sectors, 0, sizeof(sectors));
+ }
+
+ virtual ~MemFileSystem() {
+ for(int i = 0; i < 2000; i++) {
+ if(sectors[i]) {
+ free(sectors[i]);
+ }
+ }
+ }
+
+ // read a sector in to the buffer, return 0 if ok
+ virtual int disk_read(char *buffer, int sector) {
+ if(sectors[sector] == 0) {
+ // nothing allocated means sector is empty
+ memset(buffer, 0, 512);
+ } else {
+ memcpy(buffer, sectors[sector], 512);
+ }
+ return 0;
+ }
+
+ // write a sector from the buffer, return 0 if ok
+ virtual int disk_write(const char *buffer, int sector) {
+ // if buffer is zero deallocate sector
+ char zero[512];
+ memset(zero, 0, 512);
+ if(memcmp(zero, buffer, 512)==0) {
+ if(sectors[sector] != 0) {
+ free(sectors[sector]);
+ sectors[sector] = 0;
+ }
+ return 0;
+ }
+ // else allocate a sector if needed, and write
+ if(sectors[sector] == 0) {
+ char *sec = (char*)malloc(512);
+ if(sec==0) {
+ return 1; // out of memory
+ }
+ sectors[sector] = sec;
+ }
+ memcpy(sectors[sector], buffer, 512);
+ return 0;
+ }
+
+ // return the number of sectors
+ virtual int disk_sectors() {
+ return sizeof(sectors)/sizeof(sectors[0]);
+ }
+
+ };
+
+}
+
+#endif
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHost/IUSBEnumerator.h Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,36 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef IUSBENUMERATOR_H_
+#define IUSBENUMERATOR_H_
+
+#include "stdint.h"
+#include "USBEndpoint.h"
+
+/*
+Generic interface to implement for "smart" USB enumeration
+*/
+
+class IUSBEnumerator
+{
+public:
+ virtual void setVidPid(uint16_t vid, uint16_t pid) = 0;
+ virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) = 0; //Must return true if the interface should be parsed
+ virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) = 0; //Must return true if the endpoint will be used
+};
+
+#endif /*IUSBENUMERATOR_H_*/
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHost/USBDeviceConnected.cpp Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,124 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "USBDeviceConnected.h"
+#include "dbg.h"
+
+USBDeviceConnected::USBDeviceConnected() {
+ init();
+}
+
+void USBDeviceConnected::init() {
+ hub_nb = 0;
+ port = 0;
+ vid = 0;
+ pid = 0;
+ nb_interf = 0;
+ enumerated = false;
+ activeAddr = false;
+ sizeControlEndpoint = 8;
+ device_class = 0;
+ device_subclass = 0;
+ proto = 0;
+ speed = false;
+ for (int i = 0; i < MAX_INTF; i++) {
+ memset((void *)&intf[i], 0, sizeof(INTERFACE));
+ intf[i].in_use = false;
+ for (int j = 0; j < MAX_ENDPOINT_PER_INTERFACE; j++) {
+ intf[i].ep[j] = NULL;
+ strcpy(intf[i].name, "Unknown");
+ }
+ }
+ hub_parent = NULL;
+ hub = NULL;
+ nb_interf = 0;
+}
+
+INTERFACE * USBDeviceConnected::getInterface(uint8_t index) {
+ if (index >= MAX_INTF)
+ return NULL;
+
+ if (intf[index].in_use)
+ return &intf[index];
+
+ return NULL;
+}
+
+bool USBDeviceConnected::addInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) {
+ if ((intf_nb >= MAX_INTF) || (intf[intf_nb].in_use)) {
+ return false;
+ }
+ intf[intf_nb].in_use = true;
+ intf[intf_nb].intf_class = intf_class;
+ intf[intf_nb].intf_subclass = intf_subclass;
+ intf[intf_nb].intf_protocol = intf_protocol;
+ intf[intf_nb].nb_endpoint = 0;
+ return true;
+}
+
+bool USBDeviceConnected::addEndpoint(uint8_t intf_nb, USBEndpoint * ept) {
+ if ((intf_nb >= MAX_INTF) || (intf[intf_nb].in_use == false) || (intf[intf_nb].nb_endpoint >= MAX_ENDPOINT_PER_INTERFACE)) {
+ return false;
+ }
+ intf[intf_nb].nb_endpoint++;
+
+ for (int i = 0; i < MAX_ENDPOINT_PER_INTERFACE; i++) {
+ if (intf[intf_nb].ep[i] == NULL) {
+ intf[intf_nb].ep[i] = ept;
+ return true;
+ }
+ }
+ return false;
+}
+
+void USBDeviceConnected::init(uint8_t hub_, uint8_t port_, bool lowSpeed_) {
+ USB_DBG("init dev: %p", this);
+ init();
+ hub_nb = hub_;
+ port = port_;
+ speed = lowSpeed_;
+}
+
+void USBDeviceConnected::disconnect() {
+ for(int i = 0; i < MAX_INTF; i++) {
+ intf[i].detach.call();
+ }
+ init();
+}
+
+
+USBEndpoint * USBDeviceConnected::getEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir, uint8_t index) {
+ if (intf_nb >= MAX_INTF) {
+ return NULL;
+ }
+ for (int i = 0; i < MAX_ENDPOINT_PER_INTERFACE; i++) {
+ if ((intf[intf_nb].ep[i]->getType() == type) && (intf[intf_nb].ep[i]->getDir() == dir)) {
+ if(index) {
+ index--;
+ } else {
+ return intf[intf_nb].ep[i];
+ }
+ }
+ }
+ return NULL;
+}
+
+USBEndpoint * USBDeviceConnected::getEndpoint(uint8_t intf_nb, uint8_t index) {
+ if ((intf_nb >= MAX_INTF) || (index >= MAX_ENDPOINT_PER_INTERFACE)) {
+ return NULL;
+ }
+ return intf[intf_nb].ep[index];
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHost/USBDeviceConnected.h Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,185 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef USBDEVICECONNECTED_H
+#define USBDEVICECONNECTED_H
+
+#include "stdint.h"
+#include "USBEndpoint.h"
+#include "USBHostConf.h"
+#include "rtos.h"
+
+class USBHostHub;
+
+typedef struct {
+ bool in_use;
+ uint8_t nb_endpoint;
+ uint8_t intf_class;
+ uint8_t intf_subclass;
+ uint8_t intf_protocol;
+ USBEndpoint * ep[MAX_ENDPOINT_PER_INTERFACE];
+ FunctionPointer detach;
+ char name[10];
+} INTERFACE;
+
+/**
+* USBDeviceConnected class
+*/
+class USBDeviceConnected
+{
+public:
+
+ /**
+ * Constructor
+ */
+ USBDeviceConnected();
+
+ /**
+ * Attach an USBEndpoint to this device
+ *
+ * @param intf_nb interface number
+ * @param ep pointeur on the USBEndpoint which will be attached
+ * @returns true if successful, false otherwise
+ */
+ bool addEndpoint(uint8_t intf_nb, USBEndpoint * ep);
+
+ /**
+ * Retrieve an USBEndpoint by its TYPE and DIRECTION
+ *
+ * @param intf_nb the interface on which to lookup the USBEndpoint
+ * @param type type of the USBEndpoint looked for
+ * @param dir direction of the USBEndpoint looked for
+ * @param index the index of the USBEndpoint whitin the interface
+ * @returns pointer on the USBEndpoint if found, NULL otherwise
+ */
+ USBEndpoint * getEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir, uint8_t index = 0);
+
+ /**
+ * Retrieve an USBEndpoint by its index
+ *
+ * @param intf_nb interface number
+ * @param index index of the USBEndpoint
+ * @returns pointer on the USBEndpoint if found, NULL otherwise
+ */
+ USBEndpoint * getEndpoint(uint8_t intf_nb, uint8_t index);
+
+ /**
+ * Add a new interface to this device
+ *
+ * @param intf_nb interface number
+ * @param intf_class interface class
+ * @param intf_subclass interface subclass
+ * @param intf_protocol interface protocol
+ * @returns true if successful, false otherwise
+ */
+ bool addInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol);
+
+ /**
+ * Get a specific interface
+ *
+ * @param index index of the interface to be fetched
+ * @returns interface
+ */
+ INTERFACE * getInterface(uint8_t index);
+
+ /**
+ * Attach a member function to call when a the device has been disconnected
+ *
+ * @param intf_nb interface number
+ * @param tptr pointer to the object to call the member function on
+ * @param mptr pointer to the member function to be called
+ */
+ template<typename T>
+ inline void onDisconnect(uint8_t intf_nb, T* tptr, void (T::*mptr)(void)) {
+ if ((mptr != NULL) && (tptr != NULL)) {
+ intf[intf_nb].detach.attach(tptr, mptr);
+ }
+ }
+
+ /**
+ * Attach a callback called when the device has been disconnected
+ *
+ * @param intf_nb interface number
+ * @param fn function pointer
+ */
+ inline void onDisconnect(uint8_t intf_nb, void (*fn)(void)) {
+ if (fn != NULL) {
+ intf[intf_nb].detach.attach(fn);
+ }
+ }
+
+ /**
+ * Disconnect the device by calling a callback function registered by a driver
+ */
+ void disconnect();
+
+ // setters
+ void init(uint8_t hub, uint8_t port, bool lowSpeed);
+ inline void setAddress(uint8_t addr_) { addr = addr_; };
+ inline void setVid(uint16_t vid_) { vid = vid_; };
+ inline void setPid(uint16_t pid_) { pid = pid_; };
+ inline void setClass(uint8_t device_class_) { device_class = device_class_; };
+ inline void setSubClass(uint8_t device_subclass_) { device_subclass = device_subclass_; };
+ inline void setProtocol(uint8_t pr) { proto = pr; };
+ inline void setSizeControlEndpoint(uint32_t size) { sizeControlEndpoint = size; };
+ inline void activeAddress(bool active) { activeAddr = active; };
+ inline void setEnumerated() { enumerated = true; };
+ inline void setNbIntf(uint8_t nb_intf) {nb_interf = nb_intf; };
+ inline void setHubParent(USBHostHub * hub) { hub_parent = hub; };
+ inline void setName(const char * name_, uint8_t intf_nb) { strcpy(intf[intf_nb].name, name_); };
+
+ //getters
+ inline uint8_t getPort() { return port; };
+ inline uint8_t getHub() { return hub_nb; };
+ inline uint8_t getAddress() { return addr; };
+ inline uint16_t getVid() { return vid; };
+ inline uint16_t getPid() { return pid; };
+ inline uint8_t getClass() { return device_class; };
+ inline uint8_t getSubClass() { return device_subclass; };
+ inline uint8_t getProtocol() { return proto; };
+ inline bool getSpeed() { return speed; };
+ inline uint32_t getSizeControlEndpoint() { return sizeControlEndpoint; };
+ inline bool isActiveAddress() { return activeAddr; };
+ inline bool isEnumerated() { return enumerated; };
+ inline USBHostHub * getHubParent() { return hub_parent; };
+ inline uint8_t getNbIntf() { return nb_interf; };
+ inline const char * getName(uint8_t intf_nb) { return intf[intf_nb].name; };
+
+ // in case this device is a hub
+ USBHostHub * hub;
+
+private:
+ USBHostHub * hub_parent;
+
+ INTERFACE intf[MAX_INTF];
+ uint32_t sizeControlEndpoint;
+ uint8_t hub_nb;
+ uint8_t port;
+ uint16_t vid;
+ uint16_t pid;
+ uint8_t addr;
+ uint8_t device_class;
+ uint8_t device_subclass;
+ uint8_t proto;
+ bool speed;
+ volatile bool activeAddr;
+ volatile bool enumerated;
+ uint8_t nb_interf;
+
+ void init();
+};
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHost/USBEndpoint.cpp Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,162 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include "dbg.h"
+#include "USBEndpoint.h"
+
+void USBEndpoint::init(HCED * hced_, ENDPOINT_TYPE type_, ENDPOINT_DIRECTION dir_, uint32_t size, uint8_t ep_number, HCTD* td_list_[2])
+{
+ hced = hced_;
+ type = type_;
+ dir = dir_;
+ setup = (type == CONTROL_ENDPOINT) ? true : false;
+
+ //TDs have been allocated by the host
+ memcpy((HCTD**)td_list, td_list_, sizeof(HCTD*)*2); //TODO: Maybe should add a param for td_list size... at least a define
+ memset(td_list_[0], 0, sizeof(HCTD));
+ memset(td_list_[1], 0, sizeof(HCTD));
+
+ td_list[0]->ep = this;
+ td_list[1]->ep = this;
+
+ hced->control = 0;
+ //Empty queue
+ hced->tailTD = td_list[0];
+ hced->headTD = td_list[0];
+ hced->nextED = 0;
+
+ address = (ep_number & 0x7F) | ((dir - 1) << 7);
+
+ hced->control = ((ep_number & 0x7F) << 7) // Endpoint address
+ | (type != CONTROL_ENDPOINT ? ( dir << 11) : 0 ) // direction : Out = 1, 2 = In
+ | ((size & 0x3ff) << 16); // MaxPkt Size
+
+ transfer_len = 0;
+ transferred = 0;
+ buf_start = 0;
+ nextEp = NULL;
+
+ td_current = td_list[0];
+ td_next = td_list[1];
+
+ intf_nb = 0;
+
+ state = USB_TYPE_IDLE;
+}
+
+void USBEndpoint::setSize(uint32_t size)
+{
+ hced->control &= ~(0x3ff << 16);
+ hced->control |= (size << 16);
+}
+
+
+void USBEndpoint::setDeviceAddress(uint8_t addr)
+{
+ hced->control &= ~(0x7f);
+ hced->control |= (addr & 0x7F);
+}
+
+void USBEndpoint::setSpeed(uint8_t speed)
+{
+ hced->control &= ~(1 << 13);
+ hced->control |= (speed << 13);
+}
+
+//Only for control Eps
+void USBEndpoint::setNextToken(uint32_t token)
+{
+ switch (token) {
+ case TD_SETUP:
+ dir = OUT;
+ setup = true;
+ break;
+ case TD_IN:
+ dir = IN;
+ setup = false;
+ break;
+ case TD_OUT:
+ dir = OUT;
+ setup = false;
+ break;
+ }
+}
+
+struct {
+ USB_TYPE type;
+ const char * str;
+} static type_string[] = {
+/*0*/ {USB_TYPE_OK, "USB_TYPE_OK"},
+ {USB_TYPE_CRC_ERROR, "USB_TYPE_CRC_ERROR"},
+ {USB_TYPE_BIT_STUFFING_ERROR, "USB_TYPE_BIT_STUFFING_ERROR"},
+ {USB_TYPE_DATA_TOGGLE_MISMATCH_ERROR, "USB_TYPE_DATA_TOGGLE_MISMATCH_ERROR"},
+ {USB_TYPE_STALL_ERROR, "USB_TYPE_STALL_ERROR"},
+/*5*/ {USB_TYPE_DEVICE_NOT_RESPONDING_ERROR, "USB_TYPE_DEVICE_NOT_RESPONDING_ERROR"},
+ {USB_TYPE_PID_CHECK_FAILURE_ERROR, "USB_TYPE_PID_CHECK_FAILURE_ERROR"},
+ {USB_TYPE_UNEXPECTED_PID_ERROR, "USB_TYPE_UNEXPECTED_PID_ERROR"},
+ {USB_TYPE_DATA_OVERRUN_ERROR, "USB_TYPE_DATA_OVERRUN_ERROR"},
+ {USB_TYPE_DATA_UNDERRUN_ERROR, "USB_TYPE_DATA_UNDERRUN_ERROR"},
+/*10*/ {USB_TYPE_ERROR, "USB_TYPE_ERROR"},
+ {USB_TYPE_ERROR, "USB_TYPE_ERROR"},
+ {USB_TYPE_BUFFER_OVERRUN_ERROR, "USB_TYPE_BUFFER_OVERRUN_ERROR"},
+ {USB_TYPE_BUFFER_UNDERRUN_ERROR, "USB_TYPE_BUFFER_UNDERRUN_ERROR"},
+ {USB_TYPE_DISCONNECTED, "USB_TYPE_DISCONNECTED"},
+/*15*/ {USB_TYPE_FREE, "USB_TYPE_FREE"},
+ {USB_TYPE_IDLE, "USB_TYPE_IDLE"},
+ {USB_TYPE_PROCESSING, "USB_TYPE_PROCESSING"},
+ {USB_TYPE_ERROR, "USB_TYPE_ERROR"}
+};
+
+void USBEndpoint::setState(uint8_t st) {
+ if (st > 18)
+ return;
+ state = type_string[st].type;
+}
+
+
+const char * USBEndpoint::getStateString() {
+ return type_string[state].str;
+}
+
+void USBEndpoint::queueTransfer()
+{
+ transfer_len = (uint32_t)td_current->bufEnd - (uint32_t)td_current->currBufPtr + 1;
+ transferred = transfer_len;
+ buf_start = (uint8_t *)td_current->currBufPtr;
+
+ //Now add this free TD at this end of the queue
+ state = USB_TYPE_PROCESSING;
+ td_current->nextTD = td_next;
+ hced->tailTD = td_next;
+}
+
+void USBEndpoint::unqueueTransfer(volatile HCTD * td)
+{
+ td->control=0;
+ td->currBufPtr=0;
+ td->bufEnd=0;
+ td->nextTD=0;
+ hced->headTD = (HCTD *)((uint32_t)hced->tailTD | ((uint32_t)hced->headTD & 0x2)); //Carry bit
+ td_current = td_next;
+ td_next = td;
+}
+
+void USBEndpoint::queueEndpoint(USBEndpoint * ed)
+{
+ nextEp = ed;
+ hced->nextED = (ed == NULL) ? 0 : ed->getHCED();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHost/USBEndpoint.h Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,171 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef USBENDPOINT_H
+#define USBENDPOINT_H
+
+#include "FunctionPointer.h"
+#include "USBHostTypes.h"
+#include "rtos.h"
+
+class USBDeviceConnected;
+
+/**
+* USBEndpoint class
+*/
+class USBEndpoint
+{
+public:
+ /**
+ * Constructor
+ */
+ USBEndpoint() {
+ state = USB_TYPE_FREE;
+ nextEp = NULL;
+ };
+
+ /**
+ * Initialize an endpoint
+ *
+ * @param hced hced associated to the endpoint
+ * @param type endpoint type
+ * @param dir endpoint direction
+ * @param size endpoint size
+ * @param ep_number endpoint number
+ * @param td_list array of two allocated transfer descriptors
+ */
+ void init(HCED * hced, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir, uint32_t size, uint8_t ep_number, HCTD* td_list[2]);
+
+ /**
+ * Set next token. Warning: only useful for the control endpoint
+ *
+ * @param token IN, OUT or SETUP token
+ */
+ void setNextToken(uint32_t token);
+
+ /**
+ * Queue an endpoint
+ *
+ * @param endpoint endpoint which will be queued in the linked list
+ */
+ void queueEndpoint(USBEndpoint * endpoint);
+
+
+ /**
+ * Queue a transfer on the endpoint
+ */
+ void queueTransfer();
+
+ /**
+ * Unqueue a transfer from the endpoint
+ *
+ * @param td hctd which will be unqueued
+ */
+ void unqueueTransfer(volatile HCTD * td);
+
+ /**
+ * Attach a member function to call when a transfer is finished
+ *
+ * @param tptr pointer to the object to call the member function on
+ * @param mptr pointer to the member function to be called
+ */
+ template<typename T>
+ inline void attach(T* tptr, void (T::*mptr)(void)) {
+ if((mptr != NULL) && (tptr != NULL)) {
+ rx.attach(tptr, mptr);
+ }
+ }
+
+ /**
+ * Attach a callback called when a transfer is finished
+ *
+ * @param fptr function pointer
+ */
+ inline void attach(void (*fptr)(void)) {
+ if(fptr != NULL) {
+ rx.attach(fptr);
+ }
+ }
+
+ /**
+ * Call the handler associted to the end of a transfer
+ */
+ inline void call() {
+ rx.call();
+ };
+
+
+ // setters
+ inline void setState(USB_TYPE st) { state = st; }
+ void setState(uint8_t st);
+ void setDeviceAddress(uint8_t addr);
+ inline void setLengthTransferred(int len) { transferred = len; };
+ void setSpeed(uint8_t speed);
+ void setSize(uint32_t size);
+ inline void setDir(ENDPOINT_DIRECTION d) { dir = d; }
+ inline void setIntfNb(uint8_t intf_nb_) { intf_nb = intf_nb_; };
+
+ // getters
+ const char * getStateString();
+ inline USB_TYPE getState() { return state; }
+ inline ENDPOINT_TYPE getType() { return type; };
+ inline uint8_t getDeviceAddress() { return hced->control & 0x7f; };
+ inline int getLengthTransferred() { return transferred; }
+ inline uint8_t * getBufStart() { return buf_start; }
+ inline uint8_t getAddress(){ return address; };
+ inline uint32_t getSize() { return (hced->control >> 16) & 0x3ff; };
+ inline volatile HCTD * getHeadTD() { return (volatile HCTD*) ((uint32_t)hced->headTD & ~0xF); };
+ inline volatile HCTD** getTDList() { return td_list; };
+ inline volatile HCED * getHCED() { return hced; };
+ inline ENDPOINT_DIRECTION getDir() { return dir; }
+ inline volatile HCTD * getProcessedTD() { return td_current; };
+ inline volatile HCTD* getNextTD() { return td_current; };
+ inline bool isSetup() { return setup; }
+ inline USBEndpoint * nextEndpoint() { return (USBEndpoint*)nextEp; };
+ inline uint8_t getIntfNb() { return intf_nb; };
+
+ USBDeviceConnected * dev;
+
+ Queue<uint8_t, 1> ep_queue;
+
+private:
+ ENDPOINT_TYPE type;
+ volatile USB_TYPE state;
+ ENDPOINT_DIRECTION dir;
+ bool setup;
+
+ uint8_t address;
+
+ int transfer_len;
+ int transferred;
+ uint8_t * buf_start;
+
+ FunctionPointer rx;
+
+ USBEndpoint* nextEp;
+
+ // USBEndpoint descriptor
+ volatile HCED * hced;
+
+ volatile HCTD * td_list[2];
+ volatile HCTD * td_current;
+ volatile HCTD * td_next;
+
+ uint8_t intf_nb;
+
+};
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHost/USBHALHost.h Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,169 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef USBHALHOST_H
+#define USBHALHOST_H
+
+#include "USBHostTypes.h"
+#include "USBHostConf.h"
+
+class USBHostHub;
+
+/**
+* USBHALHost class
+*/
+class USBHALHost {
+protected:
+
+ /**
+ * Constructor
+ * init variables and memory where will be stored HCCA, ED and TD
+ */
+ USBHALHost();
+
+ /**
+ * Initialize host controller. Enable USB interrupts. This part is not in the constructor because,
+ * this function calls a virtual method if a device is already connected
+ */
+ void init();
+
+ /**
+ * reset the root hub
+ */
+ void resetRootHub();
+
+ /**
+ * return the value contained in the control HEAD ED register
+ *
+ * @returns address of the control Head ED
+ */
+ uint32_t controlHeadED();
+
+ /**
+ * return the value contained in the bulk HEAD ED register
+ *
+ * @returns address of the bulk head ED
+ */
+ uint32_t bulkHeadED();
+
+ /**
+ * return the value of the head interrupt ED contained in the HCCA
+ *
+ * @returns address of the head interrupt ED contained in the HCCA
+ */
+ uint32_t interruptHeadED();
+
+ /**
+ * Update the head ED for control transfers
+ */
+ void updateControlHeadED(uint32_t addr);
+
+ /**
+ * Update the head ED for bulk transfers
+ */
+ void updateBulkHeadED(uint32_t addr);
+
+ /**
+ * Update the head ED for interrupt transfers
+ */
+ void updateInterruptHeadED(uint32_t addr);
+
+ /**
+ * Enable List for the specified endpoint type
+ *
+ * @param type enable the list of ENDPOINT_TYPE type
+ */
+ void enableList(ENDPOINT_TYPE type);
+
+ /**
+ * Disable List for the specified endpoint type
+ *
+ * @param type disable the list of ENDPOINT_TYPE type
+ */
+ bool disableList(ENDPOINT_TYPE type);
+
+ /**
+ * Virtual method called when a device has been connected
+ *
+ * @param hub hub number of the device
+ * @param port port number of the device
+ * @param lowSpeed 1 if low speed, 0 otherwise
+ * @param hub_parent reference to the hub where the device is connected (NULL if the hub parent is the root hub)
+ */
+ virtual void deviceConnected(int hub, int port, bool lowSpeed, USBHostHub * hub_parent = NULL) = 0;
+
+ /**
+ * Virtual method called when a device has been disconnected
+ *
+ * @param hub hub number of the device
+ * @param port port number of the device
+ * @param hub_parent reference to the hub where the device is connected (NULL if the hub parent is the root hub)
+ * @param addr list of the TDs which have been completed to dequeue freed TDs
+ */
+ virtual void deviceDisconnected(int hub, int port, USBHostHub * hub_parent, volatile uint32_t addr) = 0;
+
+ /**
+ * Virtual method called when a transfer has been completed
+ *
+ * @param addr list of the TDs which have been completed
+ */
+ virtual void transferCompleted(volatile uint32_t addr) = 0;
+
+ /**
+ * Find a memory section for a new ED
+ *
+ * @returns the address of the new ED
+ */
+ volatile uint8_t * getED();
+
+ /**
+ * Find a memory section for a new TD
+ *
+ * @returns the address of the new TD
+ */
+ volatile uint8_t * getTD();
+
+ /**
+ * Release a previous memory section reserved for an ED
+ *
+ * @param ed address of the ED
+ */
+ void freeED(volatile uint8_t * ed);
+
+ /**
+ * Release a previous memory section reserved for an TD
+ *
+ * @param td address of the TD
+ */
+ void freeTD(volatile uint8_t * td);
+
+private:
+ static void _usbisr(void);
+ void UsbIrqhandler();
+
+ void memInit();
+
+ HCCA volatile * usb_hcca; //256 bytes aligned
+ uint8_t volatile * usb_edBuf; //4 bytes aligned
+ uint8_t volatile * usb_tdBuf; //4 bytes aligned
+
+ static USBHALHost * instHost;
+
+ bool volatile edBufAlloc[MAX_ENDPOINT];
+ bool volatile tdBufAlloc[MAX_TD];
+};
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHost/USBHALHost_LPC17.cpp Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,325 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#if defined(TARGET_LPC1768)
+
+#include "mbed.h"
+#include "USBHALHost.h"
+#include "dbg.h"
+
+// bits of the USB/OTG clock control register
+#define HOST_CLK_EN (1<<0)
+#define DEV_CLK_EN (1<<1)
+#define PORTSEL_CLK_EN (1<<3)
+#define AHB_CLK_EN (1<<4)
+
+// bits of the USB/OTG clock status register
+#define HOST_CLK_ON (1<<0)
+#define DEV_CLK_ON (1<<1)
+#define PORTSEL_CLK_ON (1<<3)
+#define AHB_CLK_ON (1<<4)
+
+// we need host clock, OTG/portsel clock and AHB clock
+#define CLOCK_MASK (HOST_CLK_EN | PORTSEL_CLK_EN | AHB_CLK_EN)
+
+#define HCCA_SIZE sizeof(HCCA)
+#define ED_SIZE sizeof(HCED)
+#define TD_SIZE sizeof(HCTD)
+
+#define TOTAL_SIZE (HCCA_SIZE + (MAX_ENDPOINT*ED_SIZE) + (MAX_TD*TD_SIZE))
+
+static volatile uint8_t usb_buf[TOTAL_SIZE] __attribute((section("AHBSRAM1"),aligned(256))); //256 bytes aligned!
+
+USBHALHost * USBHALHost::instHost;
+
+USBHALHost::USBHALHost() {
+ instHost = this;
+ memInit();
+ memset((void*)usb_hcca, 0, HCCA_SIZE);
+ for (int i = 0; i < MAX_ENDPOINT; i++) {
+ edBufAlloc[i] = false;
+ }
+ for (int i = 0; i < MAX_TD; i++) {
+ tdBufAlloc[i] = false;
+ }
+}
+
+void USBHALHost::init() {
+ NVIC_DisableIRQ(USB_IRQn);
+
+ //Cut power
+ LPC_SC->PCONP &= ~(1UL<<31);
+ wait_ms(100);
+
+ // 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);
+
+ // it seems the bits[0:1] mean the following
+ // 0: U1=device, U2=host
+ // 1: U1=host, U2=host
+ // 2: reserved
+ // 3: U1=host, U2=device
+ // NB: this register is only available if OTG clock (aka "port select") is enabled!!
+ // since we don't care about port 2, set just bit 0 to 1 (U1=host)
+ LPC_USB->OTGStCtrl |= 1;
+
+ // now that we've configured the ports, we can turn off the portsel clock
+ LPC_USB->USBClkCtrl &= ~PORTSEL_CLK_EN;
+
+ // configure USB D+/D- pins
+ // P0[29] = USB_D+, 01
+ // P0[30] = USB_D-, 01
+ LPC_PINCON->PINSEL1 &= ~((3<<26) | (3<<28));
+ LPC_PINCON->PINSEL1 |= ((1<<26) | (1<<28));
+
+ LPC_USB->HcControl = 0; // HARDWARE RESET
+ LPC_USB->HcControlHeadED = 0; // Initialize Control list head to Zero
+ LPC_USB->HcBulkHeadED = 0; // Initialize Bulk list head to Zero
+
+ // Wait 100 ms before apply reset
+ wait_ms(100);
+
+ // software reset
+ LPC_USB->HcCommandStatus = OR_CMD_STATUS_HCR;
+
+ // Write Fm Interval and Largest Data Packet Counter
+ LPC_USB->HcFmInterval = DEFAULT_FMINTERVAL;
+ LPC_USB->HcPeriodicStart = FI * 90 / 100;
+
+ // Put HC in operational state
+ LPC_USB->HcControl = (LPC_USB->HcControl & (~OR_CONTROL_HCFS)) | OR_CONTROL_HC_OPER;
+ // Set Global Power
+ LPC_USB->HcRhStatus = OR_RH_STATUS_LPSC;
+
+ LPC_USB->HcHCCA = (uint32_t)(usb_hcca);
+
+ // Clear Interrrupt Status
+ LPC_USB->HcInterruptStatus |= LPC_USB->HcInterruptStatus;
+
+ LPC_USB->HcInterruptEnable = OR_INTR_ENABLE_MIE | OR_INTR_ENABLE_WDH | OR_INTR_ENABLE_RHSC;
+
+ // Enable the USB Interrupt
+ NVIC_SetVector(USB_IRQn, (uint32_t)(_usbisr));
+ LPC_USB->HcRhPortStatus1 = OR_RH_PORT_CSC;
+ LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC;
+
+ NVIC_EnableIRQ(USB_IRQn);
+
+ // Check for any connected devices
+ if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_CCS) {
+ //Device connected
+ wait_ms(150);
+ USB_DBG("Device connected (%08x)\n\r", LPC_USB->HcRhPortStatus1);
+ deviceConnected(0, 1, LPC_USB->HcRhPortStatus1 & OR_RH_PORT_LSDA);
+ }
+}
+
+uint32_t USBHALHost::controlHeadED() {
+ return LPC_USB->HcControlHeadED;
+}
+
+uint32_t USBHALHost::bulkHeadED() {
+ return LPC_USB->HcBulkHeadED;
+}
+
+uint32_t USBHALHost::interruptHeadED() {
+ return usb_hcca->IntTable[0];
+}
+
+void USBHALHost::updateBulkHeadED(uint32_t addr) {
+ LPC_USB->HcBulkHeadED = addr;
+}
+
+
+void USBHALHost::updateControlHeadED(uint32_t addr) {
+ LPC_USB->HcControlHeadED = addr;
+}
+
+void USBHALHost::updateInterruptHeadED(uint32_t addr) {
+ usb_hcca->IntTable[0] = addr;
+}
+
+
+void USBHALHost::enableList(ENDPOINT_TYPE type) {
+ switch(type) {
+ case CONTROL_ENDPOINT:
+ LPC_USB->HcCommandStatus = OR_CMD_STATUS_CLF;
+ LPC_USB->HcControl |= OR_CONTROL_CLE;
+ break;
+ case ISOCHRONOUS_ENDPOINT:
+ break;
+ case BULK_ENDPOINT:
+ LPC_USB->HcCommandStatus = OR_CMD_STATUS_BLF;
+ LPC_USB->HcControl |= OR_CONTROL_BLE;
+ break;
+ case INTERRUPT_ENDPOINT:
+ LPC_USB->HcControl |= OR_CONTROL_PLE;
+ break;
+ }
+}
+
+
+bool USBHALHost::disableList(ENDPOINT_TYPE type) {
+ switch(type) {
+ case CONTROL_ENDPOINT:
+ if(LPC_USB->HcControl & OR_CONTROL_CLE) {
+ LPC_USB->HcControl &= ~OR_CONTROL_CLE;
+ return true;
+ }
+ return false;
+ case ISOCHRONOUS_ENDPOINT:
+ return false;
+ case BULK_ENDPOINT:
+ if(LPC_USB->HcControl & OR_CONTROL_BLE){
+ LPC_USB->HcControl &= ~OR_CONTROL_BLE;
+ return true;
+ }
+ return false;
+ case INTERRUPT_ENDPOINT:
+ if(LPC_USB->HcControl & OR_CONTROL_PLE) {
+ LPC_USB->HcControl &= ~OR_CONTROL_PLE;
+ return true;
+ }
+ return false;
+ }
+ return false;
+}
+
+
+void USBHALHost::memInit() {
+ usb_hcca = (volatile HCCA *)usb_buf;
+ usb_edBuf = usb_buf + HCCA_SIZE;
+ usb_tdBuf = usb_buf + HCCA_SIZE + (MAX_ENDPOINT*ED_SIZE);
+}
+
+volatile uint8_t * USBHALHost::getED() {
+ for (int i = 0; i < MAX_ENDPOINT; i++) {
+ if ( !edBufAlloc[i] ) {
+ edBufAlloc[i] = true;
+ return (volatile uint8_t *)(usb_edBuf + i*ED_SIZE);
+ }
+ }
+ perror("Could not allocate ED\r\n");
+ return NULL; //Could not alloc ED
+}
+
+volatile uint8_t * USBHALHost::getTD() {
+ int i;
+ for (i = 0; i < MAX_TD; i++) {
+ if ( !tdBufAlloc[i] ) {
+ tdBufAlloc[i] = true;
+ return (volatile uint8_t *)(usb_tdBuf + i*TD_SIZE);
+ }
+ }
+ perror("Could not allocate TD\r\n");
+ return NULL; //Could not alloc TD
+}
+
+
+void USBHALHost::freeED(volatile uint8_t * ed) {
+ int i;
+ i = (ed - usb_edBuf) / ED_SIZE;
+ edBufAlloc[i] = false;
+}
+
+void USBHALHost::freeTD(volatile uint8_t * td) {
+ int i;
+ i = (td - usb_tdBuf) / TD_SIZE;
+ tdBufAlloc[i] = false;
+}
+
+
+void USBHALHost::resetRootHub() {
+ // Initiate port reset
+ LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRS;
+
+ while (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_PRS);
+
+ // ...and clear port reset signal
+ LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC;
+}
+
+
+void USBHALHost::_usbisr(void) {
+ if (instHost) {
+ instHost->UsbIrqhandler();
+ }
+}
+
+void USBHALHost::UsbIrqhandler() {
+ if( LPC_USB->HcInterruptStatus & LPC_USB->HcInterruptEnable ) //Is there something to actually process?
+ {
+
+ uint32_t int_status = LPC_USB->HcInterruptStatus & LPC_USB->HcInterruptEnable;
+
+ // Root hub status change interrupt
+ if (int_status & OR_INTR_STATUS_RHSC) {
+ if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_CSC) {
+ if (LPC_USB->HcRhStatus & OR_RH_STATUS_DRWE) {
+ // When DRWE is on, Connect Status Change
+ // means a remote wakeup event.
+ } else {
+
+ //Root device connected
+ if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_CCS) {
+
+ // wait 150ms to avoid bounce
+ wait_ms(150);
+
+ //Hub 0 (root hub), Port 1 (count starts at 1), Low or High speed
+ deviceConnected(0, 1, LPC_USB->HcRhPortStatus1 & OR_RH_PORT_LSDA);
+ }
+
+ //Root device disconnected
+ else {
+
+ if (!(int_status & OR_INTR_STATUS_WDH)) {
+ usb_hcca->DoneHead = 0;
+ }
+
+ // wait 200ms to avoid bounce
+ wait_ms(200);
+
+ deviceDisconnected(0, 1, NULL, usb_hcca->DoneHead & 0xFFFFFFFE);
+
+ if (int_status & OR_INTR_STATUS_WDH) {
+ usb_hcca->DoneHead = 0;
+ LPC_USB->HcInterruptStatus = OR_INTR_STATUS_WDH;
+ }
+ }
+ }
+ LPC_USB->HcRhPortStatus1 = OR_RH_PORT_CSC;
+ }
+ if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_PRSC) {
+ LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC;
+ }
+ LPC_USB->HcInterruptStatus = OR_INTR_STATUS_RHSC;
+ }
+
+ // Writeback Done Head interrupt
+ if (int_status & OR_INTR_STATUS_WDH) {
+ transferCompleted(usb_hcca->DoneHead & 0xFFFFFFFE);
+ LPC_USB->HcInterruptStatus = OR_INTR_STATUS_WDH;
+ }
+ }
+}
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHost/USBHALHost_RZ_A1.cpp Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,293 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#if defined(TARGET_RZ_A1H)
+
+#include "mbed.h"
+#include "USBHALHost.h"
+#include "dbg.h"
+
+#include "ohci_wrapp_RZ_A1.h"
+
+
+#define HCCA_SIZE sizeof(HCCA)
+#define ED_SIZE sizeof(HCED)
+#define TD_SIZE sizeof(HCTD)
+
+#define TOTAL_SIZE (HCCA_SIZE + (MAX_ENDPOINT*ED_SIZE) + (MAX_TD*TD_SIZE))
+#define ALIGNE_MSK (0x0000000F)
+
+static volatile uint8_t usb_buf[TOTAL_SIZE + ALIGNE_MSK]; //16 bytes aligned!
+
+USBHALHost * USBHALHost::instHost;
+
+USBHALHost::USBHALHost() {
+ instHost = this;
+ memInit();
+ memset((void*)usb_hcca, 0, HCCA_SIZE);
+ for (int i = 0; i < MAX_ENDPOINT; i++) {
+ edBufAlloc[i] = false;
+ }
+ for (int i = 0; i < MAX_TD; i++) {
+ tdBufAlloc[i] = false;
+ }
+}
+
+void USBHALHost::init() {
+ ohciwrapp_init(&_usbisr, 1);
+
+ ohciwrapp_reg_w(OHCI_REG_CONTROL, 1); // HARDWARE RESET
+ ohciwrapp_reg_w(OHCI_REG_CONTROLHEADED, 0); // Initialize Control list head to Zero
+ ohciwrapp_reg_w(OHCI_REG_BULKHEADED, 0); // Initialize Bulk list head to Zero
+
+ // Wait 100 ms before apply reset
+ wait_ms(100);
+
+ // software reset
+ ohciwrapp_reg_w(OHCI_REG_COMMANDSTATUS, OR_CMD_STATUS_HCR);
+
+ // Write Fm Interval and Largest Data Packet Counter
+ ohciwrapp_reg_w(OHCI_REG_FMINTERVAL, DEFAULT_FMINTERVAL);
+ ohciwrapp_reg_w(OHCI_REG_PERIODICSTART, FI * 90 / 100);
+
+ // Put HC in operational state
+ ohciwrapp_reg_w(OHCI_REG_CONTROL, (ohciwrapp_reg_r(OHCI_REG_CONTROL) & (~OR_CONTROL_HCFS)) | OR_CONTROL_HC_OPER);
+ // Set Global Power
+ ohciwrapp_reg_w(OHCI_REG_RHSTATUS, OR_RH_STATUS_LPSC);
+
+ ohciwrapp_reg_w(OHCI_REG_HCCA, (uint32_t)(usb_hcca));
+
+ // Clear Interrrupt Status
+ ohciwrapp_reg_w(OHCI_REG_INTERRUPTSTATUS, ohciwrapp_reg_r(OHCI_REG_INTERRUPTSTATUS));
+
+ ohciwrapp_reg_w(OHCI_REG_INTERRUPTENABLE, OR_INTR_ENABLE_MIE | OR_INTR_ENABLE_WDH | OR_INTR_ENABLE_RHSC);
+
+ // Enable the USB Interrupt
+ ohciwrapp_reg_w(OHCI_REG_RHPORTSTATUS1, OR_RH_PORT_CSC);
+ ohciwrapp_reg_w(OHCI_REG_RHPORTSTATUS1, OR_RH_PORT_PRSC);
+
+ // Check for any connected devices
+ if (ohciwrapp_reg_r(OHCI_REG_RHPORTSTATUS1) & OR_RH_PORT_CCS) {
+ //Device connected
+ wait_ms(150);
+ USB_DBG("Device connected (%08x)\n\r", ohciwrapp_reg_r(OHCI_REG_RHPORTSTATUS1));
+ deviceConnected(0, 1, ohciwrapp_reg_r(OHCI_REG_RHPORTSTATUS1) & OR_RH_PORT_LSDA);
+ }
+}
+
+uint32_t USBHALHost::controlHeadED() {
+ return ohciwrapp_reg_r(OHCI_REG_CONTROLHEADED);
+}
+
+uint32_t USBHALHost::bulkHeadED() {
+ return ohciwrapp_reg_r(OHCI_REG_BULKHEADED);
+}
+
+uint32_t USBHALHost::interruptHeadED() {
+ return usb_hcca->IntTable[0];
+}
+
+void USBHALHost::updateBulkHeadED(uint32_t addr) {
+ ohciwrapp_reg_w(OHCI_REG_BULKHEADED, addr);
+}
+
+
+void USBHALHost::updateControlHeadED(uint32_t addr) {
+ ohciwrapp_reg_w(OHCI_REG_CONTROLHEADED, addr);
+}
+
+void USBHALHost::updateInterruptHeadED(uint32_t addr) {
+ usb_hcca->IntTable[0] = addr;
+}
+
+
+void USBHALHost::enableList(ENDPOINT_TYPE type) {
+ uint32_t wk_data;
+
+ switch(type) {
+ case CONTROL_ENDPOINT:
+ ohciwrapp_reg_w(OHCI_REG_COMMANDSTATUS, OR_CMD_STATUS_CLF);
+ wk_data = (ohciwrapp_reg_r(OHCI_REG_CONTROL) | OR_CONTROL_CLE);
+ ohciwrapp_reg_w(OHCI_REG_CONTROL, wk_data);
+ break;
+ case ISOCHRONOUS_ENDPOINT:
+ break;
+ case BULK_ENDPOINT:
+ ohciwrapp_reg_w(OHCI_REG_COMMANDSTATUS, OR_CMD_STATUS_BLF);
+ wk_data = (ohciwrapp_reg_r(OHCI_REG_CONTROL) | OR_CONTROL_BLE);
+ ohciwrapp_reg_w(OHCI_REG_CONTROL, wk_data);
+ break;
+ case INTERRUPT_ENDPOINT:
+ wk_data = (ohciwrapp_reg_r(OHCI_REG_CONTROL) | OR_CONTROL_PLE);
+ ohciwrapp_reg_w(OHCI_REG_CONTROL, wk_data);
+ break;
+ }
+}
+
+
+bool USBHALHost::disableList(ENDPOINT_TYPE type) {
+ uint32_t wk_data;
+
+ switch(type) {
+ case CONTROL_ENDPOINT:
+ wk_data = ohciwrapp_reg_r(OHCI_REG_CONTROL);
+ if(wk_data & OR_CONTROL_CLE) {
+ wk_data &= ~OR_CONTROL_CLE;
+ ohciwrapp_reg_w(OHCI_REG_CONTROL, wk_data);
+ return true;
+ }
+ return false;
+ case ISOCHRONOUS_ENDPOINT:
+ return false;
+ case BULK_ENDPOINT:
+ wk_data = ohciwrapp_reg_r(OHCI_REG_CONTROL);
+ if(wk_data & OR_CONTROL_BLE) {
+ wk_data &= ~OR_CONTROL_BLE;
+ ohciwrapp_reg_w(OHCI_REG_CONTROL, wk_data);
+ return true;
+ }
+ return false;
+ case INTERRUPT_ENDPOINT:
+ wk_data = ohciwrapp_reg_r(OHCI_REG_CONTROL);
+ if(wk_data & OR_CONTROL_PLE) {
+ wk_data &= ~OR_CONTROL_PLE;
+ ohciwrapp_reg_w(OHCI_REG_CONTROL, wk_data);
+ return true;
+ }
+ return false;
+ }
+ return false;
+}
+
+
+void USBHALHost::memInit() {
+ volatile uint8_t *p_wk_buf = (uint8_t *)(((uint32_t)usb_buf + ALIGNE_MSK) & ~ALIGNE_MSK);
+
+ usb_hcca = (volatile HCCA *)p_wk_buf;
+ usb_edBuf = (volatile uint8_t *)(p_wk_buf + HCCA_SIZE);
+ usb_tdBuf = (volatile uint8_t *)(p_wk_buf + HCCA_SIZE + (MAX_ENDPOINT*ED_SIZE));
+}
+
+volatile uint8_t * USBHALHost::getED() {
+ for (int i = 0; i < MAX_ENDPOINT; i++) {
+ if ( !edBufAlloc[i] ) {
+ edBufAlloc[i] = true;
+ return (volatile uint8_t *)(usb_edBuf + i*ED_SIZE);
+ }
+ }
+ perror("Could not allocate ED\r\n");
+ return NULL; //Could not alloc ED
+}
+
+volatile uint8_t * USBHALHost::getTD() {
+ int i;
+ for (i = 0; i < MAX_TD; i++) {
+ if ( !tdBufAlloc[i] ) {
+ tdBufAlloc[i] = true;
+ return (volatile uint8_t *)(usb_tdBuf + i*TD_SIZE);
+ }
+ }
+ perror("Could not allocate TD\r\n");
+ return NULL; //Could not alloc TD
+}
+
+
+void USBHALHost::freeED(volatile uint8_t * ed) {
+ int i;
+ i = (ed - usb_edBuf) / ED_SIZE;
+ edBufAlloc[i] = false;
+}
+
+void USBHALHost::freeTD(volatile uint8_t * td) {
+ int i;
+ i = (td - usb_tdBuf) / TD_SIZE;
+ tdBufAlloc[i] = false;
+}
+
+
+void USBHALHost::resetRootHub() {
+ // Initiate port reset
+ ohciwrapp_reg_w(OHCI_REG_RHPORTSTATUS1, OR_RH_PORT_PRS);
+
+ while (ohciwrapp_reg_r(OHCI_REG_RHPORTSTATUS1) & OR_RH_PORT_PRS);
+
+ // ...and clear port reset signal
+ ohciwrapp_reg_w(OHCI_REG_RHPORTSTATUS1, OR_RH_PORT_PRSC);
+}
+
+
+void USBHALHost::_usbisr(void) {
+ if (instHost) {
+ instHost->UsbIrqhandler();
+ }
+}
+
+void USBHALHost::UsbIrqhandler() {
+ uint32_t int_status = ohciwrapp_reg_r(OHCI_REG_INTERRUPTSTATUS) & ohciwrapp_reg_r(OHCI_REG_INTERRUPTENABLE);
+
+ if (int_status != 0) { //Is there something to actually process?
+ // Root hub status change interrupt
+ if (int_status & OR_INTR_STATUS_RHSC) {
+ if (ohciwrapp_reg_r(OHCI_REG_RHPORTSTATUS1) & OR_RH_PORT_CSC) {
+ if (ohciwrapp_reg_r(OHCI_REG_RHSTATUS) & OR_RH_STATUS_DRWE) {
+ // When DRWE is on, Connect Status Change
+ // means a remote wakeup event.
+ } else {
+
+ //Root device connected
+ if (ohciwrapp_reg_r(OHCI_REG_RHPORTSTATUS1) & OR_RH_PORT_CCS) {
+
+ // wait 150ms to avoid bounce
+ wait_ms(150);
+
+ //Hub 0 (root hub), Port 1 (count starts at 1), Low or High speed
+ deviceConnected(0, 1, ohciwrapp_reg_r(OHCI_REG_RHPORTSTATUS1) & OR_RH_PORT_LSDA);
+ }
+
+ //Root device disconnected
+ else {
+
+ if (!(int_status & OR_INTR_STATUS_WDH)) {
+ usb_hcca->DoneHead = 0;
+ }
+
+ // wait 200ms to avoid bounce
+ wait_ms(200);
+
+ deviceDisconnected(0, 1, NULL, usb_hcca->DoneHead & 0xFFFFFFFE);
+
+ if (int_status & OR_INTR_STATUS_WDH) {
+ usb_hcca->DoneHead = 0;
+ ohciwrapp_reg_w(OHCI_REG_INTERRUPTSTATUS, OR_INTR_STATUS_WDH);
+ }
+ }
+ }
+ ohciwrapp_reg_w(OHCI_REG_RHPORTSTATUS1, OR_RH_PORT_CSC);
+ }
+ if (ohciwrapp_reg_r(OHCI_REG_RHPORTSTATUS1) & OR_RH_PORT_PRSC) {
+ ohciwrapp_reg_w(OHCI_REG_RHPORTSTATUS1, OR_RH_PORT_PRSC);
+ }
+ ohciwrapp_reg_w(OHCI_REG_INTERRUPTSTATUS, OR_INTR_STATUS_RHSC);
+ }
+
+ // Writeback Done Head interrupt
+ if (int_status & OR_INTR_STATUS_WDH) {
+ transferCompleted(usb_hcca->DoneHead & 0xFFFFFFFE);
+ ohciwrapp_reg_w(OHCI_REG_INTERRUPTSTATUS, OR_INTR_STATUS_WDH);
+ }
+ }
+}
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHost/USBHost.cpp Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,1160 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include "USBHost.h"
+#include "USBHostHub.h"
+
+USBHost * USBHost::instHost = NULL;
+
+#define DEVICE_CONNECTED_EVENT (1 << 0)
+#define DEVICE_DISCONNECTED_EVENT (1 << 1)
+#define TD_PROCESSED_EVENT (1 << 2)
+
+#define MAX_TRY_ENUMERATE_HUB 3
+
+#define MIN(a, b) ((a > b) ? b : a)
+
+/**
+* How interrupts are processed:
+* - new device connected:
+* - a message is queued in queue_usb_event with the id DEVICE_CONNECTED_EVENT
+* - when the usb_thread receives the event, it:
+* - resets the device
+* - reads the device descriptor
+* - sets the address of the device
+* - if it is a hub, enumerates it
+* - device disconnected:
+* - a message is queued in queue_usb_event with the id DEVICE_DISCONNECTED_EVENT
+* - when the usb_thread receives the event, it:
+* - free the device and all its children (hub)
+* - td processed
+* - a message is queued in queue_usb_event with the id TD_PROCESSED_EVENT
+* - when the usb_thread receives the event, it:
+* - call the callback attached to the endpoint where the td is attached
+*/
+void USBHost::usb_process() {
+
+ bool controlListState;
+ bool bulkListState;
+ bool interruptListState;
+ USBEndpoint * ep;
+ uint8_t i, j, res, timeout_set_addr = 10;
+ uint8_t buf[8];
+ bool too_many_hub;
+ int idx;
+
+#if DEBUG_TRANSFER
+ uint8_t * buf_transfer;
+#endif
+
+#if MAX_HUB_NB
+ uint8_t k;
+#endif
+
+ while(1) {
+ osEvent evt = mail_usb_event.get();
+
+ if (evt.status == osEventMail) {
+
+ message_t * usb_msg = (message_t*)evt.value.p;
+
+ switch (usb_msg->event_id) {
+
+ // a new device has been connected
+ case DEVICE_CONNECTED_EVENT:
+ too_many_hub = false;
+ buf[4] = 0;
+
+ do
+ {
+ Lock lock(this);
+
+ for (i = 0; i < MAX_DEVICE_CONNECTED; i++) {
+ if (!deviceInUse[i]) {
+ USB_DBG_EVENT("new device connected: %p\r\n", &devices[i]);
+ devices[i].init(usb_msg->hub, usb_msg->port, usb_msg->lowSpeed);
+ deviceReset[i] = false;
+ deviceInited[i] = true;
+ break;
+ }
+ }
+
+ if (i == MAX_DEVICE_CONNECTED) {
+ USB_ERR("Too many device connected!!\r\n");
+ continue;
+ }
+
+ if (!controlEndpointAllocated) {
+ control = newEndpoint(CONTROL_ENDPOINT, OUT, 0x08, 0x00);
+ addEndpoint(NULL, 0, (USBEndpoint*)control);
+ controlEndpointAllocated = true;
+ }
+
+ #if MAX_HUB_NB
+ if (usb_msg->hub_parent)
+ devices[i].setHubParent((USBHostHub *)(usb_msg->hub_parent));
+ #endif
+
+ for (j = 0; j < timeout_set_addr; j++) {
+
+ resetDevice(&devices[i]);
+
+ // set size of control endpoint
+ devices[i].setSizeControlEndpoint(8);
+
+ devices[i].activeAddress(false);
+
+ // get first 8 bit of device descriptor
+ // and check if we deal with a hub
+ USB_DBG("usb_thread read device descriptor on dev: %p\r\n", &devices[i]);
+ res = getDeviceDescriptor(&devices[i], buf, 8);
+
+ if (res != USB_TYPE_OK) {
+ USB_ERR("usb_thread could not read dev descr");
+ continue;
+ }
+
+ // set size of control endpoint
+ devices[i].setSizeControlEndpoint(buf[7]);
+
+ // second step: set an address to the device
+ res = setAddress(&devices[i], devices[i].getAddress());
+
+ if (res != USB_TYPE_OK) {
+ USB_ERR("SET ADDR FAILED");
+ continue;
+ }
+ devices[i].activeAddress(true);
+ USB_DBG("Address of %p: %d", &devices[i], devices[i].getAddress());
+
+ // try to read again the device descriptor to check if the device
+ // answers to its new address
+ res = getDeviceDescriptor(&devices[i], buf, 8);
+
+ if (res == USB_TYPE_OK) {
+ break;
+ }
+
+ Thread::wait(100);
+ }
+
+ USB_INFO("New device connected: %p [hub: %d - port: %d]", &devices[i], usb_msg->hub, usb_msg->port);
+
+ #if MAX_HUB_NB
+ if (buf[4] == HUB_CLASS) {
+ for (k = 0; k < MAX_HUB_NB; k++) {
+ if (hub_in_use[k] == false) {
+ for (uint8_t j = 0; j < MAX_TRY_ENUMERATE_HUB; j++) {
+ if (hubs[k].connect(&devices[i])) {
+ devices[i].hub = &hubs[k];
+ hub_in_use[k] = true;
+ break;
+ }
+ }
+ if (hub_in_use[k] == true)
+ break;
+ }
+ }
+
+ if (k == MAX_HUB_NB) {
+ USB_ERR("Too many hubs connected!!\r\n");
+ too_many_hub = true;
+ }
+ }
+
+ if (usb_msg->hub_parent)
+ ((USBHostHub *)(usb_msg->hub_parent))->deviceConnected(&devices[i]);
+ #endif
+
+ if ((i < MAX_DEVICE_CONNECTED) && !too_many_hub) {
+ deviceInUse[i] = true;
+ }
+
+ } while(0);
+
+ break;
+
+ // a device has been disconnected
+ case DEVICE_DISCONNECTED_EVENT:
+
+ do
+ {
+ Lock lock(this);
+
+ controlListState = disableList(CONTROL_ENDPOINT);
+ bulkListState = disableList(BULK_ENDPOINT);
+ interruptListState = disableList(INTERRUPT_ENDPOINT);
+
+ idx = findDevice(usb_msg->hub, usb_msg->port, (USBHostHub *)(usb_msg->hub_parent));
+ if (idx != -1) {
+ freeDevice((USBDeviceConnected*)&devices[idx]);
+ }
+
+ if (controlListState) enableList(CONTROL_ENDPOINT);
+ if (bulkListState) enableList(BULK_ENDPOINT);
+ if (interruptListState) enableList(INTERRUPT_ENDPOINT);
+
+ } while(0);
+
+ break;
+
+ // a td has been processed
+ // call callback on the ed associated to the td
+ // we are not in ISR -> users can use printf in their callback method
+ case TD_PROCESSED_EVENT:
+ ep = (USBEndpoint *) ((HCTD *)usb_msg->td_addr)->ep;
+ if (usb_msg->td_state == USB_TYPE_IDLE) {
+ USB_DBG_EVENT("call callback on td %p [ep: %p state: %s - dev: %p - %s]", usb_msg->td_addr, ep, ep->getStateString(), ep->dev, ep->dev->getName(ep->getIntfNb()));
+
+#if DEBUG_TRANSFER
+ if (ep->getDir() == IN) {
+ buf_transfer = ep->getBufStart();
+ printf("READ SUCCESS [%d bytes transferred - td: 0x%08X] on ep: [%p - addr: %02X]: ", ep->getLengthTransferred(), usb_msg->td_addr, ep, ep->getAddress());
+ for (int i = 0; i < ep->getLengthTransferred(); i++)
+ printf("%02X ", buf_transfer[i]);
+ printf("\r\n\r\n");
+ }
+#endif
+ ep->call();
+ } else {
+ idx = findDevice(ep->dev);
+ if (idx != -1) {
+ if (deviceInUse[idx]) {
+ USB_WARN("td %p processed but not in idle state: %s [ep: %p - dev: %p - %s]", usb_msg->td_addr, ep->getStateString(), ep, ep->dev, ep->dev->getName(ep->getIntfNb()));
+ ep->setState(USB_TYPE_IDLE);
+ }
+ }
+ }
+ break;
+ }
+
+ mail_usb_event.free(usb_msg);
+ }
+ }
+}
+
+/* static */void USBHost::usb_process_static(void const * arg) {
+ ((USBHost *)arg)->usb_process();
+}
+
+USBHost::USBHost() : usbThread(USBHost::usb_process_static, (void *)this, osPriorityNormal, USB_THREAD_STACK)
+{
+ headControlEndpoint = NULL;
+ headBulkEndpoint = NULL;
+ headInterruptEndpoint = NULL;
+ tailControlEndpoint = NULL;
+ tailBulkEndpoint = NULL;
+ tailInterruptEndpoint = NULL;
+
+ lenReportDescr = 0;
+
+ controlEndpointAllocated = false;
+
+ for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) {
+ deviceInUse[i] = false;
+ devices[i].setAddress(i + 1);
+ deviceReset[i] = false;
+ deviceInited[i] = false;
+ for (uint8_t j = 0; j < MAX_INTF; j++)
+ deviceAttachedDriver[i][j] = false;
+ }
+
+#if MAX_HUB_NB
+ for (uint8_t i = 0; i < MAX_HUB_NB; i++) {
+ hubs[i].setHost(this);
+ hub_in_use[i] = false;
+ }
+#endif
+}
+
+USBHost::Lock::Lock(USBHost* pHost) : m_pHost(pHost)
+{
+ m_pHost->usb_mutex.lock();
+}
+
+USBHost::Lock::~Lock()
+{
+ m_pHost->usb_mutex.unlock();
+}
+
+void USBHost::transferCompleted(volatile uint32_t addr)
+{
+ uint8_t state;
+
+ if(addr == 0)
+ return;
+
+ volatile HCTD* tdList = NULL;
+
+ //First we must reverse the list order and dequeue each TD
+ do {
+ volatile HCTD* td = (volatile HCTD*)addr;
+ addr = (uint32_t)td->nextTD; //Dequeue from physical list
+ td->nextTD = tdList; //Enqueue into reversed list
+ tdList = td;
+ } while(addr);
+
+ while(tdList != NULL) {
+ volatile HCTD* td = tdList;
+ tdList = (volatile HCTD*)td->nextTD; //Dequeue element now as it could be modified below
+ if (td->ep != NULL) {
+ USBEndpoint * ep = (USBEndpoint *)(td->ep);
+
+ if (((HCTD *)td)->control >> 28) {
+ state = ((HCTD *)td)->control >> 28;
+ } else {
+ if (td->currBufPtr)
+ ep->setLengthTransferred((uint32_t)td->currBufPtr - (uint32_t)ep->getBufStart());
+ state = 16 /*USB_TYPE_IDLE*/;
+ }
+
+ ep->unqueueTransfer(td);
+
+ if (ep->getType() != CONTROL_ENDPOINT) {
+ // callback on the processed td will be called from the usb_thread (not in ISR)
+ message_t * usb_msg = mail_usb_event.alloc();
+ usb_msg->event_id = TD_PROCESSED_EVENT;
+ usb_msg->td_addr = (void *)td;
+ usb_msg->td_state = state;
+ mail_usb_event.put(usb_msg);
+ }
+ ep->setState(state);
+ ep->ep_queue.put((uint8_t*)1);
+ }
+ }
+}
+
+USBHost * USBHost::getHostInst()
+{
+ if (instHost == NULL) {
+ instHost = new USBHost();
+ instHost->init();
+ }
+ return instHost;
+}
+
+
+/*
+ * Called when a device has been connected
+ * Called in ISR!!!! (no printf)
+ */
+/* virtual */ void USBHost::deviceConnected(int hub, int port, bool lowSpeed, USBHostHub * hub_parent)
+{
+ // be sure that the new device connected is not already connected...
+ int idx = findDevice(hub, port, hub_parent);
+ if (idx != -1) {
+ if (deviceInited[idx])
+ return;
+ }
+
+ message_t * usb_msg = mail_usb_event.alloc();
+ usb_msg->event_id = DEVICE_CONNECTED_EVENT;
+ usb_msg->hub = hub;
+ usb_msg->port = port;
+ usb_msg->lowSpeed = lowSpeed;
+ usb_msg->hub_parent = hub_parent;
+ mail_usb_event.put(usb_msg);
+}
+
+/*
+ * Called when a device has been disconnected
+ * Called in ISR!!!! (no printf)
+ */
+/* virtual */ void USBHost::deviceDisconnected(int hub, int port, USBHostHub * hub_parent, volatile uint32_t addr)
+{
+ // be sure that the device disconnected is connected...
+ int idx = findDevice(hub, port, hub_parent);
+ if (idx != -1) {
+ if (!deviceInUse[idx])
+ return;
+ } else {
+ return;
+ }
+
+ message_t * usb_msg = mail_usb_event.alloc();
+ usb_msg->event_id = DEVICE_DISCONNECTED_EVENT;
+ usb_msg->hub = hub;
+ usb_msg->port = port;
+ usb_msg->hub_parent = hub_parent;
+ mail_usb_event.put(usb_msg);
+}
+
+void USBHost::freeDevice(USBDeviceConnected * dev)
+{
+ USBEndpoint * ep = NULL;
+ HCED * ed = NULL;
+
+#if MAX_HUB_NB
+ if (dev->getClass() == HUB_CLASS) {
+ if (dev->hub == NULL) {
+ USB_ERR("HUB NULL!!!!!\r\n");
+ } else {
+ dev->hub->hubDisconnected();
+ for (uint8_t i = 0; i < MAX_HUB_NB; i++) {
+ if (dev->hub == &hubs[i]) {
+ hub_in_use[i] = false;
+ break;
+ }
+ }
+ }
+ }
+
+ // notify hub parent that this device has been disconnected
+ if (dev->getHubParent())
+ dev->getHubParent()->deviceDisconnected(dev);
+
+#endif
+
+ int idx = findDevice(dev);
+ if (idx != -1) {
+ deviceInUse[idx] = false;
+ deviceReset[idx] = false;
+
+ for (uint8_t j = 0; j < MAX_INTF; j++) {
+ deviceAttachedDriver[idx][j] = false;
+ if (dev->getInterface(j) != NULL) {
+ USB_DBG("FREE INTF %d on dev: %p, %p, nb_endpot: %d, %s", j, (void *)dev->getInterface(j), dev, dev->getInterface(j)->nb_endpoint, dev->getName(j));
+ for (int i = 0; i < dev->getInterface(j)->nb_endpoint; i++) {
+ if ((ep = dev->getEndpoint(j, i)) != NULL) {
+ ed = (HCED *)ep->getHCED();
+ ed->control |= (1 << 14); //sKip bit
+ unqueueEndpoint(ep);
+
+ freeTD((volatile uint8_t*)ep->getTDList()[0]);
+ freeTD((volatile uint8_t*)ep->getTDList()[1]);
+
+ freeED((uint8_t *)ep->getHCED());
+ }
+ printList(BULK_ENDPOINT);
+ printList(INTERRUPT_ENDPOINT);
+ }
+ USB_INFO("Device disconnected [%p - %s - hub: %d - port: %d]", dev, dev->getName(j), dev->getHub(), dev->getPort());
+ }
+ }
+ dev->disconnect();
+ }
+}
+
+
+void USBHost::unqueueEndpoint(USBEndpoint * ep)
+{
+ USBEndpoint * prec = NULL;
+ USBEndpoint * current = NULL;
+
+ for (int i = 0; i < 2; i++) {
+ current = (i == 0) ? (USBEndpoint*)headBulkEndpoint : (USBEndpoint*)headInterruptEndpoint;
+ prec = current;
+ while (current != NULL) {
+ if (current == ep) {
+ if (current->nextEndpoint() != NULL) {
+ prec->queueEndpoint(current->nextEndpoint());
+ if (current == headBulkEndpoint) {
+ updateBulkHeadED((uint32_t)current->nextEndpoint()->getHCED());
+ headBulkEndpoint = current->nextEndpoint();
+ } else if (current == headInterruptEndpoint) {
+ updateInterruptHeadED((uint32_t)current->nextEndpoint()->getHCED());
+ headInterruptEndpoint = current->nextEndpoint();
+ }
+ }
+ // here we are dequeuing the queue of ed
+ // we need to update the tail pointer
+ else {
+ prec->queueEndpoint(NULL);
+ if (current == headBulkEndpoint) {
+ updateBulkHeadED(0);
+ headBulkEndpoint = current->nextEndpoint();
+ } else if (current == headInterruptEndpoint) {
+ updateInterruptHeadED(0);
+ headInterruptEndpoint = current->nextEndpoint();
+ }
+
+ // modify tail
+ switch (current->getType()) {
+ case BULK_ENDPOINT:
+ tailBulkEndpoint = prec;
+ break;
+ case INTERRUPT_ENDPOINT:
+ tailInterruptEndpoint = prec;
+ break;
+ default:
+ break;
+ }
+ }
+ current->setState(USB_TYPE_FREE);
+ return;
+ }
+ prec = current;
+ current = current->nextEndpoint();
+ }
+ }
+}
+
+
+USBDeviceConnected * USBHost::getDevice(uint8_t index)
+{
+ if ((index >= MAX_DEVICE_CONNECTED) || (!deviceInUse[index])) {
+ return NULL;
+ }
+ return (USBDeviceConnected*)&devices[index];
+}
+
+// create an USBEndpoint descriptor. the USBEndpoint is not linked
+USBEndpoint * USBHost::newEndpoint(ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir, uint32_t size, uint8_t addr)
+{
+ int i = 0;
+ HCED * ed = (HCED *)getED();
+ HCTD* td_list[2] = { (HCTD*)getTD(), (HCTD*)getTD() };
+
+ memset((void *)td_list[0], 0x00, sizeof(HCTD));
+ memset((void *)td_list[1], 0x00, sizeof(HCTD));
+
+ // search a free USBEndpoint
+ for (i = 0; i < MAX_ENDPOINT; i++) {
+ if (endpoints[i].getState() == USB_TYPE_FREE) {
+ endpoints[i].init(ed, type, dir, size, addr, td_list);
+ USB_DBG("USBEndpoint created (%p): type: %d, dir: %d, size: %d, addr: %d, state: %s", &endpoints[i], type, dir, size, addr, endpoints[i].getStateString());
+ return &endpoints[i];
+ }
+ }
+ USB_ERR("could not allocate more endpoints!!!!");
+ return NULL;
+}
+
+
+USB_TYPE USBHost::resetDevice(USBDeviceConnected * dev)
+{
+ int index = findDevice(dev);
+ if (index != -1) {
+ USB_DBG("Resetting hub %d, port %d\n", dev->getHub(), dev->getPort());
+ Thread::wait(100);
+ if (dev->getHub() == 0) {
+ resetRootHub();
+ }
+#if MAX_HUB_NB
+ else {
+ dev->getHubParent()->portReset(dev->getPort());
+ }
+#endif
+ Thread::wait(100);
+ deviceReset[index] = true;
+ return USB_TYPE_OK;
+ }
+
+ return USB_TYPE_ERROR;
+}
+
+// link the USBEndpoint to the linked list and attach an USBEndpoint to a device
+bool USBHost::addEndpoint(USBDeviceConnected * dev, uint8_t intf_nb, USBEndpoint * ep)
+{
+
+ if (ep == NULL) {
+ return false;
+ }
+
+ HCED * prevEd;
+
+ // set device address in the USBEndpoint descriptor
+ if (dev == NULL) {
+ ep->setDeviceAddress(0);
+ } else {
+ ep->setDeviceAddress(dev->getAddress());
+ }
+
+ if ((dev != NULL) && dev->getSpeed()) {
+ ep->setSpeed(dev->getSpeed());
+ }
+
+ ep->setIntfNb(intf_nb);
+
+ // queue the new USBEndpoint on the ED list
+ switch (ep->getType()) {
+
+ case CONTROL_ENDPOINT:
+ prevEd = ( HCED*) controlHeadED();
+ if (!prevEd) {
+ updateControlHeadED((uint32_t) ep->getHCED());
+ USB_DBG_TRANSFER("First control USBEndpoint: %08X", (uint32_t) ep->getHCED());
+ headControlEndpoint = ep;
+ tailControlEndpoint = ep;
+ return true;
+ }
+ tailControlEndpoint->queueEndpoint(ep);
+ tailControlEndpoint = ep;
+ return true;
+
+ case BULK_ENDPOINT:
+ prevEd = ( HCED*) bulkHeadED();
+ if (!prevEd) {
+ updateBulkHeadED((uint32_t) ep->getHCED());
+ USB_DBG_TRANSFER("First bulk USBEndpoint: %08X\r\n", (uint32_t) ep->getHCED());
+ headBulkEndpoint = ep;
+ tailBulkEndpoint = ep;
+ break;
+ }
+ USB_DBG_TRANSFER("Queue BULK Ed %p after %p\r\n",ep->getHCED(), prevEd);
+ tailBulkEndpoint->queueEndpoint(ep);
+ tailBulkEndpoint = ep;
+ break;
+
+ case INTERRUPT_ENDPOINT:
+ prevEd = ( HCED*) interruptHeadED();
+ if (!prevEd) {
+ updateInterruptHeadED((uint32_t) ep->getHCED());
+ USB_DBG_TRANSFER("First interrupt USBEndpoint: %08X\r\n", (uint32_t) ep->getHCED());
+ headInterruptEndpoint = ep;
+ tailInterruptEndpoint = ep;
+ break;
+ }
+ USB_DBG_TRANSFER("Queue INTERRUPT Ed %p after %p\r\n",ep->getHCED(), prevEd);
+ tailInterruptEndpoint->queueEndpoint(ep);
+ tailInterruptEndpoint = ep;
+ break;
+ default:
+ return false;
+ }
+
+ ep->dev = dev;
+ dev->addEndpoint(intf_nb, ep);
+
+ return true;
+}
+
+
+int USBHost::findDevice(USBDeviceConnected * dev)
+{
+ for (int i = 0; i < MAX_DEVICE_CONNECTED; i++) {
+ if (dev == &devices[i]) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+int USBHost::findDevice(uint8_t hub, uint8_t port, USBHostHub * hub_parent)
+{
+ for (int i = 0; i < MAX_DEVICE_CONNECTED; i++) {
+ if (devices[i].getHub() == hub && devices[i].getPort() == port) {
+ if (hub_parent != NULL) {
+ if (hub_parent == devices[i].getHubParent())
+ return i;
+ } else {
+ return i;
+ }
+ }
+ }
+ return -1;
+}
+
+void USBHost::printList(ENDPOINT_TYPE type)
+{
+#if DEBUG_EP_STATE
+ volatile HCED * hced;
+ switch(type) {
+ case CONTROL_ENDPOINT:
+ hced = (HCED *)controlHeadED();
+ break;
+ case BULK_ENDPOINT:
+ hced = (HCED *)bulkHeadED();
+ break;
+ case INTERRUPT_ENDPOINT:
+ hced = (HCED *)interruptHeadED();
+ break;
+ }
+ volatile HCTD * hctd = NULL;
+ const char * type_str = (type == BULK_ENDPOINT) ? "BULK" :
+ ((type == INTERRUPT_ENDPOINT) ? "INTERRUPT" :
+ ((type == CONTROL_ENDPOINT) ? "CONTROL" : "ISOCHRONOUS"));
+ printf("State of %s:\r\n", type_str);
+ while (hced != NULL) {
+ uint8_t dir = ((hced->control & (3 << 11)) >> 11);
+ printf("hced: %p [ADDR: %d, DIR: %s, EP_NB: 0x%X]\r\n", hced,
+ hced->control & 0x7f,
+ (dir == 1) ? "OUT" : ((dir == 0) ? "FROM_TD":"IN"),
+ (hced->control & (0xf << 7)) >> 7);
+ hctd = (HCTD *)((uint32_t)(hced->headTD) & ~(0xf));
+ while (hctd != hced->tailTD) {
+ printf("\thctd: %p [DIR: %s]\r\n", hctd, ((hctd->control & (3 << 19)) >> 19) == 1 ? "OUT" : "IN");
+ hctd = hctd->nextTD;
+ }
+ printf("\thctd: %p\r\n", hctd);
+ hced = hced->nextED;
+ }
+ printf("\r\n\r\n");
+#endif
+}
+
+
+// add a transfer on the TD linked list
+USB_TYPE USBHost::addTransfer(USBEndpoint * ed, uint8_t * buf, uint32_t len)
+{
+ td_mutex.lock();
+
+ // allocate a TD which will be freed in TDcompletion
+ volatile HCTD * td = ed->getNextTD();
+ if (td == NULL) {
+ return USB_TYPE_ERROR;
+ }
+
+ uint32_t token = (ed->isSetup() ? TD_SETUP : ( (ed->getDir() == IN) ? TD_IN : TD_OUT ));
+
+ uint32_t td_toggle;
+
+ if (ed->getType() == CONTROL_ENDPOINT) {
+ if (ed->isSetup()) {
+ td_toggle = TD_TOGGLE_0;
+ } else {
+ td_toggle = TD_TOGGLE_1;
+ }
+ } else {
+ td_toggle = 0;
+ }
+
+ td->control = (TD_ROUNDING | token | TD_DELAY_INT(0) | td_toggle | TD_CC);
+ td->currBufPtr = buf;
+ td->bufEnd = (buf + (len - 1));
+
+ ENDPOINT_TYPE type = ed->getType();
+
+ disableList(type);
+ ed->queueTransfer();
+ printList(type);
+ enableList(type);
+
+ td_mutex.unlock();
+
+ return USB_TYPE_PROCESSING;
+}
+
+
+
+USB_TYPE USBHost::getDeviceDescriptor(USBDeviceConnected * dev, uint8_t * buf, uint16_t max_len_buf, uint16_t * len_dev_descr)
+{
+ USB_TYPE t = controlRead( dev,
+ USB_DEVICE_TO_HOST | USB_RECIPIENT_DEVICE,
+ GET_DESCRIPTOR,
+ (DEVICE_DESCRIPTOR << 8) | (0),
+ 0, buf, MIN(DEVICE_DESCRIPTOR_LENGTH, max_len_buf));
+ if (len_dev_descr)
+ *len_dev_descr = MIN(DEVICE_DESCRIPTOR_LENGTH, max_len_buf);
+
+ return t;
+}
+
+USB_TYPE USBHost::getConfigurationDescriptor(USBDeviceConnected * dev, uint8_t * buf, uint16_t max_len_buf, uint16_t * len_conf_descr)
+{
+ USB_TYPE res;
+ uint16_t total_conf_descr_length = 0;
+
+ // fourth step: get the beginning of the configuration descriptor to have the total length of the conf descr
+ res = controlRead( dev,
+ USB_DEVICE_TO_HOST | USB_RECIPIENT_DEVICE,
+ GET_DESCRIPTOR,
+ (CONFIGURATION_DESCRIPTOR << 8) | (0),
+ 0, buf, CONFIGURATION_DESCRIPTOR_LENGTH);
+
+ if (res != USB_TYPE_OK) {
+ USB_ERR("GET CONF 1 DESCR FAILED");
+ return res;
+ }
+ total_conf_descr_length = buf[2] | (buf[3] << 8);
+ total_conf_descr_length = MIN(max_len_buf, total_conf_descr_length);
+
+ if (len_conf_descr)
+ *len_conf_descr = total_conf_descr_length;
+
+ USB_DBG("TOTAL_LENGTH: %d \t NUM_INTERF: %d", total_conf_descr_length, buf[4]);
+
+ return controlRead( dev,
+ USB_DEVICE_TO_HOST | USB_RECIPIENT_DEVICE,
+ GET_DESCRIPTOR,
+ (CONFIGURATION_DESCRIPTOR << 8) | (0),
+ 0, buf, total_conf_descr_length);
+}
+
+
+USB_TYPE USBHost::setAddress(USBDeviceConnected * dev, uint8_t address) {
+ return controlWrite( dev,
+ USB_HOST_TO_DEVICE | USB_RECIPIENT_DEVICE,
+ SET_ADDRESS,
+ address,
+ 0, NULL, 0);
+
+}
+
+USB_TYPE USBHost::setConfiguration(USBDeviceConnected * dev, uint8_t conf)
+{
+ return controlWrite( dev,
+ USB_HOST_TO_DEVICE | USB_RECIPIENT_DEVICE,
+ SET_CONFIGURATION,
+ conf,
+ 0, NULL, 0);
+}
+
+uint8_t USBHost::numberDriverAttached(USBDeviceConnected * dev) {
+ int index = findDevice(dev);
+ uint8_t cnt = 0;
+ if (index == -1)
+ return 0;
+ for (uint8_t i = 0; i < MAX_INTF; i++) {
+ if (deviceAttachedDriver[index][i])
+ cnt++;
+ }
+ return cnt;
+}
+
+// enumerate a device with the control USBEndpoint
+USB_TYPE USBHost::enumerate(USBDeviceConnected * dev, IUSBEnumerator* pEnumerator)
+{
+ uint16_t total_conf_descr_length = 0;
+ USB_TYPE res;
+
+ do
+ {
+ Lock lock(this);
+
+ // don't enumerate a device which all interfaces are registered to a specific driver
+ int index = findDevice(dev);
+
+ if (index == -1) {
+ return USB_TYPE_ERROR;
+ }
+
+ uint8_t nb_intf_attached = numberDriverAttached(dev);
+ USB_DBG("dev: %p nb_intf: %d", dev, dev->getNbIntf());
+ USB_DBG("dev: %p nb_intf_attached: %d", dev, nb_intf_attached);
+ if ((nb_intf_attached != 0) && (dev->getNbIntf() == nb_intf_attached)) {
+ USB_DBG("Don't enumerate dev: %p because all intf are registered with a driver", dev);
+ return USB_TYPE_OK;
+ }
+
+ USB_DBG("Enumerate dev: %p", dev);
+
+ // third step: get the whole device descriptor to see vid, pid
+ res = getDeviceDescriptor(dev, data, DEVICE_DESCRIPTOR_LENGTH);
+
+ if (res != USB_TYPE_OK) {
+ USB_DBG("GET DEV DESCR FAILED");
+ return res;
+ }
+
+ dev->setClass(data[4]);
+ dev->setSubClass(data[5]);
+ dev->setProtocol(data[6]);
+ dev->setVid(data[8] | (data[9] << 8));
+ dev->setPid(data[10] | (data[11] << 8));
+ USB_DBG("CLASS: %02X \t VID: %04X \t PID: %04X", data[4], data[8] | (data[9] << 8), data[10] | (data[11] << 8));
+
+ pEnumerator->setVidPid( data[8] | (data[9] << 8), data[10] | (data[11] << 8) );
+
+ res = getConfigurationDescriptor(dev, data, sizeof(data), &total_conf_descr_length);
+ if (res != USB_TYPE_OK) {
+ return res;
+ }
+
+ #if (DEBUG > 3)
+ USB_DBG("CONFIGURATION DESCRIPTOR:\r\n");
+ for (int i = 0; i < total_conf_descr_length; i++)
+ printf("%02X ", data[i]);
+ printf("\r\n\r\n");
+ #endif
+
+ // Parse the configuration descriptor
+ parseConfDescr(dev, data, total_conf_descr_length, pEnumerator);
+
+ // only set configuration if not enumerated before
+ if (!dev->isEnumerated()) {
+
+ USB_DBG("Set configuration 1 on dev: %p", dev);
+ // sixth step: set configuration (only 1 supported)
+ res = setConfiguration(dev, 1);
+
+ if (res != USB_TYPE_OK) {
+ USB_DBG("SET CONF FAILED");
+ return res;
+ }
+ }
+
+ dev->setEnumerated();
+
+ // Now the device is enumerated!
+ USB_DBG("dev %p is enumerated\r\n", dev);
+
+ } while(0);
+
+ // Some devices may require this delay
+ Thread::wait(100);
+
+ return USB_TYPE_OK;
+}
+// this method fills the USBDeviceConnected object: class,.... . It also add endpoints found in the descriptor.
+void USBHost::parseConfDescr(USBDeviceConnected * dev, uint8_t * conf_descr, uint32_t len, IUSBEnumerator* pEnumerator)
+{
+ uint32_t index = 0;
+ uint32_t len_desc = 0;
+ uint8_t id = 0;
+ int nb_endpoints_used = 0;
+ USBEndpoint * ep = NULL;
+ uint8_t intf_nb = 0;
+ bool parsing_intf = false;
+ uint8_t current_intf = 0;
+
+ while (index < len) {
+ len_desc = conf_descr[index];
+ id = conf_descr[index+1];
+ switch (id) {
+ case CONFIGURATION_DESCRIPTOR:
+ USB_DBG("dev: %p has %d intf", dev, conf_descr[4]);
+ dev->setNbIntf(conf_descr[4]);
+ break;
+ case INTERFACE_DESCRIPTOR:
+ if(pEnumerator->parseInterface(conf_descr[index + 2], conf_descr[index + 5], conf_descr[index + 6], conf_descr[index + 7])) {
+ if (intf_nb++ <= MAX_INTF) {
+ current_intf = conf_descr[index + 2];
+ dev->addInterface(current_intf, conf_descr[index + 5], conf_descr[index + 6], conf_descr[index + 7]);
+ nb_endpoints_used = 0;
+ USB_DBG("ADD INTF %d on device %p: class: %d, subclass: %d, proto: %d", current_intf, dev, conf_descr[index + 5],conf_descr[index + 6],conf_descr[index + 7]);
+ } else {
+ USB_DBG("Drop intf...");
+ }
+ parsing_intf = true;
+ } else {
+ parsing_intf = false;
+ }
+ break;
+ case ENDPOINT_DESCRIPTOR:
+ if (parsing_intf && (intf_nb <= MAX_INTF) ) {
+ if (nb_endpoints_used < MAX_ENDPOINT_PER_INTERFACE) {
+ if( pEnumerator->useEndpoint(current_intf, (ENDPOINT_TYPE)(conf_descr[index + 3] & 0x03), (ENDPOINT_DIRECTION)((conf_descr[index + 2] >> 7) + 1)) ) {
+ // if the USBEndpoint is isochronous -> skip it (TODO: fix this)
+ if ((conf_descr[index + 3] & 0x03) != ISOCHRONOUS_ENDPOINT) {
+ ep = newEndpoint((ENDPOINT_TYPE)(conf_descr[index+3] & 0x03),
+ (ENDPOINT_DIRECTION)((conf_descr[index + 2] >> 7) + 1),
+ conf_descr[index + 4] | (conf_descr[index + 5] << 8),
+ conf_descr[index + 2] & 0x0f);
+ USB_DBG("ADD USBEndpoint %p, on interf %d on device %p", ep, current_intf, dev);
+ if (ep != NULL && dev != NULL) {
+ addEndpoint(dev, current_intf, ep);
+ } else {
+ USB_DBG("EP NULL");
+ }
+ nb_endpoints_used++;
+ } else {
+ USB_DBG("ISO USBEndpoint NOT SUPPORTED");
+ }
+ }
+ }
+ }
+ break;
+ case HID_DESCRIPTOR:
+ lenReportDescr = conf_descr[index + 7] | (conf_descr[index + 8] << 8);
+ break;
+ default:
+ break;
+ }
+ index += len_desc;
+ }
+}
+
+
+USB_TYPE USBHost::bulkWrite(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking)
+{
+ return generalTransfer(dev, ep, buf, len, blocking, BULK_ENDPOINT, true);
+}
+
+USB_TYPE USBHost::bulkRead(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking)
+{
+ return generalTransfer(dev, ep, buf, len, blocking, BULK_ENDPOINT, false);
+}
+
+USB_TYPE USBHost::interruptWrite(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking)
+{
+ return generalTransfer(dev, ep, buf, len, blocking, INTERRUPT_ENDPOINT, true);
+}
+
+USB_TYPE USBHost::interruptRead(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking)
+{
+ return generalTransfer(dev, ep, buf, len, blocking, INTERRUPT_ENDPOINT, false);
+}
+
+USB_TYPE USBHost::generalTransfer(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking, ENDPOINT_TYPE type, bool write) {
+
+#if DEBUG_TRANSFER
+ const char * type_str = (type == BULK_ENDPOINT) ? "BULK" : ((type == INTERRUPT_ENDPOINT) ? "INTERRUPT" : "ISOCHRONOUS");
+ USB_DBG_TRANSFER("----- %s %s [dev: %p - %s - hub: %d - port: %d - addr: %d - ep: %02X]------", type_str, (write) ? "WRITE" : "READ", dev, dev->getName(ep->getIntfNb()), dev->getHub(), dev->getPort(), dev->getAddress(), ep->getAddress());
+#endif
+
+ Lock lock(this);
+
+ USB_TYPE res;
+ ENDPOINT_DIRECTION dir = (write) ? OUT : IN;
+
+ if (dev == NULL) {
+ USB_ERR("dev NULL");
+ return USB_TYPE_ERROR;
+ }
+
+ if (ep == NULL) {
+ USB_ERR("ep NULL");
+ return USB_TYPE_ERROR;
+ }
+
+ if (ep->getState() != USB_TYPE_IDLE) {
+ USB_WARN("[ep: %p - dev: %p - %s] NOT IDLE: %s", ep, ep->dev, ep->dev->getName(ep->getIntfNb()), ep->getStateString());
+ return ep->getState();
+ }
+
+ if ((ep->getDir() != dir) || (ep->getType() != type)) {
+ USB_ERR("[ep: %p - dev: %p] wrong dir or bad USBEndpoint type", ep, ep->dev);
+ return USB_TYPE_ERROR;
+ }
+
+ if (dev->getAddress() != ep->getDeviceAddress()) {
+ USB_ERR("[ep: %p - dev: %p] USBEndpoint addr and device addr don't match", ep, ep->dev);
+ return USB_TYPE_ERROR;
+ }
+
+#if DEBUG_TRANSFER
+ if (write) {
+ USB_DBG_TRANSFER("%s WRITE buffer", type_str);
+ for (int i = 0; i < ep->getLengthTransferred(); i++)
+ printf("%02X ", buf[i]);
+ printf("\r\n\r\n");
+ }
+#endif
+ addTransfer(ep, buf, len);
+
+ if (blocking) {
+
+ ep->ep_queue.get();
+ res = ep->getState();
+
+ USB_DBG_TRANSFER("%s TRANSFER res: %s on ep: %p\r\n", type_str, ep->getStateString(), ep);
+
+ if (res != USB_TYPE_IDLE) {
+ return res;
+ }
+
+ return USB_TYPE_OK;
+ }
+
+ return USB_TYPE_PROCESSING;
+
+}
+
+
+USB_TYPE USBHost::controlRead(USBDeviceConnected * dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len) {
+ return controlTransfer(dev, requestType, request, value, index, buf, len, false);
+}
+
+USB_TYPE USBHost::controlWrite(USBDeviceConnected * dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len) {
+ return controlTransfer(dev, requestType, request, value, index, buf, len, true);
+}
+
+USB_TYPE USBHost::controlTransfer(USBDeviceConnected * dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len, bool write)
+{
+ Lock lock(this);
+ USB_DBG_TRANSFER("----- CONTROL %s [dev: %p - hub: %d - port: %d] ------", (write) ? "WRITE" : "READ", dev, dev->getHub(), dev->getPort());
+
+ int length_transfer = len;
+ USB_TYPE res;
+ uint32_t token;
+
+ control->setSpeed(dev->getSpeed());
+ control->setSize(dev->getSizeControlEndpoint());
+ if (dev->isActiveAddress()) {
+ control->setDeviceAddress(dev->getAddress());
+ } else {
+ control->setDeviceAddress(0);
+ }
+
+ USB_DBG_TRANSFER("Control transfer on device: %d\r\n", control->getDeviceAddress());
+ fillControlBuf(requestType, request, value, index, len);
+
+#if DEBUG_TRANSFER
+ USB_DBG_TRANSFER("SETUP PACKET: ");
+ for (int i = 0; i < 8; i++)
+ printf("%01X ", setupPacket[i]);
+ printf("\r\n");
+#endif
+
+ control->setNextToken(TD_SETUP);
+ addTransfer(control, (uint8_t*)setupPacket, 8);
+
+ control->ep_queue.get();
+ res = control->getState();
+
+ USB_DBG_TRANSFER("CONTROL setup stage %s", control->getStateString());
+
+ if (res != USB_TYPE_IDLE) {
+ return res;
+ }
+
+ if (length_transfer) {
+ token = (write) ? TD_OUT : TD_IN;
+ control->setNextToken(token);
+ addTransfer(control, (uint8_t *)buf, length_transfer);
+
+ control->ep_queue.get();
+ res = control->getState();
+
+#if DEBUG_TRANSFER
+ USB_DBG_TRANSFER("CONTROL %s stage %s", (write) ? "WRITE" : "READ", control->getStateString());
+ if (write) {
+ USB_DBG_TRANSFER("CONTROL WRITE buffer");
+ for (int i = 0; i < control->getLengthTransferred(); i++)
+ printf("%02X ", buf[i]);
+ printf("\r\n\r\n");
+ } else {
+ USB_DBG_TRANSFER("CONTROL READ SUCCESS [%d bytes transferred]", control->getLengthTransferred());
+ for (int i = 0; i < control->getLengthTransferred(); i++)
+ printf("%02X ", buf[i]);
+ printf("\r\n\r\n");
+ }
+#endif
+
+ if (res != USB_TYPE_IDLE) {
+ return res;
+ }
+ }
+
+ token = (write) ? TD_IN : TD_OUT;
+ control->setNextToken(token);
+ addTransfer(control, NULL, 0);
+
+ control->ep_queue.get();
+ res = control->getState();
+
+ USB_DBG_TRANSFER("CONTROL ack stage %s", control->getStateString());
+
+ if (res != USB_TYPE_IDLE)
+ return res;
+
+ return USB_TYPE_OK;
+}
+
+
+void USBHost::fillControlBuf(uint8_t requestType, uint8_t request, uint16_t value, uint16_t index, int len)
+{
+ setupPacket[0] = requestType;
+ setupPacket[1] = request;
+ setupPacket[2] = (uint8_t) value;
+ setupPacket[3] = (uint8_t) (value >> 8);
+ setupPacket[4] = (uint8_t) index;
+ setupPacket[5] = (uint8_t) (index >> 8);
+ setupPacket[6] = (uint8_t) len;
+ setupPacket[7] = (uint8_t) (len >> 8);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHost/USBHost.h Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,395 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef USBHOST_H
+#define USBHOST_H
+
+#include "USBHALHost.h"
+#include "USBDeviceConnected.h"
+#include "IUSBEnumerator.h"
+#include "USBHostConf.h"
+#include "rtos.h"
+#include "dbg.h"
+#include "USBHostHub.h"
+
+/**
+* USBHost class
+* This class is a singleton. All drivers have a reference on the static USBHost instance
+*/
+class USBHost : public USBHALHost {
+public:
+ /**
+ * Static method to create or retrieve the single USBHost instance
+ */
+ static USBHost * getHostInst();
+
+ /**
+ * Control read: setup stage, data stage and status stage
+ *
+ * @param dev the control read will be done for this device
+ * @param requestType request type
+ * @param request request
+ * @param value value
+ * @param index index
+ * @param buf pointer on a buffer where will be store the data received
+ * @param len length of the transfer
+ *
+ * @returns status of the control read
+ */
+ USB_TYPE controlRead(USBDeviceConnected * dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len);
+
+ /**
+ * Control write: setup stage, data stage and status stage
+ *
+ * @param dev the control write will be done for this device
+ * @param requestType request type
+ * @param request request
+ * @param value value
+ * @param index index
+ * @param buf pointer on a buffer which will be written
+ * @param len length of the transfer
+ *
+ * @returns status of the control write
+ */
+ USB_TYPE controlWrite(USBDeviceConnected * dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len);
+
+ /**
+ * Bulk read
+ *
+ * @param dev the bulk transfer will be done for this device
+ * @param ep USBEndpoint which will be used to read a packet
+ * @param buf pointer on a buffer where will be store the data received
+ * @param len length of the transfer
+ * @param blocking if true, the read is blocking (wait for completion)
+ *
+ * @returns status of the bulk read
+ */
+ USB_TYPE bulkRead(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking = true);
+
+ /**
+ * Bulk write
+ *
+ * @param dev the bulk transfer will be done for this device
+ * @param ep USBEndpoint which will be used to write a packet
+ * @param buf pointer on a buffer which will be written
+ * @param len length of the transfer
+ * @param blocking if true, the write is blocking (wait for completion)
+ *
+ * @returns status of the bulk write
+ */
+ USB_TYPE bulkWrite(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking = true);
+
+ /**
+ * Interrupt read
+ *
+ * @param dev the bulk transfer will be done for this device
+ * @param ep USBEndpoint which will be used to write a packet
+ * @param buf pointer on a buffer which will be written
+ * @param len length of the transfer
+ * @param blocking if true, the read is blocking (wait for completion)
+ *
+ * @returns status of the interrupt read
+ */
+ USB_TYPE interruptRead(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking = true);
+
+ /**
+ * Interrupt write
+ *
+ * @param dev the bulk transfer will be done for this device
+ * @param ep USBEndpoint which will be used to write a packet
+ * @param buf pointer on a buffer which will be written
+ * @param len length of the transfer
+ * @param blocking if true, the write is blocking (wait for completion)
+ *
+ * @returns status of the interrupt write
+ */
+ USB_TYPE interruptWrite(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking = true);
+
+ /**
+ * Enumerate a device.
+ *
+ * @param dev device which will be enumerated
+ *
+ * @returns status of the enumeration
+ */
+ USB_TYPE enumerate(USBDeviceConnected * dev, IUSBEnumerator* pEnumerator);
+
+ /**
+ * reset a specific device
+ *
+ * @param dev device which will be resetted
+ */
+ USB_TYPE resetDevice(USBDeviceConnected * dev);
+
+ /**
+ * Get a device
+ *
+ * @param index index of the device which will be returned
+ *
+ * @returns pointer on the "index" device
+ */
+ USBDeviceConnected * getDevice(uint8_t index);
+
+ /*
+ * If there is a HID device connected, the host stores the length of the report descriptor.
+ * This avoid to the driver to re-ask the configuration descriptor to request the report descriptor
+ *
+ * @returns length of the report descriptor
+ */
+ inline uint16_t getLengthReportDescr() {
+ return lenReportDescr;
+ };
+
+ /**
+ * register a driver into the host associated with a callback function called when the device is disconnected
+ *
+ * @param dev device
+ * @param intf interface number
+ * @param tptr pointer to the object to call the member function on
+ * @param mptr pointer to the member function to be called
+ */
+ template<typename T>
+ inline void registerDriver(USBDeviceConnected * dev, uint8_t intf, T* tptr, void (T::*mptr)(void)) {
+ int index = findDevice(dev);
+ if ((index != -1) && (mptr != NULL) && (tptr != NULL)) {
+ USB_DBG("register driver for dev: %p on intf: %d", dev, intf);
+ deviceAttachedDriver[index][intf] = true;
+ dev->onDisconnect(intf, tptr, mptr);
+ }
+ }
+
+ /**
+ * register a driver into the host associated with a callback function called when the device is disconnected
+ *
+ * @param dev device
+ * @param intf interface number
+ * @param fn callback called when the specified device has been disconnected
+ */
+ inline void registerDriver(USBDeviceConnected * dev, uint8_t intf, void (*fn)(void)) {
+ int index = findDevice(dev);
+ if ((index != -1) && (fn != NULL)) {
+ USB_DBG("register driver for dev: %p on intf: %d", dev, intf);
+ deviceAttachedDriver[index][intf] = true;
+ dev->onDisconnect(intf, fn);
+ }
+ }
+
+ /**
+ * Instantiate to protect USB thread from accessing shared objects (USBConnectedDevices and Interfaces)
+ */
+ class Lock
+ {
+ public:
+ Lock(USBHost* pHost);
+ ~Lock();
+ private:
+ USBHost* m_pHost;
+ };
+
+ friend class USBHostHub;
+
+protected:
+
+ /**
+ * Virtual method called when a transfer has been completed
+ *
+ * @param addr list of the TDs which have been completed
+ */
+ virtual void transferCompleted(volatile uint32_t addr);
+
+ /**
+ * Virtual method called when a device has been connected
+ *
+ * @param hub hub number of the device
+ * @param port port number of the device
+ * @param lowSpeed 1 if low speed, 0 otherwise
+ * @param hub_parent reference on the parent hub
+ */
+ virtual void deviceConnected(int hub, int port, bool lowSpeed, USBHostHub * hub_parent = NULL);
+
+ /**
+ * Virtuel method called when a device has been disconnected
+ *
+ * @param hub hub number of the device
+ * @param port port number of the device
+ * @param addr list of the TDs which have been completed to dequeue freed TDs
+ */
+ virtual void deviceDisconnected(int hub, int port, USBHostHub * hub_parent, volatile uint32_t addr);
+
+
+private:
+ // singleton class -> constructor is private
+ USBHost();
+ static USBHost * instHost;
+ uint16_t lenReportDescr;
+
+ // endpoints
+ void unqueueEndpoint(USBEndpoint * ep) ;
+ USBEndpoint endpoints[MAX_ENDPOINT];
+ USBEndpoint* volatile control;
+
+ USBEndpoint* volatile headControlEndpoint;
+ USBEndpoint* volatile headBulkEndpoint;
+ USBEndpoint* volatile headInterruptEndpoint;
+
+ USBEndpoint* volatile tailControlEndpoint;
+ USBEndpoint* volatile tailBulkEndpoint;
+ USBEndpoint* volatile tailInterruptEndpoint;
+
+ bool controlEndpointAllocated;
+
+ // devices connected
+ USBDeviceConnected devices[MAX_DEVICE_CONNECTED];
+ bool deviceInUse[MAX_DEVICE_CONNECTED];
+ bool deviceAttachedDriver[MAX_DEVICE_CONNECTED][MAX_INTF];
+ bool deviceReset[MAX_DEVICE_CONNECTED];
+ bool deviceInited[MAX_DEVICE_CONNECTED];
+
+#if MAX_HUB_NB
+ USBHostHub hubs[MAX_HUB_NB];
+ bool hub_in_use[MAX_HUB_NB];
+#endif
+
+ // to store a setup packet
+ uint8_t setupPacket[8];
+
+ typedef struct {
+ uint8_t event_id;
+ void * td_addr;
+ uint8_t hub;
+ uint8_t port;
+ uint8_t lowSpeed;
+ uint8_t td_state;
+ void * hub_parent;
+ } message_t;
+
+ Thread usbThread;
+ void usb_process();
+ static void usb_process_static(void const * arg);
+ Mail<message_t, 10> mail_usb_event;
+ Mutex usb_mutex;
+ Mutex td_mutex;
+
+ // buffer for conf descriptor
+ uint8_t data[415];
+
+ /**
+ * Add a transfer on the TD linked list associated to an ED
+ *
+ * @param ed the transfer is associated to this ed
+ * @param buf pointer on a buffer where will be read/write data to send or receive
+ * @param len transfer length
+ *
+ * @return status of the transfer
+ */
+ USB_TYPE addTransfer(USBEndpoint * ed, uint8_t * buf, uint32_t len) ;
+
+ /**
+ * Link the USBEndpoint to the linked list and attach an USBEndpoint this USBEndpoint to a device
+ *
+ * @param dev pointer on a USBDeviceConnected object
+ * @param ep pointer on the USBEndpoint which will be added
+ *
+ * return true if successful
+ */
+ bool addEndpoint(USBDeviceConnected * dev, uint8_t intf_nb, USBEndpoint * ep) ;
+
+ /**
+ * Create an USBEndpoint descriptor. Warning: the USBEndpoint is not linked.
+ *
+ * @param type USBEndpoint type (CONTROL_ENDPOINT, BULK_ENDPOINT, INTERRUPT_ENDPOINT)
+ * @param dir USBEndpoint direction (no meaning for CONTROL_ENDPOINT)
+ * @param size USBEndpoint max packet size
+ * @param addr USBEndpoint address
+ *
+ * @returns pointer on the USBEndpoint created
+ */
+ USBEndpoint * newEndpoint(ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir, uint32_t size, uint8_t addr) ;
+
+ /**
+ * Request the device descriptor
+ *
+ * @param dev request the device descriptor on this device
+ * @param buf buffer to store the device descriptor
+ * @param max_len_buf maximum size of buf
+ * @param len_dev_descr pointer to store the length of the packet transferred
+ */
+ USB_TYPE getDeviceDescriptor(USBDeviceConnected * dev, uint8_t * buf, uint16_t max_len_buf, uint16_t * len_dev_descr = NULL);
+
+ /**
+ * Request the configuration descriptor
+ *
+ * @param dev request the configuration descriptor on this device
+ * @param buf buffer to store the configuration descriptor
+ * @param max_len_buf maximum size of buf
+ * @param len_conf_descr pointer to store the length of the packet transferred
+ */
+ USB_TYPE getConfigurationDescriptor(USBDeviceConnected * dev, uint8_t * buf, uint16_t max_len_buf, uint16_t * len_conf_descr = NULL);
+
+ /**
+ * Set the address of a specific device
+ *
+ * @param dev device to set the address
+ * @param address address
+ */
+ USB_TYPE setAddress(USBDeviceConnected * dev, uint8_t address);
+
+ /**
+ * Set the configuration of a device
+ *
+ * @param dev device on which the specified configuration will be activated
+ * @param conf configuration number to activate (usually 1)
+ */
+ USB_TYPE setConfiguration(USBDeviceConnected * dev, uint8_t conf);
+
+ /**
+ * Free a specific device
+ *
+ * @param dev device to be freed
+ */
+ void freeDevice(USBDeviceConnected * dev);
+
+ USB_TYPE controlTransfer( USBDeviceConnected * dev,
+ uint8_t requestType,
+ uint8_t request,
+ uint32_t value,
+ uint32_t index,
+ uint8_t * buf,
+ uint32_t len,
+ bool write);
+
+ USB_TYPE generalTransfer( USBDeviceConnected * dev,
+ USBEndpoint * ep,
+ uint8_t * buf,
+ uint32_t len,
+ bool blocking,
+ ENDPOINT_TYPE type,
+ bool write) ;
+
+ void fillControlBuf(uint8_t requestType, uint8_t request, uint16_t value, uint16_t index, int len) ;
+ void parseConfDescr(USBDeviceConnected * dev, uint8_t * conf_descr, uint32_t len, IUSBEnumerator* pEnumerator) ;
+ int findDevice(USBDeviceConnected * dev) ;
+ int findDevice(uint8_t hub, uint8_t port, USBHostHub * hub_parent = NULL) ;
+ uint8_t numberDriverAttached(USBDeviceConnected * dev);
+
+ /////////////////////////
+ /// FOR DEBUG
+ /////////////////////////
+ void printList(ENDPOINT_TYPE type);
+
+};
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/USBHost/USBHostConf.h Wed Apr 15 06:23:18 2015 +0000 @@ -0,0 +1,91 @@ +/* mbed USBHost Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef USBHOST_CONF_H +#define USBHOST_CONF_H + +/* +* Maximum number of devices that can be connected +* to the usb host +*/ +#define MAX_DEVICE_CONNECTED 5 + +/* +* Maximum of Hub connected to the usb host +*/ +#define MAX_HUB_NB 2 + +/* +* Maximum number of ports on a USB hub +*/ +#define MAX_HUB_PORT 4 + +/* +* Enable USBHostMSD +*/ +#define USBHOST_MSD 1 + +/* +* Enable USBHostKeyboard +*/ +#define USBHOST_KEYBOARD 1 + +/* +* Enable USBHostMouse +*/ +#define USBHOST_MOUSE 1 + +/* +* Enable USBHostSerial or USBHostMultiSerial (if set > 1) +*/ +#define USBHOST_SERIAL 1 + +/* +* Enable USB3Gmodule +*/ +#define USBHOST_3GMODULE 1 + +/* +* Enable USB MIDI +*/ +#define USBHOST_MIDI 1 + +/* +* Maximum number of interfaces of a usb device +*/ +#define MAX_INTF 4 + +/* +* Maximum number of endpoints on each interface +*/ +#define MAX_ENDPOINT_PER_INTERFACE 3 + +/* +* Maximum number of endpoint descriptors that can be allocated +*/ +#define MAX_ENDPOINT (MAX_DEVICE_CONNECTED * MAX_INTF * MAX_ENDPOINT_PER_INTERFACE) + +/* +* Maximum number of transfer descriptors that can be allocated +*/ +#define MAX_TD (MAX_ENDPOINT*2) + +/* +* usb_thread stack size +*/ +#define USB_THREAD_STACK (256*4 + MAX_HUB_NB*256*4) + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHost/USBHostTypes.h Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,226 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef USB_INC_H
+#define USB_INC_H
+
+#include "mbed.h"
+#include "toolchain.h"
+
+enum USB_TYPE {
+ USB_TYPE_OK = 0,
+
+ // completion code
+ USB_TYPE_CRC_ERROR = 1,
+ USB_TYPE_BIT_STUFFING_ERROR = 2,
+ USB_TYPE_DATA_TOGGLE_MISMATCH_ERROR = 3,
+ USB_TYPE_STALL_ERROR = 4,
+ USB_TYPE_DEVICE_NOT_RESPONDING_ERROR = 5,
+ USB_TYPE_PID_CHECK_FAILURE_ERROR = 6,
+ USB_TYPE_UNEXPECTED_PID_ERROR = 7,
+ USB_TYPE_DATA_OVERRUN_ERROR = 8,
+ USB_TYPE_DATA_UNDERRUN_ERROR = 9,
+ USB_TYPE_RESERVED = 9,
+ USB_TYPE_RESERVED_ = 10,
+ USB_TYPE_BUFFER_OVERRUN_ERROR = 12,
+ USB_TYPE_BUFFER_UNDERRUN_ERROR = 13,
+
+ // general usb state
+ USB_TYPE_DISCONNECTED = 14,
+ USB_TYPE_FREE = 15,
+ USB_TYPE_IDLE = 16,
+ USB_TYPE_PROCESSING = 17,
+
+ USB_TYPE_ERROR = 18,
+};
+
+
+enum ENDPOINT_DIRECTION {
+ OUT = 1,
+ IN
+};
+
+enum ENDPOINT_TYPE {
+ CONTROL_ENDPOINT = 0,
+ ISOCHRONOUS_ENDPOINT,
+ BULK_ENDPOINT,
+ INTERRUPT_ENDPOINT
+};
+
+#define AUDIO_CLASS 0x01
+#define CDC_CLASS 0x02
+#define HID_CLASS 0x03
+#define MSD_CLASS 0x08
+#define HUB_CLASS 0x09
+#define SERIAL_CLASS 0x0A
+
+// ------------------ HcControl Register ---------------------
+#define OR_CONTROL_PLE 0x00000004
+#define OR_CONTROL_CLE 0x00000010
+#define OR_CONTROL_BLE 0x00000020
+#define OR_CONTROL_HCFS 0x000000C0
+#define OR_CONTROL_HC_OPER 0x00000080
+// ----------------- HcCommandStatus Register -----------------
+#define OR_CMD_STATUS_HCR 0x00000001
+#define OR_CMD_STATUS_CLF 0x00000002
+#define OR_CMD_STATUS_BLF 0x00000004
+// --------------- HcInterruptStatus Register -----------------
+#define OR_INTR_STATUS_WDH 0x00000002
+#define OR_INTR_STATUS_RHSC 0x00000040
+#define OR_INTR_STATUS_UE 0x00000010
+// --------------- HcInterruptEnable Register -----------------
+#define OR_INTR_ENABLE_WDH 0x00000002
+#define OR_INTR_ENABLE_RHSC 0x00000040
+#define OR_INTR_ENABLE_MIE 0x80000000
+// ---------------- HcRhDescriptorA Register ------------------
+#define OR_RH_STATUS_LPSC 0x00010000
+#define OR_RH_STATUS_DRWE 0x00008000
+// -------------- HcRhPortStatus[1:NDP] Register --------------
+#define OR_RH_PORT_CCS 0x00000001
+#define OR_RH_PORT_PRS 0x00000010
+#define OR_RH_PORT_CSC 0x00010000
+#define OR_RH_PORT_PRSC 0x00100000
+#define OR_RH_PORT_LSDA 0x00000200
+
+#define FI 0x2EDF // 12000 bits per frame (-1)
+#define DEFAULT_FMINTERVAL ((((6 * (FI - 210)) / 7) << 16) | FI)
+
+#define ED_SKIP (uint32_t) (0x00001000) // Skip this ep in queue
+
+#define TD_ROUNDING (uint32_t) (0x00040000) // Buffer Rounding
+#define TD_SETUP (uint32_t)(0) // Direction of Setup Packet
+#define TD_IN (uint32_t)(0x00100000) // Direction In
+#define TD_OUT (uint32_t)(0x00080000) // Direction Out
+#define TD_DELAY_INT(x) (uint32_t)((x) << 21) // Delay Interrupt
+#define TD_TOGGLE_0 (uint32_t)(0x02000000) // Toggle 0
+#define TD_TOGGLE_1 (uint32_t)(0x03000000) // Toggle 1
+#define TD_CC (uint32_t)(0xF0000000) // Completion Code
+
+#define DEVICE_DESCRIPTOR (1)
+#define CONFIGURATION_DESCRIPTOR (2)
+#define INTERFACE_DESCRIPTOR (4)
+#define ENDPOINT_DESCRIPTOR (5)
+#define HID_DESCRIPTOR (33)
+
+// ----------- Control RequestType Fields -----------
+#define USB_DEVICE_TO_HOST 0x80
+#define USB_HOST_TO_DEVICE 0x00
+#define USB_REQUEST_TYPE_CLASS 0x20
+#define USB_REQUEST_TYPE_STANDARD 0x00
+#define USB_RECIPIENT_DEVICE 0x00
+#define USB_RECIPIENT_INTERFACE 0x01
+#define USB_RECIPIENT_ENDPOINT 0x02
+
+// -------------- USB Standard Requests --------------
+#define SET_ADDRESS 0x05
+#define GET_DESCRIPTOR 0x06
+#define SET_CONFIGURATION 0x09
+#define SET_INTERFACE 0x0b
+#define CLEAR_FEATURE 0x01
+
+// -------------- USB Descriptor Length --------------
+#define DEVICE_DESCRIPTOR_LENGTH 0x12
+#define CONFIGURATION_DESCRIPTOR_LENGTH 0x09
+
+// ------------ HostController Transfer Descriptor ------------
+typedef struct HCTD {
+ __IO uint32_t control; // Transfer descriptor control
+ __IO uint8_t * currBufPtr; // Physical address of current buffer pointer
+ __IO HCTD * nextTD; // Physical pointer to next Transfer Descriptor
+ __IO uint8_t * bufEnd; // Physical address of end of buffer
+ void * ep; // ep address where a td is linked in
+ uint32_t dummy[3]; // padding
+} PACKED HCTD;
+
+// ----------- HostController EndPoint Descriptor -------------
+typedef struct hcEd {
+ __IO uint32_t control; // Endpoint descriptor control
+ __IO HCTD * tailTD; // Physical address of tail in Transfer descriptor list
+ __IO HCTD * headTD; // Physcial address of head in Transfer descriptor list
+ __IO hcEd * nextED; // Physical address of next Endpoint descriptor
+} PACKED HCED;
+
+
+// ----------- Host Controller Communication Area ------------
+typedef struct hcca {
+ __IO uint32_t IntTable[32]; // Interrupt Table
+ __IO uint32_t FrameNumber; // Frame Number
+ __IO uint32_t DoneHead; // Done Head
+ volatile uint8_t Reserved[116]; // Reserved for future use
+ volatile uint8_t Unknown[4]; // Unused
+} PACKED HCCA;
+
+typedef struct {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint16_t bcdUSB;
+ uint8_t bDeviceClass;
+ uint8_t bDeviceSubClass;
+ uint8_t bDeviceProtocol;
+ uint8_t bMaxPacketSize;
+ uint16_t idVendor;
+ uint16_t idProduct;
+ uint16_t bcdDevice;
+ uint8_t iManufacturer;
+ uint8_t iProduct;
+ uint8_t iSerialNumber;
+ uint8_t bNumConfigurations;
+} PACKED DeviceDescriptor;
+
+typedef struct {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint16_t wTotalLength;
+ uint8_t bNumInterfaces;
+ uint8_t bConfigurationValue;
+ uint8_t iConfiguration;
+ uint8_t bmAttributes;
+ uint8_t bMaxPower;
+} PACKED ConfigurationDescriptor;
+
+typedef struct {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bInterfaceNumber;
+ uint8_t bAlternateSetting;
+ uint8_t bNumEndpoints;
+ uint8_t bInterfaceClass;
+ uint8_t bInterfaceSubClass;
+ uint8_t bInterfaceProtocol;
+ uint8_t iInterface;
+} InterfaceDescriptor;
+
+typedef struct {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bEndpointAddress;
+ uint8_t bmAttributes;
+ uint16_t wMaxPacketSize;
+ uint8_t bInterval;
+} EndpointDescriptor;
+
+typedef struct {
+ uint8_t bDescLength;
+ uint8_t bDescriptorType;
+ uint8_t bNbrPorts;
+ uint16_t wHubCharacteristics;
+ uint8_t bPwrOn2PwrGood;
+ uint8_t bHubContrCurrent;
+ uint8_t DeviceRemovable;
+ uint8_t PortPweCtrlMak;
+} HubDescriptor;
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHost/dbg.h Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,66 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef USB_DEBUG_H
+#define USB_DEBUG_H
+
+//Debug is disabled by default
+#define DEBUG 0 /*INFO,ERR,WARN*/
+#define DEBUG_TRANSFER 0
+#define DEBUG_EP_STATE 0
+#define DEBUG_EVENT 0
+
+#if (DEBUG > 3)
+#define USB_DBG(x, ...) std::printf("[USB_DBG: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
+#else
+#define USB_DBG(x, ...)
+#endif
+
+#if (DEBUG > 2)
+#define USB_INFO(x, ...) std::printf("[USB_INFO: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
+#else
+#define USB_INFO(x, ...)
+#endif
+
+#if (DEBUG > 1)
+#define USB_WARN(x, ...) std::printf("[USB_WARNING: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
+#else
+#define USB_WARN(x, ...)
+#endif
+
+#if (DEBUG > 0)
+#define USB_ERR(x, ...) std::printf("[USB_ERR: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
+#else
+#define USB_ERR(x, ...)
+#endif
+
+#if (DEBUG_TRANSFER)
+#define USB_DBG_TRANSFER(x, ...) std::printf("[USB_TRANSFER: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
+#else
+#define USB_DBG_TRANSFER(x, ...)
+#endif
+
+#if (DEBUG_EVENT)
+#define USB_DBG_EVENT(x, ...) std::printf("[USB_EVENT: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
+#else
+#define USB_DBG_EVENT(x, ...)
+#endif
+
+
+#endif
+
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHost3GModule/IUSBHostSerial.h Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,95 @@
+/* IUSBHostSerial.h */
+/* Copyright (c) 2010-2012 mbed.org, MIT License
+*
+* 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 IUSBHOSTSERIAL_H_
+#define IUSBHOSTSERIAL_H_
+
+/**
+ * Generic interface to abstract 3G dongles' impl
+ */
+
+#include "USBHostConf.h"
+
+#ifdef USBHOST_3GMODULE
+
+#include "IUSBHostSerialListener.h"
+
+// This is needed by some versions of GCC
+#undef putc
+#undef getc
+
+class IUSBHostSerial {
+public:
+
+ enum IrqType {
+ RxIrq,
+ TxIrq
+ };
+
+ /*
+ * Get a char from the dongle's serial interface
+ */
+ virtual int getc() = 0;
+
+ /*
+ * Put a char to the dongle's serial interface
+ */
+ virtual int putc(int c) = 0;
+
+ /*
+ * Read a packet from the dongle's serial interface, to be called after multiple getc() calls
+ */
+ virtual int readPacket() = 0;
+
+ /*
+ * Write a packet to the dongle's serial interface, to be called after multiple putc() calls
+ */
+ virtual int writePacket() = 0;
+
+ /**
+ * Check the number of bytes available.
+ *
+ * @returns the number of bytes available
+ */
+ virtual int readable() = 0;
+
+ /**
+ * Check the free space in output.
+ *
+ * @returns the number of bytes available
+ */
+ virtual int writeable() = 0;
+
+ /**
+ * Attach a handler to call when a packet is received / when a packet has been transmitted.
+ *
+ * @param pListener instance of the listener deriving from the IUSBHostSerialListener
+ */
+ virtual void attach(IUSBHostSerialListener* pListener) = 0;
+
+ /**
+ * Enable or disable readable/writeable callbacks
+ */
+ virtual void setupIrq(bool en, IrqType irq = RxIrq) = 0;
+
+};
+
+#endif /* USBHOST_3GMODULE */
+
+#endif /* IUSBHOSTSERIAL_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHost3GModule/IUSBHostSerialListener.h Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,37 @@
+/* IUSBHostSerialListener.h */
+/* Copyright (c) 2010-2012 mbed.org, MIT License
+*
+* 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 IUSBHOSTSERIALLISTENER_H_
+#define IUSBHOSTSERIALLISTENER_H_
+
+#include "USBHostConf.h"
+
+#ifdef USBHOST_3GMODULE
+
+class IUSBHostSerialListener
+{
+public:
+ virtual void readable() = 0; //Called when new data is available
+ virtual void writeable() = 0; //Called when new space is available
+};
+
+#endif /* USBHOST_3GMODULE */
+
+#endif /* IUSBHOSTSERIALLISTENER_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHost3GModule/WANDongle.cpp Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,235 @@
+/* Copyright (c) 2010-2012 mbed.org, MIT License
+*
+* 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 "USBHostConf.h"
+
+#ifdef USBHOST_3GMODULE
+
+#include "dbg.h"
+#include <stdint.h>
+#include "rtos.h"
+
+#include "WANDongle.h"
+#include "WANDongleInitializer.h"
+
+WANDongle::WANDongle() : m_pInitializer(NULL), m_serialCount(0), m_totalInitializers(0)
+{
+ host = USBHost::getHostInst();
+ init();
+}
+
+
+bool WANDongle::connected() {
+ return dev_connected;
+}
+
+bool WANDongle::tryConnect()
+{
+ //FIXME should run on USB thread
+
+ USB_DBG("Trying to connect device");
+
+ if (dev_connected) {
+ USB_DBG("Device is already connected!");
+ return true;
+ }
+
+ m_pInitializer = NULL;
+
+ //Protect from concurrent access from USB thread
+ USBHost::Lock lock(host);
+
+ for (int i = 0; i < MAX_DEVICE_CONNECTED; i++)
+ {
+ if ((dev = host->getDevice(i)) != NULL)
+ {
+ m_pInitializer = NULL; //Will be set in setVidPid callback
+
+ USB_DBG("Enumerate");
+ int ret = host->enumerate(dev, this);
+ if(ret)
+ {
+ return false;
+ }
+
+ USB_DBG("Device has VID:%04x PID:%04x", dev->getVid(), dev->getPid());
+
+ if(m_pInitializer) //If an initializer has been found
+ {
+ USB_DBG("m_pInitializer=%p", m_pInitializer);
+ USB_DBG("m_pInitializer->getSerialVid()=%04x", m_pInitializer->getSerialVid());
+ USB_DBG("m_pInitializer->getSerialPid()=%04x", m_pInitializer->getSerialPid());
+ if ((dev->getVid() == m_pInitializer->getSerialVid()) && (dev->getPid() == m_pInitializer->getSerialPid()))
+ {
+ USB_DBG("The dongle is in virtual serial mode");
+ host->registerDriver(dev, 0, this, &WANDongle::init);
+ m_serialCount = m_pInitializer->getSerialPortCount();
+ if( m_serialCount > WANDONGLE_MAX_SERIAL_PORTS )
+ {
+ m_serialCount = WANDONGLE_MAX_SERIAL_PORTS;
+ }
+ for(int j = 0; j < m_serialCount; j++)
+ {
+ USB_DBG("Connecting serial port #%d", j+1);
+ USB_DBG("Ep %p", m_pInitializer->getEp(dev, j, false));
+ USB_DBG("Ep %p", m_pInitializer->getEp(dev, j, true));
+ m_serial[j].connect( dev, m_pInitializer->getEp(dev, j, false), m_pInitializer->getEp(dev, j, true) );
+ }
+
+ USB_DBG("Device connected");
+
+ dev_connected = true;
+
+
+ return true;
+ }
+ else if ((dev->getVid() == m_pInitializer->getMSDVid()) && (dev->getPid() == m_pInitializer->getMSDPid()))
+ {
+ USB_DBG("Vodafone K3370 dongle detected in MSD mode");
+ //Try to switch
+ if( m_pInitializer->switchMode(dev) )
+ {
+ USB_DBG("Switched OK");
+ return false; //Will be connected on a next iteration
+ }
+ else
+ {
+ USB_ERR("Could not switch mode");
+ return false;
+ }
+ }
+ } //if()
+ } //if()
+ } //for()
+ return false;
+}
+
+bool WANDongle::disconnect()
+{
+ dev_connected = false;
+ for(int i = 0; i < WANDONGLE_MAX_SERIAL_PORTS; i++)
+ {
+ m_serial[i].disconnect();
+ }
+ return true;
+}
+
+int WANDongle::getDongleType()
+{
+ if( m_pInitializer != NULL )
+ {
+ return m_pInitializer->getType();
+ }
+ else
+ {
+ return WAN_DONGLE_TYPE_UNKNOWN;
+ }
+}
+
+IUSBHostSerial& WANDongle::getSerial(int index)
+{
+ return m_serial[index];
+}
+
+int WANDongle::getSerialCount()
+{
+ return m_serialCount;
+}
+
+//Private methods
+void WANDongle::init()
+{
+ m_pInitializer = NULL;
+ dev_connected = false;
+ for(int i = 0; i < WANDONGLE_MAX_SERIAL_PORTS; i++)
+ {
+ m_serial[i].init(host);
+ }
+}
+
+
+/*virtual*/ void WANDongle::setVidPid(uint16_t vid, uint16_t pid)
+{
+ WANDongleInitializer* initializer;
+
+ for(int i = 0; i < m_totalInitializers; i++)
+ {
+ initializer = m_Initializers[i];
+ USB_DBG("initializer=%p", initializer);
+ USB_DBG("initializer->getSerialVid()=%04x", initializer->getSerialVid());
+ USB_DBG("initializer->getSerialPid()=%04x", initializer->getSerialPid());
+ if ((dev->getVid() == initializer->getSerialVid()) && (dev->getPid() == initializer->getSerialPid()))
+ {
+ USB_DBG("The dongle is in virtual serial mode");
+ m_pInitializer = initializer;
+ break;
+ }
+ else if ((dev->getVid() == initializer->getMSDVid()) && (dev->getPid() == initializer->getMSDPid()))
+ {
+ USB_DBG("Dongle detected in MSD mode");
+ m_pInitializer = initializer;
+ break;
+ }
+ initializer++;
+ } //for
+ if(m_pInitializer)
+ {
+ m_pInitializer->setVidPid(vid, pid);
+ }
+}
+
+/*virtual*/ bool WANDongle::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed
+{
+ if(m_pInitializer)
+ {
+ return m_pInitializer->parseInterface(intf_nb, intf_class, intf_subclass, intf_protocol);
+ }
+ else
+ {
+ return false;
+ }
+}
+
+/*virtual*/ bool WANDongle::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
+{
+ if(m_pInitializer)
+ {
+ return m_pInitializer->useEndpoint(intf_nb, type, dir);
+ }
+ else
+ {
+ return false;
+ }
+}
+
+
+bool WANDongle::addInitializer(WANDongleInitializer* pInitializer)
+{
+ if (m_totalInitializers >= WANDONGLE_MAX_INITIALIZERS)
+ return false;
+ m_Initializers[m_totalInitializers++] = pInitializer;
+ return true;
+}
+
+WANDongle::~WANDongle()
+{
+ for(int i = 0; i < m_totalInitializers; i++)
+ delete m_Initializers[i];
+}
+
+#endif /* USBHOST_3GMODULE */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHost3GModule/WANDongle.h Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,108 @@
+/* Copyright (c) 2010-2012 mbed.org, MIT License
+*
+* 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 WANDONGLE_H
+#define WANDONGLE_H
+
+#include "USBHostConf.h"
+
+#ifdef USBHOST_3GMODULE
+
+#include "USBHost.h"
+#include "IUSBHostSerial.h"
+
+#include "rtos.h"
+
+#include "WANDongleSerialPort.h"
+#include "WANDongleInitializer.h"
+#include "IUSBEnumerator.h"
+
+#define WANDONGLE_MAX_OUTEP_SIZE 64
+#define WANDONGLE_MAX_INEP_SIZE 64
+
+/** A class to use a WAN (3G/LTE) access dongle
+ *
+ */
+class WANDongle : public IUSBEnumerator {
+public:
+ /*
+ * Constructor
+ *
+ * @param rootdir mount name
+ */
+ WANDongle();
+
+ /*
+ * Destructor
+ */
+ virtual ~WANDongle();
+
+ /*
+ * Check if a serial port device is connected
+ *
+ * @return true if a serial device is connected
+ */
+ bool connected();
+
+ /*
+ * Try to connect device
+ *
+ * * @return true if connection was successful
+ */
+ bool tryConnect();
+
+ /*
+ * Disconnect device
+ *
+ * * @return true if disconnection was successful
+ */
+ bool disconnect();
+
+ int getDongleType();
+
+ IUSBHostSerial& getSerial(int index);
+ int getSerialCount();
+ bool addInitializer(WANDongleInitializer* pInitializer);
+
+ //From IUSBEnumerator
+
+ virtual void setVidPid(uint16_t vid, uint16_t pid);
+
+ virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed
+
+ virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used
+
+protected:
+ USBHost * host;
+ USBDeviceConnected * dev;
+ bool dev_connected;
+
+ WANDongleInitializer* m_pInitializer;
+
+ void init();
+
+ WANDongleSerialPort m_serial[WANDONGLE_MAX_SERIAL_PORTS];
+ int m_serialCount;
+
+ int m_totalInitializers;
+ WANDongleInitializer* m_Initializers[WANDONGLE_MAX_INITIALIZERS];
+};
+
+#endif /* USBHOST_3GMODULE */
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHost3GModule/WANDongleInitializer.h Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,73 @@
+/* Copyright (c) 2010-2012 mbed.org, MIT License
+*
+* 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 WANDONGLEINITIALIZER_H
+#define WANDONGLEINITIALIZER_H
+
+#include "USBHostConf.h"
+
+#ifdef USBHOST_3GMODULE
+
+#include <stdint.h>
+
+#include "USBHost.h"
+#include "IUSBEnumerator.h"
+
+// [TODO] move these declarations to a proper place
+#define WANDONGLE_MAX_SERIAL_PORTS 2
+#define WANDONGLE_MAX_INITIALIZERS 6
+
+#define WAN_DONGLE_TYPE_UNKNOWN (-1)
+
+class WANDongleInitializer : public IUSBEnumerator
+{
+protected:
+ WANDongleInitializer(USBHost* pHost) { m_pHost = pHost; }
+ USBHost* m_pHost;
+ uint8_t m_serialIntfMap[WANDONGLE_MAX_SERIAL_PORTS];
+
+public:
+ virtual ~WANDongleInitializer() {}
+ virtual uint16_t getMSDVid() = 0;
+ virtual uint16_t getMSDPid() = 0;
+
+ virtual uint16_t getSerialVid() = 0;
+ virtual uint16_t getSerialPid() = 0;
+
+ virtual bool switchMode(USBDeviceConnected* pDev) = 0;
+
+ virtual USBEndpoint* getEp(USBDeviceConnected* pDev, int serialPortNumber, bool tx) {
+ return pDev->getEndpoint(m_serialIntfMap[serialPortNumber], BULK_ENDPOINT, tx ? OUT : IN, 0);
+ }
+
+ virtual int getSerialPortCount() = 0;
+
+ virtual void setVidPid(uint16_t vid, uint16_t pid) = 0;
+
+ virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) = 0; //Must return true if the interface should be parsed
+
+ virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) = 0; //Must return true if the endpoint will be used
+
+ virtual int getType() = 0;
+
+ virtual uint8_t getSerialIntf(int index) { return m_serialIntfMap[index]; }
+};
+
+#endif /* USBHOST_3GMODULE */
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHost3GModule/WANDongleSerialPort.cpp Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,340 @@
+/* Copyright (c) 2010-2012 mbed.org, MIT License
+*
+* 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 "USBHostConf.h"
+
+#ifdef USBHOST_3GMODULE
+
+#define __DEBUG__ 0
+#ifndef __MODULE__
+#define __MODULE__ "WANDongleSerialPort.cpp"
+#endif
+
+#include "dbg.h"
+#include <stdint.h>
+#include "rtos.h"
+
+#include "WANDongleSerialPort.h"
+
+WANDongleSerialPort::WANDongleSerialPort() : cb_tx_en(false), cb_rx_en(false), listener(NULL)
+{
+ reset();
+}
+
+void WANDongleSerialPort::init(USBHost* pHost)
+{
+ host = pHost;
+}
+
+void WANDongleSerialPort::reset()
+{
+ tx_mtx.lock();
+ rx_mtx.lock();
+
+ bulk_in = NULL;
+ bulk_out = NULL;
+
+ buf_out_len = 0;
+ max_out_size = 0;
+ lock_tx = false;
+ cb_tx_pending = false;
+
+ buf_in_len = 0;
+ buf_in_read_pos = 0;
+ lock_rx = false;
+ cb_rx_pending = false;
+
+ tx_mtx.unlock();
+ rx_mtx.unlock();
+}
+
+int WANDongleSerialPort::readPacket()
+{
+ USB_DBG("Read packet on %p", this);
+ rx_mtx.lock();
+ if(lock_rx)
+ {
+ USB_ERR("Fail");
+ rx_mtx.unlock();
+ return -1;
+ }
+
+ if( bulk_in == NULL )
+ {
+ USB_WARN("Port is disconnected");
+ rx_mtx.unlock();
+ return -1;
+ }
+
+ lock_rx = true; //Receiving
+ rx_mtx.unlock();
+// USB_DBG("readPacket");
+ //lock_rx.lock();
+ USB_TYPE res = host->bulkRead(dev, (USBEndpoint *)bulk_in, buf_in, ((USBEndpoint *)bulk_in)->getSize(), false); //Queue transfer
+ if(res != USB_TYPE_PROCESSING)
+ {
+ //lock_rx.unlock();
+ USB_ERR("host->bulkRead() returned %d", res);
+ Thread::wait(100);
+ return -1;
+ }
+ return 0;
+}
+
+int WANDongleSerialPort::writePacket()
+{
+ tx_mtx.lock();
+ if(lock_tx)
+ {
+ USB_ERR("Fail");
+ tx_mtx.unlock();
+ return -1;
+ }
+
+ if( bulk_out == NULL )
+ {
+ USB_WARN("Port is disconnected");
+ tx_mtx.unlock();
+ return -1;
+ }
+
+ lock_tx = true; //Transmitting
+ tx_mtx.unlock();
+// USB_DBG("writePacket");
+
+ //lock_tx.lock();
+ USB_TYPE res = host->bulkWrite(dev, (USBEndpoint *)bulk_out, buf_out, buf_out_len, false); //Queue transfer
+ if(res != USB_TYPE_PROCESSING)
+ {
+ //lock_tx.unlock();
+ USB_ERR("host->bulkWrite() returned %d", res);
+ Thread::wait(100);
+ return -1;
+ }
+ return 0;
+}
+
+int WANDongleSerialPort::putc(int c)
+{
+ tx_mtx.lock();
+ if(!lock_tx)
+ {
+ if(buf_out_len < max_out_size)
+ {
+ buf_out[buf_out_len] = (uint8_t)c;
+ buf_out_len++;
+ }
+ }
+ else
+ {
+ USB_ERR("CAN'T WRITE!");
+ }
+ tx_mtx.unlock();
+ return c;
+}
+
+int WANDongleSerialPort::getc()
+{
+ rx_mtx.lock();
+ int c = 0;
+ if(!lock_rx)
+ {
+ if(buf_in_read_pos < buf_in_len)
+ {
+ c = (int)buf_in[buf_in_read_pos];
+ buf_in_read_pos++;
+ }
+ }
+ else
+ {
+ USB_ERR("CAN'T READ!");
+ }
+ rx_mtx.unlock();
+ return c;
+}
+
+int WANDongleSerialPort::readable()
+{
+ rx_mtx.lock();
+ if (lock_rx)
+ {
+ rx_mtx.unlock();
+ return 0;
+ }
+
+ /* if( !lock_rx.trylock() )
+ {
+ return 0;
+ }*/
+ int res = buf_in_len - buf_in_read_pos;
+ //lock_rx.unlock();
+ rx_mtx.unlock();
+ return res;
+}
+
+int WANDongleSerialPort::writeable()
+{
+ tx_mtx.lock();
+ if (lock_tx)
+ {
+ tx_mtx.unlock();
+ return 0;
+ }
+
+ /*if( !lock_tx.trylock() )
+ {
+ return 0;
+ }*/
+ int res = max_out_size - buf_out_len;
+ tx_mtx.unlock();
+ //lock_tx.unlock();
+ return res;
+}
+
+void WANDongleSerialPort::attach(IUSBHostSerialListener* pListener)
+{
+ if(pListener == NULL)
+ {
+ setupIrq(false, RxIrq);
+ setupIrq(false, TxIrq);
+ }
+ listener = pListener;
+ if(pListener != NULL)
+ {
+ setupIrq(true, RxIrq);
+ setupIrq(true, TxIrq);
+ }
+}
+
+void WANDongleSerialPort::setupIrq(bool en, IrqType irq /*= RxIrq*/)
+{
+ switch(irq)
+ {
+ case RxIrq:
+ rx_mtx.lock();
+ cb_rx_en = en;
+ if(en && cb_rx_pending)
+ {
+ cb_rx_pending = false;
+ rx_mtx.unlock();
+ listener->readable(); //Process the interrupt that was raised
+ }
+ else
+ {
+ rx_mtx.unlock();
+ }
+ break;
+ case TxIrq:
+ tx_mtx.lock();
+ cb_tx_en = en;
+ if(en && cb_tx_pending)
+ {
+ cb_tx_pending = false;
+ tx_mtx.unlock();
+ listener->writeable(); //Process the interrupt that was raised
+ }
+ else
+ {
+ tx_mtx.unlock();
+ }
+ break;
+ }
+}
+
+
+void WANDongleSerialPort::connect( USBDeviceConnected* pDev, USBEndpoint* pInEp, USBEndpoint* pOutEp )
+{
+ dev = pDev;
+ bulk_in = pInEp;
+ bulk_out = pOutEp;
+ max_out_size = bulk_out->getSize();
+ if( max_out_size > WANDONGLE_MAX_OUTEP_SIZE )
+ {
+ max_out_size = WANDONGLE_MAX_OUTEP_SIZE;
+ }
+ bulk_in->attach(this, &WANDongleSerialPort::rxHandler);
+ bulk_out->attach(this, &WANDongleSerialPort::txHandler);
+ readPacket(); //Start receiving data
+}
+
+void WANDongleSerialPort::disconnect( )
+{
+ reset();
+}
+
+//Private methods
+
+
+void WANDongleSerialPort::rxHandler()
+{
+ if (((USBEndpoint *) bulk_in)->getState() == USB_TYPE_IDLE) //Success
+ {
+ buf_in_read_pos = 0;
+ buf_in_len = ((USBEndpoint *) bulk_in)->getLengthTransferred(); //Update length
+ //lock_rx.unlock();
+ rx_mtx.lock();
+ lock_rx = false; //Transmission complete
+ if(cb_rx_en)
+ {
+ rx_mtx.unlock();
+ listener->readable(); //Call handler from the IRQ context
+ //readPacket() should be called by the handler subsequently once the buffer has been emptied
+ }
+ else
+ {
+ cb_rx_pending = true; //Queue the callback
+ rx_mtx.unlock();
+ }
+
+ }
+ else //Error, try reading again
+ {
+ //lock_rx.unlock();
+ USB_DBG("Trying again");
+ readPacket();
+ }
+}
+
+void WANDongleSerialPort::txHandler()
+{
+ if (((USBEndpoint *) bulk_out)->getState() == USB_TYPE_IDLE) //Success
+ {
+ tx_mtx.lock();
+ buf_out_len = 0; //Reset length
+ lock_tx = false; //Transmission complete
+ //lock_tx.unlock();
+ if(cb_tx_en)
+ {
+ tx_mtx.unlock();
+ listener->writeable(); //Call handler from the IRQ context
+ //writePacket() should be called by the handler subsequently once the buffer has been filled
+ }
+ else
+ {
+ cb_tx_pending = true; //Queue the callback
+ tx_mtx.unlock();
+ }
+ }
+ else //Error, try reading again
+ {
+ //lock_tx.unlock();
+ writePacket();
+ }
+}
+
+#endif /* USBHOST_3GMODULE */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHost3GModule/WANDongleSerialPort.h Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,133 @@
+/* Copyright (c) 2010-2012 mbed.org, MIT License
+*
+* 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 WANDONGLESERIALPORT_H
+#define WANDONGLESERIALPORT_H
+
+#include "USBHostConf.h"
+
+#ifdef USBHOST_3GMODULE
+
+#include "USBHost.h"
+#include "IUSBHostSerial.h"
+
+#include "rtos.h"
+
+
+#define WANDONGLE_MAX_OUTEP_SIZE 64
+#define WANDONGLE_MAX_INEP_SIZE 64
+
+/** A class to use a WAN (3G/LTE) access dongle
+ *
+ */
+class WANDongleSerialPort : public IUSBHostSerial {
+public:
+ /*
+ * Constructor
+ *
+ */
+ WANDongleSerialPort();
+
+ void init( USBHost* pHost );
+
+ void connect( USBDeviceConnected* pDev, USBEndpoint* pInEp, USBEndpoint* pOutEp );
+
+ void disconnect( );
+
+ /*
+ * Get a char from the dongle's serial interface
+ */
+ virtual int getc();
+
+ /*
+ * Put a char to the dongle's serial interface
+ */
+ virtual int putc(int c);
+
+ /*
+ * Read a packet from the dongle's serial interface, to be called after multiple getc() calls
+ */
+ virtual int readPacket();
+
+ /*
+ * Write a packet to the dongle's serial interface, to be called after multiple putc() calls
+ */
+ virtual int writePacket();
+
+ /**
+ * Check the number of bytes available.
+ *
+ * @returns the number of bytes available
+ */
+ virtual int readable();
+
+ /**
+ * Check the free space in output.
+ *
+ * @returns the number of bytes available
+ */
+ virtual int writeable();
+
+ /**
+ * Attach a handler to call when a packet is received / when a packet has been transmitted.
+ *
+ * @param pListener instance of the listener deriving from the IUSBHostSerialListener
+ */
+ virtual void attach(IUSBHostSerialListener* pListener);
+
+ /**
+ * Enable or disable readable/writeable callbacks
+ */
+ virtual void setupIrq(bool en, IrqType irq = RxIrq);
+
+
+protected:
+ USBEndpoint * bulk_in;
+ USBEndpoint * bulk_out;
+ USBHost * host;
+ USBDeviceConnected * dev;
+
+ uint8_t buf_out[WANDONGLE_MAX_OUTEP_SIZE];
+ volatile uint32_t buf_out_len;
+ uint32_t max_out_size;
+ volatile bool lock_tx;
+ volatile bool cb_tx_en;
+ volatile bool cb_tx_pending;
+ Mutex tx_mtx;
+
+ uint8_t buf_in[WANDONGLE_MAX_INEP_SIZE];
+ volatile uint32_t buf_in_len;
+ volatile uint32_t buf_in_read_pos;
+ volatile bool lock_rx;
+ volatile bool cb_rx_en;
+ volatile bool cb_rx_pending;
+ Mutex rx_mtx;
+
+ IUSBHostSerialListener* listener;
+
+ void reset();
+
+ void rxHandler();
+ void txHandler();
+
+};
+
+#endif /* USBHOST_3GMODULE */
+
+#endif
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHostHID/USBHostKeyboard.cpp Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,184 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "USBHostKeyboard.h"
+
+#if USBHOST_KEYBOARD
+
+static uint8_t keymap[4][0x39] = {
+ { 0, 0, 0, 0, 'a', 'b' /*0x05*/,
+ 'c', 'd', 'e', 'f', 'g' /*0x0a*/,
+ 'h', 'i', 'j', 'k', 'l'/*0x0f*/,
+ 'm', 'n', 'o', 'p', 'q'/*0x14*/,
+ 'r', 's', 't', 'u', 'v'/*0x19*/,
+ 'w', 'x', 'y', 'z', '1'/*0x1E*/,
+ '2', '3', '4', '5', '6'/*0x23*/,
+ '7', '8', '9', '0', 0x0A /*enter*/, /*0x28*/
+ 0x1B /*escape*/, 0x08 /*backspace*/, 0x09/*tab*/, 0x20/*space*/, '-', /*0x2d*/
+ '=', '[', ']', '\\', '#', /*0x32*/
+ ';', '\'', 0, ',', '.', /*0x37*/
+ '/'},
+
+ /* CTRL MODIFIER */
+ { 0, 0, 0, 0, 0, 0 /*0x05*/,
+ 0, 0, 0, 0, 0 /*0x0a*/,
+ 0, 0, 0, 0, 0/*0x0f*/,
+ 0, 0, 0, 0, 0/*0x14*/,
+ 0, 0, 0, 0, 0/*0x19*/,
+ 0, 0, 0, 0, 0/*0x1E*/,
+ 0, 0, 0, 0, 0/*0x23*/,
+ 0, 0, 0, 0, 0 /*enter*/, /*0x28*/
+ 0, 0, 0, 0, 0, /*0x2d*/
+ 0, 0, 0, 0, 0, /*0x32*/
+ 0, 0, 0, 0, 0, /*0x37*/
+ 0},
+
+ /* SHIFT MODIFIER */
+ { 0, 0, 0, 0, 'A', 'B' /*0x05*/,
+ 'C', 'D', 'E', 'F', 'G' /*0x0a*/,
+ 'H', 'I', 'J', 'K', 'L'/*0x0f*/,
+ 'M', 'N', 'O', 'P', 'Q'/*0x14*/,
+ 'R', 'S', 'T', 'U', 'V'/*0x19*/,
+ 'W', 'X', 'Y', 'Z', '!'/*0x1E*/,
+ '@', '#', '$', '%', '^'/*0x23*/,
+ '&', '*', '(', ')', 0, /*0x28*/
+ 0, 0, 0, 0, 0, /*0x2d*/
+ '+', '{', '}', '|', '~', /*0x32*/
+ ':', '"', 0, '<', '>', /*0x37*/
+ '?'},
+
+ /* ALT MODIFIER */
+ { 0, 0, 0, 0, 0, 0 /*0x05*/,
+ 0, 0, 0, 0, 0 /*0x0a*/,
+ 0, 0, 0, 0, 0/*0x0f*/,
+ 0, 0, 0, 0, 0/*0x14*/,
+ 0, 0, 0, 0, 0/*0x19*/,
+ 0, 0, 0, 0, 0/*0x1E*/,
+ 0, 0, 0, 0, 0/*0x23*/,
+ 0, 0, 0, 0, 0 /*enter*/, /*0x28*/
+ 0, 0, 0, 0, 0, /*0x2d*/
+ 0, 0, 0, 0, 0, /*0x32*/
+ 0, 0, 0, 0, 0, /*0x37*/
+ 0}
+
+};
+
+
+USBHostKeyboard::USBHostKeyboard() {
+ host = USBHost::getHostInst();
+ init();
+}
+
+
+void USBHostKeyboard::init() {
+ dev = NULL;
+ int_in = NULL;
+ report_id = 0;
+ onKey = NULL;
+ onKeyCode = NULL;
+ dev_connected = false;
+ keyboard_intf = -1;
+ keyboard_device_found = false;
+}
+
+bool USBHostKeyboard::connected() {
+ return dev_connected;
+}
+
+
+bool USBHostKeyboard::connect() {
+
+ if (dev_connected) {
+ return true;
+ }
+
+ for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) {
+ if ((dev = host->getDevice(i)) != NULL) {
+
+ if (host->enumerate(dev, this))
+ break;
+
+ if (keyboard_device_found) {
+ int_in = dev->getEndpoint(keyboard_intf, INTERRUPT_ENDPOINT, IN);
+
+ if (!int_in)
+ break;
+
+ USB_INFO("New Keyboard device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, keyboard_intf);
+ dev->setName("Keyboard", keyboard_intf);
+ host->registerDriver(dev, keyboard_intf, this, &USBHostKeyboard::init);
+
+ int_in->attach(this, &USBHostKeyboard::rxHandler);
+ host->interruptRead(dev, int_in, report, int_in->getSize(), false);
+
+ dev_connected = true;
+ return true;
+ }
+ }
+ }
+ init();
+ return false;
+}
+
+void USBHostKeyboard::rxHandler() {
+ int len = int_in->getLengthTransferred();
+ int index = (len == 9) ? 1 : 0;
+ int len_listen = int_in->getSize();
+ uint8_t key = 0;
+ if (len == 8 || len == 9) {
+ uint8_t modifier = (report[index] == 4) ? 3 : report[index];
+ len_listen = len;
+ key = keymap[modifier][report[index + 2]];
+ if (key && onKey) {
+ (*onKey)(key);
+ }
+ if ((report[index + 2] || modifier) && onKeyCode) {
+ (*onKeyCode)(report[index + 2], modifier);
+ }
+ }
+ if (dev && int_in)
+ host->interruptRead(dev, int_in, report, len_listen, false);
+}
+
+/*virtual*/ void USBHostKeyboard::setVidPid(uint16_t vid, uint16_t pid)
+{
+ // we don't check VID/PID for keyboard driver
+}
+
+/*virtual*/ bool USBHostKeyboard::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed
+{
+ if ((keyboard_intf == -1) &&
+ (intf_class == HID_CLASS) &&
+ (intf_subclass == 0x01) &&
+ (intf_protocol == 0x01)) {
+ keyboard_intf = intf_nb;
+ return true;
+ }
+ return false;
+}
+
+/*virtual*/ bool USBHostKeyboard::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
+{
+ if (intf_nb == keyboard_intf) {
+ if (type == INTERRUPT_ENDPOINT && dir == IN) {
+ keyboard_device_found = true;
+ return true;
+ }
+ }
+ return false;
+}
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHostHID/USBHostKeyboard.h Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,102 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef USBHOSTKEYBOARD_H
+#define USBHOSTKEYBOARD_H
+
+#include "USBHostConf.h"
+
+#if USBHOST_KEYBOARD
+
+#include "USBHost.h"
+
+/**
+ * A class to communicate a USB keyboard
+ */
+class USBHostKeyboard : public IUSBEnumerator {
+public:
+
+ /**
+ * Constructor
+ */
+ USBHostKeyboard();
+
+ /**
+ * Try to connect a keyboard device
+ *
+ * @return true if connection was successful
+ */
+ bool connect();
+
+ /**
+ * Check if a keyboard is connected
+ *
+ * @returns true if a keyboard is connected
+ */
+ bool connected();
+
+ /**
+ * Attach a callback called when a keyboard event is received
+ *
+ * @param ptr function pointer
+ */
+ inline void attach(void (*ptr)(uint8_t key)) {
+ if (ptr != NULL) {
+ onKey = ptr;
+ }
+ }
+
+ /**
+ * Attach a callback called when a keyboard event is received
+ *
+ * @param ptr function pointer
+ */
+ inline void attach(void (*ptr)(uint8_t keyCode, uint8_t modifier)) {
+ if (ptr != NULL) {
+ onKeyCode = ptr;
+ }
+ }
+
+protected:
+ //From IUSBEnumerator
+ virtual void setVidPid(uint16_t vid, uint16_t pid);
+ virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed
+ virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used
+
+private:
+ USBHost * host;
+ USBDeviceConnected * dev;
+ USBEndpoint * int_in;
+ uint8_t report[9];
+ int keyboard_intf;
+ bool keyboard_device_found;
+
+ bool dev_connected;
+
+ void rxHandler();
+
+ void (*onKey)(uint8_t key);
+ void (*onKeyCode)(uint8_t key, uint8_t modifier);
+
+ int report_id;
+
+ void init();
+
+};
+
+#endif
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHostHID/USBHostMouse.cpp Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,153 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "USBHostMouse.h"
+
+#if USBHOST_MOUSE
+
+USBHostMouse::USBHostMouse() {
+ host = USBHost::getHostInst();
+ init();
+}
+
+void USBHostMouse::init() {
+ dev = NULL;
+ int_in = NULL;
+ onUpdate = NULL;
+ onButtonUpdate = NULL;
+ onXUpdate = NULL;
+ onYUpdate = NULL;
+ onZUpdate = NULL;
+ report_id = 0;
+ dev_connected = false;
+ mouse_device_found = false;
+ mouse_intf = -1;
+
+ buttons = 0;
+ x = 0;
+ y = 0;
+ z = 0;
+}
+
+bool USBHostMouse::connected() {
+ return dev_connected;
+}
+
+bool USBHostMouse::connect() {
+ int len_listen;
+
+ if (dev_connected) {
+ return true;
+ }
+
+ for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) {
+ if ((dev = host->getDevice(i)) != NULL) {
+
+ if(host->enumerate(dev, this))
+ break;
+
+ if (mouse_device_found) {
+
+ int_in = dev->getEndpoint(mouse_intf, INTERRUPT_ENDPOINT, IN);
+ if (!int_in)
+ break;
+
+ USB_INFO("New Mouse device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, mouse_intf);
+ dev->setName("Mouse", mouse_intf);
+ host->registerDriver(dev, mouse_intf, this, &USBHostMouse::init);
+
+ int_in->attach(this, &USBHostMouse::rxHandler);
+ len_listen = int_in->getSize();
+ if (len_listen > sizeof(report)) {
+ len_listen = sizeof(report);
+ }
+ host->interruptRead(dev, int_in, report, len_listen, false);
+
+ dev_connected = true;
+ return true;
+ }
+ }
+ }
+ init();
+ return false;
+}
+
+void USBHostMouse::rxHandler() {
+ int len_listen = int_in->getSize();
+
+ if (onUpdate) {
+ (*onUpdate)(report[0] & 0x07, report[1], report[2], report[3]);
+ }
+
+ if (onButtonUpdate && (buttons != (report[0] & 0x07))) {
+ (*onButtonUpdate)(report[0] & 0x07);
+ }
+
+ if (onXUpdate && (x != report[1])) {
+ (*onXUpdate)(report[1]);
+ }
+
+ if (onYUpdate && (y != report[2])) {
+ (*onYUpdate)(report[2]);
+ }
+
+ if (onZUpdate && (z != report[3])) {
+ (*onZUpdate)(report[3]);
+ }
+
+ // update mouse state
+ buttons = report[0] & 0x07;
+ x = report[1];
+ y = report[2];
+ z = report[3];
+
+ if (len_listen > sizeof(report)) {
+ len_listen = sizeof(report);
+ }
+
+ if (dev)
+ host->interruptRead(dev, int_in, report, len_listen, false);
+}
+
+/*virtual*/ void USBHostMouse::setVidPid(uint16_t vid, uint16_t pid)
+{
+ // we don't check VID/PID for mouse driver
+}
+
+/*virtual*/ bool USBHostMouse::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed
+{
+ if ((mouse_intf == -1) &&
+ (intf_class == HID_CLASS) &&
+ (intf_subclass == 0x01) &&
+ (intf_protocol == 0x02)) {
+ mouse_intf = intf_nb;
+ return true;
+ }
+ return false;
+}
+
+/*virtual*/ bool USBHostMouse::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
+{
+ if (intf_nb == mouse_intf) {
+ if (type == INTERRUPT_ENDPOINT && dir == IN) {
+ mouse_device_found = true;
+ return true;
+ }
+ }
+ return false;
+}
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHostHID/USBHostMouse.h Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,139 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef USBHOSTMOUSE_H
+#define USBHOSTMOUSE_H
+
+#include "USBHostConf.h"
+
+#if USBHOST_MOUSE
+
+#include "USBHost.h"
+
+/**
+ * A class to communicate a USB mouse
+ */
+class USBHostMouse : public IUSBEnumerator {
+public:
+
+ /**
+ * Constructor
+ */
+ USBHostMouse();
+
+ /**
+ * Try to connect a mouse device
+ *
+ * @return true if connection was successful
+ */
+ bool connect();
+
+ /**
+ * Check if a mouse is connected
+ *
+ * @returns true if a mouse is connected
+ */
+ bool connected();
+
+ /**
+ * Attach a callback called when a mouse event is received
+ *
+ * @param ptr function pointer
+ */
+ inline void attachEvent(void (*ptr)(uint8_t buttons, int8_t x, int8_t y, int8_t z)) {
+ if (ptr != NULL) {
+ onUpdate = ptr;
+ }
+ }
+
+ /**
+ * Attach a callback called when the button state changes
+ *
+ * @param ptr function pointer
+ */
+ inline void attachButtonEvent(void (*ptr)(uint8_t buttons)) {
+ if (ptr != NULL) {
+ onButtonUpdate = ptr;
+ }
+ }
+
+ /**
+ * Attach a callback called when the X axis value changes
+ *
+ * @param ptr function pointer
+ */
+ inline void attachXEvent(void (*ptr)(int8_t x)) {
+ if (ptr != NULL) {
+ onXUpdate = ptr;
+ }
+ }
+
+ /**
+ * Attach a callback called when the Y axis value changes
+ *
+ * @param ptr function pointer
+ */
+ inline void attachYEvent(void (*ptr)(int8_t y)) {
+ if (ptr != NULL) {
+ onYUpdate = ptr;
+ }
+ }
+
+ /**
+ * Attach a callback called when the Z axis value changes (scrolling)
+ *
+ * @param ptr function pointer
+ */
+ inline void attachZEvent(void (*ptr)(int8_t z)) {
+ if (ptr != NULL) {
+ onZUpdate = ptr;
+ }
+ }
+
+protected:
+ //From IUSBEnumerator
+ virtual void setVidPid(uint16_t vid, uint16_t pid);
+ virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed
+ virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used
+
+private:
+ USBHost * host;
+ USBDeviceConnected * dev;
+ USBEndpoint * int_in;
+ uint8_t report[4];
+
+ bool dev_connected;
+ bool mouse_device_found;
+ int mouse_intf;
+
+ uint8_t buttons;
+ int8_t x;
+ int8_t y;
+ int8_t z;
+
+ void rxHandler();
+ void (*onUpdate)(uint8_t buttons, int8_t x, int8_t y, int8_t z);
+ void (*onButtonUpdate)(uint8_t buttons);
+ void (*onXUpdate)(int8_t x);
+ void (*onYUpdate)(int8_t y);
+ void (*onZUpdate)(int8_t z);
+ int report_id;
+ void init();
+};
+
+#endif
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHostHub/USBHostHub.cpp Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,274 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "USBHostHub.h"
+
+#if MAX_HUB_NB
+
+#include "USBHost.h"
+#include "dbg.h"
+
+#define GET_STATUS 0x00
+#define CLEAR_FEATURE 0x01
+#define GET_STATE 0x02
+#define SET_FEATURE 0x03
+#define GET_DESCRIPTOR 0x06
+
+#define PORT_CONNECTION_FEATURE (0x00)
+#define PORT_ENABLE_FEATURE (0x01)
+#define PORT_RESET_FEATURE (0x04)
+#define PORT_POWER_FEATURE (0x08)
+
+#define C_PORT_CONNECTION_FEATURE (16)
+#define C_PORT_ENABLE_FEATURE (17)
+#define C_PORT_RESET_FEATURE (20)
+
+#define PORT_CONNECTION (1 << 0)
+#define PORT_ENABLE (1 << 1)
+#define PORT_SUSPEND (1 << 2)
+#define PORT_OVER_CURRENT (1 << 3)
+#define PORT_RESET (1 << 4)
+#define PORT_POWER (1 << 8)
+#define PORT_LOW_SPEED (1 << 9)
+
+#define C_PORT_CONNECTION (1 << 16)
+#define C_PORT_ENABLE (1 << 17)
+#define C_PORT_SUSPEND (1 << 18)
+#define C_PORT_OVER_CURRENT (1 << 19)
+#define C_PORT_RESET (1 << 20)
+
+USBHostHub::USBHostHub() {
+ host = NULL;
+ init();
+}
+
+void USBHostHub::init() {
+ dev_connected = false;
+ dev = NULL;
+ int_in = NULL;
+ dev_connected = false;
+ hub_intf = -1;
+ hub_device_found = false;
+ nb_port = 0;
+ hub_characteristics = 0;
+
+ for (int i = 0; i < MAX_HUB_PORT; i++) {
+ device_children[i] = NULL;
+ }
+}
+
+void USBHostHub::setHost(USBHost * host_) {
+ host = host_;
+}
+
+bool USBHostHub::connected()
+{
+ return dev_connected;
+}
+
+bool USBHostHub::connect(USBDeviceConnected * dev)
+{
+ if (dev_connected) {
+ return true;
+ }
+
+ if(host->enumerate(dev, this)) {
+ init();
+ return false;
+ }
+
+ if (hub_device_found) {
+ this->dev = dev;
+
+ int_in = dev->getEndpoint(hub_intf, INTERRUPT_ENDPOINT, IN);
+
+ if (!int_in) {
+ init();
+ return false;
+ }
+
+ USB_INFO("New HUB: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, hub_intf);
+ dev->setName("Hub", hub_intf);
+ host->registerDriver(dev, hub_intf, this, &USBHostHub::disconnect);
+
+ int_in->attach(this, &USBHostHub::rxHandler);
+
+ // get HUB descriptor
+ host->controlRead( dev,
+ USB_DEVICE_TO_HOST | USB_REQUEST_TYPE_CLASS,
+ GET_DESCRIPTOR,
+ 0x29 << 8, 0, buf, sizeof(HubDescriptor));
+ nb_port = buf[2];
+ hub_characteristics = buf[3];
+
+ USB_DBG("Hub has %d port", nb_port);
+
+ for (uint8_t j = 1; j <= nb_port; j++) {
+ setPortFeature(PORT_POWER_FEATURE, j);
+ }
+ wait_ms(buf[5]*2);
+
+ host->interruptRead(dev, int_in, buf, 1, false);
+ dev_connected = true;
+ return true;
+ }
+
+ return false;
+}
+
+void USBHostHub::disconnect() {
+ init();
+}
+
+/*virtual*/ void USBHostHub::setVidPid(uint16_t vid, uint16_t pid)
+{
+ // we don't check VID/PID for MSD driver
+}
+
+/*virtual*/ bool USBHostHub::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed
+{
+ if ((hub_intf == -1) &&
+ (intf_class == HUB_CLASS) &&
+ (intf_subclass == 0) &&
+ (intf_protocol == 0)) {
+ hub_intf = intf_nb;
+ return true;
+ }
+ return false;
+}
+
+/*virtual*/ bool USBHostHub::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
+{
+ if (intf_nb == hub_intf) {
+ if ((type == INTERRUPT_ENDPOINT) && (dir == IN)) {
+ hub_device_found = true;
+ return true;
+ }
+ }
+ return false;
+}
+
+void USBHostHub::deviceConnected(USBDeviceConnected * dev) {
+ device_children[dev->getPort() - 1] = dev;
+}
+
+void USBHostHub::deviceDisconnected(USBDeviceConnected * dev) {
+ device_children[dev->getPort() - 1] = NULL;
+}
+
+void USBHostHub::hubDisconnected() {
+ for (uint8_t i = 0; i < MAX_HUB_PORT; i++) {
+ if (device_children[i] != NULL) {
+ host->freeDevice(device_children[i]);
+ }
+ }
+}
+
+void USBHostHub::rxHandler() {
+ uint32_t status;
+ if (int_in) {
+ if (int_in->getState() == USB_TYPE_IDLE) {
+ for (int port = 1; port <= nb_port; port++) {
+ status = getPortStatus(port);
+ USB_DBG("[hub handler hub: %d] status port %d [hub: %p]: 0x%X", dev->getHub(), port, dev, status);
+
+ // if connection status has changed
+ if (status & C_PORT_CONNECTION) {
+ if (status & PORT_CONNECTION) {
+ USB_DBG("[hub handler hub: %d - port: %d] new device connected", dev->getHub(), port);
+ host->deviceConnected(dev->getHub() + 1, port, status & PORT_LOW_SPEED, this);
+ } else {
+ USB_DBG("[hub handler hub: %d - port: %d] device disconnected", dev->getHub(), port);
+ host->deviceDisconnected(dev->getHub() + 1, port, this, 0);
+ }
+
+ clearPortFeature(C_PORT_CONNECTION_FEATURE, port);
+ }
+
+ if (status & C_PORT_RESET) {
+ clearPortFeature(C_PORT_RESET_FEATURE, port);
+ }
+
+ if (status & C_PORT_ENABLE) {
+ clearPortFeature(C_PORT_ENABLE_FEATURE, port);
+ }
+
+ if ((status & PORT_OVER_CURRENT)) {
+ USB_ERR("OVER CURRENT DETECTED\r\n");
+ clearPortFeature(PORT_OVER_CURRENT, port);
+ host->deviceDisconnected(dev->getHub() + 1, port, this, 0);
+ }
+ }
+ }
+ host->interruptRead(dev, int_in, buf, 1, false);
+ }
+}
+
+void USBHostHub::portReset(uint8_t port) {
+ // reset port
+ uint32_t status;
+ USB_DBG("reset port %d on hub: %p [this: %p]", port, dev, this)
+ setPortFeature(PORT_RESET_FEATURE, port);
+#if defined(TARGET_RZ_A1H)
+ Thread::wait(50); // Reset release waiting for Hi-Speed check.
+#endif
+ while(1) {
+ status = getPortStatus(port);
+ if (status & (PORT_ENABLE | PORT_RESET))
+ break;
+ if (status & PORT_OVER_CURRENT) {
+ USB_ERR("OVER CURRENT DETECTED\r\n");
+ clearPortFeature(PORT_OVER_CURRENT, port);
+ host->deviceDisconnected(dev->getHub() + 1, port, this, 0);
+ break;
+ }
+ Thread::wait(10);
+ }
+}
+
+void USBHostHub::setPortFeature(uint32_t feature, uint8_t port) {
+ host->controlWrite( dev,
+ USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_CLASS | USB_RECIPIENT_INTERFACE | USB_RECIPIENT_ENDPOINT,
+ SET_FEATURE,
+ feature,
+ port,
+ NULL,
+ 0);
+}
+
+void USBHostHub::clearPortFeature(uint32_t feature, uint8_t port) {
+ host->controlWrite( dev,
+ USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_CLASS | USB_RECIPIENT_INTERFACE | USB_RECIPIENT_ENDPOINT,
+ CLEAR_FEATURE,
+ feature,
+ port,
+ NULL,
+ 0);
+}
+
+uint32_t USBHostHub::getPortStatus(uint8_t port) {
+ uint32_t st;
+ host->controlRead( dev,
+ USB_DEVICE_TO_HOST | USB_REQUEST_TYPE_CLASS | USB_RECIPIENT_INTERFACE | USB_RECIPIENT_ENDPOINT,
+ GET_STATUS,
+ 0,
+ port,
+ (uint8_t *)&st,
+ 4);
+ return st;
+}
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHostHub/USBHostHub.h Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,125 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef USBHOSTHUB_H
+#define USBHOSTHUB_H
+
+#include "USBHostConf.h"
+
+#if MAX_HUB_NB
+
+#include "USBHostTypes.h"
+#include "IUSBEnumerator.h"
+
+class USBHost;
+class USBDeviceConnected;
+class USBEndpoint;
+
+/**
+ * A class to use a USB Hub
+ */
+class USBHostHub : public IUSBEnumerator {
+public:
+ /**
+ * Constructor
+ */
+ USBHostHub();
+
+ /**
+ * Check if a USB Hub is connected
+ *
+ * @return true if a serial device is connected
+ */
+ bool connected();
+
+ /**
+ * Try to connect device
+ *
+ * @param dev device to connect
+ * @return true if connection was successful
+ */
+ bool connect(USBDeviceConnected * dev);
+
+ /**
+ * Automatically called by USBHost when a device
+ * has been enumerated by usb_thread
+ *
+ * @param dev device connected
+ */
+ void deviceConnected(USBDeviceConnected * dev);
+
+ /**
+ * Automatically called by USBHost when a device
+ * has been disconnected from this hub
+ *
+ * @param dev device disconnected
+ */
+ void deviceDisconnected(USBDeviceConnected * dev);
+
+ /**
+ * Rest a specific port
+ *
+ * @param port port number
+ */
+ void portReset(uint8_t port);
+
+ /*
+ * Called by USBHost to set the instance of USBHost
+ *
+ * @param host host instance
+ */
+ void setHost(USBHost * host);
+
+ /**
+ * Called by USBhost when a hub has been disconnected
+ */
+ void hubDisconnected();
+
+protected:
+ //From IUSBEnumerator
+ virtual void setVidPid(uint16_t vid, uint16_t pid);
+ virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed
+ virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used
+
+private:
+ USBHost * host;
+ USBDeviceConnected * dev;
+ bool dev_connected;
+ USBEndpoint * int_in;
+ uint8_t nb_port;
+ uint8_t hub_characteristics;
+
+ void rxHandler();
+
+ uint8_t buf[sizeof(HubDescriptor)];
+
+ int hub_intf;
+ bool hub_device_found;
+
+ void setPortFeature(uint32_t feature, uint8_t port);
+ void clearPortFeature(uint32_t feature, uint8_t port);
+ uint32_t getPortStatus(uint8_t port);
+
+ USBDeviceConnected * device_children[MAX_HUB_PORT];
+
+ void init();
+ void disconnect();
+
+};
+
+#endif
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHostMIDI/USBHostMIDI.cpp Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,362 @@
+/* Copyright (c) 2014 mbed.org, MIT License
+ *
+ * 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 "USBHostMIDI.h"
+
+#if USBHOST_MIDI
+
+#include "dbg.h"
+
+#define SET_LINE_CODING 0x20
+
+USBHostMIDI::USBHostMIDI() {
+ host = USBHost::getHostInst();
+ size_bulk_in = 0;
+ size_bulk_out = 0;
+ init();
+}
+
+void USBHostMIDI::init() {
+ dev = NULL;
+ bulk_in = NULL;
+ bulk_out = NULL;
+ dev_connected = false;
+ midi_intf = -1;
+ midi_device_found = false;
+ sysExBufferPos = 0;
+}
+
+bool USBHostMIDI::connected() {
+ return dev_connected;
+}
+
+bool USBHostMIDI::connect() {
+ if (dev_connected) {
+ return true;
+ }
+
+ for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) {
+ if ((dev = host->getDevice(i)) != NULL) {
+
+ USB_DBG("Trying to connect MIDI device\r\n");
+
+ if (host->enumerate(dev, this)) {
+ break;
+ }
+
+ if (midi_device_found) {
+ bulk_in = dev->getEndpoint(midi_intf, BULK_ENDPOINT, IN);
+ bulk_out = dev->getEndpoint(midi_intf, BULK_ENDPOINT, OUT);
+
+ if (!bulk_in || !bulk_out) {
+ break;
+ }
+
+ USB_INFO("New MIDI device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, midi_intf);
+ dev->setName("MIDI", midi_intf);
+ host->registerDriver(dev, midi_intf, this, &USBHostMIDI::init);
+
+ size_bulk_in = bulk_in->getSize();
+ size_bulk_out = bulk_out->getSize();
+
+ bulk_in->attach(this, &USBHostMIDI::rxHandler);
+
+ host->bulkRead(dev, bulk_in, buf, size_bulk_in, false);
+ dev_connected = true;
+ return true;
+ }
+ }
+ }
+
+ init();
+ return false;
+}
+
+void USBHostMIDI::rxHandler() {
+ uint8_t *midi;
+ if (bulk_in) {
+ int length = bulk_in->getLengthTransferred();
+ if (bulk_in->getState() == USB_TYPE_IDLE || bulk_in->getState() == USB_TYPE_FREE) {
+ // MIDI event handling
+ for (int i = 0; i < length; i += 4) {
+ if (i + 4 > length) {
+ // length shortage, ignored.
+ break;
+ }
+
+ // read each four bytes
+ midi = &buf[i];
+ // process MIDI message
+ // switch by code index number
+ switch (midi[0] & 0xf) {
+ case 0: // miscellaneous function codes
+ miscellaneousFunctionCode(midi[1], midi[2], midi[3]);
+ break;
+ case 1: // cable events
+ cableEvent(midi[1], midi[2], midi[3]);
+ break;
+ case 2: // two bytes system common messages
+ systemCommonTwoBytes(midi[1], midi[2]);
+ break;
+ case 3: // three bytes system common messages
+ systemCommonThreeBytes(midi[1], midi[2], midi[3]);
+ break;
+ case 4: // SysEx starts or continues
+ sysExBuffer[sysExBufferPos++] = midi[1];
+ if (sysExBufferPos >= 64) {
+ systemExclusive(sysExBuffer, sysExBufferPos, true);
+ sysExBufferPos = 0;
+ }
+ sysExBuffer[sysExBufferPos++] = midi[2];
+ if (sysExBufferPos >= 64) {
+ systemExclusive(sysExBuffer, sysExBufferPos, true);
+ sysExBufferPos = 0;
+ }
+ sysExBuffer[sysExBufferPos++] = midi[3];
+ // SysEx continues. don't send
+ break;
+ case 5: // SysEx ends with single byte
+ sysExBuffer[sysExBufferPos++] = midi[1];
+ systemExclusive(sysExBuffer, sysExBufferPos, false);
+ sysExBufferPos = 0;
+ break;
+ case 6: // SysEx ends with two bytes
+ sysExBuffer[sysExBufferPos++] = midi[1];
+ if (sysExBufferPos >= 64) {
+ systemExclusive(sysExBuffer, sysExBufferPos, true);
+ sysExBufferPos = 0;
+ }
+ sysExBuffer[sysExBufferPos++] = midi[2];
+ systemExclusive(sysExBuffer, sysExBufferPos, false);
+ sysExBufferPos = 0;
+ break;
+ case 7: // SysEx ends with three bytes
+ sysExBuffer[sysExBufferPos++] = midi[1];
+ if (sysExBufferPos >= 64) {
+ systemExclusive(sysExBuffer, sysExBufferPos, true);
+ sysExBufferPos = 0;
+ }
+ sysExBuffer[sysExBufferPos++] = midi[2];
+ if (sysExBufferPos >= 64) {
+ systemExclusive(sysExBuffer, sysExBufferPos, true);
+ sysExBufferPos = 0;
+ }
+ sysExBuffer[sysExBufferPos++] = midi[3];
+ systemExclusive(sysExBuffer, sysExBufferPos, false);
+ sysExBufferPos = 0;
+ break;
+ case 8:
+ noteOff(midi[1] & 0xf, midi[2], midi[3]);
+ break;
+ case 9:
+ if (midi[3]) {
+ noteOn(midi[1] & 0xf, midi[2], midi[3]);
+ } else {
+ noteOff(midi[1] & 0xf, midi[2], midi[3]);
+ }
+ break;
+ case 10:
+ polyKeyPress(midi[1] & 0xf, midi[2], midi[3]);
+ break;
+ case 11:
+ controlChange(midi[1] & 0xf, midi[2], midi[3]);
+ break;
+ case 12:
+ programChange(midi[1] & 0xf, midi[2]);
+ break;
+ case 13:
+ channelPressure(midi[1] & 0xf, midi[2]);
+ break;
+ case 14:
+ pitchBend(midi[1] & 0xf, midi[2] | (midi[3] << 7));
+ break;
+ case 15:
+ singleByte(midi[1]);
+ break;
+ }
+ }
+
+ // read another message
+ host->bulkRead(dev, bulk_in, buf, size_bulk_in, false);
+ }
+ }
+}
+
+bool USBHostMIDI::sendMidiBuffer(uint8_t data0, uint8_t data1, uint8_t data2, uint8_t data3) {
+ if (bulk_out) {
+ uint8_t midi[4];
+
+ midi[0] = data0;
+ midi[1] = data1;
+ midi[2] = data2;
+ midi[3] = data3;
+ if (host->bulkWrite(dev, bulk_out, (uint8_t *)midi, 4) == USB_TYPE_OK) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool USBHostMIDI::sendMiscellaneousFunctionCode(uint8_t data1, uint8_t data2, uint8_t data3) {
+ return sendMidiBuffer(0, data1, data2, data3);
+}
+
+bool USBHostMIDI::sendCableEvent(uint8_t data1, uint8_t data2, uint8_t data3) {
+ return sendMidiBuffer(1, data1, data2, data3);
+}
+
+bool USBHostMIDI::sendSystemCommmonTwoBytes(uint8_t data1, uint8_t data2) {
+ return sendMidiBuffer(2, data1, data2, 0);
+}
+
+bool USBHostMIDI::sendSystemCommmonThreeBytes(uint8_t data1, uint8_t data2, uint8_t data3) {
+ return sendMidiBuffer(3, data1, data2, 0);
+}
+
+bool USBHostMIDI::sendSystemExclusive(uint8_t *buffer, int length) {
+ uint8_t midi[64];
+ int midiLength;
+ int midiPos;
+ if (bulk_out) {
+ for (int i = 0; i < length; i += 48) {
+ if (i + 48 >= length) {
+ // contains last data
+ midiLength = (((length - i) + 2) / 3) * 4;
+ for (int pos = i; pos < length; pos += 3) {
+ midiPos = (pos + 2) / 3 * 4;
+ if (pos + 3 >= length) {
+ // last data
+ switch (pos % 3) {
+ case 0:
+ midi[midiPos ] = 7;
+ midi[midiPos + 1] = buffer[pos ];
+ midi[midiPos + 2] = buffer[pos + 1];
+ midi[midiPos + 3] = buffer[pos + 2];
+ break;
+ case 1:
+ midi[midiPos ] = 5;
+ midi[midiPos + 1] = buffer[pos ];
+ midi[midiPos + 2] = 0;
+ midi[midiPos + 3] = 0;
+ break;
+ case 2:
+ midi[midiPos ] = 6;
+ midi[midiPos + 1] = buffer[pos ];
+ midi[midiPos + 2] = buffer[pos + 1];
+ midi[midiPos + 3] = 0;
+ break;
+ }
+ } else {
+ // has more data
+ midi[midiPos ] = 4;
+ midi[midiPos + 1] = buffer[pos ];
+ midi[midiPos + 2] = buffer[pos + 1];
+ midi[midiPos + 3] = buffer[pos + 2];
+ }
+ }
+ } else {
+ // has more data
+ midiLength = 64;
+ for (int pos = i; pos < length; pos += 3) {
+ midiPos = (pos + 2) / 3 * 4;
+ midi[midiPos ] = 4;
+ midi[midiPos + 1] = buffer[pos ];
+ midi[midiPos + 2] = buffer[pos + 1];
+ midi[midiPos + 3] = buffer[pos + 2];
+ }
+ }
+
+ if (host->bulkWrite(dev, bulk_out, (uint8_t *)midi, midiLength) != USB_TYPE_OK) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+bool USBHostMIDI::sendNoteOff(uint8_t channel, uint8_t note, uint8_t velocity) {
+ return sendMidiBuffer(8, channel & 0xf | 0x80, note & 0x7f, velocity & 0x7f);
+}
+
+bool USBHostMIDI::sendNoteOn(uint8_t channel, uint8_t note, uint8_t velocity) {
+ return sendMidiBuffer(9, channel & 0xf | 0x90, note & 0x7f, velocity & 0x7f);
+}
+
+bool USBHostMIDI::sendPolyKeyPress(uint8_t channel, uint8_t note, uint8_t pressure) {
+ return sendMidiBuffer(10, channel & 0xf | 0xa0, note & 0x7f, pressure & 0x7f);
+}
+
+bool USBHostMIDI::sendControlChange(uint8_t channel, uint8_t key, uint8_t value) {
+ return sendMidiBuffer(11, channel & 0xf | 0xb0, key & 0x7f, value & 0x7f);
+}
+
+bool USBHostMIDI::sendProgramChange(uint8_t channel, uint8_t program) {
+ return sendMidiBuffer(12, channel & 0xf | 0xc0, program & 0x7f, 0);
+}
+
+bool USBHostMIDI::sendChannelPressure(uint8_t channel, uint8_t pressure) {
+ return sendMidiBuffer(13, channel & 0xf | 0xd0, pressure & 0x7f, 0);
+}
+
+bool USBHostMIDI::sendPitchBend(uint8_t channel, uint16_t value) {
+ return sendMidiBuffer(14, channel & 0xf | 0xe0, value & 0x7f, (value >> 7) & 0x7f);
+}
+
+bool USBHostMIDI::sendSingleByte(uint8_t data) {
+ return sendMidiBuffer(15, data, 0, 0);
+}
+
+/*virtual*/ void USBHostMIDI::setVidPid(uint16_t vid, uint16_t pid)
+{
+ // we don't check VID/PID for this driver
+}
+
+/*virtual*/ bool USBHostMIDI::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed
+{
+ // USB MIDI class/subclass
+ if ((midi_intf == -1) &&
+ (intf_class == AUDIO_CLASS) &&
+ (intf_subclass == 0x03)) {
+ midi_intf = intf_nb;
+ return true;
+ }
+
+ // vendor specific device
+ if ((midi_intf == -1) &&
+ (intf_class == 0xff) &&
+ (intf_subclass == 0x03)) {
+ midi_intf = intf_nb;
+ return true;
+ }
+
+ return false;
+}
+
+/*virtual*/ bool USBHostMIDI::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
+{
+ if (intf_nb == midi_intf) {
+ if (type == BULK_ENDPOINT) {
+ midi_device_found = true;
+ return true;
+ }
+ }
+ return false;
+}
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHostMIDI/USBHostMIDI.h Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,353 @@
+/* Copyright (c) 2014 mbed.org, MIT License
+ *
+ * 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 USBHOSTMIDI_H
+#define USBHOSTMIDI_H
+
+#include "USBHostConf.h"
+
+#if USBHOST_MIDI
+
+#include "USBHost.h"
+
+/**
+ * A class to communicate a USB MIDI device
+ */
+class USBHostMIDI : public IUSBEnumerator {
+public:
+ /**
+ * Constructor
+ */
+ USBHostMIDI();
+
+ /**
+ * Check if a USB MIDI device is connected
+ *
+ * @returns true if a midi device is connected
+ */
+ bool connected();
+
+ /**
+ * Try to connect a midi device
+ *
+ * @return true if connection was successful
+ */
+ bool connect();
+
+ /**
+ * Attach a callback called when miscellaneous function code is received
+ *
+ * @param ptr function pointer
+ * prototype: void onMiscellaneousFunctionCode(uint8_t data1, uint8_t data2, uint8_t data3);
+ */
+ inline void attachMiscellaneousFunctionCode(void (*fn)(uint8_t, uint8_t, uint8_t)) {
+ miscellaneousFunctionCode = fn;
+ }
+
+ /**
+ * Attach a callback called when cable event is received
+ *
+ * @param ptr function pointer
+ * prototype: void onCableEvent(uint8_t data1, uint8_t data2, uint8_t data3);
+ */
+ inline void attachCableEvent(void (*fn)(uint8_t, uint8_t, uint8_t)) {
+ cableEvent = fn;
+ }
+
+ /**
+ * Attach a callback called when system exclusive is received
+ *
+ * @param ptr function pointer
+ * prototype: void onSystemCommonTwoBytes(uint8_t data1, uint8_t data2);
+ */
+ inline void attachSystemCommonTwoBytes(void (*fn)(uint8_t, uint8_t)) {
+ systemCommonTwoBytes = fn;
+ }
+
+ /**
+ * Attach a callback called when system exclusive is received
+ *
+ * @param ptr function pointer
+ * prototype: void onSystemCommonThreeBytes(uint8_t data1, uint8_t data2, uint8_t data3);
+ */
+ inline void attachSystemCommonThreeBytes(void (*fn)(uint8_t, uint8_t, uint8_t)) {
+ systemCommonThreeBytes = fn;
+ }
+
+ /**
+ * Attach a callback called when system exclusive is received
+ *
+ * @param ptr function pointer
+ * prototype: void onSystemExclusive(uint8_t *data, uint16_t length, bool hasNextData);
+ */
+ inline void attachSystemExclusive(void (*fn)(uint8_t *, uint16_t, bool)) {
+ systemExclusive = fn;
+ }
+
+ /**
+ * Attach a callback called when note on is received
+ *
+ * @param ptr function pointer
+ * prototype: void onNoteOn(uint8_t channel, uint8_t note, uint8_t velocity);
+ */
+ inline void attachNoteOn(void (*fn)(uint8_t, uint8_t, uint8_t)) {
+ noteOn = fn;
+ }
+
+ /**
+ * Attach a callback called when note off is received
+ *
+ * @param ptr function pointer
+ * prototype: void onNoteOff(uint8_t channel, uint8_t note, uint8_t velocity);
+ */
+ inline void attachNoteOff(void (*fn)(uint8_t, uint8_t, uint8_t)) {
+ noteOff = fn;
+ }
+
+ /**
+ * Attach a callback called when poly keypress is received
+ *
+ * @param ptr function pointer
+ * prototype: void onPolyKeyPress(uint8_t channel, uint8_t note, uint8_t pressure);
+ */
+ inline void attachPolyKeyPress(void (*fn)(uint8_t, uint8_t, uint8_t)) {
+ polyKeyPress = fn;
+ }
+
+ /**
+ * Attach a callback called when control change is received
+ *
+ * @param ptr function pointer
+ * prototype: void onControlChange(uint8_t channel, uint8_t key, uint8_t value);
+ */
+ inline void attachControlChange(void (*fn)(uint8_t, uint8_t, uint8_t)) {
+ controlChange = fn;
+ }
+
+ /**
+ * Attach a callback called when program change is received
+ *
+ * @param ptr function pointer
+ * prototype: void onProgramChange(uint8_t channel, uint8_t program);
+ */
+ inline void attachProgramChange(void (*fn)(uint8_t, uint8_t)) {
+ programChange = fn;
+ }
+
+ /**
+ * Attach a callback called when channel pressure is received
+ *
+ * @param ptr function pointer
+ * prototype: void onChannelPressure(uint8_t channel, uint8_t pressure);
+ */
+ inline void attachChannelPressure(void (*fn)(uint8_t, uint8_t)) {
+ channelPressure = fn;
+ }
+
+ /**
+ * Attach a callback called when pitch bend is received
+ *
+ * @param ptr function pointer
+ * prototype: void onPitchBend(uint8_t channel, uint16_t value);
+ */
+ inline void attachPitchBend(void (*fn)(uint8_t, uint16_t)) {
+ pitchBend = fn;
+ }
+
+ /**
+ * Attach a callback called when single byte is received
+ *
+ * @param ptr function pointer
+ * prototype: void onSingleByte(uint8_t value);
+ */
+ inline void attachSingleByte(void (*fn)(uint8_t)) {
+ singleByte = fn;
+ }
+
+ /**
+ * Send a cable event with 3 bytes event
+ *
+ * @param data1 0-255
+ * @param data2 0-255
+ * @param data3 0-255
+ * @return true if message sent successfully
+ */
+ bool sendMiscellaneousFunctionCode(uint8_t data1, uint8_t data2, uint8_t data3);
+
+ /**
+ * Send a cable event with 3 bytes event
+ *
+ * @param data1 0-255
+ * @param data2 0-255
+ * @param data3 0-255
+ * @return true if message sent successfully
+ */
+ bool sendCableEvent(uint8_t data1, uint8_t data2, uint8_t data3);
+
+ /**
+ * Send a system common message with 2 bytes event
+ *
+ * @param data1 0-255
+ * @param data2 0-255
+ * @return true if message sent successfully
+ */
+ bool sendSystemCommmonTwoBytes(uint8_t data1, uint8_t data2);
+
+ /**
+ * Send a system common message with 3 bytes event
+ *
+ * @param data1 0-255
+ * @param data2 0-255
+ * @param data3 0-255
+ * @return true if message sent successfully
+ */
+ bool sendSystemCommmonThreeBytes(uint8_t data1, uint8_t data2, uint8_t data3);
+
+ /**
+ * Send a system exclusive event
+ *
+ * @param buffer, starts with 0xF0, and end with 0xf7
+ * @param length
+ * @return true if message sent successfully
+ */
+ bool sendSystemExclusive(uint8_t *buffer, int length);
+
+ /**
+ * Send a note off event
+ *
+ * @param channel 0-15
+ * @param note 0-127
+ * @param velocity 0-127
+ * @return true if message sent successfully
+ */
+ bool sendNoteOff(uint8_t channel, uint8_t note, uint8_t velocity);
+
+ /**
+ * Send a note on event
+ *
+ * @param channel 0-15
+ * @param note 0-127
+ * @param velocity 0-127 (0 means note off)
+ * @return true if message sent successfully
+ */
+ bool sendNoteOn(uint8_t channel, uint8_t note, uint8_t velocity);
+
+ /**
+ * Send a poly keypress event
+ *
+ * @param channel 0-15
+ * @param note 0-127
+ * @param pressure 0-127
+ * @return true if message sent successfully
+ */
+ bool sendPolyKeyPress(uint8_t channel, uint8_t note, uint8_t pressure);
+
+ /**
+ * Send a control change event
+ *
+ * @param channel 0-15
+ * @param key 0-127
+ * @param value 0-127
+ * @return true if message sent successfully
+ */
+ bool sendControlChange(uint8_t channel, uint8_t key, uint8_t value);
+
+ /**
+ * Send a program change event
+ *
+ * @param channel 0-15
+ * @param program 0-127
+ * @return true if message sent successfully
+ */
+ bool sendProgramChange(uint8_t channel, uint8_t program);
+
+ /**
+ * Send a channel pressure event
+ *
+ * @param channel 0-15
+ * @param pressure 0-127
+ * @return true if message sent successfully
+ */
+ bool sendChannelPressure(uint8_t channel, uint8_t pressure);
+
+ /**
+ * Send a control change event
+ *
+ * @param channel 0-15
+ * @param key 0(lower)-8191(center)-16383(higher)
+ * @return true if message sent successfully
+ */
+ bool sendPitchBend(uint8_t channel, uint16_t value);
+
+ /**
+ * Send a single byte event
+ *
+ * @param data 0-255
+ * @return true if message sent successfully
+ */
+ bool sendSingleByte(uint8_t data);
+
+protected:
+ //From IUSBEnumerator
+ virtual void setVidPid(uint16_t vid, uint16_t pid);
+ virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed
+ virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used
+
+private:
+ USBHost * host;
+ USBDeviceConnected * dev;
+ USBEndpoint * bulk_in;
+ USBEndpoint * bulk_out;
+ uint32_t size_bulk_in;
+ uint32_t size_bulk_out;
+
+ bool dev_connected;
+
+ void init();
+
+ uint8_t buf[64];
+
+ void rxHandler();
+
+ uint16_t sysExBufferPos;
+ uint8_t sysExBuffer[64];
+
+ void (*miscellaneousFunctionCode)(uint8_t, uint8_t, uint8_t);
+ void (*cableEvent)(uint8_t, uint8_t, uint8_t);
+ void (*systemCommonTwoBytes)(uint8_t, uint8_t);
+ void (*systemCommonThreeBytes)(uint8_t, uint8_t, uint8_t);
+ void (*systemExclusive)(uint8_t *, uint16_t, bool);
+ void (*noteOff)(uint8_t, uint8_t, uint8_t);
+ void (*noteOn)(uint8_t, uint8_t, uint8_t);
+ void (*polyKeyPress)(uint8_t, uint8_t, uint8_t);
+ void (*controlChange)(uint8_t, uint8_t, uint8_t);
+ void (*programChange)(uint8_t, uint8_t);
+ void (*channelPressure)(uint8_t, uint8_t);
+ void (*pitchBend)(uint8_t, uint16_t);
+ void (*singleByte)(uint8_t);
+
+ bool sendMidiBuffer(uint8_t data0, uint8_t data1, uint8_t data2, uint8_t data3);
+
+ int midi_intf;
+ bool midi_device_found;
+
+};
+
+#endif /* USBHOST_MIDI */
+
+#endif /* USBHOSTMIDI_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHostMSD/USBHostMSD.cpp Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,366 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "USBHostMSD.h"
+
+#if USBHOST_MSD
+
+#include "dbg.h"
+
+#define CBW_SIGNATURE 0x43425355
+#define CSW_SIGNATURE 0x53425355
+
+#define DEVICE_TO_HOST 0x80
+#define HOST_TO_DEVICE 0x00
+
+#define GET_MAX_LUN (0xFE)
+#define BO_MASS_STORAGE_RESET (0xFF)
+
+USBHostMSD::USBHostMSD(const char * rootdir) : FATFileSystem(rootdir)
+{
+ host = USBHost::getHostInst();
+ init();
+}
+
+void USBHostMSD::init() {
+ dev_connected = false;
+ dev = NULL;
+ bulk_in = NULL;
+ bulk_out = NULL;
+ dev_connected = false;
+ blockSize = 0;
+ blockCount = 0;
+ msd_intf = -1;
+ msd_device_found = false;
+ disk_init = false;
+ dev_connected = false;
+ nb_ep = 0;
+}
+
+
+bool USBHostMSD::connected()
+{
+ return dev_connected;
+}
+
+bool USBHostMSD::connect()
+{
+
+ if (dev_connected) {
+ return true;
+ }
+
+ for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) {
+ if ((dev = host->getDevice(i)) != NULL) {
+
+ USB_DBG("Trying to connect MSD device\r\n");
+
+ if(host->enumerate(dev, this))
+ break;
+
+ if (msd_device_found) {
+ bulk_in = dev->getEndpoint(msd_intf, BULK_ENDPOINT, IN);
+ bulk_out = dev->getEndpoint(msd_intf, BULK_ENDPOINT, OUT);
+
+ if (!bulk_in || !bulk_out)
+ continue;
+
+ USB_INFO("New MSD device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, msd_intf);
+ dev->setName("MSD", msd_intf);
+ host->registerDriver(dev, msd_intf, this, &USBHostMSD::init);
+
+ dev_connected = true;
+ return true;
+ }
+ } //if()
+ } //for()
+ init();
+ return false;
+}
+
+/*virtual*/ void USBHostMSD::setVidPid(uint16_t vid, uint16_t pid)
+{
+ // we don't check VID/PID for MSD driver
+}
+
+/*virtual*/ bool USBHostMSD::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed
+{
+ if ((msd_intf == -1) &&
+ (intf_class == MSD_CLASS) &&
+ (intf_subclass == 0x06) &&
+ (intf_protocol == 0x50)) {
+ msd_intf = intf_nb;
+ return true;
+ }
+ return false;
+}
+
+/*virtual*/ bool USBHostMSD::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
+{
+ if (intf_nb == msd_intf) {
+ if (type == BULK_ENDPOINT) {
+ nb_ep++;
+ if (nb_ep == 2)
+ msd_device_found = true;
+ return true;
+ }
+ }
+ return false;
+}
+
+
+int USBHostMSD::testUnitReady() {
+ USB_DBG("Test unit ready");
+ return SCSITransfer(NULL, 6, DEVICE_TO_HOST, 0, 0);
+}
+
+
+int USBHostMSD::readCapacity() {
+ USB_DBG("Read capacity");
+ uint8_t cmd[10] = {0x25,0,0,0,0,0,0,0,0,0};
+ uint8_t result[8];
+ int status = SCSITransfer(cmd, 10, DEVICE_TO_HOST, result, 8);
+ if (status == 0) {
+ blockCount = (result[0] << 24) | (result[1] << 16) | (result[2] << 8) | result[3];
+ blockSize = (result[4] << 24) | (result[5] << 16) | (result[6] << 8) | result[7];
+ USB_INFO("MSD [dev: %p] - blockCount: %lld, blockSize: %d, Capacity: %lld\r\n", dev, blockCount, blockSize, blockCount*blockSize);
+ }
+ return status;
+}
+
+
+int USBHostMSD::SCSIRequestSense() {
+ USB_DBG("Request sense");
+ uint8_t cmd[6] = {0x03,0,0,0,18,0};
+ uint8_t result[18];
+ int status = SCSITransfer(cmd, 6, DEVICE_TO_HOST, result, 18);
+ return status;
+}
+
+
+int USBHostMSD::inquiry(uint8_t lun, uint8_t page_code) {
+ USB_DBG("Inquiry");
+ uint8_t evpd = (page_code == 0) ? 0 : 1;
+ uint8_t cmd[6] = {0x12, uint8_t((lun << 5) | evpd), page_code, 0, 36, 0};
+ uint8_t result[36];
+ int status = SCSITransfer(cmd, 6, DEVICE_TO_HOST, result, 36);
+ if (status == 0) {
+ char vid_pid[17];
+ memcpy(vid_pid, &result[8], 8);
+ vid_pid[8] = 0;
+ USB_INFO("MSD [dev: %p] - Vendor ID: %s", dev, vid_pid);
+
+ memcpy(vid_pid, &result[16], 16);
+ vid_pid[16] = 0;
+ USB_INFO("MSD [dev: %p] - Product ID: %s", dev, vid_pid);
+
+ memcpy(vid_pid, &result[32], 4);
+ vid_pid[4] = 0;
+ USB_INFO("MSD [dev: %p] - Product rev: %s", dev, vid_pid);
+ }
+ return status;
+}
+
+int USBHostMSD::checkResult(uint8_t res, USBEndpoint * ep) {
+ // if ep stalled: send clear feature
+ if (res == USB_TYPE_STALL_ERROR) {
+ res = host->controlWrite( dev,
+ USB_RECIPIENT_ENDPOINT | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_STANDARD,
+ CLEAR_FEATURE,
+ 0, ep->getAddress(), NULL, 0);
+ // set state to IDLE if clear feature successful
+ if (res == USB_TYPE_OK) {
+ ep->setState(USB_TYPE_IDLE);
+ }
+ }
+
+ if (res != USB_TYPE_OK)
+ return -1;
+
+ return 0;
+}
+
+
+int USBHostMSD::SCSITransfer(uint8_t * cmd, uint8_t cmd_len, int flags, uint8_t * data, uint32_t transfer_len) {
+
+ int res = 0;
+
+ cbw.Signature = CBW_SIGNATURE;
+ cbw.Tag = 0;
+ cbw.DataLength = transfer_len;
+ cbw.Flags = flags;
+ cbw.LUN = 0;
+ cbw.CBLength = cmd_len;
+ memset(cbw.CB,0,sizeof(cbw.CB));
+ if (cmd) {
+ memcpy(cbw.CB,cmd,cmd_len);
+ }
+
+ // send the cbw
+ USB_DBG("Send CBW");
+ res = host->bulkWrite(dev, bulk_out,(uint8_t *)&cbw, 31);
+ if (checkResult(res, bulk_out))
+ return -1;
+
+ // data stage if needed
+ if (data) {
+ USB_DBG("data stage");
+ if (flags == HOST_TO_DEVICE) {
+
+ res = host->bulkWrite(dev, bulk_out, data, transfer_len);
+ if (checkResult(res, bulk_out))
+ return -1;
+
+ } else if (flags == DEVICE_TO_HOST) {
+
+ res = host->bulkRead(dev, bulk_in, data, transfer_len);
+ if (checkResult(res, bulk_in))
+ return -1;
+ }
+ }
+
+ // status stage
+ csw.Signature = 0;
+ USB_DBG("Read CSW");
+ res = host->bulkRead(dev, bulk_in,(uint8_t *)&csw, 13);
+ if (checkResult(res, bulk_in))
+ return -1;
+
+ if (csw.Signature != CSW_SIGNATURE) {
+ return -1;
+ }
+
+ USB_DBG("recv csw: status: %d", csw.Status);
+
+ // ModeSense?
+ if ((csw.Status == 1) && (cmd[0] != 0x03)) {
+ USB_DBG("request mode sense");
+ return SCSIRequestSense();
+ }
+
+ // perform reset recovery
+ if ((csw.Status == 2) && (cmd[0] != 0x03)) {
+
+ // send Bulk-Only Mass Storage Reset request
+ res = host->controlWrite( dev,
+ USB_RECIPIENT_INTERFACE | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_CLASS,
+ BO_MASS_STORAGE_RESET,
+ 0, msd_intf, NULL, 0);
+
+ // unstall both endpoints
+ res = host->controlWrite( dev,
+ USB_RECIPIENT_ENDPOINT | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_STANDARD,
+ CLEAR_FEATURE,
+ 0, bulk_in->getAddress(), NULL, 0);
+
+ res = host->controlWrite( dev,
+ USB_RECIPIENT_ENDPOINT | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_STANDARD,
+ CLEAR_FEATURE,
+ 0, bulk_out->getAddress(), NULL, 0);
+
+ }
+
+ return csw.Status;
+}
+
+
+int USBHostMSD::dataTransfer(uint8_t * buf, uint32_t block, uint8_t nbBlock, int direction) {
+ uint8_t cmd[10];
+ memset(cmd,0,10);
+ cmd[0] = (direction == DEVICE_TO_HOST) ? 0x28 : 0x2A;
+
+ cmd[2] = (block >> 24) & 0xff;
+ cmd[3] = (block >> 16) & 0xff;
+ cmd[4] = (block >> 8) & 0xff;
+ cmd[5] = block & 0xff;
+
+ cmd[7] = (nbBlock >> 8) & 0xff;
+ cmd[8] = nbBlock & 0xff;
+
+ return SCSITransfer(cmd, 10, direction, buf, blockSize*nbBlock);
+}
+
+int USBHostMSD::getMaxLun() {
+ uint8_t buf[1], res;
+ res = host->controlRead( dev, USB_RECIPIENT_INTERFACE | USB_DEVICE_TO_HOST | USB_REQUEST_TYPE_CLASS,
+ 0xfe, 0, msd_intf, buf, 1);
+ USB_DBG("max lun: %d", buf[0]);
+ return res;
+}
+
+int USBHostMSD::disk_initialize() {
+ USB_DBG("FILESYSTEM: init");
+ uint16_t i, timeout = 10;
+
+ getMaxLun();
+
+ for (i = 0; i < timeout; i++) {
+ Thread::wait(100);
+ if (!testUnitReady())
+ break;
+ }
+
+ if (i == timeout) {
+ disk_init = false;
+ return -1;
+ }
+
+ inquiry(0, 0);
+ disk_init = 1;
+ return readCapacity();
+}
+
+int USBHostMSD::disk_write(const uint8_t* buffer, uint64_t block_number, uint8_t count) {
+ USB_DBG("FILESYSTEM: write block: %lld, count: %d", block_number, count);
+ if (!disk_init) {
+ disk_initialize();
+ }
+ if (!disk_init)
+ return -1;
+ for (uint64_t b = block_number; b < block_number + count; b++) {
+ if (dataTransfer((uint8_t*)buffer, b, 1, HOST_TO_DEVICE))
+ return -1;
+ buffer += 512;
+ }
+ return 0;
+}
+
+int USBHostMSD::disk_read(uint8_t* buffer, uint64_t block_number, uint8_t count) {
+ USB_DBG("FILESYSTEM: read block: %lld, count: %d", block_number, count);
+ if (!disk_init) {
+ disk_initialize();
+ }
+ if (!disk_init)
+ return -1;
+ for (uint64_t b = block_number; b < block_number + count; b++) {
+ if (dataTransfer((uint8_t*)buffer, b, 1, DEVICE_TO_HOST))
+ return -1;
+ buffer += 512;
+ }
+ return 0;
+}
+
+uint64_t USBHostMSD::disk_sectors() {
+ USB_DBG("FILESYSTEM: sectors");
+ if (!disk_init) {
+ disk_initialize();
+ }
+ if (!disk_init)
+ return 0;
+ return blockCount;
+}
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHostMSD/USBHostMSD.h Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,119 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef USBHOSTMSD_H
+#define USBHOSTMSD_H
+
+#include "USBHostConf.h"
+
+#if USBHOST_MSD
+
+#include "USBHost.h"
+#include "FATFileSystem.h"
+
+/**
+ * A class to communicate a USB flash disk
+ */
+class USBHostMSD : public IUSBEnumerator, public FATFileSystem {
+public:
+ /**
+ * Constructor
+ *
+ * @param rootdir mount name
+ */
+ USBHostMSD(const char * rootdir);
+
+ /**
+ * Check if a MSD device is connected
+ *
+ * @return true if a MSD device is connected
+ */
+ bool connected();
+
+ /**
+ * Try to connect to a MSD device
+ *
+ * @return true if connection was successful
+ */
+ bool connect();
+
+protected:
+ //From IUSBEnumerator
+ virtual void setVidPid(uint16_t vid, uint16_t pid);
+ virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed
+ virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used
+
+ // From FATFileSystem
+ virtual int disk_initialize();
+ virtual int disk_status() {return 0;};
+ virtual int disk_read(uint8_t* buffer, uint64_t sector, uint8_t count);
+ virtual int disk_write(const uint8_t* buffer, uint64_t sector, uint8_t count);
+ virtual int disk_sync() {return 0;};
+ virtual uint64_t disk_sectors();
+
+private:
+ USBHost * host;
+ USBDeviceConnected * dev;
+ bool dev_connected;
+ USBEndpoint * bulk_in;
+ USBEndpoint * bulk_out;
+ uint8_t nb_ep;
+
+ // Bulk-only CBW
+ typedef struct {
+ uint32_t Signature;
+ uint32_t Tag;
+ uint32_t DataLength;
+ uint8_t Flags;
+ uint8_t LUN;
+ uint8_t CBLength;
+ uint8_t CB[16];
+ } PACKED CBW;
+
+ // Bulk-only CSW
+ typedef struct {
+ uint32_t Signature;
+ uint32_t Tag;
+ uint32_t DataResidue;
+ uint8_t Status;
+ } PACKED CSW;
+
+ CBW cbw;
+ CSW csw;
+
+ int SCSITransfer(uint8_t * cmd, uint8_t cmd_len, int flags, uint8_t * data, uint32_t transfer_len);
+ int testUnitReady();
+ int readCapacity();
+ int inquiry(uint8_t lun, uint8_t page_code);
+ int SCSIRequestSense();
+ int dataTransfer(uint8_t * buf, uint32_t block, uint8_t nbBlock, int direction);
+ int checkResult(uint8_t res, USBEndpoint * ep);
+ int getMaxLun();
+
+ int blockSize;
+ uint64_t blockCount;
+
+ int msd_intf;
+ bool msd_device_found;
+ bool disk_init;
+
+ void init();
+
+};
+
+#endif
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHostSerial/MtxCircBuffer.h Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,89 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MTXCIRCBUFFER_H
+#define MTXCIRCBUFFER_H
+
+#include "stdint.h"
+#include "rtos.h"
+
+//Mutex protected circular buffer
+template<typename T, int size>
+class MtxCircBuffer {
+public:
+
+ MtxCircBuffer() {
+ write = 0;
+ read = 0;
+ }
+
+ bool isFull() {
+ mtx.lock();
+ bool r = (((write + 1) % size) == read);
+ mtx.unlock();
+ return r;
+ }
+
+ bool isEmpty() {
+ mtx.lock();
+ bool r = (read == write);
+ mtx.unlock();
+ return r;
+ }
+
+ void flush() {
+ write = 0;
+ read = 0;
+ }
+
+ void queue(T k) {
+ mtx.lock();
+ while (((write + 1) % size) == read) {
+ mtx.unlock();
+ Thread::wait(10);
+ mtx.lock();
+ }
+ buf[write++] = k;
+ write %= size;
+ mtx.unlock();
+ }
+
+ uint16_t available() {
+ mtx.lock();
+ uint16_t a = (write >= read) ? (write - read) : (size - read + write);
+ mtx.unlock();
+ return a;
+ }
+
+ bool dequeue(T * c) {
+ mtx.lock();
+ bool empty = (read == write);
+ if (!empty) {
+ *c = buf[read++];
+ read %= size;
+ }
+ mtx.unlock();
+ return (!empty);
+ }
+
+private:
+ volatile uint16_t write;
+ volatile uint16_t read;
+ volatile T buf[size];
+ Mutex mtx;
+};
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHostSerial/USBHostSerial.cpp Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,345 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "USBHostSerial.h"
+
+#if USBHOST_SERIAL
+
+#include "dbg.h"
+
+#define CHECK_INTERFACE(cls,subcls,proto) \
+ (((cls == 0xFF) && (subcls == 0xFF) && (proto == 0xFF)) /* QUALCOM CDC */ || \
+ ((cls == SERIAL_CLASS) && (subcls == 0x00) && (proto == 0x00)) /* STANDARD CDC */ )
+
+#if (USBHOST_SERIAL <= 1)
+
+USBHostSerial::USBHostSerial()
+{
+ host = USBHost::getHostInst();
+ ports_found = 0;
+ dev_connected = false;
+}
+
+bool USBHostSerial::connected()
+{
+ return dev_connected;
+}
+
+void USBHostSerial::disconnect(void)
+{
+ ports_found = 0;
+ dev = NULL;
+}
+
+bool USBHostSerial::connect() {
+
+ if (dev)
+ {
+ for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++)
+ {
+ USBDeviceConnected* d = host->getDevice(i);
+ if (dev == d)
+ return true;
+ }
+ disconnect();
+ }
+ for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++)
+ {
+ USBDeviceConnected* d = host->getDevice(i);
+ if (d != NULL) {
+
+ USB_DBG("Trying to connect serial device \r\n");
+ if(host->enumerate(d, this))
+ break;
+
+ USBEndpoint* bulk_in = d->getEndpoint(port_intf, BULK_ENDPOINT, IN);
+ USBEndpoint* bulk_out = d->getEndpoint(port_intf, BULK_ENDPOINT, OUT);
+ if (bulk_in && bulk_out)
+ {
+ USBHostSerialPort::connect(host,d,port_intf,bulk_in, bulk_out);
+ dev = d;
+ dev_connected = true;
+ }
+ }
+ }
+ return dev != NULL;
+}
+
+/*virtual*/ void USBHostSerial::setVidPid(uint16_t vid, uint16_t pid)
+{
+ // we don't check VID/PID for MSD driver
+}
+
+/*virtual*/ bool USBHostSerial::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed
+{
+ if (!ports_found &&
+ CHECK_INTERFACE(intf_class, intf_subclass, intf_protocol)) {
+ port_intf = intf_nb;
+ ports_found = true;
+ return true;
+ }
+ return false;
+}
+
+/*virtual*/ bool USBHostSerial::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
+{
+ if (ports_found && (intf_nb == port_intf)) {
+ if (type == BULK_ENDPOINT)
+ return true;
+ }
+ return false;
+}
+
+#else // (USBHOST_SERIAL > 1)
+
+//------------------------------------------------------------------------------
+
+USBHostMultiSerial::USBHostMultiSerial()
+{
+ host = USBHost::getHostInst();
+ dev = NULL;
+ memset(ports, NULL, sizeof(ports));
+ ports_found = 0;
+ dev_connected = false;
+}
+
+USBHostMultiSerial::~USBHostMultiSerial()
+{
+ disconnect();
+}
+
+bool USBHostMultiSerial::connected()
+{
+ return dev_connected;
+}
+
+void USBHostMultiSerial::disconnect(void)
+{
+ for (int port = 0; port < USBHOST_SERIAL; port ++)
+ {
+ if (ports[port])
+ {
+ delete ports[port];
+ ports[port] = NULL;
+ }
+ }
+ ports_found = 0;
+ dev = NULL;
+}
+
+bool USBHostMultiSerial::connect() {
+
+ if (dev)
+ {
+ for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++)
+ {
+ USBDeviceConnected* d = host->getDevice(i);
+ if (dev == d)
+ return true;
+ }
+ disconnect();
+ }
+ for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++)
+ {
+ USBDeviceConnected* d = host->getDevice(i);
+ if (d != NULL) {
+
+ USB_DBG("Trying to connect serial device \r\n");
+ if(host->enumerate(d, this))
+ break;
+
+ for (int port = 0; port < ports_found; port ++)
+ {
+ USBEndpoint* bulk_in = d->getEndpoint(port_intf[port], BULK_ENDPOINT, IN);
+ USBEndpoint* bulk_out = d->getEndpoint(port_intf[port], BULK_ENDPOINT, OUT);
+ if (bulk_in && bulk_out)
+ {
+ ports[port] = new USBHostSerialPort();
+ if (ports[port])
+ {
+ ports[port]->connect(host,d,port_intf[port],bulk_in, bulk_out);
+ dev = d;
+ dev_connected = true;
+ }
+ }
+ }
+ }
+ }
+ return dev != NULL;
+}
+
+/*virtual*/ void USBHostMultiSerial::setVidPid(uint16_t vid, uint16_t pid)
+{
+ // we don't check VID/PID for MSD driver
+}
+
+/*virtual*/ bool USBHostMultiSerial::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed
+{
+ if ((ports_found < USBHOST_SERIAL) &&
+ CHECK_INTERFACE(intf_class, intf_subclass, intf_protocol)) {
+ port_intf[ports_found++] = intf_nb;
+ return true;
+ }
+ return false;
+}
+
+/*virtual*/ bool USBHostMultiSerial::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
+{
+ if ((ports_found > 0) && (intf_nb == port_intf[ports_found-1])) {
+ if (type == BULK_ENDPOINT)
+ return true;
+ }
+ return false;
+}
+
+#endif
+
+//------------------------------------------------------------------------------
+
+#define SET_LINE_CODING 0x20
+
+USBHostSerialPort::USBHostSerialPort(): circ_buf()
+{
+ init();
+}
+
+void USBHostSerialPort::init(void)
+{
+ host = NULL;
+ dev = NULL;
+ serial_intf = NULL;
+ size_bulk_in = 0;
+ size_bulk_out = 0;
+ bulk_in = NULL;
+ bulk_out = NULL;
+ line_coding.baudrate = 750000;
+ line_coding.data_bits = 8;
+ line_coding.parity = None;
+ line_coding.stop_bits = 1;
+ circ_buf.flush();
+}
+
+void USBHostSerialPort::connect(USBHost* _host, USBDeviceConnected * _dev,
+ uint8_t _serial_intf, USBEndpoint* _bulk_in, USBEndpoint* _bulk_out)
+{
+ host = _host;
+ dev = _dev;
+ serial_intf = _serial_intf;
+ bulk_in = _bulk_in;
+ bulk_out = _bulk_out;
+
+ USB_INFO("New Serial device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, serial_intf);
+ dev->setName("Serial", serial_intf);
+ host->registerDriver(dev, serial_intf, this, &USBHostSerialPort::init);
+ baud(750000);
+ size_bulk_in = bulk_in->getSize();
+ size_bulk_out = bulk_out->getSize();
+ bulk_in->attach(this, &USBHostSerialPort::rxHandler);
+ bulk_out->attach(this, &USBHostSerialPort::txHandler);
+ host->bulkRead(dev, bulk_in, buf, size_bulk_in, false);
+}
+
+void USBHostSerialPort::rxHandler() {
+ if (bulk_in) {
+ int len = bulk_in->getLengthTransferred();
+ if (bulk_in->getState() == USB_TYPE_IDLE) {
+ for (int i = 0; i < len; i++) {
+ circ_buf.queue(buf[i]);
+ }
+ rx.call();
+ host->bulkRead(dev, bulk_in, buf, size_bulk_in, false);
+ }
+ }
+}
+
+void USBHostSerialPort::txHandler() {
+ if (bulk_out) {
+ if (bulk_out->getState() == USB_TYPE_IDLE) {
+ tx.call();
+ }
+ }
+}
+
+int USBHostSerialPort::_putc(int c) {
+ if (bulk_out) {
+ if (host->bulkWrite(dev, bulk_out, (uint8_t *)&c, 1) == USB_TYPE_OK) {
+ return 1;
+ }
+ }
+ return -1;
+}
+
+void USBHostSerialPort::baud(int baudrate) {
+ line_coding.baudrate = baudrate;
+ format(line_coding.data_bits, (Parity)line_coding.parity, line_coding.stop_bits);
+}
+
+void USBHostSerialPort::format(int bits, Parity parity, int stop_bits) {
+ line_coding.data_bits = bits;
+ line_coding.parity = parity;
+ line_coding.stop_bits = (stop_bits == 1) ? 0 : 2;
+
+ // set line coding
+ host->controlWrite( dev,
+ USB_RECIPIENT_INTERFACE | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_CLASS,
+ SET_LINE_CODING,
+ 0, serial_intf, (uint8_t *)&line_coding, 7);
+}
+
+int USBHostSerialPort::_getc() {
+ uint8_t c = 0;
+ if (bulk_in == NULL) {
+ init();
+ return -1;
+ }
+ while (circ_buf.isEmpty());
+ circ_buf.dequeue(&c);
+ return c;
+}
+
+int USBHostSerialPort::writeBuf(const char* b, int s)
+{
+ int c = 0;
+ if (bulk_out)
+ {
+ while (c < s)
+ {
+ int i = (s < size_bulk_out) ? s : size_bulk_out;
+ if (host->bulkWrite(dev, bulk_out, (uint8_t *)(b+c), i) == USB_TYPE_OK)
+ c += i;
+ }
+ }
+ return s;
+}
+
+int USBHostSerialPort::readBuf(char* b, int s)
+{
+ int i = 0;
+ if (bulk_in)
+ {
+ for (i = 0; i < s; )
+ b[i++] = getc();
+ }
+ return i;
+}
+
+uint8_t USBHostSerialPort::available() {
+ return circ_buf.available();
+}
+
+
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHostSerial/USBHostSerial.h Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,231 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef USBHOSTSERIAL_H
+#define USBHOSTSERIAL_H
+
+#include "USBHostConf.h"
+
+#if USBHOST_SERIAL
+
+#include "USBHost.h"
+#include "Stream.h"
+#include "MtxCircBuffer.h"
+
+/**
+ * A class to communicate a USB virtual serial port
+ */
+class USBHostSerialPort : public Stream {
+public:
+ /**
+ * Constructor
+ */
+ USBHostSerialPort();
+
+ enum IrqType {
+ RxIrq,
+ TxIrq
+ };
+
+ enum Parity {
+ None = 0,
+ Odd,
+ Even,
+ Mark,
+ Space
+ };
+
+ void connect(USBHost* _host, USBDeviceConnected * _dev,
+ uint8_t _serial_intf, USBEndpoint* _bulk_in, USBEndpoint* _bulk_out);
+
+ /**
+ * Check the number of bytes available.
+ *
+ * @returns the number of bytes available
+ */
+ uint8_t available();
+
+ /**
+ * Attach a member function to call when a packet is received.
+ *
+ * @param tptr pointer to the object to call the member function on
+ * @param mptr pointer to the member function to be called
+ * @param irq irq type
+ */
+ template<typename T>
+ inline void attach(T* tptr, void (T::*mptr)(void), IrqType irq = RxIrq) {
+ if ((mptr != NULL) && (tptr != NULL)) {
+ if (irq == RxIrq) {
+ rx.attach(tptr, mptr);
+ } else {
+ tx.attach(tptr, mptr);
+ }
+ }
+ }
+
+ /**
+ * Attach a callback called when a packet is received
+ *
+ * @param ptr function pointer
+ */
+ inline void attach(void (*fn)(void), IrqType irq = RxIrq) {
+ if (fn != NULL) {
+ if (irq == RxIrq) {
+ rx.attach(fn);
+ } else {
+ tx.attach(fn);
+ }
+ }
+ }
+
+ /** Set the baud rate of the serial port
+ *
+ * @param baudrate The baudrate of the serial port (default = 9600).
+ */
+ void baud(int baudrate = 750000);
+
+ /** Set the transmission format used by the Serial port
+ *
+ * @param bits The number of bits in a word (default = 8)
+ * @param parity The parity used (USBHostSerialPort::None, USBHostSerialPort::Odd, USBHostSerialPort::Even, USBHostSerialPort::Mark, USBHostSerialPort::Space; default = USBHostSerialPort::None)
+ * @param stop The number of stop bits (1 or 2; default = 1)
+ */
+ void format(int bits = 8, Parity parity = USBHostSerialPort::None, int stop_bits = 1);
+ virtual int writeBuf(const char* b, int s);
+ virtual int readBuf(char* b, int s);
+
+protected:
+ virtual int _getc();
+ virtual int _putc(int c);
+
+private:
+ USBHost * host;
+ USBDeviceConnected * dev;
+
+ USBEndpoint * bulk_in;
+ USBEndpoint * bulk_out;
+ uint32_t size_bulk_in;
+ uint32_t size_bulk_out;
+
+ void init();
+
+ MtxCircBuffer<uint8_t, 2048> circ_buf;
+
+ uint8_t buf[2048];
+
+ typedef struct {
+ uint32_t baudrate;
+ uint8_t stop_bits;
+ uint8_t parity;
+ uint8_t data_bits;
+ } PACKED LINE_CODING;
+
+ LINE_CODING line_coding;
+
+ void rxHandler();
+ void txHandler();
+ FunctionPointer rx;
+ FunctionPointer tx;
+
+ uint8_t serial_intf;
+};
+
+#if (USBHOST_SERIAL <= 1)
+
+class USBHostSerial : public IUSBEnumerator, public USBHostSerialPort
+{
+public:
+ USBHostSerial();
+
+ /**
+ * Try to connect a serial device
+ *
+ * @return true if connection was successful
+ */
+ bool connect();
+
+ void disconnect();
+
+ /**
+ * Check if a any serial port is connected
+ *
+ * @returns true if a serial device is connected
+ */
+ bool connected();
+
+protected:
+ USBHost* host;
+ USBDeviceConnected* dev;
+ uint8_t port_intf;
+ int ports_found;
+
+ //From IUSBEnumerator
+ virtual void setVidPid(uint16_t vid, uint16_t pid);
+ virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed
+ virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used
+
+private:
+ bool dev_connected;
+};
+
+#else // (USBHOST_SERIAL > 1)
+
+class USBHostMultiSerial : public IUSBEnumerator {
+public:
+ USBHostMultiSerial();
+ virtual ~USBHostMultiSerial();
+
+ USBHostSerialPort* getPort(int port)
+ {
+ return port < USBHOST_SERIAL ? ports[port] : NULL;
+ }
+
+ /**
+ * Try to connect a serial device
+ *
+ * @return true if connection was successful
+ */
+ bool connect();
+
+ void disconnect();
+
+ /**
+ * Check if a any serial port is connected
+ *
+ * @returns true if a serial device is connected
+ */
+ bool connected();
+
+protected:
+ USBHost* host;
+ USBDeviceConnected* dev;
+ USBHostSerialPort* ports[USBHOST_SERIAL];
+ uint8_t port_intf[USBHOST_SERIAL];
+ int ports_found;
+
+ //From IUSBEnumerator
+ virtual void setVidPid(uint16_t vid, uint16_t pid);
+ virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed
+ virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used
+
+private:
+ bool dev_connected;
+};
+#endif // (USBHOST_SERIAL <= 1)
+
+#endif
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtos/Mail.h Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,109 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2012 ARM Limited
+ *
+ * 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 MAIL_H
+#define MAIL_H
+
+#include <stdint.h>
+#include <string.h>
+
+#include "cmsis_os.h"
+
+namespace rtos {
+
+/** The Mail class allow to control, send, receive, or wait for mail.
+ A mail is a memory block that is send to a thread or interrupt service routine.
+ @tparam T data type of a single message element.
+ @tparam queue_sz maximum number of messages in queue.
+*/
+template<typename T, uint32_t queue_sz>
+class Mail {
+public:
+ /** Create and Initialise Mail queue. */
+ Mail() {
+ #ifdef CMSIS_OS_RTX
+ memset(_mail_q, 0, sizeof(_mail_q));
+ _mail_p[0] = _mail_q;
+
+ memset(_mail_m, 0, sizeof(_mail_m));
+ _mail_p[1] = _mail_m;
+
+ _mail_def.pool = _mail_p;
+ _mail_def.queue_sz = queue_sz;
+ _mail_def.item_sz = sizeof(T);
+ #endif
+ _mail_id = osMailCreate(&_mail_def, NULL);
+ }
+
+ /** Allocate a memory block of type T
+ @param millisec timeout value or 0 in case of no time-out. (default: 0).
+ @return pointer to memory block that can be filled with mail or NULL in case error.
+ */
+ T* alloc(uint32_t millisec=0) {
+ return (T*)osMailAlloc(_mail_id, millisec);
+ }
+
+ /** Allocate a memory block of type T and set memory block to zero.
+ @param millisec timeout value or 0 in case of no time-out. (default: 0).
+ @return pointer to memory block that can be filled with mail or NULL in case error.
+ */
+ T* calloc(uint32_t millisec=0) {
+ return (T*)osMailCAlloc(_mail_id, millisec);
+ }
+
+ /** Put a mail in the queue.
+ @param mptr memory block previously allocated with Mail::alloc or Mail::calloc.
+ @return status code that indicates the execution status of the function.
+ */
+ osStatus put(T *mptr) {
+ return osMailPut(_mail_id, (void*)mptr);
+ }
+
+ /** Get a mail from a queue.
+ @param millisec timeout value or 0 in case of no time-out. (default: osWaitForever).
+ @return event that contains mail information or error code.
+ */
+ osEvent get(uint32_t millisec=osWaitForever) {
+ return osMailGet(_mail_id, millisec);
+ }
+
+ /** Free a memory block from a mail.
+ @param mptr pointer to the memory block that was obtained with Mail::get.
+ @return status code that indicates the execution status of the function.
+ */
+ osStatus free(T *mptr) {
+ return osMailFree(_mail_id, (void*)mptr);
+ }
+
+private:
+ osMailQId _mail_id;
+ osMailQDef_t _mail_def;
+#ifdef CMSIS_OS_RTX
+ uint32_t _mail_q[4+(queue_sz)];
+ uint32_t _mail_m[3+((sizeof(T)+3)/4)*(queue_sz)];
+ void *_mail_p[2];
+#endif
+};
+
+}
+
+#endif
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtos/MemoryPool.h Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,82 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2012 ARM Limited
+ *
+ * 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 MEMORYPOOL_H
+#define MEMORYPOOL_H
+
+#include <stdint.h>
+#include <string.h>
+
+#include "cmsis_os.h"
+
+namespace rtos {
+
+/** Define and manage fixed-size memory pools of objects of a given type.
+ @tparam T data type of a single object (element).
+ @tparam queue_sz maximum number of objects (elements) in the memory pool.
+*/
+template<typename T, uint32_t pool_sz>
+class MemoryPool {
+public:
+ /** Create and Initialize a memory pool. */
+ MemoryPool() {
+ #ifdef CMSIS_OS_RTX
+ memset(_pool_m, 0, sizeof(_pool_m));
+ _pool_def.pool = _pool_m;
+
+ _pool_def.pool_sz = pool_sz;
+ _pool_def.item_sz = sizeof(T);
+ #endif
+ _pool_id = osPoolCreate(&_pool_def);
+ }
+
+ /** Allocate a memory block of type T from a memory pool.
+ @return address of the allocated memory block or NULL in case of no memory available.
+ */
+ T* alloc(void) {
+ return (T*)osPoolAlloc(_pool_id);
+ }
+
+ /** Allocate a memory block of type T from a memory pool and set memory block to zero.
+ @return address of the allocated memory block or NULL in case of no memory available.
+ */
+ T* calloc(void) {
+ return (T*)osPoolCAlloc(_pool_id);
+ }
+
+ /** Return an allocated memory block back to a specific memory pool.
+ @param address of the allocated memory block that is returned to the memory pool.
+ @return status code that indicates the execution status of the function.
+ */
+ osStatus free(T *block) {
+ return osPoolFree(_pool_id, (void*)block);
+ }
+
+private:
+ osPoolId _pool_id;
+ osPoolDef_t _pool_def;
+#ifdef CMSIS_OS_RTX
+ uint32_t _pool_m[3+((sizeof(T)+3)/4)*(pool_sz)];
+#endif
+};
+
+}
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtos/Mutex.cpp Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,56 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2012 ARM Limited
+ *
+ * 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 "Mutex.h"
+
+#include <string.h>
+#include "mbed_error.h"
+
+namespace rtos {
+
+Mutex::Mutex() {
+#ifdef CMSIS_OS_RTX
+ memset(_mutex_data, 0, sizeof(_mutex_data));
+ _osMutexDef.mutex = _mutex_data;
+#endif
+ _osMutexId = osMutexCreate(&_osMutexDef);
+ if (_osMutexId == NULL) {
+ error("Error initializing the mutex object\n");
+ }
+}
+
+osStatus Mutex::lock(uint32_t millisec) {
+ return osMutexWait(_osMutexId, millisec);
+}
+
+bool Mutex::trylock() {
+ return (osMutexWait(_osMutexId, 0) == osOK);
+}
+
+osStatus Mutex::unlock() {
+ return osMutexRelease(_osMutexId);
+}
+
+Mutex::~Mutex() {
+ osMutexDelete(_osMutexId);
+}
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtos/Mutex.h Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,65 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2012 ARM Limited
+ *
+ * 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 MUTEX_H
+#define MUTEX_H
+
+#include <stdint.h>
+#include "cmsis_os.h"
+
+namespace rtos {
+
+/** The Mutex class is used to synchronise the execution of threads.
+ This is for example used to protect access to a shared resource.
+*/
+class Mutex {
+public:
+ /** Create and Initialize a Mutex object */
+ Mutex();
+
+ /** Wait until a Mutex becomes available.
+ @param millisec timeout value or 0 in case of no time-out. (default: osWaitForever)
+ @return status code that indicates the execution status of the function.
+ */
+ osStatus lock(uint32_t millisec=osWaitForever);
+
+ /** Try to lock the mutex, and return immediately
+ @return true if the mutex was acquired, false otherwise.
+ */
+ bool trylock();
+
+ /** Unlock the mutex that has previously been locked by the same thread
+ @return status code that indicates the execution status of the function.
+ */
+ osStatus unlock();
+
+ ~Mutex();
+
+private:
+ osMutexId _osMutexId;
+ osMutexDef_t _osMutexDef;
+#ifdef CMSIS_OS_RTX
+ int32_t _mutex_data[3];
+#endif
+};
+
+}
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtos/Queue.h Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,81 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2012 ARM Limited
+ *
+ * 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 QUEUE_H
+#define QUEUE_H
+
+#include <stdint.h>
+#include <string.h>
+
+#include "cmsis_os.h"
+#include "mbed_error.h"
+
+namespace rtos {
+
+/** The Queue class allow to control, send, receive, or wait for messages.
+ A message can be a integer or pointer value to a certain type T that is send
+ to a thread or interrupt service routine.
+ @tparam T data type of a single message element.
+ @tparam queue_sz maximum number of messages in queue.
+*/
+template<typename T, uint32_t queue_sz>
+class Queue {
+public:
+ /** Create and initialise a message Queue. */
+ Queue() {
+ #ifdef CMSIS_OS_RTX
+ memset(_queue_q, 0, sizeof(_queue_q));
+ _queue_def.pool = _queue_q;
+ _queue_def.queue_sz = queue_sz;
+ #endif
+ _queue_id = osMessageCreate(&_queue_def, NULL);
+ if (_queue_id == NULL) {
+ error("Error initialising the queue object\n");
+ }
+ }
+
+ /** Put a message in a Queue.
+ @param data message pointer.
+ @param millisec timeout value or 0 in case of no time-out. (default: 0)
+ @return status code that indicates the execution status of the function.
+ */
+ osStatus put(T* data, uint32_t millisec=0) {
+ return osMessagePut(_queue_id, (uint32_t)data, millisec);
+ }
+
+ /** Get a message or Wait for a message from a Queue.
+ @param millisec timeout value or 0 in case of no time-out. (default: osWaitForever).
+ @return event information that includes the message and the status code.
+ */
+ osEvent get(uint32_t millisec=osWaitForever) {
+ return osMessageGet(_queue_id, millisec);
+ }
+
+private:
+ osMessageQId _queue_id;
+ osMessageQDef_t _queue_def;
+#ifdef CMSIS_OS_RTX
+ uint32_t _queue_q[4+(queue_sz)];
+#endif
+};
+
+}
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtos/RtosTimer.cpp Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,53 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2012 ARM Limited
+ *
+ * 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 "RtosTimer.h"
+
+#include <string.h>
+
+#include "cmsis_os.h"
+#include "mbed_error.h"
+
+namespace rtos {
+
+RtosTimer::RtosTimer(void (*periodic_task)(void const *argument), os_timer_type type, void *argument) {
+#ifdef CMSIS_OS_RTX
+ _timer.ptimer = periodic_task;
+
+ memset(_timer_data, 0, sizeof(_timer_data));
+ _timer.timer = _timer_data;
+#endif
+ _timer_id = osTimerCreate(&_timer, type, argument);
+}
+
+osStatus RtosTimer::start(uint32_t millisec) {
+ return osTimerStart(_timer_id, millisec);
+}
+
+osStatus RtosTimer::stop(void) {
+ return osTimerStop(_timer_id);
+}
+
+RtosTimer::~RtosTimer() {
+ osTimerDelete(_timer_id);
+}
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtos/RtosTimer.h Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,71 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2012 ARM Limited
+ *
+ * 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 RTOS_TIMER_H
+#define RTOS_TIMER_H
+
+#include <stdint.h>
+#include "cmsis_os.h"
+
+namespace rtos {
+
+/** The RtosTimer class allow creating and and controlling of timer functions in the system.
+ A timer function is called when a time period expires whereby both on-shot and
+ periodic timers are possible. A timer can be started, restarted, or stopped.
+
+ Timers are handled in the thread osTimerThread.
+ Callback functions run under control of this thread and may use CMSIS-RTOS API calls.
+*/
+class RtosTimer {
+public:
+ /** Create and Start timer.
+ @param task name of the timer call back function.
+ @param type osTimerOnce for one-shot or osTimerPeriodic for periodic behaviour. (default: osTimerPeriodic)
+ @param argument argument to the timer call back function. (default: NULL)
+ */
+ RtosTimer(void (*task)(void const *argument),
+ os_timer_type type=osTimerPeriodic,
+ void *argument=NULL);
+
+ /** Stop the timer.
+ @return status code that indicates the execution status of the function.
+ */
+ osStatus stop(void);
+
+ /** start a timer.
+ @param millisec time delay value of the timer.
+ @return status code that indicates the execution status of the function.
+ */
+ osStatus start(uint32_t millisec);
+
+ ~RtosTimer();
+
+private:
+ osTimerId _timer_id;
+ osTimerDef_t _timer;
+#ifdef CMSIS_OS_RTX
+ uint32_t _timer_data[5];
+#endif
+};
+
+}
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtos/Semaphore.cpp Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,48 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2012 ARM Limited
+ *
+ * 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 "Semaphore.h"
+
+#include <string.h>
+
+namespace rtos {
+
+Semaphore::Semaphore(int32_t count) {
+#ifdef CMSIS_OS_RTX
+ memset(_semaphore_data, 0, sizeof(_semaphore_data));
+ _osSemaphoreDef.semaphore = _semaphore_data;
+#endif
+ _osSemaphoreId = osSemaphoreCreate(&_osSemaphoreDef, count);
+}
+
+int32_t Semaphore::wait(uint32_t millisec) {
+ return osSemaphoreWait(_osSemaphoreId, millisec);
+}
+
+osStatus Semaphore::release(void) {
+ return osSemaphoreRelease(_osSemaphoreId);
+}
+
+Semaphore::~Semaphore() {
+ osSemaphoreDelete(_osSemaphoreId);
+}
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtos/Semaphore.h Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,60 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2012 ARM Limited
+ *
+ * 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 SEMAPHORE_H
+#define SEMAPHORE_H
+
+#include <stdint.h>
+#include "cmsis_os.h"
+
+namespace rtos {
+
+/** The Semaphore class is used to manage and protect access to a set of shared resources. */
+class Semaphore {
+public:
+ /** Create and Initialize a Semaphore object used for managing resources.
+ @param number of available resources; maximum index value is (count-1).
+ */
+ Semaphore(int32_t count);
+
+ /** Wait until a Semaphore resource becomes available.
+ @param millisec timeout value or 0 in case of no time-out. (default: osWaitForever).
+ @return number of available tokens, or -1 in case of incorrect parameters
+ */
+ int32_t wait(uint32_t millisec=osWaitForever);
+
+ /** Release a Semaphore resource that was obtain with Semaphore::wait.
+ @return status code that indicates the execution status of the function.
+ */
+ osStatus release(void);
+
+ ~Semaphore();
+
+private:
+ osSemaphoreId _osSemaphoreId;
+ osSemaphoreDef_t _osSemaphoreDef;
+#ifdef CMSIS_OS_RTX
+ uint32_t _semaphore_data[2];
+#endif
+};
+
+}
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtos/Thread.cpp Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,100 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2012 ARM Limited
+ *
+ * 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 "Thread.h"
+
+#include "mbed_error.h"
+
+namespace rtos {
+
+Thread::Thread(void (*task)(void const *argument), void *argument,
+ osPriority priority, uint32_t stack_size, unsigned char *stack_pointer) {
+#ifdef CMSIS_OS_RTX
+ _thread_def.pthread = task;
+ _thread_def.tpriority = priority;
+ _thread_def.stacksize = stack_size;
+#ifndef __MBED_CMSIS_RTOS_CA9
+ if (stack_pointer != NULL) {
+ _thread_def.stack_pointer = (uint32_t*)stack_pointer;
+ _dynamic_stack = false;
+ } else {
+ _thread_def.stack_pointer = new uint32_t[stack_size/sizeof(uint32_t)];
+ if (_thread_def.stack_pointer == NULL)
+ error("Error allocating the stack memory\n");
+ _dynamic_stack = true;
+ }
+#endif
+#endif
+ _tid = osThreadCreate(&_thread_def, argument);
+}
+
+osStatus Thread::terminate() {
+ return osThreadTerminate(_tid);
+}
+
+osStatus Thread::set_priority(osPriority priority) {
+ return osThreadSetPriority(_tid, priority);
+}
+
+osPriority Thread::get_priority() {
+ return osThreadGetPriority(_tid);
+}
+
+int32_t Thread::signal_set(int32_t signals) {
+ return osSignalSet(_tid, signals);
+}
+
+Thread::State Thread::get_state() {
+#ifndef __MBED_CMSIS_RTOS_CA9
+ return ((State)_thread_def.tcb.state);
+#else
+ uint8_t status;
+ status = osThreadGetState(_tid);
+ return ((State)status);
+#endif
+}
+
+osEvent Thread::signal_wait(int32_t signals, uint32_t millisec) {
+ return osSignalWait(signals, millisec);
+}
+
+osStatus Thread::wait(uint32_t millisec) {
+ return osDelay(millisec);
+}
+
+osStatus Thread::yield() {
+ return osThreadYield();
+}
+
+osThreadId Thread::gettid() {
+ return osThreadGetId();
+}
+
+Thread::~Thread() {
+ terminate();
+#ifndef __MBED_CMSIS_RTOS_CA9
+ if (_dynamic_stack) {
+ delete[] (_thread_def.stack_pointer);
+ }
+#endif
+}
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtos/Thread.h Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,118 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2012 ARM Limited
+ *
+ * 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 THREAD_H
+#define THREAD_H
+
+#include <stdint.h>
+#include "cmsis_os.h"
+
+namespace rtos {
+
+/** The Thread class allow defining, creating, and controlling thread functions in the system. */
+class Thread {
+public:
+ /** Create a new thread, and start it executing the specified function.
+ @param task function to be executed by this thread.
+ @param argument pointer that is passed to the thread function as start argument. (default: NULL).
+ @param priority initial priority of the thread function. (default: osPriorityNormal).
+ @param stack_size stack size (in bytes) requirements for the thread function. (default: DEFAULT_STACK_SIZE).
+ @param stack_pointer pointer to the stack area to be used by this thread (default: NULL).
+ */
+ Thread(void (*task)(void const *argument), void *argument=NULL,
+ osPriority priority=osPriorityNormal,
+ uint32_t stack_size=DEFAULT_STACK_SIZE,
+ unsigned char *stack_pointer=NULL);
+
+ /** Terminate execution of a thread and remove it from Active Threads
+ @return status code that indicates the execution status of the function.
+ */
+ osStatus terminate();
+
+ /** Set priority of an active thread
+ @param priority new priority value for the thread function.
+ @return status code that indicates the execution status of the function.
+ */
+ osStatus set_priority(osPriority priority);
+
+ /** Get priority of an active thread
+ @return current priority value of the thread function.
+ */
+ osPriority get_priority();
+
+ /** Set the specified Signal Flags of an active thread.
+ @param signals specifies the signal flags of the thread that should be set.
+ @return previous signal flags of the specified thread or 0x80000000 in case of incorrect parameters.
+ */
+ int32_t signal_set(int32_t signals);
+
+ /** State of the Thread */
+ enum State {
+ Inactive, /**< Not created or terminated */
+ Ready, /**< Ready to run */
+ Running, /**< Running */
+ WaitingDelay, /**< Waiting for a delay to occur */
+ WaitingInterval, /**< Waiting for an interval to occur */
+ WaitingOr, /**< Waiting for one event in a set to occur */
+ WaitingAnd, /**< Waiting for multiple events in a set to occur */
+ WaitingSemaphore, /**< Waiting for a semaphore event to occur */
+ WaitingMailbox, /**< Waiting for a mailbox event to occur */
+ WaitingMutex, /**< Waiting for a mutex event to occur */
+ };
+
+ /** State of this Thread
+ @return the State of this Thread
+ */
+ State get_state();
+
+ /** Wait for one or more Signal Flags to become signaled for the current RUNNING thread.
+ @param signals wait until all specified signal flags set or 0 for any single signal flag.
+ @param millisec timeout value or 0 in case of no time-out. (default: osWaitForever).
+ @return event flag information or error code.
+ */
+ static osEvent signal_wait(int32_t signals, uint32_t millisec=osWaitForever);
+
+ /** Wait for a specified time period in millisec:
+ @param millisec time delay value
+ @return status code that indicates the execution status of the function.
+ */
+ static osStatus wait(uint32_t millisec);
+
+ /** Pass control to next thread that is in state READY.
+ @return status code that indicates the execution status of the function.
+ */
+ static osStatus yield();
+
+ /** Get the thread id of the current running thread.
+ @return thread ID for reference by other functions or NULL in case of error.
+ */
+ static osThreadId gettid();
+
+ virtual ~Thread();
+
+private:
+ osThreadId _tid;
+ osThreadDef_t _thread_def;
+ bool _dynamic_stack;
+};
+
+}
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/mbed-rtos/rtos/rtos.h Wed Apr 15 06:23:18 2015 +0000 @@ -0,0 +1,35 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2012 ARM Limited + * + * 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 RTOS_H +#define RTOS_H + +#include "Thread.h" +#include "Mutex.h" +#include "RtosTimer.h" +#include "Semaphore.h" +#include "Mail.h" +#include "MemoryPool.h" +#include "Queue.h" + +using namespace rtos; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/TARGET_CORTEX_M/HAL_CM.c Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,170 @@
+/*----------------------------------------------------------------------------
+ * RL-ARM - RTX
+ *----------------------------------------------------------------------------
+ * Name: HAL_CM.C
+ * Purpose: Hardware Abstraction Layer for Cortex-M
+ * Rev.: V4.60
+ *----------------------------------------------------------------------------
+ *
+ * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *---------------------------------------------------------------------------*/
+
+#include "rt_TypeDef.h"
+#include "RTX_Conf.h"
+#include "rt_HAL_CM.h"
+
+
+/*----------------------------------------------------------------------------
+ * Global Variables
+ *---------------------------------------------------------------------------*/
+
+#ifdef DBG_MSG
+BIT dbg_msg;
+#endif
+
+/*----------------------------------------------------------------------------
+ * Functions
+ *---------------------------------------------------------------------------*/
+
+
+/*--------------------------- rt_init_stack ---------------------------------*/
+
+void rt_init_stack (P_TCB p_TCB, FUNCP task_body) {
+ /* Prepare TCB and saved context for a first time start of a task. */
+ U32 *stk,i,size;
+
+ /* Prepare a complete interrupt frame for first task start */
+ size = p_TCB->priv_stack >> 2;
+
+ /* Write to the top of stack. */
+ stk = &p_TCB->stack[size];
+
+ /* Auto correct to 8-byte ARM stack alignment. */
+ if ((U32)stk & 0x04) {
+ stk--;
+ }
+
+ stk -= 16;
+
+ /* Default xPSR and initial PC */
+ stk[15] = INITIAL_xPSR;
+ stk[14] = (U32)task_body;
+
+ /* Clear R4-R11,R0-R3,R12,LR registers. */
+ for (i = 0; i < 14; i++) {
+ stk[i] = 0;
+ }
+
+ /* Assign a void pointer to R0. */
+ stk[8] = (U32)p_TCB->msg;
+
+ /* Initial Task stack pointer. */
+ p_TCB->tsk_stack = (U32)stk;
+
+ /* Task entry point. */
+ p_TCB->ptask = task_body;
+
+ /* Set a magic word for checking of stack overflow.
+ For the main thread (ID: 0x01) the stack is in a memory area shared with the
+ heap, therefore the last word of the stack is a moving target.
+ We want to do stack/heap collision detection instead.
+ */
+ if (p_TCB->task_id != 0x01)
+ p_TCB->stack[0] = MAGIC_WORD;
+}
+
+
+/*--------------------------- rt_ret_val ----------------------------------*/
+
+static __inline U32 *rt_ret_regs (P_TCB p_TCB) {
+ /* Get pointer to task return value registers (R0..R3) in Stack */
+#if (__TARGET_FPU_VFP)
+ if (p_TCB->stack_frame) {
+ /* Extended Stack Frame: R4-R11,S16-S31,R0-R3,R12,LR,PC,xPSR,S0-S15,FPSCR */
+ return (U32 *)(p_TCB->tsk_stack + 8*4 + 16*4);
+ } else {
+ /* Basic Stack Frame: R4-R11,R0-R3,R12,LR,PC,xPSR */
+ return (U32 *)(p_TCB->tsk_stack + 8*4);
+ }
+#else
+ /* Stack Frame: R4-R11,R0-R3,R12,LR,PC,xPSR */
+ return (U32 *)(p_TCB->tsk_stack + 8*4);
+#endif
+}
+
+void rt_ret_val (P_TCB p_TCB, U32 v0) {
+ U32 *ret;
+
+ ret = rt_ret_regs(p_TCB);
+ ret[0] = v0;
+}
+
+void rt_ret_val2(P_TCB p_TCB, U32 v0, U32 v1) {
+ U32 *ret;
+
+ ret = rt_ret_regs(p_TCB);
+ ret[0] = v0;
+ ret[1] = v1;
+}
+
+
+/*--------------------------- dbg_init --------------------------------------*/
+
+#ifdef DBG_MSG
+void dbg_init (void) {
+ if ((DEMCR & DEMCR_TRCENA) &&
+ (ITM_CONTROL & ITM_ITMENA) &&
+ (ITM_ENABLE & (1UL << 31))) {
+ dbg_msg = __TRUE;
+ }
+}
+#endif
+
+/*--------------------------- dbg_task_notify -------------------------------*/
+
+#ifdef DBG_MSG
+void dbg_task_notify (P_TCB p_tcb, BOOL create) {
+ while (ITM_PORT31_U32 == 0);
+ ITM_PORT31_U32 = (U32)p_tcb->ptask;
+ while (ITM_PORT31_U32 == 0);
+ ITM_PORT31_U16 = (create << 8) | p_tcb->task_id;
+}
+#endif
+
+/*--------------------------- dbg_task_switch -------------------------------*/
+
+#ifdef DBG_MSG
+void dbg_task_switch (U32 task_id) {
+ while (ITM_PORT31_U32 == 0);
+ ITM_PORT31_U8 = task_id;
+}
+#endif
+
+
+/*----------------------------------------------------------------------------
+ * end of file
+ *---------------------------------------------------------------------------*/
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/TARGET_CORTEX_M/RTX_CM_lib.h Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,491 @@
+/*----------------------------------------------------------------------------
+ * RL-ARM - RTX
+ *----------------------------------------------------------------------------
+ * Name: RTX_CM_LIB.H
+ * Purpose: RTX Kernel System Configuration
+ * Rev.: V4.60
+ *----------------------------------------------------------------------------
+ *
+ * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *---------------------------------------------------------------------------*/
+#include "mbed_error.h"
+
+#if defined (__CC_ARM)
+#pragma O3
+#define __USED __attribute__((used))
+#elif defined (__GNUC__)
+#pragma GCC optimize ("O3")
+#define __USED __attribute__((used))
+#elif defined (__ICCARM__)
+#define __USED __root
+#endif
+
+
+/*----------------------------------------------------------------------------
+ * Definitions
+ *---------------------------------------------------------------------------*/
+
+#define _declare_box(pool,size,cnt) uint32_t pool[(((size)+3)/4)*(cnt) + 3]
+#define _declare_box8(pool,size,cnt) uint64_t pool[(((size)+7)/8)*(cnt) + 2]
+
+#define OS_TCB_SIZE 48
+#define OS_TMR_SIZE 8
+
+#if defined (__CC_ARM) && !defined (__MICROLIB)
+
+typedef void *OS_ID;
+typedef uint32_t OS_TID;
+typedef uint32_t OS_MUT[3];
+typedef uint32_t OS_RESULT;
+
+#define runtask_id() rt_tsk_self()
+#define mutex_init(m) rt_mut_init(m)
+#define mutex_wait(m) os_mut_wait(m,0xFFFF)
+#define mutex_rel(m) os_mut_release(m)
+
+extern OS_TID rt_tsk_self (void);
+extern void rt_mut_init (OS_ID mutex);
+extern OS_RESULT rt_mut_release (OS_ID mutex);
+extern OS_RESULT rt_mut_wait (OS_ID mutex, uint16_t timeout);
+
+#define os_mut_wait(mutex,timeout) _os_mut_wait((uint32_t)rt_mut_wait,mutex,timeout)
+#define os_mut_release(mutex) _os_mut_release((uint32_t)rt_mut_release,mutex)
+
+OS_RESULT _os_mut_release (uint32_t p, OS_ID mutex) __svc_indirect(0);
+OS_RESULT _os_mut_wait (uint32_t p, OS_ID mutex, uint16_t timeout) __svc_indirect(0);
+
+#endif
+
+
+/*----------------------------------------------------------------------------
+ * Global Variables
+ *---------------------------------------------------------------------------*/
+
+#if (OS_TIMERS != 0)
+#define OS_TASK_CNT (OS_TASKCNT + 1)
+#else
+#define OS_TASK_CNT OS_TASKCNT
+#endif
+
+uint16_t const os_maxtaskrun = OS_TASK_CNT;
+uint32_t const os_rrobin = (OS_ROBIN << 16) | OS_ROBINTOUT;
+uint32_t const os_trv = OS_TRV;
+uint8_t const os_flags = OS_RUNPRIV;
+
+/* Export following defines to uVision debugger. */
+__USED uint32_t const os_clockrate = OS_TICK;
+__USED uint32_t const os_timernum = 0;
+
+/* Stack for the os_idle_demon */
+unsigned int idle_task_stack[OS_IDLESTKSIZE];
+unsigned short const idle_task_stack_size = OS_IDLESTKSIZE;
+
+#ifndef OS_FIFOSZ
+ #define OS_FIFOSZ 16
+#endif
+
+/* Fifo Queue buffer for ISR requests.*/
+uint32_t os_fifo[OS_FIFOSZ*2+1];
+uint8_t const os_fifo_size = OS_FIFOSZ;
+
+/* An array of Active task pointers. */
+void *os_active_TCB[OS_TASK_CNT];
+
+/* User Timers Resources */
+#if (OS_TIMERS != 0)
+extern void osTimerThread (void const *argument);
+osThreadDef(osTimerThread, (osPriority)(OS_TIMERPRIO-3), 4*OS_TIMERSTKSZ);
+osThreadId osThreadId_osTimerThread;
+osMessageQDef(osTimerMessageQ, OS_TIMERCBQS, void *);
+osMessageQId osMessageQId_osTimerMessageQ;
+#else
+osThreadDef_t os_thread_def_osTimerThread = { NULL };
+osThreadId osThreadId_osTimerThread;
+osMessageQDef(osTimerMessageQ, 0, void *);
+osMessageQId osMessageQId_osTimerMessageQ;
+#endif
+
+
+/*----------------------------------------------------------------------------
+ * RTX Optimizations (empty functions)
+ *---------------------------------------------------------------------------*/
+
+#if OS_ROBIN == 0
+ void rt_init_robin (void) {;}
+ void rt_chk_robin (void) {;}
+#endif
+
+#if OS_STKCHECK == 0
+ void rt_stk_check (void) {;}
+#endif
+
+
+/*----------------------------------------------------------------------------
+ * Standard Library multithreading interface
+ *---------------------------------------------------------------------------*/
+
+#if defined (__CC_ARM) && !defined (__MICROLIB)
+ static OS_MUT std_libmutex[OS_MUTEXCNT];
+ static uint32_t nr_mutex;
+
+ /*--------------------------- _mutex_initialize -----------------------------*/
+
+int _mutex_initialize (OS_ID *mutex) {
+ /* Allocate and initialize a system mutex. */
+
+ if (nr_mutex >= OS_MUTEXCNT) {
+ /* If you are here, you need to increase the number OS_MUTEXCNT. */
+ error("Not enough stdlib mutexes\n");
+ }
+ *mutex = &std_libmutex[nr_mutex++];
+ mutex_init (*mutex);
+ return (1);
+}
+
+
+/*--------------------------- _mutex_acquire --------------------------------*/
+
+__attribute__((used)) void _mutex_acquire (OS_ID *mutex) {
+ /* Acquire a system mutex, lock stdlib resources. */
+ if (runtask_id ()) {
+ /* RTX running, acquire a mutex. */
+ mutex_wait (*mutex);
+ }
+}
+
+
+/*--------------------------- _mutex_release --------------------------------*/
+
+__attribute__((used)) void _mutex_release (OS_ID *mutex) {
+ /* Release a system mutex, unlock stdlib resources. */
+ if (runtask_id ()) {
+ /* RTX running, release a mutex. */
+ mutex_rel (*mutex);
+ }
+}
+
+#endif
+
+
+/*----------------------------------------------------------------------------
+ * RTX Startup
+ *---------------------------------------------------------------------------*/
+
+/* Main Thread definition */
+extern int main (void);
+osThreadDef_t os_thread_def_main = {(os_pthread)main, osPriorityNormal, 0, NULL};
+
+// This define should be probably moved to the CMSIS layer
+#if defined(TARGET_LPC1768)
+#define INITIAL_SP (0x10008000UL)
+
+#elif defined(TARGET_LPC11U24)
+#define INITIAL_SP (0x10002000UL)
+
+#elif defined(TARGET_LPC11U35_401) || defined(TARGET_LPC11U35_501) || defined(TARGET_LPCCAPPUCCINO)
+#define INITIAL_SP (0x10002000UL)
+
+#elif defined(TARGET_LPC1114)
+#define INITIAL_SP (0x10001000UL)
+
+#elif defined(TARGET_LPC812)
+#define INITIAL_SP (0x10001000UL)
+
+#elif defined(TARGET_LPC824)
+#define INITIAL_SP (0x10002000UL)
+
+#elif defined(TARGET_KL25Z)
+#define INITIAL_SP (0x20003000UL)
+
+#elif defined(TARGET_K64F)
+#define INITIAL_SP (0x20030000UL)
+
+#elif defined(TARGET_K22F)
+#define INITIAL_SP (0x20010000UL)
+
+#elif defined(TARGET_KL46Z)
+#define INITIAL_SP (0x20006000UL)
+
+#elif defined(TARGET_KL43Z)
+#define INITIAL_SP (0x20006000UL)
+
+#elif defined(TARGET_KL05Z)
+#define INITIAL_SP (0x20000C00UL)
+
+#elif defined(TARGET_LPC4088) || defined(TARGET_LPC4088_DM)
+#define INITIAL_SP (0x10010000UL)
+
+#elif defined(TARGET_LPC4330)
+#define INITIAL_SP (0x10008000UL)
+
+#elif defined(TARGET_LPC4337)
+#define INITIAL_SP (0x10008000UL)
+
+#elif defined(TARGET_LPC1347)
+#define INITIAL_SP (0x10002000UL)
+
+#elif defined(TARGET_STM32F100RB) || defined(TARGET_STM32F051R8)
+#define INITIAL_SP (0x20002000UL)
+
+#elif defined(TARGET_DISCO_F303VC)
+#define INITIAL_SP (0x2000A000UL)
+
+#elif defined(TARGET_STM32F407) || defined(TARGET_F407VG)
+#define INITIAL_SP (0x20020000UL)
+
+#elif defined(TARGET_STM32F401RE)
+#define INITIAL_SP (0x20018000UL)
+
+#elif defined(TARGET_LPC1549)
+#define INITIAL_SP (0x02009000UL)
+
+#elif defined(TARGET_LPC11U68)
+#define INITIAL_SP (0x10004000UL)
+
+#elif defined(TARGET_STM32F411RE)
+#define INITIAL_SP (0x20020000UL)
+
+#elif defined(TARGET_STM32F103RB)
+#define INITIAL_SP (0x20005000UL)
+
+#elif defined(TARGET_STM32F302R8)
+#define INITIAL_SP (0x20004000UL)
+
+#elif defined(TARGET_STM32F334R8)
+#define INITIAL_SP (0x20003000UL)
+
+#elif defined(TARGET_STM32F334C8)
+#define INITIAL_SP (0x20003000UL)
+
+#elif defined(TARGET_STM32F405RG)
+#define INITIAL_SP (0x20020000UL)
+
+#elif defined(TARGET_STM32F429ZI)
+#define INITIAL_SP (0x20030000UL)
+
+#elif defined(TARGET_STM32L053R8) || defined(TARGET_STM32L053C8)
+#define INITIAL_SP (0x20002000UL)
+
+#elif defined(TARGET_STM32F072RB)
+#define INITIAL_SP (0x20004000UL)
+
+#elif defined(TARGET_STM32F091RC)
+#define INITIAL_SP (0x20008000UL)
+
+#elif defined(TARGET_STM32F401VC)
+#define INITIAL_SP (0x20010000UL)
+
+#else
+#error "no target defined"
+
+#endif
+
+#ifdef __CC_ARM
+extern uint32_t Image$$RW_IRAM1$$ZI$$Limit[];
+#define HEAP_START (Image$$RW_IRAM1$$ZI$$Limit)
+#elif defined(__GNUC__)
+extern uint32_t __end__[];
+#define HEAP_START (__end__)
+#elif defined(__ICCARM__)
+#pragma section="HEAP"
+#define HEAP_START (void *)__section_begin("HEAP")
+#endif
+
+void set_main_stack(void) {
+ // That is the bottom of the main stack block: no collision detection
+ os_thread_def_main.stack_pointer = HEAP_START;
+
+ // Leave OS_SCHEDULERSTKSIZE words for the scheduler and interrupts
+ os_thread_def_main.stacksize = (INITIAL_SP - (unsigned int)HEAP_START) - (OS_SCHEDULERSTKSIZE * 4);
+}
+
+#if defined (__CC_ARM)
+#ifdef __MICROLIB
+void _main_init (void) __attribute__((section(".ARM.Collect$$$$000000FF")));
+void _main_init (void) {
+ osKernelInitialize();
+ set_main_stack();
+ osThreadCreate(&os_thread_def_main, NULL);
+ osKernelStart();
+ for (;;);
+}
+#else
+
+/* The single memory model is checking for stack collision at run time, verifing
+ that the heap pointer is underneath the stack pointer.
+
+ With the RTOS there is not only one stack above the heap, there are multiple
+ stacks and some of them are underneath the heap pointer.
+*/
+#pragma import(__use_two_region_memory)
+
+__asm void __rt_entry (void) {
+
+ IMPORT __user_setup_stackheap
+ IMPORT __rt_lib_init
+ IMPORT os_thread_def_main
+ IMPORT osKernelInitialize
+ IMPORT set_main_stack
+ IMPORT osKernelStart
+ IMPORT osThreadCreate
+ IMPORT exit
+
+ BL __user_setup_stackheap
+ MOV R1,R2
+ BL __rt_lib_init
+ BL osKernelInitialize
+ BL set_main_stack
+ LDR R0,=os_thread_def_main
+ MOVS R1,#0
+ BL osThreadCreate
+ BL osKernelStart
+ BL exit
+
+ ALIGN
+}
+#endif
+
+#elif defined (__GNUC__)
+
+#ifdef __CS3__
+
+/* CS3 start_c routine.
+ *
+ * Copyright (c) 2006, 2007 CodeSourcery Inc
+ *
+ * The authors hereby grant permission to use, copy, modify, distribute,
+ * and license this software and its documentation for any purpose, provided
+ * that existing copyright notices are retained in all copies and that this
+ * notice is included verbatim in any distributions. No written agreement,
+ * license, or royalty fee is required for any of the authorized uses.
+ * Modifications to this software may be copyrighted by their authors
+ * and need not follow the licensing terms described here, provided that
+ * the new terms are clearly indicated on the first page of each file where
+ * they apply.
+ */
+
+#include "cs3.h"
+
+extern void __libc_init_array (void);
+
+__attribute ((noreturn)) void __cs3_start_c (void){
+ unsigned regions = __cs3_region_num;
+ const struct __cs3_region *rptr = __cs3_regions;
+
+ /* Initialize memory */
+ for (regions = __cs3_region_num, rptr = __cs3_regions; regions--; rptr++) {
+ long long *src = (long long *)rptr->init;
+ long long *dst = (long long *)rptr->data;
+ unsigned limit = rptr->init_size;
+ unsigned count;
+
+ if (src != dst)
+ for (count = 0; count != limit; count += sizeof (long long))
+ *dst++ = *src++;
+ else
+ dst = (long long *)((char *)dst + limit);
+ limit = rptr->zero_size;
+ for (count = 0; count != limit; count += sizeof (long long))
+ *dst++ = 0;
+ }
+
+ /* Run initializers. */
+ __libc_init_array ();
+
+ osKernelInitialize();
+ set_main_stack();
+ osThreadCreate(&os_thread_def_main, NULL);
+ osKernelStart();
+ for (;;);
+}
+
+#else
+
+__attribute__((naked)) void software_init_hook (void) {
+ __asm (
+ ".syntax unified\n"
+ ".thumb\n"
+ "movs r0,#0\n"
+ "movs r1,#0\n"
+ "mov r4,r0\n"
+ "mov r5,r1\n"
+ "ldr r0,= __libc_fini_array\n"
+ "bl atexit\n"
+ "bl __libc_init_array\n"
+ "mov r0,r4\n"
+ "mov r1,r5\n"
+ "bl osKernelInitialize\n"
+ "bl set_main_stack\n"
+ "ldr r0,=os_thread_def_main\n"
+ "movs r1,#0\n"
+ "bl osThreadCreate\n"
+ "bl osKernelStart\n"
+ "bl exit\n"
+ );
+}
+
+#endif
+
+#elif defined (__ICCARM__)
+
+extern void* __vector_table;
+extern int __low_level_init(void);
+extern void __iar_data_init3(void);
+extern __weak void __iar_init_core( void );
+extern __weak void __iar_init_vfp( void );
+extern void __iar_dynamic_initialization(void);
+extern void mbed_sdk_init(void);
+extern void exit(int arg);
+
+#pragma required=__vector_table
+void __iar_program_start( void )
+{
+ __iar_init_core();
+ __iar_init_vfp();
+
+ int a;
+
+ if (__low_level_init() != 0) {
+ __iar_data_init3();
+ mbed_sdk_init();
+ __iar_dynamic_initialization();
+ }
+ osKernelInitialize();
+ set_main_stack();
+ osThreadCreate(&os_thread_def_main, NULL);
+ a = osKernelStart();
+ exit(a);
+
+}
+
+#endif
+
+
+/*----------------------------------------------------------------------------
+ * end of file
+ *---------------------------------------------------------------------------*/
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/mbed-rtos/rtx/TARGET_CORTEX_M/RTX_Conf.h Wed Apr 15 06:23:18 2015 +0000 @@ -0,0 +1,72 @@ +/*---------------------------------------------------------------------------- + * RL-ARM - RTX + *---------------------------------------------------------------------------- + * Name: RTX_CONFIG.H + * Purpose: Exported functions of RTX_Config.c + * Rev.: V4.60 + *---------------------------------------------------------------------------- + * + * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH + * All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + *---------------------------------------------------------------------------*/ + + +/* Error Codes */ +#define OS_ERR_STK_OVF 1 +#define OS_ERR_FIFO_OVF 2 +#define OS_ERR_MBX_OVF 3 + +/* Definitions */ +#define BOX_ALIGN_8 0x80000000 +#define _declare_box(pool,size,cnt) U32 pool[(((size)+3)/4)*(cnt) + 3] +#define _declare_box8(pool,size,cnt) U64 pool[(((size)+7)/8)*(cnt) + 2] +#define _init_box8(pool,size,bsize) _init_box (pool,size,(bsize) | BOX_ALIGN_8) + +/* Variables */ +extern U32 idle_task_stack[]; +extern U32 os_fifo[]; +extern void *os_active_TCB[]; + +/* Constants */ +extern U16 const os_maxtaskrun; +extern U32 const os_trv; +extern U8 const os_flags; +extern U32 const os_rrobin; +extern U32 const os_clockrate; +extern U32 const os_timernum; +extern U16 const idle_task_stack_size; + +extern U8 const os_fifo_size; + +/* Functions */ +extern void os_idle_demon (void); +extern int os_tick_init (void); +extern void os_tick_irqack (void); +extern void os_tmr_call (U16 info); +extern void os_error (U32 err_code); + +/*---------------------------------------------------------------------------- + * end of file + *---------------------------------------------------------------------------*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/TARGET_CORTEX_M/RTX_Conf_CM.c Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,307 @@
+/*----------------------------------------------------------------------------
+ * RL-ARM - RTX
+ *----------------------------------------------------------------------------
+ * Name: RTX_Conf_CM.C
+ * Purpose: Configuration of CMSIS RTX Kernel for Cortex-M
+ * Rev.: V4.60
+ *----------------------------------------------------------------------------
+ *
+ * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *---------------------------------------------------------------------------*/
+
+#include "cmsis_os.h"
+
+
+/*----------------------------------------------------------------------------
+ * RTX User configuration part BEGIN
+ *---------------------------------------------------------------------------*/
+
+//-------- <<< Use Configuration Wizard in Context Menu >>> -----------------
+//
+// <h>Thread Configuration
+// =======================
+//
+// <o>Number of concurrent running threads <0-250>
+// <i> Defines max. number of threads that will run at the same time.
+// counting "main", but not counting "osTimerThread"
+// <i> Default: 6
+#ifndef OS_TASKCNT
+# if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) || defined(TARGET_LPC4088) || defined(TARGET_LPC4088_DM) || defined(TARGET_LPC4330) || defined(TARGET_LPC4337) || defined(TARGET_LPC1347) || defined(TARGET_K64F) || defined(TARGET_STM32F401RE)\
+ || defined(TARGET_KL46Z) || defined(TARGET_KL43Z) || defined(TARGET_STM32F407) || defined(TARGET_F407VG) || defined(TARGET_STM32F303VC) || defined(TARGET_LPC1549) || defined(TARGET_LPC11U68) \
+ || defined(TARGET_STM32F411RE) || defined(TARGET_STM32F405RG) || defined(TARGET_K22F) || defined(TARGET_STM32F429ZI) || defined(TARGET_STM32F401VC)
+# define OS_TASKCNT 14
+# elif defined(TARGET_LPC11U24) || defined(TARGET_LPC11U35_401) || defined(TARGET_LPC11U35_501) || defined(TARGET_LPCCAPPUCCINO) || defined(TARGET_LPC1114) \
+ || defined(TARGET_LPC812) || defined(TARGET_KL25Z) || defined(TARGET_KL05Z) || defined(TARGET_STM32F100RB) || defined(TARGET_STM32F051R8) \
+ || defined(TARGET_STM32F103RB) || defined(TARGET_LPC824) || defined(TARGET_STM32F302R8) || defined(TARGET_STM32F334R8) || defined(TARGET_STM32F334C8) \
+ || defined(TARGET_STM32L053R8) || defined(TARGET_STM32L053C8) || defined(TARGET_STM32F072RB) || defined(TARGET_STM32F091RC)
+# define OS_TASKCNT 6
+# else
+# error "no target defined"
+# endif
+#endif
+
+// <o>Scheduler (+ interrupts) stack size [bytes] <64-4096:8><#/4>
+#ifndef OS_SCHEDULERSTKSIZE
+# if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) || defined(TARGET_LPC4088) || defined(TARGET_LPC4088_DM) || defined(TARGET_LPC4330) || defined(TARGET_LPC4337) || defined(TARGET_LPC1347) || defined(TARGET_K64F) || defined(TARGET_STM32F401RE)\
+ || defined(TARGET_KL46Z) || defined(TARGET_KL43Z) || defined(TARGET_STM32F407) || defined(TARGET_F407VG) || defined(TARGET_STM32F303VC) || defined(TARGET_LPC1549) || defined(TARGET_LPC11U68) \
+ || defined(TARGET_STM32F411RE) || defined(TARGET_STM32F405RG) || defined(TARGET_K22F) || defined(TARGET_STM32F429ZI) || defined(TARGET_STM32F401VC)
+# define OS_SCHEDULERSTKSIZE 256
+# elif defined(TARGET_LPC11U24) || defined(TARGET_LPC11U35_401) || defined(TARGET_LPC11U35_501) || defined(TARGET_LPCCAPPUCCINO) || defined(TARGET_LPC1114) \
+ || defined(TARGET_LPC812) || defined(TARGET_KL25Z) || defined(TARGET_KL05Z) || defined(TARGET_STM32F100RB) || defined(TARGET_STM32F051R8) \
+ || defined(TARGET_STM32F103RB) || defined(TARGET_LPC824) || defined(TARGET_STM32F302R8) || defined(TARGET_STM32F072RB) || defined(TARGET_STM32F091RC)
+# define OS_SCHEDULERSTKSIZE 128
+# elif defined(TARGET_STM32F334R8) || defined(TARGET_STM32F334C8) || defined(TARGET_STM32L053R8) || defined(TARGET_STM32L053C8)
+# define OS_SCHEDULERSTKSIZE 112
+# else
+# error "no target defined"
+# endif
+#endif
+
+// <o>Idle stack size [bytes] <64-4096:8><#/4>
+// <i> Defines default stack size for the Idle thread.
+#ifndef OS_IDLESTKSIZE
+ #define OS_IDLESTKSIZE 128
+#endif
+
+// <o>Timer Thread stack size [bytes] <64-4096:8><#/4>
+// <i> Defines stack size for Timer thread.
+// <i> Default: 200
+#ifndef OS_TIMERSTKSZ
+ #define OS_TIMERSTKSZ WORDS_STACK_SIZE
+#endif
+
+// <q>Check for stack overflow
+// <i> Includes the stack checking code for stack overflow.
+// <i> Note that additional code reduces the Kernel performance.
+#ifndef OS_STKCHECK
+ #define OS_STKCHECK 1
+#endif
+
+// <o>Processor mode for thread execution
+// <0=> Unprivileged mode
+// <1=> Privileged mode
+// <i> Default: Privileged mode
+#ifndef OS_RUNPRIV
+ #define OS_RUNPRIV 1
+#endif
+
+// </h>
+// <h>SysTick Timer Configuration
+// ==============================
+//
+// <o>Timer clock value [Hz] <1-1000000000>
+// <i> Defines the timer clock value.
+// <i> Default: 6000000 (6MHz)
+#ifndef OS_CLOCK
+# if defined(TARGET_LPC1768) || defined(TARGET_LPC2368)
+# define OS_CLOCK 96000000
+
+# elif defined(TARGET_LPC1347) || defined(TARGET_STM32F303VC) || defined(TARGET_LPC1549) || defined(TARGET_STM32F334R8) || defined(TARGET_STM32F334C8)
+# define OS_CLOCK 72000000
+
+# elif defined(TARGET_LPC11U24) || defined(TARGET_LPC11U35_401) || defined(TARGET_LPC11U35_501) || defined(TARGET_LPCCAPPUCCINO) || defined(TARGET_LPC1114) || defined(TARGET_KL25Z) \
+ || defined(TARGET_KL05Z) || defined(TARGET_KL46Z) || defined(TARGET_KL43Z) || defined(TARGET_STM32F051R8) || defined(TARGET_LPC11U68) || defined(TARGET_STM32F072RB) || defined(TARGET_STM32F091RC)
+# define OS_CLOCK 48000000
+
+# elif defined(TARGET_LPC812)
+# define OS_CLOCK 36000000
+
+# elif defined(TARGET_LPC824)
+# define OS_CLOCK 30000000
+
+# elif defined(TARGET_STM32F100RB)
+# define OS_CLOCK 24000000
+
+# elif defined(TARGET_LPC4088) || defined(TARGET_LPC4088_DM) || defined(TARGET_K64F) || defined(TARGET_K22F)
+# define OS_CLOCK 120000000
+
+# elif defined(TARGET_LPC4330)
+# define OS_CLOCK 204000000
+
+# elif defined(TARGET_LPC4337)
+# define OS_CLOCK 204000000
+
+# elif defined(TARGET_STM32F407) || defined(TARGET_F407VG)
+# define OS_CLOCK 168000000
+
+# elif defined(TARGET_STM32F401RE)
+# define OS_CLOCK 84000000
+
+# elif defined(TARGET_STM32F411RE)
+# define OS_CLOCK 100000000
+
+#elif defined(TARGET_STM32F103RB)
+# define OS_CLOCK 72000000
+
+#elif defined(TARGET_STM32F429ZI)
+# define OS_CLOCK 168000000
+
+#elif defined(TARGET_STM32F302R8)
+# define OS_CLOCK 64000000
+
+#elif defined(TARGET_STM32L053R8) || defined(TARGET_STM32L053C8)
+# define OS_CLOCK 32000000
+
+#elif defined(TARGET_STM32F401VC)
+# define OS_CLOCK 84000000
+
+# else
+# error "no target defined"
+# endif
+#endif
+
+// <o>Timer tick value [us] <1-1000000>
+// <i> Defines the timer tick value.
+// <i> Default: 1000 (1ms)
+#ifndef OS_TICK
+ #define OS_TICK 1000
+#endif
+
+// </h>
+
+// <h>System Configuration
+// =======================
+//
+// <e>Round-Robin Thread switching
+// ===============================
+//
+// <i> Enables Round-Robin Thread switching.
+#ifndef OS_ROBIN
+ #define OS_ROBIN 1
+#endif
+
+// <o>Round-Robin Timeout [ticks] <1-1000>
+// <i> Defines how long a thread will execute before a thread switch.
+// <i> Default: 5
+#ifndef OS_ROBINTOUT
+ #define OS_ROBINTOUT 5
+#endif
+
+// </e>
+
+// <e>User Timers
+// ==============
+// <i> Enables user Timers
+#ifndef OS_TIMERS
+ #define OS_TIMERS 1
+#endif
+
+// <o>Timer Thread Priority
+// <1=> Low
+// <2=> Below Normal
+// <3=> Normal
+// <4=> Above Normal
+// <5=> High
+// <6=> Realtime (highest)
+// <i> Defines priority for Timer Thread
+// <i> Default: High
+#ifndef OS_TIMERPRIO
+ #define OS_TIMERPRIO 5
+#endif
+
+// <o>Timer Callback Queue size <1-32>
+// <i> Number of concurrent active timer callback functions.
+// <i> Default: 4
+#ifndef OS_TIMERCBQSZ
+ #define OS_TIMERCBQS 4
+#endif
+
+// </e>
+
+// <o>ISR FIFO Queue size<4=> 4 entries <8=> 8 entries
+// <12=> 12 entries <16=> 16 entries
+// <24=> 24 entries <32=> 32 entries
+// <48=> 48 entries <64=> 64 entries
+// <96=> 96 entries
+// <i> ISR functions store requests to this buffer,
+// <i> when they are called from the interrupt handler.
+// <i> Default: 16 entries
+#ifndef OS_FIFOSZ
+ #define OS_FIFOSZ 16
+#endif
+
+// </h>
+
+//------------- <<< end of configuration section >>> -----------------------
+
+// Standard library system mutexes
+// ===============================
+// Define max. number system mutexes that are used to protect
+// the arm standard runtime library. For microlib they are not used.
+#ifndef OS_MUTEXCNT
+ #define OS_MUTEXCNT 12
+#endif
+
+/*----------------------------------------------------------------------------
+ * RTX User configuration part END
+ *---------------------------------------------------------------------------*/
+
+#define OS_TRV ((uint32_t)(((double)OS_CLOCK*(double)OS_TICK)/1E6)-1)
+
+
+/*----------------------------------------------------------------------------
+ * OS Idle daemon
+ *---------------------------------------------------------------------------*/
+void os_idle_demon (void) {
+ /* The idle demon is a system thread, running when no other thread is */
+ /* ready to run. */
+
+ /* Sleep: ideally, we should put the chip to sleep.
+ Unfortunately, this usually requires disconnecting the interface chip (debugger).
+ This can be done, but it would break the local file system.
+ */
+ for (;;) {
+ // sleep();
+ }
+}
+
+/*----------------------------------------------------------------------------
+ * RTX Errors
+ *---------------------------------------------------------------------------*/
+extern void mbed_die(void);
+
+void os_error (uint32_t err_code) {
+ /* This function is called when a runtime error is detected. Parameter */
+ /* 'err_code' holds the runtime error code (defined in RTX_Conf.h). */
+ mbed_die();
+}
+
+void sysThreadError(osStatus status) {
+ if (status != osOK) {
+ mbed_die();
+ }
+}
+
+/*----------------------------------------------------------------------------
+ * RTX Configuration Functions
+ *---------------------------------------------------------------------------*/
+
+#include "RTX_CM_lib.h"
+
+/*----------------------------------------------------------------------------
+ * end of file
+ *---------------------------------------------------------------------------*/
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/TARGET_CORTEX_M/TARGET_M3/TOOLCHAIN_ARM/HAL_CM3.c Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,249 @@
+/*----------------------------------------------------------------------------
+ * RL-ARM - RTX
+ *----------------------------------------------------------------------------
+ * Name: HAL_CM3.C
+ * Purpose: Hardware Abstraction Layer for Cortex-M3
+ * Rev.: V4.60
+ *----------------------------------------------------------------------------
+ *
+ * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *---------------------------------------------------------------------------*/
+
+#include "rt_TypeDef.h"
+#include "RTX_Conf.h"
+#include "rt_System.h"
+#include "rt_HAL_CM.h"
+#include "rt_Task.h"
+#include "rt_MemBox.h"
+
+
+/*----------------------------------------------------------------------------
+ * Functions
+ *---------------------------------------------------------------------------*/
+
+
+/*--------------------------- rt_set_PSP ------------------------------------*/
+
+__asm void rt_set_PSP (U32 stack) {
+ MSR PSP,R0
+ BX LR
+}
+
+
+/*--------------------------- rt_get_PSP ------------------------------------*/
+
+__asm U32 rt_get_PSP (void) {
+ MRS R0,PSP
+ BX LR
+}
+
+
+/*--------------------------- os_set_env ------------------------------------*/
+
+__asm void os_set_env (void) {
+ /* Switch to Unprivileged/Privileged Thread mode, use PSP. */
+ MOV R0,SP ; PSP = MSP
+ MSR PSP,R0
+ LDR R0,=__cpp(&os_flags)
+ LDRB R0,[R0]
+ LSLS R0,#31
+ MOVNE R0,#0x02 ; Privileged Thread mode, use PSP
+ MOVEQ R0,#0x03 ; Unprivileged Thread mode, use PSP
+ MSR CONTROL,R0
+ BX LR
+
+ ALIGN
+}
+
+
+/*--------------------------- _alloc_box ------------------------------------*/
+
+__asm void *_alloc_box (void *box_mem) {
+ /* Function wrapper for Unprivileged/Privileged mode. */
+ LDR R12,=__cpp(rt_alloc_box)
+ MRS R3,IPSR
+ LSLS R3,#24
+ BXNE R12
+ MRS R3,CONTROL
+ LSLS R3,#31
+ BXEQ R12
+ SVC 0
+ BX LR
+
+ ALIGN
+}
+
+
+/*--------------------------- _free_box -------------------------------------*/
+
+__asm int _free_box (void *box_mem, void *box) {
+ /* Function wrapper for Unprivileged/Privileged mode. */
+ LDR R12,=__cpp(rt_free_box)
+ MRS R3,IPSR
+ LSLS R3,#24
+ BXNE R12
+ MRS R3,CONTROL
+ LSLS R3,#31
+ BXEQ R12
+ SVC 0
+ BX LR
+
+ ALIGN
+}
+
+
+/*-------------------------- SVC_Handler ------------------------------------*/
+
+__asm void SVC_Handler (void) {
+ PRESERVE8
+
+ IMPORT SVC_Count
+ IMPORT SVC_Table
+ IMPORT rt_stk_check
+
+ MRS R0,PSP ; Read PSP
+ LDR R1,[R0,#24] ; Read Saved PC from Stack
+ LDRB R1,[R1,#-2] ; Load SVC Number
+ CBNZ R1,SVC_User
+
+ LDM R0,{R0-R3,R12} ; Read R0-R3,R12 from stack
+ BLX R12 ; Call SVC Function
+
+ MRS R12,PSP ; Read PSP
+ STM R12,{R0-R2} ; Store return values
+
+ LDR R3,=__cpp(&os_tsk)
+ LDM R3,{R1,R2} ; os_tsk.run, os_tsk.new
+ CMP R1,R2
+ BEQ SVC_Exit ; no task switch
+
+ CBZ R1,SVC_Next ; Runtask deleted?
+ STMDB R12!,{R4-R11} ; Save Old context
+ STR R12,[R1,#TCB_TSTACK] ; Update os_tsk.run->tsk_stack
+
+ PUSH {R2,R3}
+ BL rt_stk_check ; Check for Stack overflow
+ POP {R2,R3}
+
+SVC_Next
+ STR R2,[R3] ; os_tsk.run = os_tsk.new
+
+ LDR R12,[R2,#TCB_TSTACK] ; os_tsk.new->tsk_stack
+ LDMIA R12!,{R4-R11} ; Restore New Context
+ MSR PSP,R12 ; Write PSP
+
+SVC_Exit
+ MVN LR,#:NOT:0xFFFFFFFD ; set EXC_RETURN value
+ BX LR
+
+ /*------------------- User SVC ------------------------------*/
+
+SVC_User
+ PUSH {R4,LR} ; Save Registers
+ LDR R2,=SVC_Count
+ LDR R2,[R2]
+ CMP R1,R2
+ BHI SVC_Done ; Overflow
+
+ LDR R4,=SVC_Table-4
+ LDR R4,[R4,R1,LSL #2] ; Load SVC Function Address
+
+ LDM R0,{R0-R3,R12} ; Read R0-R3,R12 from stack
+ BLX R4 ; Call SVC Function
+
+ MRS R12,PSP
+ STM R12,{R0-R3} ; Function return values
+SVC_Done
+ POP {R4,PC} ; RETI
+
+ ALIGN
+}
+
+
+/*-------------------------- PendSV_Handler ---------------------------------*/
+
+__asm void PendSV_Handler (void) {
+ PRESERVE8
+
+ BL __cpp(rt_pop_req)
+
+Sys_Switch
+ LDR R3,=__cpp(&os_tsk)
+ LDM R3,{R1,R2} ; os_tsk.run, os_tsk.new
+ CMP R1,R2
+ BEQ Sys_Exit
+
+ MRS R12,PSP ; Read PSP
+ STMDB R12!,{R4-R11} ; Save Old context
+ STR R12,[R1,#TCB_TSTACK] ; Update os_tsk.run->tsk_stack
+
+ PUSH {R2,R3}
+ BL rt_stk_check ; Check for Stack overflow
+ POP {R2,R3}
+
+ STR R2,[R3] ; os_tsk.run = os_tsk.new
+
+ LDR R12,[R2,#TCB_TSTACK] ; os_tsk.new->tsk_stack
+ LDMIA R12!,{R4-R11} ; Restore New Context
+ MSR PSP,R12 ; Write PSP
+
+Sys_Exit
+ MVN LR,#:NOT:0xFFFFFFFD ; set EXC_RETURN value
+ BX LR ; Return to Thread Mode
+
+ ALIGN
+}
+
+
+/*-------------------------- SysTick_Handler --------------------------------*/
+
+__asm void SysTick_Handler (void) {
+ PRESERVE8
+
+ BL __cpp(rt_systick)
+ B Sys_Switch
+
+ ALIGN
+}
+
+
+/*-------------------------- OS_Tick_Handler --------------------------------*/
+
+__asm void OS_Tick_Handler (void) {
+ PRESERVE8
+
+ BL __cpp(os_tick_irqack)
+ BL __cpp(rt_systick)
+ B Sys_Switch
+
+ ALIGN
+}
+
+
+/*----------------------------------------------------------------------------
+ * end of file
+ *---------------------------------------------------------------------------*/
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/mbed-rtos/rtx/TARGET_CORTEX_M/TARGET_M3/TOOLCHAIN_ARM/SVC_Table.s Wed Apr 15 06:23:18 2015 +0000 @@ -0,0 +1,57 @@ +;/*---------------------------------------------------------------------------- +; * RL-ARM - RTX +; *---------------------------------------------------------------------------- +; * Name: SVC_TABLE.S +; * Purpose: Pre-defined SVC Table for Cortex-M +; * Rev.: V4.60 +; *---------------------------------------------------------------------------- +; * +; * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH +; * All rights reserved. +; * Redistribution and use in source and binary forms, with or without +; * modification, are permitted provided that the following conditions are met: +; * - Redistributions of source code must retain the above copyright +; * notice, this list of conditions and the following disclaimer. +; * - Redistributions in binary form must reproduce the above copyright +; * notice, this list of conditions and the following disclaimer in the +; * documentation and/or other materials provided with the distribution. +; * - Neither the name of ARM nor the names of its contributors may be used +; * to endorse or promote products derived from this software without +; * specific prior written permission. +; * +; * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +; * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +; * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +; * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE +; * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +; * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +; * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +; * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +; * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +; * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +; * POSSIBILITY OF SUCH DAMAGE. +; *---------------------------------------------------------------------------*/ + + + AREA SVC_TABLE, CODE, READONLY + + EXPORT SVC_Count + +SVC_Cnt EQU (SVC_End-SVC_Table)/4 +SVC_Count DCD SVC_Cnt + +; Import user SVC functions here. +; IMPORT __SVC_1 + + EXPORT SVC_Table +SVC_Table +; Insert user SVC functions here. SVC 0 used by RTL Kernel. +; DCD __SVC_1 ; user SVC function + +SVC_End + + END + +/*---------------------------------------------------------------------------- + * end of file + *---------------------------------------------------------------------------*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/TARGET_CORTEX_M/cmsis_os.h Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,774 @@
+/* ----------------------------------------------------------------------
+ * Copyright (C) 2012 ARM Limited. All rights reserved.
+ *
+ * $Date: 5. June 2012
+ * $Revision: V1.01
+ *
+ * Project: CMSIS-RTOS API
+ * Title: cmsis_os.h RTX header file
+ *
+ * Version 0.02
+ * Initial Proposal Phase
+ * Version 0.03
+ * osKernelStart added, optional feature: main started as thread
+ * osSemaphores have standard behavior
+ * osTimerCreate does not start the timer, added osTimerStart
+ * osThreadPass is renamed to osThreadYield
+ * Version 1.01
+ * Support for C++ interface
+ * - const attribute removed from the osXxxxDef_t typedef's
+ * - const attribute added to the osXxxxDef macros
+ * Added: osTimerDelete, osMutexDelete, osSemaphoreDelete
+ * Added: osKernelInitialize
+ * -------------------------------------------------------------------- */
+
+/**
+\page cmsis_os_h Header File Template: cmsis_os.h
+
+The file \b cmsis_os.h is a template header file for a CMSIS-RTOS compliant Real-Time Operating System (RTOS).
+Each RTOS that is compliant with CMSIS-RTOS shall provide a specific \b cmsis_os.h header file that represents
+its implementation.
+
+The file cmsis_os.h contains:
+ - CMSIS-RTOS API function definitions
+ - struct definitions for parameters and return types
+ - status and priority values used by CMSIS-RTOS API functions
+ - macros for defining threads and other kernel objects
+
+
+<b>Name conventions and header file modifications</b>
+
+All definitions are prefixed with \b os to give an unique name space for CMSIS-RTOS functions.
+Definitions that are prefixed \b os_ are not used in the application code but local to this header file.
+All definitions and functions that belong to a module are grouped and have a common prefix, i.e. \b osThread.
+
+Definitions that are marked with <b>CAN BE CHANGED</b> can be adapted towards the needs of the actual CMSIS-RTOS implementation.
+These definitions can be specific to the underlying RTOS kernel.
+
+Definitions that are marked with <b>MUST REMAIN UNCHANGED</b> cannot be altered. Otherwise the CMSIS-RTOS implementation is no longer
+compliant to the standard. Note that some functions are optional and need not to be provided by every CMSIS-RTOS implementation.
+
+
+<b>Function calls from interrupt service routines</b>
+
+The following CMSIS-RTOS functions can be called from threads and interrupt service routines (ISR):
+ - \ref osSignalSet
+ - \ref osSemaphoreRelease
+ - \ref osPoolAlloc, \ref osPoolCAlloc, \ref osPoolFree
+ - \ref osMessagePut, \ref osMessageGet
+ - \ref osMailAlloc, \ref osMailCAlloc, \ref osMailGet, \ref osMailPut, \ref osMailFree
+
+Functions that cannot be called from an ISR are verifying the interrupt status and return in case that they are called
+from an ISR context the status code \b osErrorISR. In some implementations this condition might be caught using the HARD FAULT vector.
+
+Some CMSIS-RTOS implementations support CMSIS-RTOS function calls from multiple ISR at the same time.
+If this is impossible, the CMSIS-RTOS rejects calls by nested ISR functions with the status code \b osErrorISRRecursive.
+
+
+<b>Define and reference object definitions</b>
+
+With <b>\#define osObjectsExternal</b> objects are defined as external symbols. This allows to create a consistent header file
+that is used throughout a project as shown below:
+
+<i>Header File</i>
+\code
+#include <cmsis_os.h> // CMSIS RTOS header file
+
+// Thread definition
+extern void thread_sample (void const *argument); // function prototype
+osThreadDef (thread_sample, osPriorityBelowNormal, 1, 100);
+
+// Pool definition
+osPoolDef(MyPool, 10, long);
+\endcode
+
+
+This header file defines all objects when included in a C/C++ source file. When <b>\#define osObjectsExternal</b> is
+present before the header file, the objects are defined as external symbols. A single consistent header file can therefore be
+used throughout the whole project.
+
+<i>Example</i>
+\code
+#include "osObjects.h" // Definition of the CMSIS-RTOS objects
+\endcode
+
+\code
+#define osObjectExternal // Objects will be defined as external symbols
+#include "osObjects.h" // Reference to the CMSIS-RTOS objects
+\endcode
+
+*/
+
+#ifndef _CMSIS_OS_H
+#define _CMSIS_OS_H
+
+/// \note MUST REMAIN UNCHANGED: \b osCMSIS identifies the CMSIS-RTOS API version.
+#define osCMSIS 0x10001 ///< API version (main [31:16] .sub [15:0])
+
+/// \note CAN BE CHANGED: \b osCMSIS_KERNEL identifies the underlying RTOS kernel and version number.
+#define osCMSIS_RTX ((4<<16)|61) ///< RTOS identification and version (main [31:16] .sub [15:0])
+
+/// \note MUST REMAIN UNCHANGED: \b osKernelSystemId shall be consistent in every CMSIS-RTOS.
+#define osKernelSystemId "RTX V4.61" ///< RTOS identification string
+
+
+#define CMSIS_OS_RTX
+
+// The stack space occupied is mainly dependent on the underling C standard library
+#if defined(TOOLCHAIN_GCC) || defined(TOOLCHAIN_ARM_STD) || defined(TOOLCHAIN_IAR)
+# define WORDS_STACK_SIZE 512
+#elif defined(TOOLCHAIN_ARM_MICRO)
+# define WORDS_STACK_SIZE 128
+#endif
+
+#define DEFAULT_STACK_SIZE (WORDS_STACK_SIZE*4)
+
+
+/// \note MUST REMAIN UNCHANGED: \b osFeature_xxx shall be consistent in every CMSIS-RTOS.
+#define osFeature_MainThread 1 ///< main thread 1=main can be thread, 0=not available
+#define osFeature_Pool 1 ///< Memory Pools: 1=available, 0=not available
+#define osFeature_MailQ 1 ///< Mail Queues: 1=available, 0=not available
+#define osFeature_MessageQ 1 ///< Message Queues: 1=available, 0=not available
+#define osFeature_Signals 16 ///< maximum number of Signal Flags available per thread
+#define osFeature_Semaphore 65535 ///< maximum count for \ref osSemaphoreCreate function
+#define osFeature_Wait 0 ///< osWait function: 1=available, 0=not available
+
+#if defined (__CC_ARM)
+#define os_InRegs __value_in_regs // Compiler specific: force struct in registers
+#elif defined (__ICCARM__)
+#define os_InRegs __value_in_regs // Compiler specific: force struct in registers
+#else
+#define os_InRegs
+#endif
+
+#include <stdint.h>
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "os_tcb.h"
+
+// ==== Enumeration, structures, defines ====
+
+/// Priority used for thread control.
+/// \note MUST REMAIN UNCHANGED: \b osPriority shall be consistent in every CMSIS-RTOS.
+typedef enum {
+ osPriorityIdle = -3, ///< priority: idle (lowest)
+ osPriorityLow = -2, ///< priority: low
+ osPriorityBelowNormal = -1, ///< priority: below normal
+ osPriorityNormal = 0, ///< priority: normal (default)
+ osPriorityAboveNormal = +1, ///< priority: above normal
+ osPriorityHigh = +2, ///< priority: high
+ osPriorityRealtime = +3, ///< priority: realtime (highest)
+ osPriorityError = 0x84 ///< system cannot determine priority or thread has illegal priority
+} osPriority;
+
+/// Timeout value.
+/// \note MUST REMAIN UNCHANGED: \b osWaitForever shall be consistent in every CMSIS-RTOS.
+#define osWaitForever 0xFFFFFFFF ///< wait forever timeout value
+
+/// Status code values returned by CMSIS-RTOS functions.
+/// \note MUST REMAIN UNCHANGED: \b osStatus shall be consistent in every CMSIS-RTOS.
+typedef enum {
+ osOK = 0, ///< function completed; no error or event occurred.
+ osEventSignal = 0x08, ///< function completed; signal event occurred.
+ osEventMessage = 0x10, ///< function completed; message event occurred.
+ osEventMail = 0x20, ///< function completed; mail event occurred.
+ osEventTimeout = 0x40, ///< function completed; timeout occurred.
+ osErrorParameter = 0x80, ///< parameter error: a mandatory parameter was missing or specified an incorrect object.
+ osErrorResource = 0x81, ///< resource not available: a specified resource was not available.
+ osErrorTimeoutResource = 0xC1, ///< resource not available within given time: a specified resource was not available within the timeout period.
+ osErrorISR = 0x82, ///< not allowed in ISR context: the function cannot be called from interrupt service routines.
+ osErrorISRRecursive = 0x83, ///< function called multiple times from ISR with same object.
+ osErrorPriority = 0x84, ///< system cannot determine priority or thread has illegal priority.
+ osErrorNoMemory = 0x85, ///< system is out of memory: it was impossible to allocate or reserve memory for the operation.
+ osErrorValue = 0x86, ///< value of a parameter is out of range.
+ osErrorOS = 0xFF, ///< unspecified RTOS error: run-time error but no other error message fits.
+ os_status_reserved = 0x7FFFFFFF ///< prevent from enum down-size compiler optimization.
+} osStatus;
+
+
+/// Timer type value for the timer definition.
+/// \note MUST REMAIN UNCHANGED: \b os_timer_type shall be consistent in every CMSIS-RTOS.
+typedef enum {
+ osTimerOnce = 0, ///< one-shot timer
+ osTimerPeriodic = 1 ///< repeating timer
+} os_timer_type;
+
+/// Entry point of a thread.
+/// \note MUST REMAIN UNCHANGED: \b os_pthread shall be consistent in every CMSIS-RTOS.
+typedef void (*os_pthread) (void const *argument);
+
+/// Entry point of a timer call back function.
+/// \note MUST REMAIN UNCHANGED: \b os_ptimer shall be consistent in every CMSIS-RTOS.
+typedef void (*os_ptimer) (void const *argument);
+
+// >>> the following data type definitions may shall adapted towards a specific RTOS
+
+/// Thread ID identifies the thread (pointer to a thread control block).
+/// \note CAN BE CHANGED: \b os_thread_cb is implementation specific in every CMSIS-RTOS.
+typedef struct os_thread_cb *osThreadId;
+
+/// Timer ID identifies the timer (pointer to a timer control block).
+/// \note CAN BE CHANGED: \b os_timer_cb is implementation specific in every CMSIS-RTOS.
+typedef struct os_timer_cb *osTimerId;
+
+/// Mutex ID identifies the mutex (pointer to a mutex control block).
+/// \note CAN BE CHANGED: \b os_mutex_cb is implementation specific in every CMSIS-RTOS.
+typedef struct os_mutex_cb *osMutexId;
+
+/// Semaphore ID identifies the semaphore (pointer to a semaphore control block).
+/// \note CAN BE CHANGED: \b os_semaphore_cb is implementation specific in every CMSIS-RTOS.
+typedef struct os_semaphore_cb *osSemaphoreId;
+
+/// Pool ID identifies the memory pool (pointer to a memory pool control block).
+/// \note CAN BE CHANGED: \b os_pool_cb is implementation specific in every CMSIS-RTOS.
+typedef struct os_pool_cb *osPoolId;
+
+/// Message ID identifies the message queue (pointer to a message queue control block).
+/// \note CAN BE CHANGED: \b os_messageQ_cb is implementation specific in every CMSIS-RTOS.
+typedef struct os_messageQ_cb *osMessageQId;
+
+/// Mail ID identifies the mail queue (pointer to a mail queue control block).
+/// \note CAN BE CHANGED: \b os_mailQ_cb is implementation specific in every CMSIS-RTOS.
+typedef struct os_mailQ_cb *osMailQId;
+
+
+/// Thread Definition structure contains startup information of a thread.
+/// \note CAN BE CHANGED: \b os_thread_def is implementation specific in every CMSIS-RTOS.
+typedef struct os_thread_def {
+ os_pthread pthread; ///< start address of thread function
+ osPriority tpriority; ///< initial thread priority
+ uint32_t stacksize; ///< stack size requirements in bytes
+ uint32_t *stack_pointer; ///< pointer to the stack memory block
+ struct OS_TCB tcb;
+} osThreadDef_t;
+
+/// Timer Definition structure contains timer parameters.
+/// \note CAN BE CHANGED: \b os_timer_def is implementation specific in every CMSIS-RTOS.
+typedef struct os_timer_def {
+ os_ptimer ptimer; ///< start address of a timer function
+ void *timer; ///< pointer to internal data
+} osTimerDef_t;
+
+/// Mutex Definition structure contains setup information for a mutex.
+/// \note CAN BE CHANGED: \b os_mutex_def is implementation specific in every CMSIS-RTOS.
+typedef struct os_mutex_def {
+ void *mutex; ///< pointer to internal data
+} osMutexDef_t;
+
+/// Semaphore Definition structure contains setup information for a semaphore.
+/// \note CAN BE CHANGED: \b os_semaphore_def is implementation specific in every CMSIS-RTOS.
+typedef struct os_semaphore_def {
+ void *semaphore; ///< pointer to internal data
+} osSemaphoreDef_t;
+
+/// Definition structure for memory block allocation.
+/// \note CAN BE CHANGED: \b os_pool_def is implementation specific in every CMSIS-RTOS.
+typedef struct os_pool_def {
+ uint32_t pool_sz; ///< number of items (elements) in the pool
+ uint32_t item_sz; ///< size of an item
+ void *pool; ///< pointer to memory for pool
+} osPoolDef_t;
+
+/// Definition structure for message queue.
+/// \note CAN BE CHANGED: \b os_messageQ_def is implementation specific in every CMSIS-RTOS.
+typedef struct os_messageQ_def {
+ uint32_t queue_sz; ///< number of elements in the queue
+ void *pool; ///< memory array for messages
+} osMessageQDef_t;
+
+/// Definition structure for mail queue.
+/// \note CAN BE CHANGED: \b os_mailQ_def is implementation specific in every CMSIS-RTOS.
+typedef struct os_mailQ_def {
+ uint32_t queue_sz; ///< number of elements in the queue
+ uint32_t item_sz; ///< size of an item
+ void *pool; ///< memory array for mail
+} osMailQDef_t;
+
+/// Event structure contains detailed information about an event.
+/// \note MUST REMAIN UNCHANGED: \b os_event shall be consistent in every CMSIS-RTOS.
+/// However the struct may be extended at the end.
+typedef struct {
+ osStatus status; ///< status code: event or error information
+ union {
+ uint32_t v; ///< message as 32-bit value
+ void *p; ///< message or mail as void pointer
+ int32_t signals; ///< signal flags
+ } value; ///< event value
+ union {
+ osMailQId mail_id; ///< mail id obtained by \ref osMailCreate
+ osMessageQId message_id; ///< message id obtained by \ref osMessageCreate
+ } def; ///< event definition
+} osEvent;
+
+
+// ==== Kernel Control Functions ====
+
+/// Initialize the RTOS Kernel for creating objects.
+/// \return status code that indicates the execution status of the function.
+/// \note MUST REMAIN UNCHANGED: \b osKernelInitialize shall be consistent in every CMSIS-RTOS.
+osStatus osKernelInitialize (void);
+
+/// Start the RTOS Kernel.
+/// \return status code that indicates the execution status of the function.
+/// \note MUST REMAIN UNCHANGED: \b osKernelStart shall be consistent in every CMSIS-RTOS.
+osStatus osKernelStart (void);
+
+/// Check if the RTOS kernel is already started.
+/// \note MUST REMAIN UNCHANGED: \b osKernelRunning shall be consistent in every CMSIS-RTOS.
+/// \return 0 RTOS is not started, 1 RTOS is started.
+int32_t osKernelRunning(void);
+
+
+// ==== Thread Management ====
+
+/// Create a Thread Definition with function, priority, and stack requirements.
+/// \param name name of the thread function.
+/// \param priority initial priority of the thread function.
+/// \param stacksz stack size (in bytes) requirements for the thread function.
+/// \note CAN BE CHANGED: The parameters to \b osThreadDef shall be consistent but the
+/// macro body is implementation specific in every CMSIS-RTOS.
+#if defined (osObjectsExternal) // object is external
+#define osThreadDef(name, priority, stacksz) \
+extern osThreadDef_t os_thread_def_##name
+#else // define the object
+#define osThreadDef(name, priority, stacksz) \
+uint32_t os_thread_def_stack_##name [stacksz / sizeof(uint32_t)]; \
+osThreadDef_t os_thread_def_##name = \
+{ (name), (priority), (stacksz), (os_thread_def_stack_##name)}
+#endif
+
+/// Access a Thread definition.
+/// \param name name of the thread definition object.
+/// \note CAN BE CHANGED: The parameter to \b osThread shall be consistent but the
+/// macro body is implementation specific in every CMSIS-RTOS.
+#define osThread(name) \
+&os_thread_def_##name
+
+/// Create a thread and add it to Active Threads and set it to state READY.
+/// \param[in] thread_def thread definition referenced with \ref osThread.
+/// \param[in] argument pointer that is passed to the thread function as start argument.
+/// \return thread ID for reference by other functions or NULL in case of error.
+/// \note MUST REMAIN UNCHANGED: \b osThreadCreate shall be consistent in every CMSIS-RTOS.
+osThreadId osThreadCreate (osThreadDef_t *thread_def, void *argument);
+
+/// Return the thread ID of the current running thread.
+/// \return thread ID for reference by other functions or NULL in case of error.
+/// \note MUST REMAIN UNCHANGED: \b osThreadGetId shall be consistent in every CMSIS-RTOS.
+osThreadId osThreadGetId (void);
+
+/// Terminate execution of a thread and remove it from Active Threads.
+/// \param[in] thread_id thread ID obtained by \ref osThreadCreate or \ref osThreadGetId.
+/// \return status code that indicates the execution status of the function.
+/// \note MUST REMAIN UNCHANGED: \b osThreadTerminate shall be consistent in every CMSIS-RTOS.
+osStatus osThreadTerminate (osThreadId thread_id);
+
+/// Pass control to next thread that is in state \b READY.
+/// \return status code that indicates the execution status of the function.
+/// \note MUST REMAIN UNCHANGED: \b osThreadYield shall be consistent in every CMSIS-RTOS.
+osStatus osThreadYield (void);
+
+/// Change priority of an active thread.
+/// \param[in] thread_id thread ID obtained by \ref osThreadCreate or \ref osThreadGetId.
+/// \param[in] priority new priority value for the thread function.
+/// \return status code that indicates the execution status of the function.
+/// \note MUST REMAIN UNCHANGED: \b osThreadSetPriority shall be consistent in every CMSIS-RTOS.
+osStatus osThreadSetPriority (osThreadId thread_id, osPriority priority);
+
+/// Get current priority of an active thread.
+/// \param[in] thread_id thread ID obtained by \ref osThreadCreate or \ref osThreadGetId.
+/// \return current priority value of the thread function.
+/// \note MUST REMAIN UNCHANGED: \b osThreadGetPriority shall be consistent in every CMSIS-RTOS.
+osPriority osThreadGetPriority (osThreadId thread_id);
+
+
+// ==== Generic Wait Functions ====
+
+/// Wait for Timeout (Time Delay).
+/// \param[in] millisec time delay value
+/// \return status code that indicates the execution status of the function.
+osStatus osDelay (uint32_t millisec);
+
+#if (defined (osFeature_Wait) && (osFeature_Wait != 0)) // Generic Wait available
+
+/// Wait for Signal, Message, Mail, or Timeout.
+/// \param[in] millisec timeout value or 0 in case of no time-out
+/// \return event that contains signal, message, or mail information or error code.
+/// \note MUST REMAIN UNCHANGED: \b osWait shall be consistent in every CMSIS-RTOS.
+os_InRegs osEvent osWait (uint32_t millisec);
+
+#endif // Generic Wait available
+
+
+// ==== Timer Management Functions ====
+/// Define a Timer object.
+/// \param name name of the timer object.
+/// \param function name of the timer call back function.
+/// \note CAN BE CHANGED: The parameter to \b osTimerDef shall be consistent but the
+/// macro body is implementation specific in every CMSIS-RTOS.
+#if defined (osObjectsExternal) // object is external
+#define osTimerDef(name, function) \
+extern osTimerDef_t os_timer_def_##name
+#else // define the object
+#define osTimerDef(name, function) \
+uint32_t os_timer_cb_##name[5]; \
+osTimerDef_t os_timer_def_##name = \
+{ (function), (os_timer_cb_##name) }
+#endif
+
+/// Access a Timer definition.
+/// \param name name of the timer object.
+/// \note CAN BE CHANGED: The parameter to \b osTimer shall be consistent but the
+/// macro body is implementation specific in every CMSIS-RTOS.
+#define osTimer(name) \
+&os_timer_def_##name
+
+/// Create a timer.
+/// \param[in] timer_def timer object referenced with \ref osTimer.
+/// \param[in] type osTimerOnce for one-shot or osTimerPeriodic for periodic behavior.
+/// \param[in] argument argument to the timer call back function.
+/// \return timer ID for reference by other functions or NULL in case of error.
+/// \note MUST REMAIN UNCHANGED: \b osTimerCreate shall be consistent in every CMSIS-RTOS.
+osTimerId osTimerCreate (osTimerDef_t *timer_def, os_timer_type type, void *argument);
+
+/// Start or restart a timer.
+/// \param[in] timer_id timer ID obtained by \ref osTimerCreate.
+/// \param[in] millisec time delay value of the timer.
+/// \return status code that indicates the execution status of the function.
+/// \note MUST REMAIN UNCHANGED: \b osTimerStart shall be consistent in every CMSIS-RTOS.
+osStatus osTimerStart (osTimerId timer_id, uint32_t millisec);
+
+/// Stop the timer.
+/// \param[in] timer_id timer ID obtained by \ref osTimerCreate.
+/// \return status code that indicates the execution status of the function.
+/// \note MUST REMAIN UNCHANGED: \b osTimerStop shall be consistent in every CMSIS-RTOS.
+osStatus osTimerStop (osTimerId timer_id);
+
+/// Delete a timer that was created by \ref osTimerCreate.
+/// \param[in] timer_id timer ID obtained by \ref osTimerCreate.
+/// \return status code that indicates the execution status of the function.
+/// \note MUST REMAIN UNCHANGED: \b osTimerDelete shall be consistent in every CMSIS-RTOS.
+osStatus osTimerDelete (osTimerId timer_id);
+
+
+// ==== Signal Management ====
+
+/// Set the specified Signal Flags of an active thread.
+/// \param[in] thread_id thread ID obtained by \ref osThreadCreate or \ref osThreadGetId.
+/// \param[in] signals specifies the signal flags of the thread that should be set.
+/// \return previous signal flags of the specified thread or 0x80000000 in case of incorrect parameters.
+/// \note MUST REMAIN UNCHANGED: \b osSignalSet shall be consistent in every CMSIS-RTOS.
+int32_t osSignalSet (osThreadId thread_id, int32_t signals);
+
+/// Clear the specified Signal Flags of an active thread.
+/// \param[in] thread_id thread ID obtained by \ref osThreadCreate or \ref osThreadGetId.
+/// \param[in] signals specifies the signal flags of the thread that shall be cleared.
+/// \return previous signal flags of the specified thread or 0x80000000 in case of incorrect parameters.
+/// \note MUST REMAIN UNCHANGED: \b osSignalClear shall be consistent in every CMSIS-RTOS.
+int32_t osSignalClear (osThreadId thread_id, int32_t signals);
+
+/// Get Signal Flags status of an active thread.
+/// \param[in] thread_id thread ID obtained by \ref osThreadCreate or \ref osThreadGetId.
+/// \return previous signal flags of the specified thread or 0x80000000 in case of incorrect parameters.
+/// \note MUST REMAIN UNCHANGED: \b osSignalGet shall be consistent in every CMSIS-RTOS.
+int32_t osSignalGet (osThreadId thread_id);
+
+/// Wait for one or more Signal Flags to become signaled for the current \b RUNNING thread.
+/// \param[in] signals wait until all specified signal flags set or 0 for any single signal flag.
+/// \param[in] millisec timeout value or 0 in case of no time-out.
+/// \return event flag information or error code.
+/// \note MUST REMAIN UNCHANGED: \b osSignalWait shall be consistent in every CMSIS-RTOS.
+os_InRegs osEvent osSignalWait (int32_t signals, uint32_t millisec);
+
+
+// ==== Mutex Management ====
+
+/// Define a Mutex.
+/// \param name name of the mutex object.
+/// \note CAN BE CHANGED: The parameter to \b osMutexDef shall be consistent but the
+/// macro body is implementation specific in every CMSIS-RTOS.
+#if defined (osObjectsExternal) // object is external
+#define osMutexDef(name) \
+extern osMutexDef_t os_mutex_def_##name
+#else // define the object
+#define osMutexDef(name) \
+uint32_t os_mutex_cb_##name[3]; \
+osMutexDef_t os_mutex_def_##name = { (os_mutex_cb_##name) }
+#endif
+
+/// Access a Mutex definition.
+/// \param name name of the mutex object.
+/// \note CAN BE CHANGED: The parameter to \b osMutex shall be consistent but the
+/// macro body is implementation specific in every CMSIS-RTOS.
+#define osMutex(name) \
+&os_mutex_def_##name
+
+/// Create and Initialize a Mutex object.
+/// \param[in] mutex_def mutex definition referenced with \ref osMutex.
+/// \return mutex ID for reference by other functions or NULL in case of error.
+/// \note MUST REMAIN UNCHANGED: \b osMutexCreate shall be consistent in every CMSIS-RTOS.
+osMutexId osMutexCreate (osMutexDef_t *mutex_def);
+
+/// Wait until a Mutex becomes available.
+/// \param[in] mutex_id mutex ID obtained by \ref osMutexCreate.
+/// \param[in] millisec timeout value or 0 in case of no time-out.
+/// \return status code that indicates the execution status of the function.
+/// \note MUST REMAIN UNCHANGED: \b osMutexWait shall be consistent in every CMSIS-RTOS.
+osStatus osMutexWait (osMutexId mutex_id, uint32_t millisec);
+
+/// Release a Mutex that was obtained by \ref osMutexWait.
+/// \param[in] mutex_id mutex ID obtained by \ref osMutexCreate.
+/// \return status code that indicates the execution status of the function.
+/// \note MUST REMAIN UNCHANGED: \b osMutexRelease shall be consistent in every CMSIS-RTOS.
+osStatus osMutexRelease (osMutexId mutex_id);
+
+/// Delete a Mutex that was created by \ref osMutexCreate.
+/// \param[in] mutex_id mutex ID obtained by \ref osMutexCreate.
+/// \return status code that indicates the execution status of the function.
+/// \note MUST REMAIN UNCHANGED: \b osMutexDelete shall be consistent in every CMSIS-RTOS.
+osStatus osMutexDelete (osMutexId mutex_id);
+
+
+// ==== Semaphore Management Functions ====
+
+#if (defined (osFeature_Semaphore) && (osFeature_Semaphore != 0)) // Semaphore available
+
+/// Define a Semaphore object.
+/// \param name name of the semaphore object.
+/// \note CAN BE CHANGED: The parameter to \b osSemaphoreDef shall be consistent but the
+/// macro body is implementation specific in every CMSIS-RTOS.
+#if defined (osObjectsExternal) // object is external
+#define osSemaphoreDef(name) \
+extern osSemaphoreDef_t os_semaphore_def_##name
+#else // define the object
+#define osSemaphoreDef(name) \
+uint32_t os_semaphore_cb_##name[2]; \
+osSemaphoreDef_t os_semaphore_def_##name = { (os_semaphore_cb_##name) }
+#endif
+
+/// Access a Semaphore definition.
+/// \param name name of the semaphore object.
+/// \note CAN BE CHANGED: The parameter to \b osSemaphore shall be consistent but the
+/// macro body is implementation specific in every CMSIS-RTOS.
+#define osSemaphore(name) \
+&os_semaphore_def_##name
+
+/// Create and Initialize a Semaphore object used for managing resources.
+/// \param[in] semaphore_def semaphore definition referenced with \ref osSemaphore.
+/// \param[in] count number of available resources.
+/// \return semaphore ID for reference by other functions or NULL in case of error.
+/// \note MUST REMAIN UNCHANGED: \b osSemaphoreCreate shall be consistent in every CMSIS-RTOS.
+osSemaphoreId osSemaphoreCreate (osSemaphoreDef_t *semaphore_def, int32_t count);
+
+/// Wait until a Semaphore token becomes available.
+/// \param[in] semaphore_id semaphore object referenced with \ref osSemaphoreCreate.
+/// \param[in] millisec timeout value or 0 in case of no time-out.
+/// \return number of available tokens, or -1 in case of incorrect parameters.
+/// \note MUST REMAIN UNCHANGED: \b osSemaphoreWait shall be consistent in every CMSIS-RTOS.
+int32_t osSemaphoreWait (osSemaphoreId semaphore_id, uint32_t millisec);
+
+/// Release a Semaphore token.
+/// \param[in] semaphore_id semaphore object referenced with \ref osSemaphoreCreate.
+/// \return status code that indicates the execution status of the function.
+/// \note MUST REMAIN UNCHANGED: \b osSemaphoreRelease shall be consistent in every CMSIS-RTOS.
+osStatus osSemaphoreRelease (osSemaphoreId semaphore_id);
+
+/// Delete a Semaphore that was created by \ref osSemaphoreCreate.
+/// \param[in] semaphore_id semaphore object referenced with \ref osSemaphoreCreate.
+/// \return status code that indicates the execution status of the function.
+/// \note MUST REMAIN UNCHANGED: \b osSemaphoreDelete shall be consistent in every CMSIS-RTOS.
+osStatus osSemaphoreDelete (osSemaphoreId semaphore_id);
+
+#endif // Semaphore available
+
+
+// ==== Memory Pool Management Functions ====
+
+#if (defined (osFeature_Pool) && (osFeature_Pool != 0)) // Memory Pool Management available
+
+/// \brief Define a Memory Pool.
+/// \param name name of the memory pool.
+/// \param no maximum number of blocks (objects) in the memory pool.
+/// \param type data type of a single block (object).
+/// \note CAN BE CHANGED: The parameter to \b osPoolDef shall be consistent but the
+/// macro body is implementation specific in every CMSIS-RTOS.
+#if defined (osObjectsExternal) // object is external
+#define osPoolDef(name, no, type) \
+extern osPoolDef_t os_pool_def_##name
+#else // define the object
+#define osPoolDef(name, no, type) \
+uint32_t os_pool_m_##name[3+((sizeof(type)+3)/4)*(no)]; \
+osPoolDef_t os_pool_def_##name = \
+{ (no), sizeof(type), (os_pool_m_##name) }
+#endif
+
+/// \brief Access a Memory Pool definition.
+/// \param name name of the memory pool
+/// \note CAN BE CHANGED: The parameter to \b osPool shall be consistent but the
+/// macro body is implementation specific in every CMSIS-RTOS.
+#define osPool(name) \
+&os_pool_def_##name
+
+/// Create and Initialize a memory pool.
+/// \param[in] pool_def memory pool definition referenced with \ref osPool.
+/// \return memory pool ID for reference by other functions or NULL in case of error.
+/// \note MUST REMAIN UNCHANGED: \b osPoolCreate shall be consistent in every CMSIS-RTOS.
+osPoolId osPoolCreate (osPoolDef_t *pool_def);
+
+/// Allocate a memory block from a memory pool.
+/// \param[in] pool_id memory pool ID obtain referenced with \ref osPoolCreate.
+/// \return address of the allocated memory block or NULL in case of no memory available.
+/// \note MUST REMAIN UNCHANGED: \b osPoolAlloc shall be consistent in every CMSIS-RTOS.
+void *osPoolAlloc (osPoolId pool_id);
+
+/// Allocate a memory block from a memory pool and set memory block to zero.
+/// \param[in] pool_id memory pool ID obtain referenced with \ref osPoolCreate.
+/// \return address of the allocated memory block or NULL in case of no memory available.
+/// \note MUST REMAIN UNCHANGED: \b osPoolCAlloc shall be consistent in every CMSIS-RTOS.
+void *osPoolCAlloc (osPoolId pool_id);
+
+/// Return an allocated memory block back to a specific memory pool.
+/// \param[in] pool_id memory pool ID obtain referenced with \ref osPoolCreate.
+/// \param[in] block address of the allocated memory block that is returned to the memory pool.
+/// \return status code that indicates the execution status of the function.
+/// \note MUST REMAIN UNCHANGED: \b osPoolFree shall be consistent in every CMSIS-RTOS.
+osStatus osPoolFree (osPoolId pool_id, void *block);
+
+#endif // Memory Pool Management available
+
+
+// ==== Message Queue Management Functions ====
+
+#if (defined (osFeature_MessageQ) && (osFeature_MessageQ != 0)) // Message Queues available
+
+/// \brief Create a Message Queue Definition.
+/// \param name name of the queue.
+/// \param queue_sz maximum number of messages in the queue.
+/// \param type data type of a single message element (for debugger).
+/// \note CAN BE CHANGED: The parameter to \b osMessageQDef shall be consistent but the
+/// macro body is implementation specific in every CMSIS-RTOS.
+#if defined (osObjectsExternal) // object is external
+#define osMessageQDef(name, queue_sz, type) \
+extern osMessageQDef_t os_messageQ_def_##name
+#else // define the object
+#define osMessageQDef(name, queue_sz, type) \
+uint32_t os_messageQ_q_##name[4+(queue_sz)]; \
+osMessageQDef_t os_messageQ_def_##name = \
+{ (queue_sz), (os_messageQ_q_##name) }
+#endif
+
+/// \brief Access a Message Queue Definition.
+/// \param name name of the queue
+/// \note CAN BE CHANGED: The parameter to \b osMessageQ shall be consistent but the
+/// macro body is implementation specific in every CMSIS-RTOS.
+#define osMessageQ(name) \
+&os_messageQ_def_##name
+
+/// Create and Initialize a Message Queue.
+/// \param[in] queue_def queue definition referenced with \ref osMessageQ.
+/// \param[in] thread_id thread ID (obtained by \ref osThreadCreate or \ref osThreadGetId) or NULL.
+/// \return message queue ID for reference by other functions or NULL in case of error.
+/// \note MUST REMAIN UNCHANGED: \b osMessageCreate shall be consistent in every CMSIS-RTOS.
+osMessageQId osMessageCreate (osMessageQDef_t *queue_def, osThreadId thread_id);
+
+/// Put a Message to a Queue.
+/// \param[in] queue_id message queue ID obtained with \ref osMessageCreate.
+/// \param[in] info message information.
+/// \param[in] millisec timeout value or 0 in case of no time-out.
+/// \return status code that indicates the execution status of the function.
+/// \note MUST REMAIN UNCHANGED: \b osMessagePut shall be consistent in every CMSIS-RTOS.
+osStatus osMessagePut (osMessageQId queue_id, uint32_t info, uint32_t millisec);
+
+/// Get a Message or Wait for a Message from a Queue.
+/// \param[in] queue_id message queue ID obtained with \ref osMessageCreate.
+/// \param[in] millisec timeout value or 0 in case of no time-out.
+/// \return event information that includes status code.
+/// \note MUST REMAIN UNCHANGED: \b osMessageGet shall be consistent in every CMSIS-RTOS.
+os_InRegs osEvent osMessageGet (osMessageQId queue_id, uint32_t millisec);
+
+#endif // Message Queues available
+
+
+// ==== Mail Queue Management Functions ====
+
+#if (defined (osFeature_MailQ) && (osFeature_MailQ != 0)) // Mail Queues available
+
+/// \brief Create a Mail Queue Definition.
+/// \param name name of the queue
+/// \param queue_sz maximum number of messages in queue
+/// \param type data type of a single message element
+/// \note CAN BE CHANGED: The parameter to \b osMailQDef shall be consistent but the
+/// macro body is implementation specific in every CMSIS-RTOS.
+#if defined (osObjectsExternal) // object is external
+#define osMailQDef(name, queue_sz, type) \
+extern osMailQDef_t os_mailQ_def_##name
+#else // define the object
+#define osMailQDef(name, queue_sz, type) \
+uint32_t os_mailQ_q_##name[4+(queue_sz)]; \
+uint32_t os_mailQ_m_##name[3+((sizeof(type)+3)/4)*(queue_sz)]; \
+void * os_mailQ_p_##name[2] = { (os_mailQ_q_##name), os_mailQ_m_##name }; \
+osMailQDef_t os_mailQ_def_##name = \
+{ (queue_sz), sizeof(type), (os_mailQ_p_##name) }
+#endif
+
+/// \brief Access a Mail Queue Definition.
+/// \param name name of the queue
+/// \note CAN BE CHANGED: The parameter to \b osMailQ shall be consistent but the
+/// macro body is implementation specific in every CMSIS-RTOS.
+#define osMailQ(name) \
+&os_mailQ_def_##name
+
+/// Create and Initialize mail queue.
+/// \param[in] queue_def reference to the mail queue definition obtain with \ref osMailQ
+/// \param[in] thread_id thread ID (obtained by \ref osThreadCreate or \ref osThreadGetId) or NULL.
+/// \return mail queue ID for reference by other functions or NULL in case of error.
+/// \note MUST REMAIN UNCHANGED: \b osMailCreate shall be consistent in every CMSIS-RTOS.
+osMailQId osMailCreate (osMailQDef_t *queue_def, osThreadId thread_id);
+
+/// Allocate a memory block from a mail.
+/// \param[in] queue_id mail queue ID obtained with \ref osMailCreate.
+/// \param[in] millisec timeout value or 0 in case of no time-out
+/// \return pointer to memory block that can be filled with mail or NULL in case of error.
+/// \note MUST REMAIN UNCHANGED: \b osMailAlloc shall be consistent in every CMSIS-RTOS.
+void *osMailAlloc (osMailQId queue_id, uint32_t millisec);
+
+/// Allocate a memory block from a mail and set memory block to zero.
+/// \param[in] queue_id mail queue ID obtained with \ref osMailCreate.
+/// \param[in] millisec timeout value or 0 in case of no time-out
+/// \return pointer to memory block that can be filled with mail or NULL in case of error.
+/// \note MUST REMAIN UNCHANGED: \b osMailCAlloc shall be consistent in every CMSIS-RTOS.
+void *osMailCAlloc (osMailQId queue_id, uint32_t millisec);
+
+/// Put a mail to a queue.
+/// \param[in] queue_id mail queue ID obtained with \ref osMailCreate.
+/// \param[in] mail memory block previously allocated with \ref osMailAlloc or \ref osMailCAlloc.
+/// \return status code that indicates the execution status of the function.
+/// \note MUST REMAIN UNCHANGED: \b osMailPut shall be consistent in every CMSIS-RTOS.
+osStatus osMailPut (osMailQId queue_id, void *mail);
+
+/// Get a mail from a queue.
+/// \param[in] queue_id mail queue ID obtained with \ref osMailCreate.
+/// \param[in] millisec timeout value or 0 in case of no time-out
+/// \return event that contains mail information or error code.
+/// \note MUST REMAIN UNCHANGED: \b osMailGet shall be consistent in every CMSIS-RTOS.
+os_InRegs osEvent osMailGet (osMailQId queue_id, uint32_t millisec);
+
+/// Free a memory block from a mail.
+/// \param[in] queue_id mail queue ID obtained with \ref osMailCreate.
+/// \param[in] mail pointer to the memory block that was obtained with \ref osMailGet.
+/// \return status code that indicates the execution status of the function.
+/// \note MUST REMAIN UNCHANGED: \b osMailFree shall be consistent in every CMSIS-RTOS.
+osStatus osMailFree (osMailQId queue_id, void *mail);
+
+#endif // Mail Queues available
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _CMSIS_OS_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/TARGET_CORTEX_M/os_tcb.h Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,51 @@
+#ifndef OS_TCB_H
+#define OS_TCB_H
+
+/* Types */
+typedef char S8;
+typedef unsigned char U8;
+typedef short S16;
+typedef unsigned short U16;
+typedef int S32;
+typedef unsigned int U32;
+typedef long long S64;
+typedef unsigned long long U64;
+typedef unsigned char BIT;
+typedef unsigned int BOOL;
+typedef void (*FUNCP)(void);
+
+typedef struct OS_TCB {
+ /* General part: identical for all implementations. */
+ U8 cb_type; /* Control Block Type */
+ U8 state; /* Task state */
+ U8 prio; /* Execution priority */
+ U8 task_id; /* Task ID value for optimized TCB access */
+ struct OS_TCB *p_lnk; /* Link pointer for ready/sem. wait list */
+ struct OS_TCB *p_rlnk; /* Link pointer for sem./mbx lst backwards */
+ struct OS_TCB *p_dlnk; /* Link pointer for delay list */
+ struct OS_TCB *p_blnk; /* Link pointer for delay list backwards */
+ U16 delta_time; /* Time until time out */
+ U16 interval_time; /* Time interval for periodic waits */
+ U16 events; /* Event flags */
+ U16 waits; /* Wait flags */
+ void **msg; /* Direct message passing when task waits */
+
+ /* Hardware dependant part: specific for CM processor */
+ U8 stack_frame; /* Stack frame: 0=Basic, 1=Extended */
+ U8 reserved1;
+ U16 reserved2;
+ U32 priv_stack; /* Private stack size in bytes */
+ U32 tsk_stack; /* Current task Stack pointer (R13) */
+ U32 *stack; /* Pointer to Task Stack memory block */
+
+ /* Library dependant part */
+#if defined (__CC_ARM) && !defined (__MICROLIB)
+ /* A memory space for arm standard library. */
+ U32 std_libspace[96/4];
+#endif
+
+ /* Task entry point used for uVision debugger */
+ FUNCP ptask; /* Task entry address */
+} *P_TCB;
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/TARGET_CORTEX_M/rt_CMSIS.c Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,1878 @@
+/*----------------------------------------------------------------------------
+ * RL-ARM - RTX
+ *----------------------------------------------------------------------------
+ * Name: rt_CMSIS.c
+ * Purpose: CMSIS RTOS API
+ * Rev.: V4.60
+ *----------------------------------------------------------------------------
+ *
+ * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *---------------------------------------------------------------------------*/
+
+#define __CMSIS_GENERIC
+
+#if defined (__CORTEX_M4) || defined (__CORTEX_M4F)
+ #include "core_cm4.h"
+#elif defined (__CORTEX_M3)
+ #include "core_cm3.h"
+#elif defined (__CORTEX_M0)
+ #include "core_cm0.h"
+#elif defined (__CORTEX_M0PLUS)
+ #include "core_cm0plus.h"
+#else
+ #error "Missing __CORTEX_Mx definition"
+#endif
+
+#include "rt_TypeDef.h"
+#include "RTX_Conf.h"
+#include "rt_System.h"
+#include "rt_Task.h"
+#include "rt_Event.h"
+#include "rt_List.h"
+#include "rt_Time.h"
+#include "rt_Mutex.h"
+#include "rt_Semaphore.h"
+#include "rt_Mailbox.h"
+#include "rt_MemBox.h"
+#include "rt_HAL_CM.h"
+
+#define os_thread_cb OS_TCB
+
+#include "cmsis_os.h"
+
+#if (osFeature_Signals != 16)
+#error Invalid "osFeature_Signals" value!
+#endif
+#if (osFeature_Semaphore > 65535)
+#error Invalid "osFeature_Semaphore" value!
+#endif
+#if (osFeature_Wait != 0)
+#error osWait not supported!
+#endif
+
+
+// ==== Enumeration, structures, defines ====
+
+// Service Calls defines
+
+#if defined (__CC_ARM) /* ARM Compiler */
+
+#define __NO_RETURN __declspec(noreturn)
+
+#define osEvent_type osEvent
+#define osEvent_ret_status ret
+#define osEvent_ret_value ret
+#define osEvent_ret_msg ret
+#define osEvent_ret_mail ret
+
+#define osCallback_type osCallback
+#define osCallback_ret ret
+
+#define SVC_0_1(f,t,...) \
+__svc_indirect(0) t _##f (t(*)()); \
+ t f (void); \
+__attribute__((always_inline)) \
+static __inline t __##f (void) { \
+ return _##f(f); \
+}
+
+#define SVC_1_1(f,t,t1,...) \
+__svc_indirect(0) t _##f (t(*)(t1),t1); \
+ t f (t1 a1); \
+__attribute__((always_inline)) \
+static __inline t __##f (t1 a1) { \
+ return _##f(f,a1); \
+}
+
+#define SVC_2_1(f,t,t1,t2,...) \
+__svc_indirect(0) t _##f (t(*)(t1,t2),t1,t2); \
+ t f (t1 a1, t2 a2); \
+__attribute__((always_inline)) \
+static __inline t __##f (t1 a1, t2 a2) { \
+ return _##f(f,a1,a2); \
+}
+
+#define SVC_3_1(f,t,t1,t2,t3,...) \
+__svc_indirect(0) t _##f (t(*)(t1,t2,t3),t1,t2,t3); \
+ t f (t1 a1, t2 a2, t3 a3); \
+__attribute__((always_inline)) \
+static __inline t __##f (t1 a1, t2 a2, t3 a3) { \
+ return _##f(f,a1,a2,a3); \
+}
+
+#define SVC_4_1(f,t,t1,t2,t3,t4,...) \
+__svc_indirect(0) t _##f (t(*)(t1,t2,t3,t4),t1,t2,t3,t4); \
+ t f (t1 a1, t2 a2, t3 a3, t4 a4); \
+__attribute__((always_inline)) \
+static __inline t __##f (t1 a1, t2 a2, t3 a3, t4 a4) { \
+ return _##f(f,a1,a2,a3,a4); \
+}
+
+#define SVC_1_2 SVC_1_1
+#define SVC_1_3 SVC_1_1
+#define SVC_2_3 SVC_2_1
+
+#elif defined (__GNUC__) /* GNU Compiler */
+
+#define __NO_RETURN __attribute__((noreturn))
+
+typedef uint32_t __attribute__((vector_size(8))) ret64;
+typedef uint32_t __attribute__((vector_size(16))) ret128;
+
+#define RET_pointer __r0
+#define RET_int32_t __r0
+#define RET_osStatus __r0
+#define RET_osPriority __r0
+#define RET_osEvent {(osStatus)__r0, {(uint32_t)__r1}, {(void *)__r2}}
+#define RET_osCallback {(void *)__r0, (void *)__r1}
+
+#define osEvent_type ret128
+#define osEvent_ret_status (ret128){ret.status}
+#define osEvent_ret_value (ret128){ret.status, ret.value.v}
+#define osEvent_ret_msg (ret128){ret.status, ret.value.v, (uint32_t)ret.def.message_id}
+#define osEvent_ret_mail (ret128){ret.status, ret.value.v, (uint32_t)ret.def.mail_id}
+
+#define osCallback_type ret64
+#define osCallback_ret (ret64) {(uint32_t)ret.fp, (uint32_t)ret.arg}
+
+#define SVC_ArgN(n) \
+ register int __r##n __asm("r"#n);
+
+#define SVC_ArgR(n,t,a) \
+ register t __r##n __asm("r"#n) = a;
+
+#define SVC_Arg0() \
+ SVC_ArgN(0) \
+ SVC_ArgN(1) \
+ SVC_ArgN(2) \
+ SVC_ArgN(3)
+
+#define SVC_Arg1(t1) \
+ SVC_ArgR(0,t1,a1) \
+ SVC_ArgN(1) \
+ SVC_ArgN(2) \
+ SVC_ArgN(3)
+
+#define SVC_Arg2(t1,t2) \
+ SVC_ArgR(0,t1,a1) \
+ SVC_ArgR(1,t2,a2) \
+ SVC_ArgN(2) \
+ SVC_ArgN(3)
+
+#define SVC_Arg3(t1,t2,t3) \
+ SVC_ArgR(0,t1,a1) \
+ SVC_ArgR(1,t2,a2) \
+ SVC_ArgR(2,t3,a3) \
+ SVC_ArgN(3)
+
+#define SVC_Arg4(t1,t2,t3,t4) \
+ SVC_ArgR(0,t1,a1) \
+ SVC_ArgR(1,t2,a2) \
+ SVC_ArgR(2,t3,a3) \
+ SVC_ArgR(3,t4,a4)
+
+#if (defined (__CORTEX_M0)) || defined (__CORTEX_M0PLUS)
+#define SVC_Call(f) \
+ __asm volatile \
+ ( \
+ "ldr r7,="#f"\n\t" \
+ "mov r12,r7\n\t" \
+ "svc 0" \
+ : "=r" (__r0), "=r" (__r1), "=r" (__r2), "=r" (__r3) \
+ : "r" (__r0), "r" (__r1), "r" (__r2), "r" (__r3) \
+ : "r7", "r12", "lr", "cc" \
+ );
+#else
+#define SVC_Call(f) \
+ __asm volatile \
+ ( \
+ "ldr r12,="#f"\n\t" \
+ "svc 0" \
+ : "=r" (__r0), "=r" (__r1), "=r" (__r2), "=r" (__r3) \
+ : "r" (__r0), "r" (__r1), "r" (__r2), "r" (__r3) \
+ : "r12", "lr", "cc" \
+ );
+#endif
+
+#define SVC_0_1(f,t,rv) \
+__attribute__((always_inline)) \
+static inline t __##f (void) { \
+ SVC_Arg0(); \
+ SVC_Call(f); \
+ return (t) rv; \
+}
+
+#define SVC_1_1(f,t,t1,rv) \
+__attribute__((always_inline)) \
+static inline t __##f (t1 a1) { \
+ SVC_Arg1(t1); \
+ SVC_Call(f); \
+ return (t) rv; \
+}
+
+#define SVC_2_1(f,t,t1,t2,rv) \
+__attribute__((always_inline)) \
+static inline t __##f (t1 a1, t2 a2) { \
+ SVC_Arg2(t1,t2); \
+ SVC_Call(f); \
+ return (t) rv; \
+}
+
+#define SVC_3_1(f,t,t1,t2,t3,rv) \
+__attribute__((always_inline)) \
+static inline t __##f (t1 a1, t2 a2, t3 a3) { \
+ SVC_Arg3(t1,t2,t3); \
+ SVC_Call(f); \
+ return (t) rv; \
+}
+
+#define SVC_4_1(f,t,t1,t2,t3,t4,rv) \
+__attribute__((always_inline)) \
+static inline t __##f (t1 a1, t2 a2, t3 a3, t4 a4) { \
+ SVC_Arg4(t1,t2,t3,t4); \
+ SVC_Call(f); \
+ return (t) rv; \
+}
+
+#define SVC_1_2 SVC_1_1
+#define SVC_1_3 SVC_1_1
+#define SVC_2_3 SVC_2_1
+
+#elif defined (__ICCARM__) /* IAR Compiler */
+
+#define __NO_RETURN __noreturn
+
+#define osEvent_type osEvent
+#define osEvent_ret_status ret
+#define osEvent_ret_value ret
+#define osEvent_ret_msg ret
+#define osEvent_ret_mail ret
+
+#define osCallback_type osCallback
+#define osCallback_ret ret
+
+#define RET_osEvent osEvent
+#define RET_osCallback osCallback
+
+#define SVC_Setup(f) \
+ __asm( \
+ "mov r12,%0\n" \
+ :: "r"(&f): "r12" \
+ );
+
+
+#define SVC_0_1(f,t,...) \
+t f (void); \
+_Pragma("swi_number=0") __swi t _##f (void); \
+static inline t __##f (void) { \
+ SVC_Setup(f); \
+ return _##f(); \
+}
+
+#define SVC_1_1(f,t,t1,...) \
+t f (t1 a1); \
+_Pragma("swi_number=0") __swi t _##f (t1 a1); \
+static inline t __##f (t1 a1) { \
+ SVC_Setup(f); \
+ return _##f(a1); \
+}
+
+#define SVC_2_1(f,t,t1,t2,...) \
+t f (t1 a1, t2 a2); \
+_Pragma("swi_number=0") __swi t _##f (t1 a1, t2 a2); \
+static inline t __##f (t1 a1, t2 a2) { \
+ SVC_Setup(f); \
+ return _##f(a1,a2); \
+}
+
+#define SVC_3_1(f,t,t1,t2,t3,...) \
+t f (t1 a1, t2 a2, t3 a3); \
+_Pragma("swi_number=0") __swi t _##f (t1 a1, t2 a2, t3 a3); \
+static inline t __##f (t1 a1, t2 a2, t3 a3) { \
+ SVC_Setup(f); \
+ return _##f(a1,a2,a3); \
+}
+
+#define SVC_4_1(f,t,t1,t2,t3,t4,...) \
+t f (t1 a1, t2 a2, t3 a3, t4 a4); \
+_Pragma("swi_number=0") __swi t _##f (t1 a1, t2 a2, t3 a3, t4 a4); \
+static inline t __##f (t1 a1, t2 a2, t3 a3, t4 a4) { \
+ SVC_Setup(f); \
+ return _##f(a1,a2,a3,a4); \
+}
+
+#define SVC_1_2 SVC_1_1
+#define SVC_1_3 SVC_1_1
+#define SVC_2_3 SVC_2_1
+
+#endif
+
+
+// Callback structure
+typedef struct {
+ void *fp; // Function pointer
+ void *arg; // Function argument
+} osCallback;
+
+
+// OS Section definitions
+#ifdef OS_SECTIONS_LINK_INFO
+extern const uint32_t os_section_id$$Base;
+extern const uint32_t os_section_id$$Limit;
+#endif
+
+// OS Timers external resources
+extern osThreadDef_t os_thread_def_osTimerThread;
+extern osThreadId osThreadId_osTimerThread;
+extern osMessageQDef_t os_messageQ_def_osTimerMessageQ;
+extern osMessageQId osMessageQId_osTimerMessageQ;
+
+
+// ==== Helper Functions ====
+
+/// Convert timeout in millisec to system ticks
+static uint32_t rt_ms2tick (uint32_t millisec) {
+ uint32_t tick;
+
+ if (millisec == osWaitForever) return 0xFFFF; // Indefinite timeout
+ if (millisec > 4000000) return 0xFFFE; // Max ticks supported
+
+ tick = ((1000 * millisec) + os_clockrate - 1) / os_clockrate;
+ if (tick > 0xFFFE) return 0xFFFE;
+
+ return tick;
+}
+
+/// Convert Thread ID to TCB pointer
+static P_TCB rt_tid2ptcb (osThreadId thread_id) {
+ P_TCB ptcb;
+
+ if (thread_id == NULL) return NULL;
+
+ if ((uint32_t)thread_id & 3) return NULL;
+
+#ifdef OS_SECTIONS_LINK_INFO
+ if ((os_section_id$$Base != 0) && (os_section_id$$Limit != 0)) {
+ if (thread_id < (osThreadId)os_section_id$$Base) return NULL;
+ if (thread_id >= (osThreadId)os_section_id$$Limit) return NULL;
+ }
+#endif
+
+ ptcb = thread_id;
+
+ if (ptcb->cb_type != TCB) return NULL;
+
+ return ptcb;
+}
+
+/// Convert ID pointer to Object pointer
+static void *rt_id2obj (void *id) {
+
+ if ((uint32_t)id & 3) return NULL;
+
+#ifdef OS_SECTIONS_LINK_INFO
+ if ((os_section_id$$Base != 0) && (os_section_id$$Limit != 0)) {
+ if (id < (void *)os_section_id$$Base) return NULL;
+ if (id >= (void *)os_section_id$$Limit) return NULL;
+ }
+#endif
+
+ return id;
+}
+
+
+// ==== Kernel Control ====
+
+uint8_t os_initialized; // Kernel Initialized flag
+uint8_t os_running; // Kernel Running flag
+
+// Kernel Control Service Calls declarations
+SVC_0_1(svcKernelInitialize, osStatus, RET_osStatus)
+SVC_0_1(svcKernelStart, osStatus, RET_osStatus)
+SVC_0_1(svcKernelRunning, int32_t, RET_int32_t)
+
+extern void sysThreadError (osStatus status);
+osThreadId svcThreadCreate (osThreadDef_t *thread_def, void *argument);
+osMessageQId svcMessageCreate (osMessageQDef_t *queue_def, osThreadId thread_id);
+
+// Kernel Control Service Calls
+
+/// Initialize the RTOS Kernel for creating objects
+osStatus svcKernelInitialize (void) {
+ if (os_initialized) return osOK;
+
+ rt_sys_init(); // RTX System Initialization
+ os_tsk.run->prio = 255; // Highest priority
+
+ sysThreadError(osOK);
+
+ os_initialized = 1;
+
+ return osOK;
+}
+
+/// Start the RTOS Kernel
+osStatus svcKernelStart (void) {
+
+ if (os_running) return osOK;
+
+ // Create OS Timers resources (Message Queue & Thread)
+ osMessageQId_osTimerMessageQ = svcMessageCreate (&os_messageQ_def_osTimerMessageQ, NULL);
+ osThreadId_osTimerThread = svcThreadCreate(&os_thread_def_osTimerThread, NULL);
+
+ rt_tsk_prio(0, 0); // Lowest priority
+ __set_PSP(os_tsk.run->tsk_stack + 8*4); // New context
+ os_tsk.run = NULL; // Force context switch
+
+ rt_sys_start();
+
+ os_running = 1;
+
+ return osOK;
+}
+
+/// Check if the RTOS kernel is already started
+int32_t svcKernelRunning(void) {
+ return os_running;
+}
+
+// Kernel Control Public API
+
+/// Initialize the RTOS Kernel for creating objects
+osStatus osKernelInitialize (void) {
+ if (__get_IPSR() != 0) return osErrorISR; // Not allowed in ISR
+ if ((__get_CONTROL() & 1) == 0) { // Privileged mode
+ return svcKernelInitialize();
+ } else {
+ return __svcKernelInitialize();
+ }
+}
+
+/// Start the RTOS Kernel
+osStatus osKernelStart (void) {
+ uint32_t stack[8];
+
+ if (__get_IPSR() != 0) return osErrorISR; // Not allowed in ISR
+ switch (__get_CONTROL() & 0x03) {
+ case 0x00: // Privileged Thread mode & MSP
+ __set_PSP((uint32_t)(stack + 8)); // Initial PSP
+ if (os_flags & 1) {
+ __set_CONTROL(0x02); // Set Privileged Thread mode & PSP
+ } else {
+ __set_CONTROL(0x03); // Set Unprivileged Thread mode & PSP
+ }
+ __DSB();
+ __ISB();
+ break;
+ case 0x01: // Unprivileged Thread mode & MSP
+ return osErrorOS;
+ case 0x02: // Privileged Thread mode & PSP
+ if ((os_flags & 1) == 0) { // Unprivileged Thread mode requested
+ __set_CONTROL(0x03); // Set Unprivileged Thread mode & PSP
+ __DSB();
+ __ISB();
+ }
+ break;
+ case 0x03: // Unprivileged Thread mode & PSP
+ if (os_flags & 1) return osErrorOS; // Privileged Thread mode requested
+ break;
+ }
+ return __svcKernelStart();
+}
+
+/// Check if the RTOS kernel is already started
+int32_t osKernelRunning(void) {
+ if ((__get_IPSR() != 0) || ((__get_CONTROL() & 1) == 0)) {
+ // in ISR or Privileged
+ return os_running;
+ } else {
+ return __svcKernelRunning();
+ }
+}
+
+
+// ==== Thread Management ====
+
+__NO_RETURN void osThreadExit (void);
+
+// Thread Service Calls declarations
+SVC_2_1(svcThreadCreate, osThreadId, osThreadDef_t *, void *, RET_pointer)
+SVC_0_1(svcThreadGetId, osThreadId, RET_pointer)
+SVC_1_1(svcThreadTerminate, osStatus, osThreadId, RET_osStatus)
+SVC_0_1(svcThreadYield, osStatus, RET_osStatus)
+SVC_2_1(svcThreadSetPriority, osStatus, osThreadId, osPriority, RET_osStatus)
+SVC_1_1(svcThreadGetPriority, osPriority, osThreadId, RET_osPriority)
+
+// Thread Service Calls
+extern OS_TID rt_get_TID (void);
+extern void rt_init_context (P_TCB p_TCB, U8 priority, FUNCP task_body);
+
+/// Create a thread and add it to Active Threads and set it to state READY
+osThreadId svcThreadCreate (osThreadDef_t *thread_def, void *argument) {
+ P_TCB ptcb;
+
+ if ((thread_def == NULL) ||
+ (thread_def->pthread == NULL) ||
+ (thread_def->tpriority < osPriorityIdle) ||
+ (thread_def->tpriority > osPriorityRealtime) ||
+ (thread_def->stacksize == 0) ||
+ (thread_def->stack_pointer == NULL) ) {
+ sysThreadError(osErrorParameter);
+ return NULL;
+ }
+
+ U8 priority = thread_def->tpriority - osPriorityIdle + 1;
+ P_TCB task_context = &thread_def->tcb;
+
+ /* Utilize the user provided stack. */
+ task_context->stack = (U32*)thread_def->stack_pointer;
+ task_context->priv_stack = thread_def->stacksize;
+ /* Find a free entry in 'os_active_TCB' table. */
+ OS_TID tsk = rt_get_TID ();
+ os_active_TCB[tsk-1] = task_context;
+ task_context->task_id = tsk;
+ /* Pass parameter 'argv' to 'rt_init_context' */
+ task_context->msg = argument;
+ /* Initialize thread context structure, including the thread's stack. */
+ rt_init_context (task_context, priority, (FUNCP)thread_def->pthread);
+
+ /* Dispatch this task to the scheduler for execution. */
+ DBG_TASK_NOTIFY(task_context, __TRUE);
+ rt_dispatch (task_context);
+
+ ptcb = (P_TCB)os_active_TCB[tsk - 1]; // TCB pointer
+
+ *((uint32_t *)ptcb->tsk_stack + 13) = (uint32_t)osThreadExit;
+
+ return ptcb;
+}
+
+/// Return the thread ID of the current running thread
+osThreadId svcThreadGetId (void) {
+ OS_TID tsk;
+
+ tsk = rt_tsk_self();
+ if (tsk == 0) return NULL;
+ return (P_TCB)os_active_TCB[tsk - 1];
+}
+
+/// Terminate execution of a thread and remove it from ActiveThreads
+osStatus svcThreadTerminate (osThreadId thread_id) {
+ OS_RESULT res;
+ P_TCB ptcb;
+
+ ptcb = rt_tid2ptcb(thread_id); // Get TCB pointer
+ if (ptcb == NULL) return osErrorParameter;
+
+ res = rt_tsk_delete(ptcb->task_id); // Delete task
+
+ if (res == OS_R_NOK) return osErrorResource; // Delete task failed
+
+ return osOK;
+}
+
+/// Pass control to next thread that is in state READY
+osStatus svcThreadYield (void) {
+ rt_tsk_pass(); // Pass control to next task
+ return osOK;
+}
+
+/// Change priority of an active thread
+osStatus svcThreadSetPriority (osThreadId thread_id, osPriority priority) {
+ OS_RESULT res;
+ P_TCB ptcb;
+
+ ptcb = rt_tid2ptcb(thread_id); // Get TCB pointer
+ if (ptcb == NULL) return osErrorParameter;
+
+ if ((priority < osPriorityIdle) || (priority > osPriorityRealtime)) {
+ return osErrorValue;
+ }
+
+ res = rt_tsk_prio( // Change task priority
+ ptcb->task_id, // Task ID
+ priority - osPriorityIdle + 1 // New task priority
+ );
+
+ if (res == OS_R_NOK) return osErrorResource; // Change task priority failed
+
+ return osOK;
+}
+
+/// Get current priority of an active thread
+osPriority svcThreadGetPriority (osThreadId thread_id) {
+ P_TCB ptcb;
+
+ ptcb = rt_tid2ptcb(thread_id); // Get TCB pointer
+ if (ptcb == NULL) return osPriorityError;
+
+ return (osPriority)(ptcb->prio - 1 + osPriorityIdle);
+}
+
+
+// Thread Public API
+
+/// Create a thread and add it to Active Threads and set it to state READY
+osThreadId osThreadCreate (osThreadDef_t *thread_def, void *argument) {
+ if (__get_IPSR() != 0) return NULL; // Not allowed in ISR
+ if (((__get_CONTROL() & 1) == 0) && (os_running == 0)) {
+ // Privileged and not running
+ return svcThreadCreate(thread_def, argument);
+ } else {
+ return __svcThreadCreate(thread_def, argument);
+ }
+}
+
+/// Return the thread ID of the current running thread
+osThreadId osThreadGetId (void) {
+ if (__get_IPSR() != 0) return NULL; // Not allowed in ISR
+ return __svcThreadGetId();
+}
+
+/// Terminate execution of a thread and remove it from ActiveThreads
+osStatus osThreadTerminate (osThreadId thread_id) {
+ if (__get_IPSR() != 0) return osErrorISR; // Not allowed in ISR
+ return __svcThreadTerminate(thread_id);
+}
+
+/// Pass control to next thread that is in state READY
+osStatus osThreadYield (void) {
+ if (__get_IPSR() != 0) return osErrorISR; // Not allowed in ISR
+ return __svcThreadYield();
+}
+
+/// Change priority of an active thread
+osStatus osThreadSetPriority (osThreadId thread_id, osPriority priority) {
+ if (__get_IPSR() != 0) return osErrorISR; // Not allowed in ISR
+ return __svcThreadSetPriority(thread_id, priority);
+}
+
+/// Get current priority of an active thread
+osPriority osThreadGetPriority (osThreadId thread_id) {
+ if (__get_IPSR() != 0) return osPriorityError;// Not allowed in ISR
+ return __svcThreadGetPriority(thread_id);
+}
+
+/// INTERNAL - Not Public
+/// Auto Terminate Thread on exit (used implicitly when thread exists)
+__NO_RETURN void osThreadExit (void) {
+ __svcThreadTerminate(__svcThreadGetId());
+ for (;;); // Should never come here
+}
+
+
+// ==== Generic Wait Functions ====
+
+// Generic Wait Service Calls declarations
+SVC_1_1(svcDelay, osStatus, uint32_t, RET_osStatus)
+#if osFeature_Wait != 0
+SVC_1_3(svcWait, os_InRegs osEvent, uint32_t, RET_osEvent)
+#endif
+
+// Generic Wait Service Calls
+
+/// Wait for Timeout (Time Delay)
+osStatus svcDelay (uint32_t millisec) {
+ if (millisec == 0) return osOK;
+ rt_dly_wait(rt_ms2tick(millisec));
+ return osEventTimeout;
+}
+
+/// Wait for Signal, Message, Mail, or Timeout
+#if osFeature_Wait != 0
+os_InRegs osEvent_type svcWait (uint32_t millisec) {
+ osEvent ret;
+
+ if (millisec == 0) {
+ ret.status = osOK;
+ return osEvent_ret_status;
+ }
+
+ /* To Do: osEventSignal, osEventMessage, osEventMail */
+ rt_dly_wait(rt_ms2tick(millisec));
+ ret.status = osEventTimeout;
+
+ return osEvent_ret_status;
+}
+#endif
+
+
+// Generic Wait API
+
+/// Wait for Timeout (Time Delay)
+osStatus osDelay (uint32_t millisec) {
+ if (__get_IPSR() != 0) return osErrorISR; // Not allowed in ISR
+ return __svcDelay(millisec);
+}
+
+/// Wait for Signal, Message, Mail, or Timeout
+os_InRegs osEvent osWait (uint32_t millisec) {
+ osEvent ret;
+
+#if osFeature_Wait == 0
+ ret.status = osErrorOS;
+ return ret;
+#else
+ if (__get_IPSR() != 0) { // Not allowed in ISR
+ ret.status = osErrorISR;
+ return ret;
+ }
+ return __svcWait(millisec);
+#endif
+}
+
+
+// ==== Timer Management ====
+
+// Timer definitions
+#define osTimerInvalid 0
+#define osTimerStopped 1
+#define osTimerRunning 2
+
+// Timer structures
+
+typedef struct os_timer_cb_ { // Timer Control Block
+ struct os_timer_cb_ *next; // Pointer to next active Timer
+ uint8_t state; // Timer State
+ uint8_t type; // Timer Type (Periodic/One-shot)
+ uint16_t reserved; // Reserved
+ uint16_t tcnt; // Timer Delay Count
+ uint16_t icnt; // Timer Initial Count
+ void *arg; // Timer Function Argument
+ osTimerDef_t *timer; // Pointer to Timer definition
+} os_timer_cb;
+
+// Timer variables
+os_timer_cb *os_timer_head; // Pointer to first active Timer
+
+
+// Timer Helper Functions
+
+// Insert Timer into the list sorted by time
+static void rt_timer_insert (os_timer_cb *pt, uint32_t tcnt) {
+ os_timer_cb *p, *prev;
+
+ prev = NULL;
+ p = os_timer_head;
+ while (p != NULL) {
+ if (tcnt < p->tcnt) break;
+ tcnt -= p->tcnt;
+ prev = p;
+ p = p->next;
+ }
+ pt->next = p;
+ pt->tcnt = (uint16_t)tcnt;
+ if (p != NULL) {
+ p->tcnt -= pt->tcnt;
+ }
+ if (prev != NULL) {
+ prev->next = pt;
+ } else {
+ os_timer_head = pt;
+ }
+}
+
+// Remove Timer from the list
+static int rt_timer_remove (os_timer_cb *pt) {
+ os_timer_cb *p, *prev;
+
+ prev = NULL;
+ p = os_timer_head;
+ while (p != NULL) {
+ if (p == pt) break;
+ prev = p;
+ p = p->next;
+ }
+ if (p == NULL) return -1;
+ if (prev != NULL) {
+ prev->next = pt->next;
+ } else {
+ os_timer_head = pt->next;
+ }
+ if (pt->next != NULL) {
+ pt->next->tcnt += pt->tcnt;
+ }
+
+ return 0;
+}
+
+
+// Timer Service Calls declarations
+SVC_3_1(svcTimerCreate, osTimerId, osTimerDef_t *, os_timer_type, void *, RET_pointer)
+SVC_2_1(svcTimerStart, osStatus, osTimerId, uint32_t, RET_osStatus)
+SVC_1_1(svcTimerStop, osStatus, osTimerId, RET_osStatus)
+SVC_1_1(svcTimerDelete, osStatus, osTimerId, RET_osStatus)
+SVC_1_2(svcTimerCall, os_InRegs osCallback, osTimerId, RET_osCallback)
+
+// Timer Management Service Calls
+
+/// Create timer
+osTimerId svcTimerCreate (osTimerDef_t *timer_def, os_timer_type type, void *argument) {
+ os_timer_cb *pt;
+
+ if ((timer_def == NULL) || (timer_def->ptimer == NULL)) {
+ sysThreadError(osErrorParameter);
+ return NULL;
+ }
+
+ pt = timer_def->timer;
+ if (pt == NULL) {
+ sysThreadError(osErrorParameter);
+ return NULL;
+ }
+
+ if ((type != osTimerOnce) && (type != osTimerPeriodic)) {
+ sysThreadError(osErrorValue);
+ return NULL;
+ }
+
+ if (osThreadId_osTimerThread == NULL) {
+ sysThreadError(osErrorResource);
+ return NULL;
+ }
+
+ if (pt->state != osTimerInvalid){
+ sysThreadError(osErrorResource);
+ return NULL;
+ }
+
+ pt->state = osTimerStopped;
+ pt->type = (uint8_t)type;
+ pt->arg = argument;
+ pt->timer = timer_def;
+
+ return (osTimerId)pt;
+}
+
+/// Start or restart timer
+osStatus svcTimerStart (osTimerId timer_id, uint32_t millisec) {
+ os_timer_cb *pt;
+ uint32_t tcnt;
+
+ pt = rt_id2obj(timer_id);
+ if (pt == NULL) return osErrorParameter;
+
+ tcnt = rt_ms2tick(millisec);
+ if (tcnt == 0) return osErrorValue;
+
+ switch (pt->state) {
+ case osTimerRunning:
+ if (rt_timer_remove(pt) != 0) {
+ return osErrorResource;
+ }
+ break;
+ case osTimerStopped:
+ pt->state = osTimerRunning;
+ pt->icnt = (uint16_t)tcnt;
+ break;
+ default:
+ return osErrorResource;
+ }
+
+ rt_timer_insert(pt, tcnt);
+
+ return osOK;
+}
+
+/// Stop timer
+osStatus svcTimerStop (osTimerId timer_id) {
+ os_timer_cb *pt;
+
+ pt = rt_id2obj(timer_id);
+ if (pt == NULL) return osErrorParameter;
+
+ if (pt->state != osTimerRunning) return osErrorResource;
+
+ pt->state = osTimerStopped;
+
+ if (rt_timer_remove(pt) != 0) {
+ return osErrorResource;
+ }
+
+ return osOK;
+}
+
+/// Delete timer
+osStatus svcTimerDelete (osTimerId timer_id) {
+ os_timer_cb *pt;
+
+ pt = rt_id2obj(timer_id);
+ if (pt == NULL) return osErrorParameter;
+
+ switch (pt->state) {
+ case osTimerRunning:
+ rt_timer_remove(pt);
+ break;
+ case osTimerStopped:
+ break;
+ default:
+ return osErrorResource;
+ }
+
+ pt->state = osTimerInvalid;
+
+ return osOK;
+}
+
+/// Get timer callback parameters
+os_InRegs osCallback_type svcTimerCall (osTimerId timer_id) {
+ os_timer_cb *pt;
+ osCallback ret;
+
+ pt = rt_id2obj(timer_id);
+ if (pt == NULL) {
+ ret.fp = NULL;
+ ret.arg = NULL;
+ return osCallback_ret;
+ }
+
+ ret.fp = (void *)pt->timer->ptimer;
+ ret.arg = pt->arg;
+
+ return osCallback_ret;
+}
+
+static __INLINE osStatus isrMessagePut (osMessageQId queue_id, uint32_t info, uint32_t millisec);
+
+/// Timer Tick (called each SysTick)
+void sysTimerTick (void) {
+ os_timer_cb *pt, *p;
+
+ p = os_timer_head;
+ if (p == NULL) return;
+
+ p->tcnt--;
+ while ((p != NULL) && (p->tcnt == 0)) {
+ pt = p;
+ p = p->next;
+ os_timer_head = p;
+ isrMessagePut(osMessageQId_osTimerMessageQ, (uint32_t)pt, 0);
+ if (pt->type == osTimerPeriodic) {
+ rt_timer_insert(pt, pt->icnt);
+ } else {
+ pt->state = osTimerStopped;
+ }
+ }
+}
+
+
+// Timer Management Public API
+
+/// Create timer
+osTimerId osTimerCreate (osTimerDef_t *timer_def, os_timer_type type, void *argument) {
+ if (__get_IPSR() != 0) return NULL; // Not allowed in ISR
+ if (((__get_CONTROL() & 1) == 0) && (os_running == 0)) {
+ // Privileged and not running
+ return svcTimerCreate(timer_def, type, argument);
+ } else {
+ return __svcTimerCreate(timer_def, type, argument);
+ }
+}
+
+/// Start or restart timer
+osStatus osTimerStart (osTimerId timer_id, uint32_t millisec) {
+ if (__get_IPSR() != 0) return osErrorISR; // Not allowed in ISR
+ return __svcTimerStart(timer_id, millisec);
+}
+
+/// Stop timer
+osStatus osTimerStop (osTimerId timer_id) {
+ if (__get_IPSR() != 0) return osErrorISR; // Not allowed in ISR
+ return __svcTimerStop(timer_id);
+}
+
+/// Delete timer
+osStatus osTimerDelete (osTimerId timer_id) {
+ if (__get_IPSR() != 0) return osErrorISR; // Not allowed in ISR
+ return __svcTimerDelete(timer_id);
+}
+
+/// INTERNAL - Not Public
+/// Get timer callback parameters (used by OS Timer Thread)
+os_InRegs osCallback osTimerCall (osTimerId timer_id) {
+ return __svcTimerCall(timer_id);
+}
+
+
+// Timer Thread
+__NO_RETURN void osTimerThread (void const *argument) {
+ osCallback cb;
+ osEvent evt;
+
+ for (;;) {
+ evt = osMessageGet(osMessageQId_osTimerMessageQ, osWaitForever);
+ if (evt.status == osEventMessage) {
+ cb = osTimerCall(evt.value.p);
+ if (cb.fp != NULL) {
+ (*(os_ptimer)cb.fp)(cb.arg);
+ }
+ }
+ }
+}
+
+
+// ==== Signal Management ====
+
+// Signal Service Calls declarations
+SVC_2_1(svcSignalSet, int32_t, osThreadId, int32_t, RET_int32_t)
+SVC_2_1(svcSignalClear, int32_t, osThreadId, int32_t, RET_int32_t)
+SVC_1_1(svcSignalGet, int32_t, osThreadId, RET_int32_t)
+SVC_2_3(svcSignalWait, os_InRegs osEvent, int32_t, uint32_t, RET_osEvent)
+
+// Signal Service Calls
+
+/// Set the specified Signal Flags of an active thread
+int32_t svcSignalSet (osThreadId thread_id, int32_t signals) {
+ P_TCB ptcb;
+ int32_t sig;
+
+ ptcb = rt_tid2ptcb(thread_id); // Get TCB pointer
+ if (ptcb == NULL) return 0x80000000;
+
+ if (signals & (0xFFFFFFFF << osFeature_Signals)) return 0x80000000;
+
+ sig = ptcb->events; // Previous signal flags
+
+ rt_evt_set(signals, ptcb->task_id); // Set event flags
+
+ return sig;
+}
+
+/// Clear the specified Signal Flags of an active thread
+int32_t svcSignalClear (osThreadId thread_id, int32_t signals) {
+ P_TCB ptcb;
+ int32_t sig;
+
+ ptcb = rt_tid2ptcb(thread_id); // Get TCB pointer
+ if (ptcb == NULL) return 0x80000000;
+
+ if (signals & (0xFFFFFFFF << osFeature_Signals)) return 0x80000000;
+
+ sig = ptcb->events; // Previous signal flags
+
+ rt_evt_clr(signals, ptcb->task_id); // Clear event flags
+
+ return sig;
+}
+
+/// Get Signal Flags status of an active thread
+int32_t svcSignalGet (osThreadId thread_id) {
+ P_TCB ptcb;
+
+ ptcb = rt_tid2ptcb(thread_id); // Get TCB pointer
+ if (ptcb == NULL) return 0x80000000;
+
+ return ptcb->events; // Return event flags
+}
+
+/// Wait for one or more Signal Flags to become signaled for the current RUNNING thread
+os_InRegs osEvent_type svcSignalWait (int32_t signals, uint32_t millisec) {
+ OS_RESULT res;
+ osEvent ret;
+
+ if (signals & (0xFFFFFFFF << osFeature_Signals)) {
+ ret.status = osErrorValue;
+ return osEvent_ret_status;
+ }
+
+ if (signals != 0) { // Wait for all specified signals
+ res = rt_evt_wait(signals, rt_ms2tick(millisec), __TRUE);
+ } else { // Wait for any signal
+ res = rt_evt_wait(0xFFFF, rt_ms2tick(millisec), __FALSE);
+ }
+
+ if (res == OS_R_EVT) {
+ ret.status = osEventSignal;
+ ret.value.signals = signals ? signals : os_tsk.run->waits;
+ } else {
+ ret.status = millisec ? osEventTimeout : osOK;
+ ret.value.signals = 0;
+ }
+
+ return osEvent_ret_value;
+}
+
+
+// Signal ISR Calls
+
+/// Set the specified Signal Flags of an active thread
+static __INLINE int32_t isrSignalSet (osThreadId thread_id, int32_t signals) {
+ P_TCB ptcb;
+ int32_t sig;
+
+ ptcb = rt_tid2ptcb(thread_id); // Get TCB pointer
+ if (ptcb == NULL) return 0x80000000;
+
+ if (signals & (0xFFFFFFFF << osFeature_Signals)) return 0x80000000;
+
+ sig = ptcb->events; // Previous signal flags
+
+ isr_evt_set(signals, ptcb->task_id); // Set event flags
+
+ return sig;
+}
+
+
+// Signal Public API
+
+/// Set the specified Signal Flags of an active thread
+int32_t osSignalSet (osThreadId thread_id, int32_t signals) {
+ if (__get_IPSR() != 0) { // in ISR
+ return isrSignalSet(thread_id, signals);
+ } else { // in Thread
+ return __svcSignalSet(thread_id, signals);
+ }
+}
+
+/// Clear the specified Signal Flags of an active thread
+int32_t osSignalClear (osThreadId thread_id, int32_t signals) {
+ if (__get_IPSR() != 0) return osErrorISR; // Not allowed in ISR
+ return __svcSignalClear(thread_id, signals);
+}
+
+/// Get Signal Flags status of an active thread
+int32_t osSignalGet (osThreadId thread_id) {
+ if (__get_IPSR() != 0) return osErrorISR; // Not allowed in ISR
+ return __svcSignalGet(thread_id);
+}
+
+/// Wait for one or more Signal Flags to become signaled for the current RUNNING thread
+os_InRegs osEvent osSignalWait (int32_t signals, uint32_t millisec) {
+ osEvent ret;
+
+ if (__get_IPSR() != 0) { // Not allowed in ISR
+ ret.status = osErrorISR;
+ return ret;
+ }
+ return __svcSignalWait(signals, millisec);
+}
+
+
+// ==== Mutex Management ====
+
+// Mutex Service Calls declarations
+SVC_1_1(svcMutexCreate, osMutexId, osMutexDef_t *, RET_pointer)
+SVC_2_1(svcMutexWait, osStatus, osMutexId, uint32_t, RET_osStatus)
+SVC_1_1(svcMutexRelease, osStatus, osMutexId, RET_osStatus)
+SVC_1_1(svcMutexDelete, osStatus, osMutexId, RET_osStatus)
+
+// Mutex Service Calls
+
+/// Create and Initialize a Mutex object
+osMutexId svcMutexCreate (osMutexDef_t *mutex_def) {
+ OS_ID mut;
+
+ if (mutex_def == NULL) {
+ sysThreadError(osErrorParameter);
+ return NULL;
+ }
+
+ mut = mutex_def->mutex;
+ if (mut == NULL) {
+ sysThreadError(osErrorParameter);
+ return NULL;
+ }
+
+ if (((P_MUCB)mut)->cb_type != 0) {
+ sysThreadError(osErrorParameter);
+ return NULL;
+ }
+
+ rt_mut_init(mut); // Initialize Mutex
+
+ return mut;
+}
+
+/// Wait until a Mutex becomes available
+osStatus svcMutexWait (osMutexId mutex_id, uint32_t millisec) {
+ OS_ID mut;
+ OS_RESULT res;
+
+ mut = rt_id2obj(mutex_id);
+ if (mut == NULL) return osErrorParameter;
+
+ if (((P_MUCB)mut)->cb_type != MUCB) return osErrorParameter;
+
+ res = rt_mut_wait(mut, rt_ms2tick(millisec)); // Wait for Mutex
+
+ if (res == OS_R_TMO) {
+ return (millisec ? osErrorTimeoutResource : osErrorResource);
+ }
+
+ return osOK;
+}
+
+/// Release a Mutex that was obtained with osMutexWait
+osStatus svcMutexRelease (osMutexId mutex_id) {
+ OS_ID mut;
+ OS_RESULT res;
+
+ mut = rt_id2obj(mutex_id);
+ if (mut == NULL) return osErrorParameter;
+
+ if (((P_MUCB)mut)->cb_type != MUCB) return osErrorParameter;
+
+ res = rt_mut_release(mut); // Release Mutex
+
+ if (res == OS_R_NOK) return osErrorResource; // Thread not owner or Zero Counter
+
+ return osOK;
+}
+
+/// Delete a Mutex that was created by osMutexCreate
+osStatus svcMutexDelete (osMutexId mutex_id) {
+ OS_ID mut;
+
+ mut = rt_id2obj(mutex_id);
+ if (mut == NULL) return osErrorParameter;
+
+ if (((P_MUCB)mut)->cb_type != MUCB) return osErrorParameter;
+
+ rt_mut_delete(mut); // Release Mutex
+
+ return osOK;
+}
+
+
+// Mutex Public API
+
+/// Create and Initialize a Mutex object
+osMutexId osMutexCreate (osMutexDef_t *mutex_def) {
+ if (__get_IPSR() != 0) return NULL; // Not allowed in ISR
+ if (((__get_CONTROL() & 1) == 0) && (os_running == 0)) {
+ // Privileged and not running
+ return svcMutexCreate(mutex_def);
+ } else {
+ return __svcMutexCreate(mutex_def);
+ }
+}
+
+/// Wait until a Mutex becomes available
+osStatus osMutexWait (osMutexId mutex_id, uint32_t millisec) {
+ if (__get_IPSR() != 0) return osErrorISR; // Not allowed in ISR
+ return __svcMutexWait(mutex_id, millisec);
+}
+
+/// Release a Mutex that was obtained with osMutexWait
+osStatus osMutexRelease (osMutexId mutex_id) {
+ if (__get_IPSR() != 0) return osErrorISR; // Not allowed in ISR
+ return __svcMutexRelease(mutex_id);
+}
+
+/// Delete a Mutex that was created by osMutexCreate
+osStatus osMutexDelete (osMutexId mutex_id) {
+ if (__get_IPSR() != 0) return osErrorISR; // Not allowed in ISR
+ return __svcMutexDelete(mutex_id);
+}
+
+
+// ==== Semaphore Management ====
+
+// Semaphore Service Calls declarations
+SVC_2_1(svcSemaphoreCreate, osSemaphoreId, const osSemaphoreDef_t *, int32_t, RET_pointer)
+SVC_2_1(svcSemaphoreWait, int32_t, osSemaphoreId, uint32_t, RET_int32_t)
+SVC_1_1(svcSemaphoreRelease, osStatus, osSemaphoreId, RET_osStatus)
+SVC_1_1(svcSemaphoreDelete, osStatus, osSemaphoreId, RET_osStatus)
+
+// Semaphore Service Calls
+
+/// Create and Initialize a Semaphore object
+osSemaphoreId svcSemaphoreCreate (const osSemaphoreDef_t *semaphore_def, int32_t count) {
+ OS_ID sem;
+
+ if (semaphore_def == NULL) {
+ sysThreadError(osErrorParameter);
+ return NULL;
+ }
+
+ sem = semaphore_def->semaphore;
+ if (sem == NULL) {
+ sysThreadError(osErrorParameter);
+ return NULL;
+ }
+
+ if (((P_SCB)sem)->cb_type != 0) {
+ sysThreadError(osErrorParameter);
+ return NULL;
+ }
+
+ if (count > osFeature_Semaphore) {
+ sysThreadError(osErrorValue);
+ return NULL;
+ }
+
+ rt_sem_init(sem, count); // Initialize Semaphore
+
+ return sem;
+}
+
+/// Wait until a Semaphore becomes available
+int32_t svcSemaphoreWait (osSemaphoreId semaphore_id, uint32_t millisec) {
+ OS_ID sem;
+ OS_RESULT res;
+
+ sem = rt_id2obj(semaphore_id);
+ if (sem == NULL) return -1;
+
+ if (((P_SCB)sem)->cb_type != SCB) return -1;
+
+ res = rt_sem_wait(sem, rt_ms2tick(millisec)); // Wait for Semaphore
+
+ if (res == OS_R_TMO) return 0; // Timeout
+
+ return (((P_SCB)sem)->tokens + 1);
+}
+
+/// Release a Semaphore
+osStatus svcSemaphoreRelease (osSemaphoreId semaphore_id) {
+ OS_ID sem;
+
+ sem = rt_id2obj(semaphore_id);
+ if (sem == NULL) return osErrorParameter;
+
+ if (((P_SCB)sem)->cb_type != SCB) return osErrorParameter;
+
+ if (((P_SCB)sem)->tokens == osFeature_Semaphore) return osErrorResource;
+
+ rt_sem_send(sem); // Release Semaphore
+
+ return osOK;
+}
+
+/// Delete a Semaphore that was created by osSemaphoreCreate
+osStatus svcSemaphoreDelete (osSemaphoreId semaphore_id) {
+ OS_ID sem;
+
+ sem = rt_id2obj(semaphore_id);
+ if (sem == NULL) return osErrorParameter;
+
+ if (((P_SCB)sem)->cb_type != SCB) return osErrorParameter;
+
+ rt_sem_delete(sem); // Delete Semaphore
+
+ return osOK;
+}
+
+
+// Semaphore ISR Calls
+
+/// Release a Semaphore
+static __INLINE osStatus isrSemaphoreRelease (osSemaphoreId semaphore_id) {
+ OS_ID sem;
+
+ sem = rt_id2obj(semaphore_id);
+ if (sem == NULL) return osErrorParameter;
+
+ if (((P_SCB)sem)->cb_type != SCB) return osErrorParameter;
+
+ if (((P_SCB)sem)->tokens == osFeature_Semaphore) return osErrorResource;
+
+ isr_sem_send(sem); // Release Semaphore
+
+ return osOK;
+}
+
+
+// Semaphore Public API
+
+/// Create and Initialize a Semaphore object
+osSemaphoreId osSemaphoreCreate (osSemaphoreDef_t *semaphore_def, int32_t count) {
+ if (__get_IPSR() != 0) return NULL; // Not allowed in ISR
+ if (((__get_CONTROL() & 1) == 0) && (os_running == 0)) {
+ // Privileged and not running
+ return svcSemaphoreCreate(semaphore_def, count);
+ } else {
+ return __svcSemaphoreCreate(semaphore_def, count);
+ }
+}
+
+/// Wait until a Semaphore becomes available
+int32_t osSemaphoreWait (osSemaphoreId semaphore_id, uint32_t millisec) {
+ if (__get_IPSR() != 0) return -1; // Not allowed in ISR
+ return __svcSemaphoreWait(semaphore_id, millisec);
+}
+
+/// Release a Semaphore
+osStatus osSemaphoreRelease (osSemaphoreId semaphore_id) {
+ if (__get_IPSR() != 0) { // in ISR
+ return isrSemaphoreRelease(semaphore_id);
+ } else { // in Thread
+ return __svcSemaphoreRelease(semaphore_id);
+ }
+}
+
+/// Delete a Semaphore that was created by osSemaphoreCreate
+osStatus osSemaphoreDelete (osSemaphoreId semaphore_id) {
+ if (__get_IPSR() != 0) return osErrorISR; // Not allowed in ISR
+ return __svcSemaphoreDelete(semaphore_id);
+}
+
+
+// ==== Memory Management Functions ====
+
+// Memory Management Helper Functions
+
+// Clear Memory Box (Zero init)
+static void rt_clr_box (void *box_mem, void *box) {
+ uint32_t *p, n;
+
+ if (box) {
+ p = box;
+ for (n = ((P_BM)box_mem)->blk_size; n; n -= 4) {
+ *p++ = 0;
+ }
+ }
+}
+
+// Memory Management Service Calls declarations
+SVC_1_1(svcPoolCreate, osPoolId, const osPoolDef_t *, RET_pointer)
+SVC_2_1(sysPoolAlloc, void *, osPoolId, uint32_t, RET_pointer)
+SVC_2_1(sysPoolFree, osStatus, osPoolId, void *, RET_osStatus)
+
+// Memory Management Service & ISR Calls
+
+/// Create and Initialize memory pool
+osPoolId svcPoolCreate (const osPoolDef_t *pool_def) {
+ uint32_t blk_sz;
+
+ if ((pool_def == NULL) ||
+ (pool_def->pool_sz == 0) ||
+ (pool_def->item_sz == 0) ||
+ (pool_def->pool == NULL)) {
+ sysThreadError(osErrorParameter);
+ return NULL;
+ }
+
+ blk_sz = (pool_def->item_sz + 3) & ~3;
+
+ _init_box(pool_def->pool, sizeof(struct OS_BM) + pool_def->pool_sz * blk_sz, blk_sz);
+
+ return pool_def->pool;
+}
+
+/// Allocate a memory block from a memory pool
+void *sysPoolAlloc (osPoolId pool_id, uint32_t clr) {
+ void *ptr;
+
+ if (pool_id == NULL) return NULL;
+
+ ptr = rt_alloc_box(pool_id);
+ if (clr) {
+ rt_clr_box(pool_id, ptr);
+ }
+
+ return ptr;
+}
+
+/// Return an allocated memory block back to a specific memory pool
+osStatus sysPoolFree (osPoolId pool_id, void *block) {
+ int32_t res;
+
+ if (pool_id == NULL) return osErrorParameter;
+
+ res = rt_free_box(pool_id, block);
+ if (res != 0) return osErrorValue;
+
+ return osOK;
+}
+
+
+// Memory Management Public API
+
+/// Create and Initialize memory pool
+osPoolId osPoolCreate (osPoolDef_t *pool_def) {
+ if (__get_IPSR() != 0) return NULL; // Not allowed in ISR
+ if (((__get_CONTROL() & 1) == 0) && (os_running == 0)) {
+ // Privileged and not running
+ return svcPoolCreate(pool_def);
+ } else {
+ return __svcPoolCreate(pool_def);
+ }
+}
+
+/// Allocate a memory block from a memory pool
+void *osPoolAlloc (osPoolId pool_id) {
+ if ((__get_IPSR() != 0) || ((__get_CONTROL() & 1) == 0)) { // in ISR or Privileged
+ return sysPoolAlloc(pool_id, 0);
+ } else { // in Thread
+ return __sysPoolAlloc(pool_id, 0);
+ }
+}
+
+/// Allocate a memory block from a memory pool and set memory block to zero
+void *osPoolCAlloc (osPoolId pool_id) {
+ if ((__get_IPSR() != 0) || ((__get_CONTROL() & 1) == 0)) { // in ISR or Privileged
+ return sysPoolAlloc(pool_id, 1);
+ } else { // in Thread
+ return __sysPoolAlloc(pool_id, 1);
+ }
+}
+
+/// Return an allocated memory block back to a specific memory pool
+osStatus osPoolFree (osPoolId pool_id, void *block) {
+ if ((__get_IPSR() != 0) || ((__get_CONTROL() & 1) == 0)) { // in ISR or Privileged
+ return sysPoolFree(pool_id, block);
+ } else { // in Thread
+ return __sysPoolFree(pool_id, block);
+ }
+}
+
+
+// ==== Message Queue Management Functions ====
+
+// Message Queue Management Service Calls declarations
+SVC_2_1(svcMessageCreate, osMessageQId, osMessageQDef_t *, osThreadId, RET_pointer)
+SVC_3_1(svcMessagePut, osStatus, osMessageQId, uint32_t, uint32_t, RET_osStatus)
+SVC_2_3(svcMessageGet, os_InRegs osEvent, osMessageQId, uint32_t, RET_osEvent)
+
+// Message Queue Service Calls
+
+/// Create and Initialize Message Queue
+osMessageQId svcMessageCreate (osMessageQDef_t *queue_def, osThreadId thread_id) {
+
+ if ((queue_def == NULL) ||
+ (queue_def->queue_sz == 0) ||
+ (queue_def->pool == NULL)) {
+ sysThreadError(osErrorParameter);
+ return NULL;
+ }
+
+ if (((P_MCB)queue_def->pool)->cb_type != 0) {
+ sysThreadError(osErrorParameter);
+ return NULL;
+ }
+
+ rt_mbx_init(queue_def->pool, 4*(queue_def->queue_sz + 4));
+
+ return queue_def->pool;
+}
+
+/// Put a Message to a Queue
+osStatus svcMessagePut (osMessageQId queue_id, uint32_t info, uint32_t millisec) {
+ OS_RESULT res;
+
+ if (queue_id == NULL) return osErrorParameter;
+
+ if (((P_MCB)queue_id)->cb_type != MCB) return osErrorParameter;
+
+ res = rt_mbx_send(queue_id, (void *)info, rt_ms2tick(millisec));
+
+ if (res == OS_R_TMO) {
+ return (millisec ? osErrorTimeoutResource : osErrorResource);
+ }
+
+ return osOK;
+}
+
+/// Get a Message or Wait for a Message from a Queue
+os_InRegs osEvent_type svcMessageGet (osMessageQId queue_id, uint32_t millisec) {
+ OS_RESULT res;
+ osEvent ret;
+
+ if (queue_id == NULL) {
+ ret.status = osErrorParameter;
+ return osEvent_ret_status;
+ }
+
+ if (((P_MCB)queue_id)->cb_type != MCB) {
+ ret.status = osErrorParameter;
+ return osEvent_ret_status;
+ }
+
+ res = rt_mbx_wait(queue_id, &ret.value.p, rt_ms2tick(millisec));
+
+ if (res == OS_R_TMO) {
+ ret.status = millisec ? osEventTimeout : osOK;
+ return osEvent_ret_value;
+ }
+
+ ret.status = osEventMessage;
+
+ return osEvent_ret_value;
+}
+
+
+// Message Queue ISR Calls
+
+/// Put a Message to a Queue
+static __INLINE osStatus isrMessagePut (osMessageQId queue_id, uint32_t info, uint32_t millisec) {
+
+ if ((queue_id == NULL) || (millisec != 0)) {
+ return osErrorParameter;
+ }
+
+ if (((P_MCB)queue_id)->cb_type != MCB) return osErrorParameter;
+
+ if (rt_mbx_check(queue_id) == 0) { // Check if Queue is full
+ return osErrorResource;
+ }
+
+ isr_mbx_send(queue_id, (void *)info);
+
+ return osOK;
+}
+
+/// Get a Message or Wait for a Message from a Queue
+static __INLINE os_InRegs osEvent isrMessageGet (osMessageQId queue_id, uint32_t millisec) {
+ OS_RESULT res;
+ osEvent ret;
+
+ if ((queue_id == NULL) || (millisec != 0)) {
+ ret.status = osErrorParameter;
+ return ret;
+ }
+
+ if (((P_MCB)queue_id)->cb_type != MCB) {
+ ret.status = osErrorParameter;
+ return ret;
+ }
+
+ res = isr_mbx_receive(queue_id, &ret.value.p);
+
+ if (res != OS_R_MBX) {
+ ret.status = osOK;
+ return ret;
+ }
+
+ ret.status = osEventMessage;
+
+ return ret;
+}
+
+
+// Message Queue Management Public API
+
+/// Create and Initialize Message Queue
+osMessageQId osMessageCreate (osMessageQDef_t *queue_def, osThreadId thread_id) {
+ if (__get_IPSR() != 0) return NULL; // Not allowed in ISR
+ if (((__get_CONTROL() & 1) == 0) && (os_running == 0)) {
+ // Privileged and not running
+ return svcMessageCreate(queue_def, thread_id);
+ } else {
+ return __svcMessageCreate(queue_def, thread_id);
+ }
+}
+
+/// Put a Message to a Queue
+osStatus osMessagePut (osMessageQId queue_id, uint32_t info, uint32_t millisec) {
+ if (__get_IPSR() != 0) { // in ISR
+ return isrMessagePut(queue_id, info, millisec);
+ } else { // in Thread
+ return __svcMessagePut(queue_id, info, millisec);
+ }
+}
+
+/// Get a Message or Wait for a Message from a Queue
+os_InRegs osEvent osMessageGet (osMessageQId queue_id, uint32_t millisec) {
+ if (__get_IPSR() != 0) { // in ISR
+ return isrMessageGet(queue_id, millisec);
+ } else { // in Thread
+ return __svcMessageGet(queue_id, millisec);
+ }
+}
+
+
+// ==== Mail Queue Management Functions ====
+
+// Mail Queue Management Service Calls declarations
+SVC_2_1(svcMailCreate, osMailQId, osMailQDef_t *, osThreadId, RET_pointer)
+SVC_4_1(sysMailAlloc, void *, osMailQId, uint32_t, uint32_t, uint32_t, RET_pointer)
+SVC_3_1(sysMailFree, osStatus, osMailQId, void *, uint32_t, RET_osStatus)
+
+// Mail Queue Management Service & ISR Calls
+
+/// Create and Initialize mail queue
+osMailQId svcMailCreate (osMailQDef_t *queue_def, osThreadId thread_id) {
+ uint32_t blk_sz;
+ P_MCB pmcb;
+ void *pool;
+
+ if ((queue_def == NULL) ||
+ (queue_def->queue_sz == 0) ||
+ (queue_def->item_sz == 0) ||
+ (queue_def->pool == NULL)) {
+ sysThreadError(osErrorParameter);
+ return NULL;
+ }
+
+ pmcb = *(((void **)queue_def->pool) + 0);
+ pool = *(((void **)queue_def->pool) + 1);
+
+ if ((pool == NULL) || (pmcb == NULL) || (pmcb->cb_type != 0)) {
+ sysThreadError(osErrorParameter);
+ return NULL;
+ }
+
+ blk_sz = (queue_def->item_sz + 3) & ~3;
+
+ _init_box(pool, sizeof(struct OS_BM) + queue_def->queue_sz * blk_sz, blk_sz);
+
+ rt_mbx_init(pmcb, 4*(queue_def->queue_sz + 4));
+
+
+ return queue_def->pool;
+}
+
+/// Allocate a memory block from a mail
+void *sysMailAlloc (osMailQId queue_id, uint32_t millisec, uint32_t isr, uint32_t clr) {
+ P_MCB pmcb;
+ void *pool;
+ void *mem;
+
+ if (queue_id == NULL) return NULL;
+
+ pmcb = *(((void **)queue_id) + 0);
+ pool = *(((void **)queue_id) + 1);
+
+ if ((pool == NULL) || (pmcb == NULL)) return NULL;
+
+ if (isr && (millisec != 0)) return NULL;
+
+ mem = rt_alloc_box(pool);
+ if (clr) {
+ rt_clr_box(pool, mem);
+ }
+
+ if ((mem == NULL) && (millisec != 0)) {
+ // Put Task to sleep when Memory not available
+ if (pmcb->p_lnk != NULL) {
+ rt_put_prio((P_XCB)pmcb, os_tsk.run);
+ } else {
+ pmcb->p_lnk = os_tsk.run;
+ os_tsk.run->p_lnk = NULL;
+ os_tsk.run->p_rlnk = (P_TCB)pmcb;
+ // Task is waiting to allocate a message
+ pmcb->state = 3;
+ }
+ rt_block(rt_ms2tick(millisec), WAIT_MBX);
+ }
+
+ return mem;
+}
+
+/// Free a memory block from a mail
+osStatus sysMailFree (osMailQId queue_id, void *mail, uint32_t isr) {
+ P_MCB pmcb;
+ P_TCB ptcb;
+ void *pool;
+ void *mem;
+ int32_t res;
+
+ if (queue_id == NULL) return osErrorParameter;
+
+ pmcb = *(((void **)queue_id) + 0);
+ pool = *(((void **)queue_id) + 1);
+
+ if ((pmcb == NULL) || (pool == NULL)) return osErrorParameter;
+
+ res = rt_free_box(pool, mail);
+
+ if (res != 0) return osErrorValue;
+
+ if (pmcb->state == 3) {
+ // Task is waiting to allocate a message
+ if (isr) {
+ rt_psq_enq (pmcb, (U32)pool);
+ rt_psh_req ();
+ } else {
+ mem = rt_alloc_box(pool);
+ if (mem != NULL) {
+ ptcb = rt_get_first((P_XCB)pmcb);
+ if (pmcb->p_lnk == NULL) {
+ pmcb->state = 0;
+ }
+ rt_ret_val(ptcb, (U32)mem);
+ rt_rmv_dly(ptcb);
+ rt_dispatch(ptcb);
+ }
+ }
+ }
+
+ return osOK;
+}
+
+
+// Mail Queue Management Public API
+
+/// Create and Initialize mail queue
+osMailQId osMailCreate (osMailQDef_t *queue_def, osThreadId thread_id) {
+ if (__get_IPSR() != 0) return NULL; // Not allowed in ISR
+ if (((__get_CONTROL() & 1) == 0) && (os_running == 0)) {
+ // Privileged and not running
+ return svcMailCreate(queue_def, thread_id);
+ } else {
+ return __svcMailCreate(queue_def, thread_id);
+ }
+}
+
+/// Allocate a memory block from a mail
+void *osMailAlloc (osMailQId queue_id, uint32_t millisec) {
+ if (__get_IPSR() != 0) { // in ISR
+ return sysMailAlloc(queue_id, millisec, 1, 0);
+ } else { // in Thread
+ return __sysMailAlloc(queue_id, millisec, 0, 0);
+ }
+}
+
+/// Allocate a memory block from a mail and set memory block to zero
+void *osMailCAlloc (osMailQId queue_id, uint32_t millisec) {
+ if (__get_IPSR() != 0) { // in ISR
+ return sysMailAlloc(queue_id, millisec, 1, 1);
+ } else { // in Thread
+ return __sysMailAlloc(queue_id, millisec, 0, 1);
+ }
+}
+
+/// Free a memory block from a mail
+osStatus osMailFree (osMailQId queue_id, void *mail) {
+ if (__get_IPSR() != 0) { // in ISR
+ return sysMailFree(queue_id, mail, 1);
+ } else { // in Thread
+ return __sysMailFree(queue_id, mail, 0);
+ }
+}
+
+/// Put a mail to a queue
+osStatus osMailPut (osMailQId queue_id, void *mail) {
+ if (queue_id == NULL) return osErrorParameter;
+ if (mail == NULL) return osErrorValue;
+ return osMessagePut(*((void **)queue_id), (uint32_t)mail, 0);
+}
+
+/// Get a mail from a queue
+os_InRegs osEvent osMailGet (osMailQId queue_id, uint32_t millisec) {
+ osEvent ret;
+
+ if (queue_id == NULL) {
+ ret.status = osErrorParameter;
+ return ret;
+ }
+
+ ret = osMessageGet(*((void **)queue_id), millisec);
+ if (ret.status == osEventMessage) ret.status = osEventMail;
+
+ return ret;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/TARGET_CORTEX_M/rt_Event.c Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,190 @@
+/*----------------------------------------------------------------------------
+ * RL-ARM - RTX
+ *----------------------------------------------------------------------------
+ * Name: RT_EVENT.C
+ * Purpose: Implements waits and wake-ups for event flags
+ * Rev.: V4.60
+ *----------------------------------------------------------------------------
+ *
+ * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *---------------------------------------------------------------------------*/
+
+#include "rt_TypeDef.h"
+#include "RTX_Conf.h"
+#include "rt_System.h"
+#include "rt_Event.h"
+#include "rt_List.h"
+#include "rt_Task.h"
+#include "rt_HAL_CM.h"
+
+
+/*----------------------------------------------------------------------------
+ * Functions
+ *---------------------------------------------------------------------------*/
+
+
+/*--------------------------- rt_evt_wait -----------------------------------*/
+
+OS_RESULT rt_evt_wait (U16 wait_flags, U16 timeout, BOOL and_wait) {
+ /* Wait for one or more event flags with optional time-out. */
+ /* "wait_flags" identifies the flags to wait for. */
+ /* "timeout" is the time-out limit in system ticks (0xffff if no time-out) */
+ /* "and_wait" specifies the AND-ing of "wait_flags" as condition to be met */
+ /* to complete the wait. (OR-ing if set to 0). */
+ U32 block_state;
+
+ if (and_wait) {
+ /* Check for AND-connected events */
+ if ((os_tsk.run->events & wait_flags) == wait_flags) {
+ os_tsk.run->events &= ~wait_flags;
+ return (OS_R_EVT);
+ }
+ block_state = WAIT_AND;
+ }
+ else {
+ /* Check for OR-connected events */
+ if (os_tsk.run->events & wait_flags) {
+ os_tsk.run->waits = os_tsk.run->events & wait_flags;
+ os_tsk.run->events &= ~wait_flags;
+ return (OS_R_EVT);
+ }
+ block_state = WAIT_OR;
+ }
+ /* Task has to wait */
+ os_tsk.run->waits = wait_flags;
+ rt_block (timeout, (U8)block_state);
+ return (OS_R_TMO);
+}
+
+
+/*--------------------------- rt_evt_set ------------------------------------*/
+
+void rt_evt_set (U16 event_flags, OS_TID task_id) {
+ /* Set one or more event flags of a selectable task. */
+ P_TCB p_tcb;
+
+ p_tcb = os_active_TCB[task_id-1];
+ if (p_tcb == NULL) {
+ return;
+ }
+ p_tcb->events |= event_flags;
+ event_flags = p_tcb->waits;
+ /* If the task is not waiting for an event, it should not be put */
+ /* to ready state. */
+ if (p_tcb->state == WAIT_AND) {
+ /* Check for AND-connected events */
+ if ((p_tcb->events & event_flags) == event_flags) {
+ goto wkup;
+ }
+ }
+ if (p_tcb->state == WAIT_OR) {
+ /* Check for OR-connected events */
+ if (p_tcb->events & event_flags) {
+ p_tcb->waits &= p_tcb->events;
+wkup: p_tcb->events &= ~event_flags;
+ rt_rmv_dly (p_tcb);
+ p_tcb->state = READY;
+#ifdef __CMSIS_RTOS
+ rt_ret_val2(p_tcb, 0x08/*osEventSignal*/, p_tcb->waits);
+#else
+ rt_ret_val (p_tcb, OS_R_EVT);
+#endif
+ rt_dispatch (p_tcb);
+ }
+ }
+}
+
+
+/*--------------------------- rt_evt_clr ------------------------------------*/
+
+void rt_evt_clr (U16 clear_flags, OS_TID task_id) {
+ /* Clear one or more event flags (identified by "clear_flags") of a */
+ /* selectable task (identified by "task"). */
+ P_TCB task = os_active_TCB[task_id-1];
+
+ if (task == NULL) {
+ return;
+ }
+ task->events &= ~clear_flags;
+}
+
+
+/*--------------------------- isr_evt_set -----------------------------------*/
+
+void isr_evt_set (U16 event_flags, OS_TID task_id) {
+ /* Same function as "os_evt_set", but to be called by ISRs. */
+ P_TCB p_tcb = os_active_TCB[task_id-1];
+
+ if (p_tcb == NULL) {
+ return;
+ }
+ rt_psq_enq (p_tcb, event_flags);
+ rt_psh_req ();
+}
+
+
+/*--------------------------- rt_evt_get ------------------------------------*/
+
+U16 rt_evt_get (void) {
+ /* Get events of a running task after waiting for OR connected events. */
+ return (os_tsk.run->waits);
+}
+
+
+/*--------------------------- rt_evt_psh ------------------------------------*/
+
+void rt_evt_psh (P_TCB p_CB, U16 set_flags) {
+ /* Check if task has to be waken up */
+ U16 event_flags;
+
+ p_CB->events |= set_flags;
+ event_flags = p_CB->waits;
+ if (p_CB->state == WAIT_AND) {
+ /* Check for AND-connected events */
+ if ((p_CB->events & event_flags) == event_flags) {
+ goto rdy;
+ }
+ }
+ if (p_CB->state == WAIT_OR) {
+ /* Check for OR-connected events */
+ if (p_CB->events & event_flags) {
+ p_CB->waits &= p_CB->events;
+rdy: p_CB->events &= ~event_flags;
+ rt_rmv_dly (p_CB);
+ p_CB->state = READY;
+#ifdef __CMSIS_RTOS
+ rt_ret_val2(p_CB, 0x08/*osEventSignal*/, p_CB->waits);
+#else
+ rt_ret_val (p_CB, OS_R_EVT);
+#endif
+ rt_put_prio (&os_rdy, p_CB);
+ }
+ }
+}
+
+/*----------------------------------------------------------------------------
+ * end of file
+ *---------------------------------------------------------------------------*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/mbed-rtos/rtx/TARGET_CORTEX_M/rt_Event.h Wed Apr 15 06:23:18 2015 +0000 @@ -0,0 +1,46 @@ +/*---------------------------------------------------------------------------- + * RL-ARM - RTX + *---------------------------------------------------------------------------- + * Name: RT_EVENT.H + * Purpose: Implements waits and wake-ups for event flags + * Rev.: V4.60 + *---------------------------------------------------------------------------- + * + * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH + * All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + *---------------------------------------------------------------------------*/ + +/* Functions */ +extern OS_RESULT rt_evt_wait (U16 wait_flags, U16 timeout, BOOL and_wait); +extern void rt_evt_set (U16 event_flags, OS_TID task_id); +extern void rt_evt_clr (U16 clear_flags, OS_TID task_id); +extern void isr_evt_set (U16 event_flags, OS_TID task_id); +extern U16 rt_evt_get (void); +extern void rt_evt_psh (P_TCB p_CB, U16 set_flags); + +/*---------------------------------------------------------------------------- + * end of file + *---------------------------------------------------------------------------*/ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/TARGET_CORTEX_M/rt_HAL_CM.h Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,276 @@
+/*----------------------------------------------------------------------------
+ * RL-ARM - RTX
+ *----------------------------------------------------------------------------
+ * Name: RT_HAL_CM.H
+ * Purpose: Hardware Abstraction Layer for Cortex-M definitions
+ * Rev.: V4.60
+ *----------------------------------------------------------------------------
+ *
+ * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *---------------------------------------------------------------------------*/
+
+/* Definitions */
+#define INITIAL_xPSR 0x01000000
+#define DEMCR_TRCENA 0x01000000
+#define ITM_ITMENA 0x00000001
+#define MAGIC_WORD 0xE25A2EA5
+
+#if defined (__CC_ARM) /* ARM Compiler */
+
+#if ((__TARGET_ARCH_7_M || __TARGET_ARCH_7E_M) && !NO_EXCLUSIVE_ACCESS)
+ #define __USE_EXCLUSIVE_ACCESS
+#else
+ #undef __USE_EXCLUSIVE_ACCESS
+#endif
+
+#elif defined (__GNUC__) /* GNU Compiler */
+
+#undef __USE_EXCLUSIVE_ACCESS
+
+#if defined (__CORTEX_M0) || defined (__CORTEX_M0PLUS)
+#define __TARGET_ARCH_6S_M 1
+#else
+#define __TARGET_ARCH_6S_M 0
+#endif
+
+#if defined (__VFP_FP__) && !defined(__SOFTFP__)
+#define __TARGET_FPU_VFP 1
+#else
+#define __TARGET_FPU_VFP 0
+#endif
+
+#define __inline inline
+#define __weak __attribute__((weak))
+
+#ifndef __CMSIS_GENERIC
+
+__attribute__((always_inline)) static inline void __enable_irq(void)
+{
+ __asm volatile ("cpsie i");
+}
+
+__attribute__((always_inline)) static inline U32 __disable_irq(void)
+{
+ U32 result;
+
+ __asm volatile ("mrs %0, primask" : "=r" (result));
+ __asm volatile ("cpsid i");
+ return(result & 1);
+}
+
+#endif
+
+__attribute__(( always_inline)) static inline U8 __clz(U32 value)
+{
+ U8 result;
+
+ __asm volatile ("clz %0, %1" : "=r" (result) : "r" (value));
+ return(result);
+}
+
+#elif defined (__ICCARM__) /* IAR Compiler */
+
+#undef __USE_EXCLUSIVE_ACCESS
+
+#if (__CORE__ == __ARM6M__)
+#define __TARGET_ARCH_6S_M 1
+#else
+#define __TARGET_ARCH_6S_M 0
+#endif
+
+#if defined __ARMVFP__
+#define __TARGET_FPU_VFP 1
+#else
+#define __TARGET_FPU_VFP 0
+#endif
+
+#define __inline inline
+
+#ifndef __CMSIS_GENERIC
+
+static inline void __enable_irq(void)
+{
+ __asm volatile ("cpsie i");
+}
+
+static inline U32 __disable_irq(void)
+{
+ U32 result;
+
+ __asm volatile ("mrs %0, primask" : "=r" (result));
+ __asm volatile ("cpsid i");
+ return(result & 1);
+}
+
+#endif
+
+static inline U8 __clz(U32 value)
+{
+ U8 result;
+
+ __asm volatile ("clz %0, %1" : "=r" (result) : "r" (value));
+ return(result);
+}
+
+#endif
+
+/* NVIC registers */
+#define NVIC_ST_CTRL (*((volatile U32 *)0xE000E010))
+#define NVIC_ST_RELOAD (*((volatile U32 *)0xE000E014))
+#define NVIC_ST_CURRENT (*((volatile U32 *)0xE000E018))
+#define NVIC_ISER ((volatile U32 *)0xE000E100)
+#define NVIC_ICER ((volatile U32 *)0xE000E180)
+#if (__TARGET_ARCH_6S_M)
+#define NVIC_IP ((volatile U32 *)0xE000E400)
+#else
+#define NVIC_IP ((volatile U8 *)0xE000E400)
+#endif
+#define NVIC_INT_CTRL (*((volatile U32 *)0xE000ED04))
+#define NVIC_AIR_CTRL (*((volatile U32 *)0xE000ED0C))
+#define NVIC_SYS_PRI2 (*((volatile U32 *)0xE000ED1C))
+#define NVIC_SYS_PRI3 (*((volatile U32 *)0xE000ED20))
+
+#define OS_PEND_IRQ() NVIC_INT_CTRL = (1<<28)
+#define OS_PENDING ((NVIC_INT_CTRL >> 26) & (1<<2 | 1))
+#define OS_UNPEND(fl) NVIC_INT_CTRL = (*fl = OS_PENDING) << 25
+#define OS_PEND(fl,p) NVIC_INT_CTRL = (fl | p<<2) << 26
+#define OS_LOCK() NVIC_ST_CTRL = 0x0005
+#define OS_UNLOCK() NVIC_ST_CTRL = 0x0007
+
+#define OS_X_PENDING ((NVIC_INT_CTRL >> 28) & 1)
+#define OS_X_UNPEND(fl) NVIC_INT_CTRL = (*fl = OS_X_PENDING) << 27
+#define OS_X_PEND(fl,p) NVIC_INT_CTRL = (fl | p) << 28
+#if (__TARGET_ARCH_6S_M)
+#define OS_X_INIT(n) NVIC_IP[n>>2] |= 0xFF << (8*(n & 0x03)); \
+ NVIC_ISER[n>>5] = 1 << (n & 0x1F)
+#else
+#define OS_X_INIT(n) NVIC_IP[n] = 0xFF; \
+ NVIC_ISER[n>>5] = 1 << (n & 0x1F)
+#endif
+#define OS_X_LOCK(n) NVIC_ICER[n>>5] = 1 << (n & 0x1F)
+#define OS_X_UNLOCK(n) NVIC_ISER[n>>5] = 1 << (n & 0x1F)
+
+/* Core Debug registers */
+#define DEMCR (*((volatile U32 *)0xE000EDFC))
+
+/* ITM registers */
+#define ITM_CONTROL (*((volatile U32 *)0xE0000E80))
+#define ITM_ENABLE (*((volatile U32 *)0xE0000E00))
+#define ITM_PORT30_U32 (*((volatile U32 *)0xE0000078))
+#define ITM_PORT31_U32 (*((volatile U32 *)0xE000007C))
+#define ITM_PORT31_U16 (*((volatile U16 *)0xE000007C))
+#define ITM_PORT31_U8 (*((volatile U8 *)0xE000007C))
+
+/* Variables */
+extern BIT dbg_msg;
+
+/* Functions */
+#ifdef __USE_EXCLUSIVE_ACCESS
+ #define rt_inc(p) while(__strex((__ldrex(p)+1),p))
+ #define rt_dec(p) while(__strex((__ldrex(p)-1),p))
+#else
+ #define rt_inc(p) __disable_irq();(*p)++;__enable_irq();
+ #define rt_dec(p) __disable_irq();(*p)--;__enable_irq();
+#endif
+
+__inline static U32 rt_inc_qi (U32 size, U8 *count, U8 *first) {
+ U32 cnt,c2;
+#ifdef __USE_EXCLUSIVE_ACCESS
+ do {
+ if ((cnt = __ldrex(count)) == size) {
+ __clrex();
+ return (cnt); }
+ } while (__strex(cnt+1, count));
+ do {
+ c2 = (cnt = __ldrex(first)) + 1;
+ if (c2 == size) c2 = 0;
+ } while (__strex(c2, first));
+#else
+ __disable_irq();
+ if ((cnt = *count) < size) {
+ *count = cnt+1;
+ c2 = (cnt = *first) + 1;
+ if (c2 == size) c2 = 0;
+ *first = c2;
+ }
+ __enable_irq ();
+#endif
+ return (cnt);
+}
+
+__inline static void rt_systick_init (void) {
+ NVIC_ST_RELOAD = os_trv;
+ NVIC_ST_CURRENT = 0;
+ NVIC_ST_CTRL = 0x0007;
+ NVIC_SYS_PRI3 |= 0xFF000000;
+}
+
+__inline static void rt_svc_init (void) {
+#if !(__TARGET_ARCH_6S_M)
+ int sh,prigroup;
+#endif
+ NVIC_SYS_PRI3 |= 0x00FF0000;
+#if (__TARGET_ARCH_6S_M)
+ NVIC_SYS_PRI2 |= (NVIC_SYS_PRI3<<(8+1)) & 0xFC000000;
+#else
+ sh = 8 - __clz (~((NVIC_SYS_PRI3 << 8) & 0xFF000000));
+ prigroup = ((NVIC_AIR_CTRL >> 8) & 0x07);
+ if (prigroup >= sh) {
+ sh = prigroup + 1;
+ }
+ NVIC_SYS_PRI2 = ((0xFEFFFFFF << sh) & 0xFF000000) | (NVIC_SYS_PRI2 & 0x00FFFFFF);
+#endif
+}
+
+extern void rt_set_PSP (U32 stack);
+extern U32 rt_get_PSP (void);
+extern void os_set_env (void);
+extern void *_alloc_box (void *box_mem);
+extern int _free_box (void *box_mem, void *box);
+
+extern void rt_init_stack (P_TCB p_TCB, FUNCP task_body);
+extern void rt_ret_val (P_TCB p_TCB, U32 v0);
+extern void rt_ret_val2 (P_TCB p_TCB, U32 v0, U32 v1);
+
+extern void dbg_init (void);
+extern void dbg_task_notify (P_TCB p_tcb, BOOL create);
+extern void dbg_task_switch (U32 task_id);
+
+#ifdef DBG_MSG
+#define DBG_INIT() dbg_init()
+#define DBG_TASK_NOTIFY(p_tcb,create) if (dbg_msg) dbg_task_notify(p_tcb,create)
+#define DBG_TASK_SWITCH(task_id) if (dbg_msg && (os_tsk.new_tsk != os_tsk.run)) \
+ dbg_task_switch(task_id)
+#else
+#define DBG_INIT()
+#define DBG_TASK_NOTIFY(p_tcb,create)
+#define DBG_TASK_SWITCH(task_id)
+#endif
+
+/*----------------------------------------------------------------------------
+ * end of file
+ *---------------------------------------------------------------------------*/
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/TARGET_CORTEX_M/rt_List.c Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,320 @@
+/*----------------------------------------------------------------------------
+ * RL-ARM - RTX
+ *----------------------------------------------------------------------------
+ * Name: RT_LIST.C
+ * Purpose: Functions for the management of different lists
+ * Rev.: V4.60
+ *----------------------------------------------------------------------------
+ *
+ * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *---------------------------------------------------------------------------*/
+
+#include "rt_TypeDef.h"
+#include "RTX_Conf.h"
+#include "rt_System.h"
+#include "rt_List.h"
+#include "rt_Task.h"
+#include "rt_Time.h"
+#include "rt_HAL_CM.h"
+
+/*----------------------------------------------------------------------------
+ * Global Variables
+ *---------------------------------------------------------------------------*/
+
+/* List head of chained ready tasks */
+struct OS_XCB os_rdy;
+/* List head of chained delay tasks */
+struct OS_XCB os_dly;
+
+
+/*----------------------------------------------------------------------------
+ * Functions
+ *---------------------------------------------------------------------------*/
+
+
+/*--------------------------- rt_put_prio -----------------------------------*/
+
+void rt_put_prio (P_XCB p_CB, P_TCB p_task) {
+ /* Put task identified with "p_task" into list ordered by priority. */
+ /* "p_CB" points to head of list; list has always an element at end with */
+ /* a priority less than "p_task->prio". */
+ P_TCB p_CB2;
+ U32 prio;
+ BOOL sem_mbx = __FALSE;
+
+ if (p_CB->cb_type == SCB || p_CB->cb_type == MCB || p_CB->cb_type == MUCB) {
+ sem_mbx = __TRUE;
+ }
+ prio = p_task->prio;
+ p_CB2 = p_CB->p_lnk;
+ /* Search for an entry in the list */
+ while (p_CB2 != NULL && prio <= p_CB2->prio) {
+ p_CB = (P_XCB)p_CB2;
+ p_CB2 = p_CB2->p_lnk;
+ }
+ /* Entry found, insert the task into the list */
+ p_task->p_lnk = p_CB2;
+ p_CB->p_lnk = p_task;
+ if (sem_mbx) {
+ if (p_CB2 != NULL) {
+ p_CB2->p_rlnk = p_task;
+ }
+ p_task->p_rlnk = (P_TCB)p_CB;
+ }
+ else {
+ p_task->p_rlnk = NULL;
+ }
+}
+
+
+/*--------------------------- rt_get_first ----------------------------------*/
+
+P_TCB rt_get_first (P_XCB p_CB) {
+ /* Get task at head of list: it is the task with highest priority. */
+ /* "p_CB" points to head of list. */
+ P_TCB p_first;
+
+ p_first = p_CB->p_lnk;
+ p_CB->p_lnk = p_first->p_lnk;
+ if (p_CB->cb_type == SCB || p_CB->cb_type == MCB || p_CB->cb_type == MUCB) {
+ if (p_first->p_lnk != NULL) {
+ p_first->p_lnk->p_rlnk = (P_TCB)p_CB;
+ p_first->p_lnk = NULL;
+ }
+ p_first->p_rlnk = NULL;
+ }
+ else {
+ p_first->p_lnk = NULL;
+ }
+ return (p_first);
+}
+
+
+/*--------------------------- rt_put_rdy_first ------------------------------*/
+
+void rt_put_rdy_first (P_TCB p_task) {
+ /* Put task identified with "p_task" at the head of the ready list. The */
+ /* task must have at least a priority equal to highest priority in list. */
+ p_task->p_lnk = os_rdy.p_lnk;
+ p_task->p_rlnk = NULL;
+ os_rdy.p_lnk = p_task;
+}
+
+
+/*--------------------------- rt_get_same_rdy_prio --------------------------*/
+
+P_TCB rt_get_same_rdy_prio (void) {
+ /* Remove a task of same priority from ready list if any exists. Other- */
+ /* wise return NULL. */
+ P_TCB p_first;
+
+ p_first = os_rdy.p_lnk;
+ if (p_first->prio == os_tsk.run->prio) {
+ os_rdy.p_lnk = os_rdy.p_lnk->p_lnk;
+ return (p_first);
+ }
+ return (NULL);
+}
+
+
+/*--------------------------- rt_resort_prio --------------------------------*/
+
+void rt_resort_prio (P_TCB p_task) {
+ /* Re-sort ordered lists after the priority of 'p_task' has changed. */
+ P_TCB p_CB;
+
+ if (p_task->p_rlnk == NULL) {
+ if (p_task->state == READY) {
+ /* Task is chained into READY list. */
+ p_CB = (P_TCB)&os_rdy;
+ goto res;
+ }
+ }
+ else {
+ p_CB = p_task->p_rlnk;
+ while (p_CB->cb_type == TCB) {
+ /* Find a header of this task chain list. */
+ p_CB = p_CB->p_rlnk;
+ }
+res:rt_rmv_list (p_task);
+ rt_put_prio ((P_XCB)p_CB, p_task);
+ }
+}
+
+
+/*--------------------------- rt_put_dly ------------------------------------*/
+
+void rt_put_dly (P_TCB p_task, U16 delay) {
+ /* Put a task identified with "p_task" into chained delay wait list using */
+ /* a delay value of "delay". */
+ P_TCB p;
+ U32 delta,idelay = delay;
+
+ p = (P_TCB)&os_dly;
+ if (p->p_dlnk == NULL) {
+ /* Delay list empty */
+ delta = 0;
+ goto last;
+ }
+ delta = os_dly.delta_time;
+ while (delta < idelay) {
+ if (p->p_dlnk == NULL) {
+ /* End of list found */
+last: p_task->p_dlnk = NULL;
+ p->p_dlnk = p_task;
+ p_task->p_blnk = p;
+ p->delta_time = (U16)(idelay - delta);
+ p_task->delta_time = 0;
+ return;
+ }
+ p = p->p_dlnk;
+ delta += p->delta_time;
+ }
+ /* Right place found */
+ p_task->p_dlnk = p->p_dlnk;
+ p->p_dlnk = p_task;
+ p_task->p_blnk = p;
+ if (p_task->p_dlnk != NULL) {
+ p_task->p_dlnk->p_blnk = p_task;
+ }
+ p_task->delta_time = (U16)(delta - idelay);
+ p->delta_time -= p_task->delta_time;
+}
+
+
+/*--------------------------- rt_dec_dly ------------------------------------*/
+
+void rt_dec_dly (void) {
+ /* Decrement delta time of list head: remove tasks having a value of zero.*/
+ P_TCB p_rdy;
+
+ if (os_dly.p_dlnk == NULL) {
+ return;
+ }
+ os_dly.delta_time--;
+ while ((os_dly.delta_time == 0) && (os_dly.p_dlnk != NULL)) {
+ p_rdy = os_dly.p_dlnk;
+ if (p_rdy->p_rlnk != NULL) {
+ /* Task is really enqueued, remove task from semaphore/mailbox */
+ /* timeout waiting list. */
+ p_rdy->p_rlnk->p_lnk = p_rdy->p_lnk;
+ if (p_rdy->p_lnk != NULL) {
+ p_rdy->p_lnk->p_rlnk = p_rdy->p_rlnk;
+ p_rdy->p_lnk = NULL;
+ }
+ p_rdy->p_rlnk = NULL;
+ }
+ rt_put_prio (&os_rdy, p_rdy);
+ os_dly.delta_time = p_rdy->delta_time;
+ if (p_rdy->state == WAIT_ITV) {
+ /* Calculate the next time for interval wait. */
+ p_rdy->delta_time = p_rdy->interval_time + (U16)os_time;
+ }
+ p_rdy->state = READY;
+ os_dly.p_dlnk = p_rdy->p_dlnk;
+ if (p_rdy->p_dlnk != NULL) {
+ p_rdy->p_dlnk->p_blnk = (P_TCB)&os_dly;
+ p_rdy->p_dlnk = NULL;
+ }
+ p_rdy->p_blnk = NULL;
+ }
+}
+
+
+/*--------------------------- rt_rmv_list -----------------------------------*/
+
+void rt_rmv_list (P_TCB p_task) {
+ /* Remove task identified with "p_task" from ready, semaphore or mailbox */
+ /* waiting list if enqueued. */
+ P_TCB p_b;
+
+ if (p_task->p_rlnk != NULL) {
+ /* A task is enqueued in semaphore / mailbox waiting list. */
+ p_task->p_rlnk->p_lnk = p_task->p_lnk;
+ if (p_task->p_lnk != NULL) {
+ p_task->p_lnk->p_rlnk = p_task->p_rlnk;
+ }
+ return;
+ }
+
+ p_b = (P_TCB)&os_rdy;
+ while (p_b != NULL) {
+ /* Search the ready list for task "p_task" */
+ if (p_b->p_lnk == p_task) {
+ p_b->p_lnk = p_task->p_lnk;
+ return;
+ }
+ p_b = p_b->p_lnk;
+ }
+}
+
+
+/*--------------------------- rt_rmv_dly ------------------------------------*/
+
+void rt_rmv_dly (P_TCB p_task) {
+ /* Remove task identified with "p_task" from delay list if enqueued. */
+ P_TCB p_b;
+
+ p_b = p_task->p_blnk;
+ if (p_b != NULL) {
+ /* Task is really enqueued */
+ p_b->p_dlnk = p_task->p_dlnk;
+ if (p_task->p_dlnk != NULL) {
+ /* 'p_task' is in the middle of list */
+ p_b->delta_time += p_task->delta_time;
+ p_task->p_dlnk->p_blnk = p_b;
+ p_task->p_dlnk = NULL;
+ }
+ else {
+ /* 'p_task' is at the end of list */
+ p_b->delta_time = 0;
+ }
+ p_task->p_blnk = NULL;
+ }
+}
+
+
+/*--------------------------- rt_psq_enq ------------------------------------*/
+
+void rt_psq_enq (OS_ID entry, U32 arg) {
+ /* Insert post service request "entry" into ps-queue. */
+ U32 idx;
+
+ idx = rt_inc_qi (os_psq->size, &os_psq->count, &os_psq->first);
+ if (idx < os_psq->size) {
+ os_psq->q[idx].id = entry;
+ os_psq->q[idx].arg = arg;
+ }
+ else {
+ os_error (OS_ERR_FIFO_OVF);
+ }
+}
+
+
+/*----------------------------------------------------------------------------
+ * end of file
+ *---------------------------------------------------------------------------*/
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/mbed-rtos/rtx/TARGET_CORTEX_M/rt_List.h Wed Apr 15 06:23:18 2015 +0000 @@ -0,0 +1,67 @@ +/*---------------------------------------------------------------------------- + * RL-ARM - RTX + *---------------------------------------------------------------------------- + * Name: RT_LIST.H + * Purpose: Functions for the management of different lists + * Rev.: V4.60 + *---------------------------------------------------------------------------- + * + * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH + * All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + *---------------------------------------------------------------------------*/ + +/* Definitions */ + +/* Values for 'cb_type' */ +#define TCB 0 +#define MCB 1 +#define SCB 2 +#define MUCB 3 +#define HCB 4 + +/* Variables */ +extern struct OS_XCB os_rdy; +extern struct OS_XCB os_dly; + +/* Functions */ +extern void rt_put_prio (P_XCB p_CB, P_TCB p_task); +extern P_TCB rt_get_first (P_XCB p_CB); +extern void rt_put_rdy_first (P_TCB p_task); +extern P_TCB rt_get_same_rdy_prio (void); +extern void rt_resort_prio (P_TCB p_task); +extern void rt_put_dly (P_TCB p_task, U16 delay); +extern void rt_dec_dly (void); +extern void rt_rmv_list (P_TCB p_task); +extern void rt_rmv_dly (P_TCB p_task); +extern void rt_psq_enq (OS_ID entry, U32 arg); + +/* This is a fast macro generating in-line code */ +#define rt_rdy_prio(void) (os_rdy.p_lnk->prio) + + +/*---------------------------------------------------------------------------- + * end of file + *---------------------------------------------------------------------------*/ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/TARGET_CORTEX_M/rt_Mailbox.c Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,292 @@
+/*----------------------------------------------------------------------------
+ * RL-ARM - RTX
+ *----------------------------------------------------------------------------
+ * Name: RT_MAILBOX.C
+ * Purpose: Implements waits and wake-ups for mailbox messages
+ * Rev.: V4.60
+ *----------------------------------------------------------------------------
+ *
+ * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *---------------------------------------------------------------------------*/
+
+#include "rt_TypeDef.h"
+#include "RTX_Conf.h"
+#include "rt_System.h"
+#include "rt_List.h"
+#include "rt_Mailbox.h"
+#include "rt_MemBox.h"
+#include "rt_Task.h"
+#include "rt_HAL_CM.h"
+
+
+/*----------------------------------------------------------------------------
+ * Functions
+ *---------------------------------------------------------------------------*/
+
+
+/*--------------------------- rt_mbx_init -----------------------------------*/
+
+void rt_mbx_init (OS_ID mailbox, U16 mbx_size) {
+ /* Initialize a mailbox */
+ P_MCB p_MCB = mailbox;
+
+ p_MCB->cb_type = MCB;
+ p_MCB->state = 0;
+ p_MCB->isr_st = 0;
+ p_MCB->p_lnk = NULL;
+ p_MCB->first = 0;
+ p_MCB->last = 0;
+ p_MCB->count = 0;
+ p_MCB->size = (mbx_size + sizeof(void *) - sizeof(struct OS_MCB)) /
+ (U32)sizeof (void *);
+}
+
+
+/*--------------------------- rt_mbx_send -----------------------------------*/
+
+OS_RESULT rt_mbx_send (OS_ID mailbox, void *p_msg, U16 timeout) {
+ /* Send message to a mailbox */
+ P_MCB p_MCB = mailbox;
+ P_TCB p_TCB;
+
+ if ((p_MCB->p_lnk != NULL) && (p_MCB->state == 1)) {
+ /* A task is waiting for message */
+ p_TCB = rt_get_first ((P_XCB)p_MCB);
+#ifdef __CMSIS_RTOS
+ rt_ret_val2(p_TCB, 0x10/*osEventMessage*/, (U32)p_msg);
+#else
+ *p_TCB->msg = p_msg;
+ rt_ret_val (p_TCB, OS_R_MBX);
+#endif
+ rt_rmv_dly (p_TCB);
+ rt_dispatch (p_TCB);
+ }
+ else {
+ /* Store message in mailbox queue */
+ if (p_MCB->count == p_MCB->size) {
+ /* No free message entry, wait for one. If message queue is full, */
+ /* then no task is waiting for message. The 'p_MCB->p_lnk' list */
+ /* pointer can now be reused for send message waits task list. */
+ if (timeout == 0) {
+ return (OS_R_TMO);
+ }
+ if (p_MCB->p_lnk != NULL) {
+ rt_put_prio ((P_XCB)p_MCB, os_tsk.run);
+ }
+ else {
+ p_MCB->p_lnk = os_tsk.run;
+ os_tsk.run->p_lnk = NULL;
+ os_tsk.run->p_rlnk = (P_TCB)p_MCB;
+ /* Task is waiting to send a message */
+ p_MCB->state = 2;
+ }
+ os_tsk.run->msg = p_msg;
+ rt_block (timeout, WAIT_MBX);
+ return (OS_R_TMO);
+ }
+ /* Yes, there is a free entry in a mailbox. */
+ p_MCB->msg[p_MCB->first] = p_msg;
+ rt_inc (&p_MCB->count);
+ if (++p_MCB->first == p_MCB->size) {
+ p_MCB->first = 0;
+ }
+ }
+ return (OS_R_OK);
+}
+
+
+/*--------------------------- rt_mbx_wait -----------------------------------*/
+
+OS_RESULT rt_mbx_wait (OS_ID mailbox, void **message, U16 timeout) {
+ /* Receive a message; possibly wait for it */
+ P_MCB p_MCB = mailbox;
+ P_TCB p_TCB;
+
+ /* If a message is available in the fifo buffer */
+ /* remove it from the fifo buffer and return. */
+ if (p_MCB->count) {
+ *message = p_MCB->msg[p_MCB->last];
+ if (++p_MCB->last == p_MCB->size) {
+ p_MCB->last = 0;
+ }
+ if ((p_MCB->p_lnk != NULL) && (p_MCB->state == 2)) {
+ /* A task is waiting to send message */
+ p_TCB = rt_get_first ((P_XCB)p_MCB);
+#ifdef __CMSIS_RTOS
+ rt_ret_val(p_TCB, 0/*osOK*/);
+#else
+ rt_ret_val(p_TCB, OS_R_OK);
+#endif
+ p_MCB->msg[p_MCB->first] = p_TCB->msg;
+ if (++p_MCB->first == p_MCB->size) {
+ p_MCB->first = 0;
+ }
+ rt_rmv_dly (p_TCB);
+ rt_dispatch (p_TCB);
+ }
+ else {
+ rt_dec (&p_MCB->count);
+ }
+ return (OS_R_OK);
+ }
+ /* No message available: wait for one */
+ if (timeout == 0) {
+ return (OS_R_TMO);
+ }
+ if (p_MCB->p_lnk != NULL) {
+ rt_put_prio ((P_XCB)p_MCB, os_tsk.run);
+ }
+ else {
+ p_MCB->p_lnk = os_tsk.run;
+ os_tsk.run->p_lnk = NULL;
+ os_tsk.run->p_rlnk = (P_TCB)p_MCB;
+ /* Task is waiting to receive a message */
+ p_MCB->state = 1;
+ }
+ rt_block(timeout, WAIT_MBX);
+#ifndef __CMSIS_RTOS
+ os_tsk.run->msg = message;
+#endif
+ return (OS_R_TMO);
+}
+
+
+/*--------------------------- rt_mbx_check ----------------------------------*/
+
+OS_RESULT rt_mbx_check (OS_ID mailbox) {
+ /* Check for free space in a mailbox. Returns the number of messages */
+ /* that can be stored to a mailbox. It returns 0 when mailbox is full. */
+ P_MCB p_MCB = mailbox;
+
+ return (p_MCB->size - p_MCB->count);
+}
+
+
+/*--------------------------- isr_mbx_send ----------------------------------*/
+
+void isr_mbx_send (OS_ID mailbox, void *p_msg) {
+ /* Same function as "os_mbx_send", but to be called by ISRs. */
+ P_MCB p_MCB = mailbox;
+
+ rt_psq_enq (p_MCB, (U32)p_msg);
+ rt_psh_req ();
+}
+
+
+/*--------------------------- isr_mbx_receive -------------------------------*/
+
+OS_RESULT isr_mbx_receive (OS_ID mailbox, void **message) {
+ /* Receive a message in the interrupt function. The interrupt function */
+ /* should not wait for a message since this would block the rtx os. */
+ P_MCB p_MCB = mailbox;
+
+ if (p_MCB->count) {
+ /* A message is available in the fifo buffer. */
+ *message = p_MCB->msg[p_MCB->last];
+ if (p_MCB->state == 2) {
+ /* A task is locked waiting to send message */
+ rt_psq_enq (p_MCB, 0);
+ rt_psh_req ();
+ }
+ rt_dec (&p_MCB->count);
+ if (++p_MCB->last == p_MCB->size) {
+ p_MCB->last = 0;
+ }
+ return (OS_R_MBX);
+ }
+ return (OS_R_OK);
+}
+
+
+/*--------------------------- rt_mbx_psh ------------------------------------*/
+
+void rt_mbx_psh (P_MCB p_CB, void *p_msg) {
+ /* Store the message to the mailbox queue or pass it to task directly. */
+ P_TCB p_TCB;
+ void *mem;
+
+ if (p_CB->p_lnk != NULL) switch (p_CB->state) {
+#ifdef __CMSIS_RTOS
+ case 3:
+ /* Task is waiting to allocate memory, remove it from the waiting list */
+ mem = rt_alloc_box(p_msg);
+ if (mem == NULL) break;
+ p_TCB = rt_get_first ((P_XCB)p_CB);
+ rt_ret_val(p_TCB, (U32)mem);
+ p_TCB->state = READY;
+ rt_rmv_dly (p_TCB);
+ rt_put_prio (&os_rdy, p_TCB);
+ break;
+#endif
+ case 2:
+ /* Task is waiting to send a message, remove it from the waiting list */
+ p_TCB = rt_get_first ((P_XCB)p_CB);
+#ifdef __CMSIS_RTOS
+ rt_ret_val(p_TCB, 0/*osOK*/);
+#else
+ rt_ret_val(p_TCB, OS_R_OK);
+#endif
+ p_CB->msg[p_CB->first] = p_TCB->msg;
+ rt_inc (&p_CB->count);
+ if (++p_CB->first == p_CB->size) {
+ p_CB->first = 0;
+ }
+ p_TCB->state = READY;
+ rt_rmv_dly (p_TCB);
+ rt_put_prio (&os_rdy, p_TCB);
+ break;
+ case 1:
+ /* Task is waiting for a message, pass the message to the task directly */
+ p_TCB = rt_get_first ((P_XCB)p_CB);
+#ifdef __CMSIS_RTOS
+ rt_ret_val2(p_TCB, 0x10/*osEventMessage*/, (U32)p_msg);
+#else
+ *p_TCB->msg = p_msg;
+ rt_ret_val (p_TCB, OS_R_MBX);
+#endif
+ p_TCB->state = READY;
+ rt_rmv_dly (p_TCB);
+ rt_put_prio (&os_rdy, p_TCB);
+ break;
+ } else {
+ /* No task is waiting for a message, store it to the mailbox queue */
+ if (p_CB->count < p_CB->size) {
+ p_CB->msg[p_CB->first] = p_msg;
+ rt_inc (&p_CB->count);
+ if (++p_CB->first == p_CB->size) {
+ p_CB->first = 0;
+ }
+ }
+ else {
+ os_error (OS_ERR_MBX_OVF);
+ }
+ }
+}
+
+/*----------------------------------------------------------------------------
+ * end of file
+ *---------------------------------------------------------------------------*/
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/mbed-rtos/rtx/TARGET_CORTEX_M/rt_Mailbox.h Wed Apr 15 06:23:18 2015 +0000 @@ -0,0 +1,48 @@ +/*---------------------------------------------------------------------------- + * RL-ARM - RTX + *---------------------------------------------------------------------------- + * Name: RT_MAILBOX.H + * Purpose: Implements waits and wake-ups for mailbox messages + * Rev.: V4.60 + *---------------------------------------------------------------------------- + * + * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH + * All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + *---------------------------------------------------------------------------*/ + +/* Functions */ +extern void rt_mbx_init (OS_ID mailbox, U16 mbx_size); +extern OS_RESULT rt_mbx_send (OS_ID mailbox, void *p_msg, U16 timeout); +extern OS_RESULT rt_mbx_wait (OS_ID mailbox, void **message, U16 timeout); +extern OS_RESULT rt_mbx_check (OS_ID mailbox); +extern void isr_mbx_send (OS_ID mailbox, void *p_msg); +extern OS_RESULT isr_mbx_receive (OS_ID mailbox, void **message); +extern void rt_mbx_psh (P_MCB p_CB, void *p_msg); + + +/*---------------------------------------------------------------------------- + * end of file + *---------------------------------------------------------------------------*/ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/TARGET_CORTEX_M/rt_MemBox.c Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,166 @@
+/*----------------------------------------------------------------------------
+ * RL-ARM - RTX
+ *----------------------------------------------------------------------------
+ * Name: RT_MEMBOX.C
+ * Purpose: Interface functions for fixed memory block management system
+ * Rev.: V4.60
+ *----------------------------------------------------------------------------
+ *
+ * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *---------------------------------------------------------------------------*/
+
+#include "rt_TypeDef.h"
+#include "RTX_Conf.h"
+#include "rt_System.h"
+#include "rt_MemBox.h"
+#include "rt_HAL_CM.h"
+
+/*----------------------------------------------------------------------------
+ * Global Functions
+ *---------------------------------------------------------------------------*/
+
+
+/*--------------------------- _init_box -------------------------------------*/
+
+int _init_box (void *box_mem, U32 box_size, U32 blk_size) {
+ /* Initialize memory block system, returns 0 if OK, 1 if fails. */
+ void *end;
+ void *blk;
+ void *next;
+ U32 sizeof_bm;
+
+ /* Create memory structure. */
+ if (blk_size & BOX_ALIGN_8) {
+ /* Memory blocks 8-byte aligned. */
+ blk_size = ((blk_size & ~BOX_ALIGN_8) + 7) & ~7;
+ sizeof_bm = (sizeof (struct OS_BM) + 7) & ~7;
+ }
+ else {
+ /* Memory blocks 4-byte aligned. */
+ blk_size = (blk_size + 3) & ~3;
+ sizeof_bm = sizeof (struct OS_BM);
+ }
+ if (blk_size == 0) {
+ return (1);
+ }
+ if ((blk_size + sizeof_bm) > box_size) {
+ return (1);
+ }
+ /* Create a Memory structure. */
+ blk = ((U8 *) box_mem) + sizeof_bm;
+ ((P_BM) box_mem)->free = blk;
+ end = ((U8 *) box_mem) + box_size;
+ ((P_BM) box_mem)->end = end;
+ ((P_BM) box_mem)->blk_size = blk_size;
+
+ /* Link all free blocks using offsets. */
+ end = ((U8 *) end) - blk_size;
+ while (1) {
+ next = ((U8 *) blk) + blk_size;
+ if (next > end) break;
+ *((void **)blk) = next;
+ blk = next;
+ }
+ /* end marker */
+ *((void **)blk) = 0;
+ return (0);
+}
+
+/*--------------------------- rt_alloc_box ----------------------------------*/
+
+void *rt_alloc_box (void *box_mem) {
+ /* Allocate a memory block and return start address. */
+ void **free;
+#ifndef __USE_EXCLUSIVE_ACCESS
+ int irq_dis;
+
+ irq_dis = __disable_irq ();
+ free = ((P_BM) box_mem)->free;
+ if (free) {
+ ((P_BM) box_mem)->free = *free;
+ }
+ if (!irq_dis) __enable_irq ();
+#else
+ do {
+ if ((free = (void **)__ldrex(&((P_BM) box_mem)->free)) == 0) {
+ __clrex();
+ break;
+ }
+ } while (__strex((U32)*free, &((P_BM) box_mem)->free));
+#endif
+ return (free);
+}
+
+
+/*--------------------------- _calloc_box -----------------------------------*/
+
+void *_calloc_box (void *box_mem) {
+ /* Allocate a 0-initialized memory block and return start address. */
+ void *free;
+ U32 *p;
+ U32 i;
+
+ free = _alloc_box (box_mem);
+ if (free) {
+ p = free;
+ for (i = ((P_BM) box_mem)->blk_size; i; i -= 4) {
+ *p = 0;
+ p++;
+ }
+ }
+ return (free);
+}
+
+
+/*--------------------------- rt_free_box -----------------------------------*/
+
+int rt_free_box (void *box_mem, void *box) {
+ /* Free a memory block, returns 0 if OK, 1 if box does not belong to box_mem */
+#ifndef __USE_EXCLUSIVE_ACCESS
+ int irq_dis;
+#endif
+
+ if (box < box_mem || box >= ((P_BM) box_mem)->end) {
+ return (1);
+ }
+
+#ifndef __USE_EXCLUSIVE_ACCESS
+ irq_dis = __disable_irq ();
+ *((void **)box) = ((P_BM) box_mem)->free;
+ ((P_BM) box_mem)->free = box;
+ if (!irq_dis) __enable_irq ();
+#else
+ do {
+ *((void **)box) = (void *)__ldrex(&((P_BM) box_mem)->free);
+ } while (__strex ((U32)box, &((P_BM) box_mem)->free));
+#endif
+ return (0);
+}
+
+/*----------------------------------------------------------------------------
+ * end of file
+ *---------------------------------------------------------------------------*/
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/mbed-rtos/rtx/TARGET_CORTEX_M/rt_MemBox.h Wed Apr 15 06:23:18 2015 +0000 @@ -0,0 +1,46 @@ +/*---------------------------------------------------------------------------- + * RL-ARM - RTX + *---------------------------------------------------------------------------- + * Name: RT_MEMBOX.H + * Purpose: Interface functions for fixed memory block management system + * Rev.: V4.60 + *---------------------------------------------------------------------------- + * + * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH + * All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + *---------------------------------------------------------------------------*/ + +/* Functions */ +#define rt_init_box _init_box +#define rt_calloc_box _calloc_box +extern int _init_box (void *box_mem, U32 box_size, U32 blk_size); +extern void *rt_alloc_box (void *box_mem); +extern void * _calloc_box (void *box_mem); +extern int rt_free_box (void *box_mem, void *box); + +/*---------------------------------------------------------------------------- + * end of file + *---------------------------------------------------------------------------*/ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/TARGET_CORTEX_M/rt_Mutex.c Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,197 @@
+/*----------------------------------------------------------------------------
+ * RL-ARM - RTX
+ *----------------------------------------------------------------------------
+ * Name: RT_MUTEX.C
+ * Purpose: Implements mutex synchronization objects
+ * Rev.: V4.60
+ *----------------------------------------------------------------------------
+ *
+ * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *---------------------------------------------------------------------------*/
+
+#include "rt_TypeDef.h"
+#include "RTX_Conf.h"
+#include "rt_List.h"
+#include "rt_Task.h"
+#include "rt_Mutex.h"
+#include "rt_HAL_CM.h"
+
+
+/*----------------------------------------------------------------------------
+ * Functions
+ *---------------------------------------------------------------------------*/
+
+
+/*--------------------------- rt_mut_init -----------------------------------*/
+
+void rt_mut_init (OS_ID mutex) {
+ /* Initialize a mutex object */
+ P_MUCB p_MCB = mutex;
+
+ p_MCB->cb_type = MUCB;
+ p_MCB->prio = 0;
+ p_MCB->level = 0;
+ p_MCB->p_lnk = NULL;
+ p_MCB->owner = NULL;
+}
+
+
+/*--------------------------- rt_mut_delete ---------------------------------*/
+
+#ifdef __CMSIS_RTOS
+OS_RESULT rt_mut_delete (OS_ID mutex) {
+ /* Delete a mutex object */
+ P_MUCB p_MCB = mutex;
+ P_TCB p_TCB;
+
+ /* Restore owner task's priority. */
+ if (p_MCB->level != 0) {
+ p_MCB->owner->prio = p_MCB->prio;
+ if (p_MCB->owner != os_tsk.run) {
+ rt_resort_prio (p_MCB->owner);
+ }
+ }
+
+ while (p_MCB->p_lnk != NULL) {
+ /* A task is waiting for mutex. */
+ p_TCB = rt_get_first ((P_XCB)p_MCB);
+ rt_ret_val(p_TCB, 0/*osOK*/);
+ rt_rmv_dly(p_TCB);
+ p_TCB->state = READY;
+ rt_put_prio (&os_rdy, p_TCB);
+ }
+
+ if (os_rdy.p_lnk && (os_rdy.p_lnk->prio > os_tsk.run->prio)) {
+ /* preempt running task */
+ rt_put_prio (&os_rdy, os_tsk.run);
+ os_tsk.run->state = READY;
+ rt_dispatch (NULL);
+ }
+
+ p_MCB->cb_type = 0;
+
+ return (OS_R_OK);
+}
+#endif
+
+
+/*--------------------------- rt_mut_release --------------------------------*/
+
+OS_RESULT rt_mut_release (OS_ID mutex) {
+ /* Release a mutex object */
+ P_MUCB p_MCB = mutex;
+ P_TCB p_TCB;
+
+ if (p_MCB->level == 0 || p_MCB->owner != os_tsk.run) {
+ /* Unbalanced mutex release or task is not the owner */
+ return (OS_R_NOK);
+ }
+ if (--p_MCB->level != 0) {
+ return (OS_R_OK);
+ }
+ /* Restore owner task's priority. */
+ os_tsk.run->prio = p_MCB->prio;
+ if (p_MCB->p_lnk != NULL) {
+ /* A task is waiting for mutex. */
+ p_TCB = rt_get_first ((P_XCB)p_MCB);
+#ifdef __CMSIS_RTOS
+ rt_ret_val(p_TCB, 0/*osOK*/);
+#else
+ rt_ret_val(p_TCB, OS_R_MUT);
+#endif
+ rt_rmv_dly (p_TCB);
+ /* A waiting task becomes the owner of this mutex. */
+ p_MCB->level = 1;
+ p_MCB->owner = p_TCB;
+ p_MCB->prio = p_TCB->prio;
+ /* Priority inversion, check which task continues. */
+ if (os_tsk.run->prio >= rt_rdy_prio()) {
+ rt_dispatch (p_TCB);
+ }
+ else {
+ /* Ready task has higher priority than running task. */
+ rt_put_prio (&os_rdy, os_tsk.run);
+ rt_put_prio (&os_rdy, p_TCB);
+ os_tsk.run->state = READY;
+ p_TCB->state = READY;
+ rt_dispatch (NULL);
+ }
+ }
+ else {
+ /* Check if own priority raised by priority inversion. */
+ if (rt_rdy_prio() > os_tsk.run->prio) {
+ rt_put_prio (&os_rdy, os_tsk.run);
+ os_tsk.run->state = READY;
+ rt_dispatch (NULL);
+ }
+ }
+ return (OS_R_OK);
+}
+
+
+/*--------------------------- rt_mut_wait -----------------------------------*/
+
+OS_RESULT rt_mut_wait (OS_ID mutex, U16 timeout) {
+ /* Wait for a mutex, continue when mutex is free. */
+ P_MUCB p_MCB = mutex;
+
+ if (p_MCB->level == 0) {
+ p_MCB->owner = os_tsk.run;
+ p_MCB->prio = os_tsk.run->prio;
+ goto inc;
+ }
+ if (p_MCB->owner == os_tsk.run) {
+ /* OK, running task is the owner of this mutex. */
+inc:p_MCB->level++;
+ return (OS_R_OK);
+ }
+ /* Mutex owned by another task, wait until released. */
+ if (timeout == 0) {
+ return (OS_R_TMO);
+ }
+ /* Raise the owner task priority if lower than current priority. */
+ /* This priority inversion is called priority inheritance. */
+ if (p_MCB->prio < os_tsk.run->prio) {
+ p_MCB->owner->prio = os_tsk.run->prio;
+ rt_resort_prio (p_MCB->owner);
+ }
+ if (p_MCB->p_lnk != NULL) {
+ rt_put_prio ((P_XCB)p_MCB, os_tsk.run);
+ }
+ else {
+ p_MCB->p_lnk = os_tsk.run;
+ os_tsk.run->p_lnk = NULL;
+ os_tsk.run->p_rlnk = (P_TCB)p_MCB;
+ }
+ rt_block(timeout, WAIT_MUT);
+ return (OS_R_TMO);
+}
+
+
+/*----------------------------------------------------------------------------
+ * end of file
+ *---------------------------------------------------------------------------*/
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/mbed-rtos/rtx/TARGET_CORTEX_M/rt_Mutex.h Wed Apr 15 06:23:18 2015 +0000 @@ -0,0 +1,44 @@ +/*---------------------------------------------------------------------------- + * RL-ARM - RTX + *---------------------------------------------------------------------------- + * Name: RT_MUTEX.H + * Purpose: Implements mutex synchronization objects + * Rev.: V4.60 + *---------------------------------------------------------------------------- + * + * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH + * All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + *---------------------------------------------------------------------------*/ + +/* Functions */ +extern void rt_mut_init (OS_ID mutex); +extern OS_RESULT rt_mut_delete (OS_ID mutex); +extern OS_RESULT rt_mut_release (OS_ID mutex); +extern OS_RESULT rt_mut_wait (OS_ID mutex, U16 timeout); + +/*---------------------------------------------------------------------------- + * end of file + *---------------------------------------------------------------------------*/ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/TARGET_CORTEX_M/rt_Robin.c Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,84 @@
+/*----------------------------------------------------------------------------
+ * RL-ARM - RTX
+ *----------------------------------------------------------------------------
+ * Name: RT_ROBIN.C
+ * Purpose: Round Robin Task switching
+ * Rev.: V4.60
+ *----------------------------------------------------------------------------
+ *
+ * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *---------------------------------------------------------------------------*/
+
+#include "rt_TypeDef.h"
+#include "RTX_Conf.h"
+#include "rt_List.h"
+#include "rt_Task.h"
+#include "rt_Time.h"
+#include "rt_Robin.h"
+#include "rt_HAL_CM.h"
+
+/*----------------------------------------------------------------------------
+ * Global Variables
+ *---------------------------------------------------------------------------*/
+
+struct OS_ROBIN os_robin;
+
+
+/*----------------------------------------------------------------------------
+ * Global Functions
+ *---------------------------------------------------------------------------*/
+
+/*--------------------------- rt_init_robin ---------------------------------*/
+
+__weak void rt_init_robin (void) {
+ /* Initialize Round Robin variables. */
+ os_robin.task = NULL;
+ os_robin.tout = (U16)os_rrobin;
+}
+
+/*--------------------------- rt_chk_robin ----------------------------------*/
+
+__weak void rt_chk_robin (void) {
+ /* Check if Round Robin timeout expired and switch to the next ready task.*/
+ P_TCB p_new;
+
+ if (os_robin.task != os_rdy.p_lnk) {
+ /* New task was suspended, reset Round Robin timeout. */
+ os_robin.task = os_rdy.p_lnk;
+ os_robin.time = (U16)os_time + os_robin.tout - 1;
+ }
+ if (os_robin.time == (U16)os_time) {
+ /* Round Robin timeout has expired, swap Robin tasks. */
+ os_robin.task = NULL;
+ p_new = rt_get_first (&os_rdy);
+ rt_put_prio ((P_XCB)&os_rdy, p_new);
+ }
+}
+
+/*----------------------------------------------------------------------------
+ * end of file
+ *---------------------------------------------------------------------------*/
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/mbed-rtos/rtx/TARGET_CORTEX_M/rt_Robin.h Wed Apr 15 06:23:18 2015 +0000 @@ -0,0 +1,45 @@ +/*---------------------------------------------------------------------------- + * RL-ARM - RTX + *---------------------------------------------------------------------------- + * Name: RT_ROBIN.H + * Purpose: Round Robin Task switching definitions + * Rev.: V4.60 + *---------------------------------------------------------------------------- + * + * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH + * All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + *---------------------------------------------------------------------------*/ + +/* Variables */ +extern struct OS_ROBIN os_robin; + +/* Functions */ +extern void rt_init_robin (void); +extern void rt_chk_robin (void); + +/*---------------------------------------------------------------------------- + * end of file + *---------------------------------------------------------------------------*/ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/TARGET_CORTEX_M/rt_Semaphore.c Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,183 @@
+/*----------------------------------------------------------------------------
+ * RL-ARM - RTX
+ *----------------------------------------------------------------------------
+ * Name: RT_SEMAPHORE.C
+ * Purpose: Implements binary and counting semaphores
+ * Rev.: V4.60
+ *----------------------------------------------------------------------------
+ *
+ * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *---------------------------------------------------------------------------*/
+
+#include "rt_TypeDef.h"
+#include "RTX_Conf.h"
+#include "rt_System.h"
+#include "rt_List.h"
+#include "rt_Task.h"
+#include "rt_Semaphore.h"
+#include "rt_HAL_CM.h"
+
+
+/*----------------------------------------------------------------------------
+ * Functions
+ *---------------------------------------------------------------------------*/
+
+
+/*--------------------------- rt_sem_init -----------------------------------*/
+
+void rt_sem_init (OS_ID semaphore, U16 token_count) {
+ /* Initialize a semaphore */
+ P_SCB p_SCB = semaphore;
+
+ p_SCB->cb_type = SCB;
+ p_SCB->p_lnk = NULL;
+ p_SCB->tokens = token_count;
+}
+
+
+/*--------------------------- rt_sem_delete ---------------------------------*/
+
+#ifdef __CMSIS_RTOS
+OS_RESULT rt_sem_delete (OS_ID semaphore) {
+ /* Delete semaphore */
+ P_SCB p_SCB = semaphore;
+ P_TCB p_TCB;
+
+ while (p_SCB->p_lnk != NULL) {
+ /* A task is waiting for token */
+ p_TCB = rt_get_first ((P_XCB)p_SCB);
+ rt_ret_val(p_TCB, 0);
+ rt_rmv_dly(p_TCB);
+ p_TCB->state = READY;
+ rt_put_prio (&os_rdy, p_TCB);
+ }
+
+ if (os_rdy.p_lnk && (os_rdy.p_lnk->prio > os_tsk.run->prio)) {
+ /* preempt running task */
+ rt_put_prio (&os_rdy, os_tsk.run);
+ os_tsk.run->state = READY;
+ rt_dispatch (NULL);
+ }
+
+ p_SCB->cb_type = 0;
+
+ return (OS_R_OK);
+}
+#endif
+
+
+/*--------------------------- rt_sem_send -----------------------------------*/
+
+OS_RESULT rt_sem_send (OS_ID semaphore) {
+ /* Return a token to semaphore */
+ P_SCB p_SCB = semaphore;
+ P_TCB p_TCB;
+
+ if (p_SCB->p_lnk != NULL) {
+ /* A task is waiting for token */
+ p_TCB = rt_get_first ((P_XCB)p_SCB);
+#ifdef __CMSIS_RTOS
+ rt_ret_val(p_TCB, 1);
+#else
+ rt_ret_val(p_TCB, OS_R_SEM);
+#endif
+ rt_rmv_dly (p_TCB);
+ rt_dispatch (p_TCB);
+ }
+ else {
+ /* Store token. */
+ p_SCB->tokens++;
+ }
+ return (OS_R_OK);
+}
+
+
+/*--------------------------- rt_sem_wait -----------------------------------*/
+
+OS_RESULT rt_sem_wait (OS_ID semaphore, U16 timeout) {
+ /* Obtain a token; possibly wait for it */
+ P_SCB p_SCB = semaphore;
+
+ if (p_SCB->tokens) {
+ p_SCB->tokens--;
+ return (OS_R_OK);
+ }
+ /* No token available: wait for one */
+ if (timeout == 0) {
+ return (OS_R_TMO);
+ }
+ if (p_SCB->p_lnk != NULL) {
+ rt_put_prio ((P_XCB)p_SCB, os_tsk.run);
+ }
+ else {
+ p_SCB->p_lnk = os_tsk.run;
+ os_tsk.run->p_lnk = NULL;
+ os_tsk.run->p_rlnk = (P_TCB)p_SCB;
+ }
+ rt_block(timeout, WAIT_SEM);
+ return (OS_R_TMO);
+}
+
+
+/*--------------------------- isr_sem_send ----------------------------------*/
+
+void isr_sem_send (OS_ID semaphore) {
+ /* Same function as "os_sem"send", but to be called by ISRs */
+ P_SCB p_SCB = semaphore;
+
+ rt_psq_enq (p_SCB, 0);
+ rt_psh_req ();
+}
+
+
+/*--------------------------- rt_sem_psh ------------------------------------*/
+
+void rt_sem_psh (P_SCB p_CB) {
+ /* Check if task has to be waken up */
+ P_TCB p_TCB;
+
+ if (p_CB->p_lnk != NULL) {
+ /* A task is waiting for token */
+ p_TCB = rt_get_first ((P_XCB)p_CB);
+ rt_rmv_dly (p_TCB);
+ p_TCB->state = READY;
+#ifdef __CMSIS_RTOS
+ rt_ret_val(p_TCB, 1);
+#else
+ rt_ret_val(p_TCB, OS_R_SEM);
+#endif
+ rt_put_prio (&os_rdy, p_TCB);
+ }
+ else {
+ /* Store token */
+ p_CB->tokens++;
+ }
+}
+
+/*----------------------------------------------------------------------------
+ * end of file
+ *---------------------------------------------------------------------------*/
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/mbed-rtos/rtx/TARGET_CORTEX_M/rt_Semaphore.h Wed Apr 15 06:23:18 2015 +0000 @@ -0,0 +1,46 @@ +/*---------------------------------------------------------------------------- + * RL-ARM - RTX + *---------------------------------------------------------------------------- + * Name: RT_SEMAPHORE.H + * Purpose: Implements binary and counting semaphores + * Rev.: V4.60 + *---------------------------------------------------------------------------- + * + * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH + * All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + *---------------------------------------------------------------------------*/ + +/* Functions */ +extern void rt_sem_init (OS_ID semaphore, U16 token_count); +extern OS_RESULT rt_sem_delete(OS_ID semaphore); +extern OS_RESULT rt_sem_send (OS_ID semaphore); +extern OS_RESULT rt_sem_wait (OS_ID semaphore, U16 timeout); +extern void isr_sem_send (OS_ID semaphore); +extern void rt_sem_psh (P_SCB p_CB); + +/*---------------------------------------------------------------------------- + * end of file + *---------------------------------------------------------------------------*/ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/TARGET_CORTEX_M/rt_System.c Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,299 @@
+/*----------------------------------------------------------------------------
+ * RL-ARM - RTX
+ *----------------------------------------------------------------------------
+ * Name: RT_SYSTEM.C
+ * Purpose: System Task Manager
+ * Rev.: V4.60
+ *----------------------------------------------------------------------------
+ *
+ * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *---------------------------------------------------------------------------*/
+
+#include "rt_TypeDef.h"
+#include "RTX_Conf.h"
+#include "rt_Task.h"
+#include "rt_System.h"
+#include "rt_Event.h"
+#include "rt_List.h"
+#include "rt_Mailbox.h"
+#include "rt_Semaphore.h"
+#include "rt_Time.h"
+#include "rt_Robin.h"
+#include "rt_HAL_CM.h"
+
+/*----------------------------------------------------------------------------
+ * Global Variables
+ *---------------------------------------------------------------------------*/
+
+int os_tick_irqn;
+
+/*----------------------------------------------------------------------------
+ * Local Variables
+ *---------------------------------------------------------------------------*/
+
+static volatile BIT os_lock;
+static volatile BIT os_psh_flag;
+static U8 pend_flags;
+
+/*----------------------------------------------------------------------------
+ * Global Functions
+ *---------------------------------------------------------------------------*/
+
+#if defined (__CC_ARM)
+__asm void $$RTX$$version (void) {
+ /* Export a version number symbol for a version control. */
+
+ EXPORT __RL_RTX_VER
+
+__RL_RTX_VER EQU 0x450
+}
+#endif
+
+
+/*--------------------------- rt_suspend ------------------------------------*/
+U32 rt_suspend (void) {
+ /* Suspend OS scheduler */
+ U32 delta = 0xFFFF;
+
+ rt_tsk_lock();
+
+ if (os_dly.p_dlnk) {
+ delta = os_dly.delta_time;
+ }
+#ifndef __CMSIS_RTOS
+ if (os_tmr.next) {
+ if (os_tmr.tcnt < delta) delta = os_tmr.tcnt;
+ }
+#endif
+
+ return (delta);
+}
+
+
+/*--------------------------- rt_resume -------------------------------------*/
+void rt_resume (U32 sleep_time) {
+ /* Resume OS scheduler after suspend */
+ P_TCB next;
+ U32 delta;
+
+ os_tsk.run->state = READY;
+ rt_put_rdy_first (os_tsk.run);
+
+ os_robin.task = NULL;
+
+ /* Update delays. */
+ if (os_dly.p_dlnk) {
+ delta = sleep_time;
+ if (delta >= os_dly.delta_time) {
+ delta -= os_dly.delta_time;
+ os_time += os_dly.delta_time;
+ os_dly.delta_time = 1;
+ while (os_dly.p_dlnk) {
+ rt_dec_dly();
+ if (delta == 0) break;
+ delta--;
+ os_time++;
+ }
+ } else {
+ os_time += delta;
+ os_dly.delta_time -= delta;
+ }
+ } else {
+ os_time += sleep_time;
+ }
+
+#ifndef __CMSIS_RTOS
+ /* Check the user timers. */
+ if (os_tmr.next) {
+ delta = sleep_time;
+ if (delta >= os_tmr.tcnt) {
+ delta -= os_tmr.tcnt;
+ os_tmr.tcnt = 1;
+ while (os_tmr.next) {
+ rt_tmr_tick();
+ if (delta == 0) break;
+ delta--;
+ }
+ } else {
+ os_tmr.tcnt -= delta;
+ }
+ }
+#endif
+
+ /* Switch back to highest ready task */
+ next = rt_get_first (&os_rdy);
+ rt_switch_req (next);
+
+ rt_tsk_unlock();
+}
+
+
+/*--------------------------- rt_tsk_lock -----------------------------------*/
+
+void rt_tsk_lock (void) {
+ /* Prevent task switching by locking out scheduler */
+ if (os_tick_irqn < 0) {
+ OS_LOCK();
+ os_lock = __TRUE;
+ OS_UNPEND (&pend_flags);
+ } else {
+ OS_X_LOCK(os_tick_irqn);
+ os_lock = __TRUE;
+ OS_X_UNPEND (&pend_flags);
+ }
+}
+
+
+/*--------------------------- rt_tsk_unlock ---------------------------------*/
+
+void rt_tsk_unlock (void) {
+ /* Unlock scheduler and re-enable task switching */
+ if (os_tick_irqn < 0) {
+ OS_UNLOCK();
+ os_lock = __FALSE;
+ OS_PEND (pend_flags, os_psh_flag);
+ os_psh_flag = __FALSE;
+ } else {
+ OS_X_UNLOCK(os_tick_irqn);
+ os_lock = __FALSE;
+ OS_X_PEND (pend_flags, os_psh_flag);
+ os_psh_flag = __FALSE;
+ }
+}
+
+
+/*--------------------------- rt_psh_req ------------------------------------*/
+
+void rt_psh_req (void) {
+ /* Initiate a post service handling request if required. */
+ if (os_lock == __FALSE) {
+ OS_PEND_IRQ ();
+ }
+ else {
+ os_psh_flag = __TRUE;
+ }
+}
+
+
+/*--------------------------- rt_pop_req ------------------------------------*/
+
+void rt_pop_req (void) {
+ /* Process an ISR post service requests. */
+ struct OS_XCB *p_CB;
+ P_TCB next;
+ U32 idx;
+
+ os_tsk.run->state = READY;
+ rt_put_rdy_first (os_tsk.run);
+
+ idx = os_psq->last;
+ while (os_psq->count) {
+ p_CB = os_psq->q[idx].id;
+ if (p_CB->cb_type == TCB) {
+ /* Is of TCB type */
+ rt_evt_psh ((P_TCB)p_CB, (U16)os_psq->q[idx].arg);
+ }
+ else if (p_CB->cb_type == MCB) {
+ /* Is of MCB type */
+ rt_mbx_psh ((P_MCB)p_CB, (void *)os_psq->q[idx].arg);
+ }
+ else {
+ /* Must be of SCB type */
+ rt_sem_psh ((P_SCB)p_CB);
+ }
+ if (++idx == os_psq->size) idx = 0;
+ rt_dec (&os_psq->count);
+ }
+ os_psq->last = idx;
+
+ next = rt_get_first (&os_rdy);
+ rt_switch_req (next);
+}
+
+
+/*--------------------------- os_tick_init ----------------------------------*/
+
+__weak int os_tick_init (void) {
+ /* Initialize SysTick timer as system tick timer. */
+ rt_systick_init ();
+ return (-1); /* Return IRQ number of SysTick timer */
+}
+
+
+/*--------------------------- os_tick_irqack --------------------------------*/
+
+__weak void os_tick_irqack (void) {
+ /* Acknowledge timer interrupt. */
+}
+
+
+/*--------------------------- rt_systick ------------------------------------*/
+
+extern void sysTimerTick(void);
+
+void rt_systick (void) {
+ /* Check for system clock update, suspend running task. */
+ P_TCB next;
+
+ os_tsk.run->state = READY;
+ rt_put_rdy_first (os_tsk.run);
+
+ /* Check Round Robin timeout. */
+ rt_chk_robin ();
+
+ /* Update delays. */
+ os_time++;
+ rt_dec_dly ();
+
+ /* Check the user timers. */
+#ifdef __CMSIS_RTOS
+ sysTimerTick();
+#else
+ rt_tmr_tick ();
+#endif
+
+ /* Switch back to highest ready task */
+ next = rt_get_first (&os_rdy);
+ rt_switch_req (next);
+}
+
+/*--------------------------- rt_stk_check ----------------------------------*/
+__weak void rt_stk_check (void) {
+ /* Check for stack overflow. */
+ if (os_tsk.run->task_id == 0x01) {
+ // TODO: For the main thread the check should be done against the main heap pointer
+ } else {
+ if ((os_tsk.run->tsk_stack < (U32)os_tsk.run->stack) ||
+ (os_tsk.run->stack[0] != MAGIC_WORD)) {
+ os_error (OS_ERR_STK_OVF);
+ }
+ }
+}
+
+/*----------------------------------------------------------------------------
+ * end of file
+ *---------------------------------------------------------------------------*/
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/mbed-rtos/rtx/TARGET_CORTEX_M/rt_System.h Wed Apr 15 06:23:18 2015 +0000 @@ -0,0 +1,52 @@ +/*---------------------------------------------------------------------------- + * RL-ARM - RTX + *---------------------------------------------------------------------------- + * Name: RT_SYSTEM.H + * Purpose: System Task Manager definitions + * Rev.: V4.60 + *---------------------------------------------------------------------------- + * + * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH + * All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + *---------------------------------------------------------------------------*/ + +/* Variables */ +#define os_psq ((P_PSQ)&os_fifo) +extern int os_tick_irqn; + +/* Functions */ +extern U32 rt_suspend (void); +extern void rt_resume (U32 sleep_time); +extern void rt_tsk_lock (void); +extern void rt_tsk_unlock (void); +extern void rt_psh_req (void); +extern void rt_pop_req (void); +extern void rt_systick (void); +extern void rt_stk_check (void); + +/*---------------------------------------------------------------------------- + * end of file + *---------------------------------------------------------------------------*/ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/TARGET_CORTEX_M/rt_Task.c Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,339 @@
+/*----------------------------------------------------------------------------
+ * RL-ARM - RTX
+ *----------------------------------------------------------------------------
+ * Name: RT_TASK.C
+ * Purpose: Task functions and system start up.
+ * Rev.: V4.60
+ *----------------------------------------------------------------------------
+ *
+ * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *---------------------------------------------------------------------------*/
+
+#include "rt_TypeDef.h"
+#include "RTX_Conf.h"
+#include "rt_System.h"
+#include "rt_Task.h"
+#include "rt_List.h"
+#include "rt_MemBox.h"
+#include "rt_Robin.h"
+#include "rt_HAL_CM.h"
+
+/*----------------------------------------------------------------------------
+ * Global Variables
+ *---------------------------------------------------------------------------*/
+
+/* Running and next task info. */
+struct OS_TSK os_tsk;
+
+/* Task Control Blocks of idle demon */
+struct OS_TCB os_idle_TCB;
+
+
+/*----------------------------------------------------------------------------
+ * Local Functions
+ *---------------------------------------------------------------------------*/
+
+OS_TID rt_get_TID (void) {
+ U32 tid;
+
+ for (tid = 1; tid <= os_maxtaskrun; tid++) {
+ if (os_active_TCB[tid-1] == NULL) {
+ return ((OS_TID)tid);
+ }
+ }
+ return (0);
+}
+
+#if defined (__CC_ARM) && !defined (__MICROLIB)
+/*--------------------------- __user_perthread_libspace ---------------------*/
+extern void *__libspace_start;
+
+void *__user_perthread_libspace (void) {
+ /* Provide a separate libspace for each task. */
+ if (os_tsk.run == NULL) {
+ /* RTX not running yet. */
+ return (&__libspace_start);
+ }
+ return (void *)(os_tsk.run->std_libspace);
+}
+#endif
+
+/*--------------------------- rt_init_context -------------------------------*/
+
+void rt_init_context (P_TCB p_TCB, U8 priority, FUNCP task_body) {
+ /* Initialize general part of the Task Control Block. */
+ p_TCB->cb_type = TCB;
+ p_TCB->state = READY;
+ p_TCB->prio = priority;
+ p_TCB->p_lnk = NULL;
+ p_TCB->p_rlnk = NULL;
+ p_TCB->p_dlnk = NULL;
+ p_TCB->p_blnk = NULL;
+ p_TCB->delta_time = 0;
+ p_TCB->interval_time = 0;
+ p_TCB->events = 0;
+ p_TCB->waits = 0;
+ p_TCB->stack_frame = 0;
+
+ rt_init_stack (p_TCB, task_body);
+}
+
+
+/*--------------------------- rt_switch_req ---------------------------------*/
+
+void rt_switch_req (P_TCB p_new) {
+ /* Switch to next task (identified by "p_new"). */
+ os_tsk.new_tsk = p_new;
+ p_new->state = RUNNING;
+ DBG_TASK_SWITCH(p_new->task_id);
+}
+
+
+/*--------------------------- rt_dispatch -----------------------------------*/
+
+void rt_dispatch (P_TCB next_TCB) {
+ /* Dispatch next task if any identified or dispatch highest ready task */
+ /* "next_TCB" identifies a task to run or has value NULL (=no next task) */
+ if (next_TCB == NULL) {
+ /* Running task was blocked: continue with highest ready task */
+ next_TCB = rt_get_first (&os_rdy);
+ rt_switch_req (next_TCB);
+ }
+ else {
+ /* Check which task continues */
+ if (next_TCB->prio > os_tsk.run->prio) {
+ /* preempt running task */
+ rt_put_rdy_first (os_tsk.run);
+ os_tsk.run->state = READY;
+ rt_switch_req (next_TCB);
+ }
+ else {
+ /* put next task into ready list, no task switch takes place */
+ next_TCB->state = READY;
+ rt_put_prio (&os_rdy, next_TCB);
+ }
+ }
+}
+
+
+/*--------------------------- rt_block --------------------------------------*/
+
+void rt_block (U16 timeout, U8 block_state) {
+ /* Block running task and choose next ready task. */
+ /* "timeout" sets a time-out value or is 0xffff (=no time-out). */
+ /* "block_state" defines the appropriate task state */
+ P_TCB next_TCB;
+
+ if (timeout) {
+ if (timeout < 0xffff) {
+ rt_put_dly (os_tsk.run, timeout);
+ }
+ os_tsk.run->state = block_state;
+ next_TCB = rt_get_first (&os_rdy);
+ rt_switch_req (next_TCB);
+ }
+}
+
+
+/*--------------------------- rt_tsk_pass -----------------------------------*/
+
+void rt_tsk_pass (void) {
+ /* Allow tasks of same priority level to run cooperatively.*/
+ P_TCB p_new;
+
+ p_new = rt_get_same_rdy_prio();
+ if (p_new != NULL) {
+ rt_put_prio ((P_XCB)&os_rdy, os_tsk.run);
+ os_tsk.run->state = READY;
+ rt_switch_req (p_new);
+ }
+}
+
+
+/*--------------------------- rt_tsk_self -----------------------------------*/
+
+OS_TID rt_tsk_self (void) {
+ /* Return own task identifier value. */
+ if (os_tsk.run == NULL) {
+ return (0);
+ }
+ return (os_tsk.run->task_id);
+}
+
+
+/*--------------------------- rt_tsk_prio -----------------------------------*/
+
+OS_RESULT rt_tsk_prio (OS_TID task_id, U8 new_prio) {
+ /* Change execution priority of a task to "new_prio". */
+ P_TCB p_task;
+
+ if (task_id == 0) {
+ /* Change execution priority of calling task. */
+ os_tsk.run->prio = new_prio;
+run:if (rt_rdy_prio() > new_prio) {
+ rt_put_prio (&os_rdy, os_tsk.run);
+ os_tsk.run->state = READY;
+ rt_dispatch (NULL);
+ }
+ return (OS_R_OK);
+ }
+
+ /* Find the task in the "os_active_TCB" array. */
+ if (task_id > os_maxtaskrun || os_active_TCB[task_id-1] == NULL) {
+ /* Task with "task_id" not found or not started. */
+ return (OS_R_NOK);
+ }
+ p_task = os_active_TCB[task_id-1];
+ p_task->prio = new_prio;
+ if (p_task == os_tsk.run) {
+ goto run;
+ }
+ rt_resort_prio (p_task);
+ if (p_task->state == READY) {
+ /* Task enqueued in a ready list. */
+ p_task = rt_get_first (&os_rdy);
+ rt_dispatch (p_task);
+ }
+ return (OS_R_OK);
+}
+
+/*--------------------------- rt_tsk_delete ---------------------------------*/
+
+OS_RESULT rt_tsk_delete (OS_TID task_id) {
+ /* Terminate the task identified with "task_id". */
+ P_TCB task_context;
+
+ if (task_id == 0 || task_id == os_tsk.run->task_id) {
+ /* Terminate itself. */
+ os_tsk.run->state = INACTIVE;
+ os_tsk.run->tsk_stack = rt_get_PSP ();
+ rt_stk_check ();
+ os_active_TCB[os_tsk.run->task_id-1] = NULL;
+
+ os_tsk.run->stack = NULL;
+ DBG_TASK_NOTIFY(os_tsk.run, __FALSE);
+ os_tsk.run = NULL;
+ rt_dispatch (NULL);
+ /* The program should never come to this point. */
+ }
+ else {
+ /* Find the task in the "os_active_TCB" array. */
+ if (task_id > os_maxtaskrun || os_active_TCB[task_id-1] == NULL) {
+ /* Task with "task_id" not found or not started. */
+ return (OS_R_NOK);
+ }
+ task_context = os_active_TCB[task_id-1];
+ rt_rmv_list (task_context);
+ rt_rmv_dly (task_context);
+ os_active_TCB[task_id-1] = NULL;
+
+ task_context->stack = NULL;
+ DBG_TASK_NOTIFY(task_context, __FALSE);
+ }
+ return (OS_R_OK);
+}
+
+
+/*--------------------------- rt_sys_init -----------------------------------*/
+
+#ifdef __CMSIS_RTOS
+void rt_sys_init (void) {
+#else
+void rt_sys_init (FUNCP first_task, U32 prio_stksz, void *stk) {
+#endif
+ /* Initialize system and start up task declared with "first_task". */
+ U32 i;
+
+ DBG_INIT();
+
+ /* Initialize dynamic memory and task TCB pointers to NULL. */
+ for (i = 0; i < os_maxtaskrun; i++) {
+ os_active_TCB[i] = NULL;
+ }
+
+ /* Set up TCB of idle demon */
+ os_idle_TCB.task_id = 255;
+ os_idle_TCB.priv_stack = idle_task_stack_size;
+ os_idle_TCB.stack = idle_task_stack;
+ rt_init_context (&os_idle_TCB, 0, os_idle_demon);
+
+ /* Set up ready list: initially empty */
+ os_rdy.cb_type = HCB;
+ os_rdy.p_lnk = NULL;
+ /* Set up delay list: initially empty */
+ os_dly.cb_type = HCB;
+ os_dly.p_dlnk = NULL;
+ os_dly.p_blnk = NULL;
+ os_dly.delta_time = 0;
+
+ /* Fix SP and systemvariables to assume idle task is running */
+ /* Transform main program into idle task by assuming idle TCB */
+#ifndef __CMSIS_RTOS
+ rt_set_PSP (os_idle_TCB.tsk_stack+32);
+#endif
+ os_tsk.run = &os_idle_TCB;
+ os_tsk.run->state = RUNNING;
+
+ /* Initialize ps queue */
+ os_psq->first = 0;
+ os_psq->last = 0;
+ os_psq->size = os_fifo_size;
+
+ rt_init_robin ();
+
+ /* Intitialize SVC and PendSV */
+ rt_svc_init ();
+
+#ifndef __CMSIS_RTOS
+ /* Intitialize and start system clock timer */
+ os_tick_irqn = os_tick_init ();
+ if (os_tick_irqn >= 0) {
+ OS_X_INIT(os_tick_irqn);
+ }
+
+ /* Start up first user task before entering the endless loop */
+ rt_tsk_create (first_task, prio_stksz, stk, NULL);
+#endif
+}
+
+
+/*--------------------------- rt_sys_start ----------------------------------*/
+
+#ifdef __CMSIS_RTOS
+void rt_sys_start (void) {
+ /* Start system */
+
+ /* Intitialize and start system clock timer */
+ os_tick_irqn = os_tick_init ();
+ if (os_tick_irqn >= 0) {
+ OS_X_INIT(os_tick_irqn);
+ }
+}
+#endif
+
+/*----------------------------------------------------------------------------
+ * end of file
+ *---------------------------------------------------------------------------*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/mbed-rtos/rtx/TARGET_CORTEX_M/rt_Task.h Wed Apr 15 06:23:18 2015 +0000 @@ -0,0 +1,73 @@ +/*---------------------------------------------------------------------------- + * RL-ARM - RTX + *---------------------------------------------------------------------------- + * Name: RT_TASK.H + * Purpose: Task functions and system start up. + * Rev.: V4.60 + *---------------------------------------------------------------------------- + * + * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH + * All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + *---------------------------------------------------------------------------*/ + +/* Definitions */ +#define __CMSIS_RTOS 1 + +/* Values for 'state' */ +#define INACTIVE 0 +#define READY 1 +#define RUNNING 2 +#define WAIT_DLY 3 +#define WAIT_ITV 4 +#define WAIT_OR 5 +#define WAIT_AND 6 +#define WAIT_SEM 7 +#define WAIT_MBX 8 +#define WAIT_MUT 9 + +/* Return codes */ +#define OS_R_TMO 0x01 +#define OS_R_EVT 0x02 +#define OS_R_SEM 0x03 +#define OS_R_MBX 0x04 +#define OS_R_MUT 0x05 + +#define OS_R_OK 0x00 +#define OS_R_NOK 0xff + +/* Variables */ +extern struct OS_TSK os_tsk; +extern struct OS_TCB os_idle_TCB; + +/* Functions */ +extern void rt_switch_req (P_TCB p_new); +extern void rt_dispatch (P_TCB next_TCB); +extern void rt_block (U16 timeout, U8 block_state); +extern void rt_tsk_pass (void); +extern OS_TID rt_tsk_self (void); +extern OS_RESULT rt_tsk_prio (OS_TID task_id, U8 new_prio); +extern OS_RESULT rt_tsk_delete (OS_TID task_id); +extern void rt_sys_init (void); +extern void rt_sys_start (void);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/TARGET_CORTEX_M/rt_Time.c Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,94 @@
+/*----------------------------------------------------------------------------
+ * RL-ARM - RTX
+ *----------------------------------------------------------------------------
+ * Name: RT_TIME.C
+ * Purpose: Delay and interval wait functions
+ * Rev.: V4.60
+ *----------------------------------------------------------------------------
+ *
+ * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *---------------------------------------------------------------------------*/
+
+#include "rt_TypeDef.h"
+#include "RTX_Conf.h"
+#include "rt_Task.h"
+#include "rt_Time.h"
+
+/*----------------------------------------------------------------------------
+ * Global Variables
+ *---------------------------------------------------------------------------*/
+
+/* Free running system tick counter */
+U32 os_time;
+
+
+/*----------------------------------------------------------------------------
+ * Functions
+ *---------------------------------------------------------------------------*/
+
+
+/*--------------------------- rt_time_get -----------------------------------*/
+
+U32 rt_time_get (void) {
+ /* Get system time tick */
+ return (os_time);
+}
+
+
+/*--------------------------- rt_dly_wait -----------------------------------*/
+
+void rt_dly_wait (U16 delay_time) {
+ /* Delay task by "delay_time" */
+ rt_block (delay_time, WAIT_DLY);
+}
+
+
+/*--------------------------- rt_itv_set ------------------------------------*/
+
+void rt_itv_set (U16 interval_time) {
+ /* Set interval length and define start of first interval */
+ os_tsk.run->interval_time = interval_time;
+ os_tsk.run->delta_time = interval_time + (U16)os_time;
+}
+
+
+/*--------------------------- rt_itv_wait -----------------------------------*/
+
+void rt_itv_wait (void) {
+ /* Wait for interval end and define start of next one */
+ U16 delta;
+
+ delta = os_tsk.run->delta_time - (U16)os_time;
+ os_tsk.run->delta_time += os_tsk.run->interval_time;
+ if ((delta & 0x8000) == 0) {
+ rt_block (delta, WAIT_ITV);
+ }
+}
+
+/*----------------------------------------------------------------------------
+ * end of file
+ *---------------------------------------------------------------------------*/
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/mbed-rtos/rtx/TARGET_CORTEX_M/rt_Time.h Wed Apr 15 06:23:18 2015 +0000 @@ -0,0 +1,47 @@ +/*---------------------------------------------------------------------------- + * RL-ARM - RTX + *---------------------------------------------------------------------------- + * Name: RT_TIME.H + * Purpose: Delay and interval wait functions definitions + * Rev.: V4.60 + *---------------------------------------------------------------------------- + * + * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH + * All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + *---------------------------------------------------------------------------*/ + +/* Variables */ +extern U32 os_time; + +/* Functions */ +extern U32 rt_time_get (void); +extern void rt_dly_wait (U16 delay_time); +extern void rt_itv_set (U16 interval_time); +extern void rt_itv_wait (void); + +/*---------------------------------------------------------------------------- + * end of file + *---------------------------------------------------------------------------*/ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/TARGET_CORTEX_M/rt_TypeDef.h Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,128 @@
+/*----------------------------------------------------------------------------
+ * RL-ARM - RTX
+ *----------------------------------------------------------------------------
+ * Name: RT_TYPEDEF.H
+ * Purpose: Type Definitions
+ * Rev.: V4.60
+ *----------------------------------------------------------------------------
+ *
+ * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *---------------------------------------------------------------------------*/
+#ifndef RT_TYPE_DEF_H
+#define RT_TYPE_DEF_H
+
+#include "os_tcb.h"
+
+typedef U32 OS_TID;
+typedef void *OS_ID;
+typedef U32 OS_RESULT;
+
+#define TCB_STACKF 32 /* 'stack_frame' offset */
+#define TCB_TSTACK 40 /* 'tsk_stack' offset */
+
+typedef struct OS_PSFE { /* Post Service Fifo Entry */
+ void *id; /* Object Identification */
+ U32 arg; /* Object Argument */
+} *P_PSFE;
+
+typedef struct OS_PSQ { /* Post Service Queue */
+ U8 first; /* FIFO Head Index */
+ U8 last; /* FIFO Tail Index */
+ U8 count; /* Number of stored items in FIFO */
+ U8 size; /* FIFO Size */
+ struct OS_PSFE q[1]; /* FIFO Content */
+} *P_PSQ;
+
+typedef struct OS_TSK {
+ P_TCB run; /* Current running task */
+ P_TCB new_tsk; /* Scheduled task to run */
+} *P_TSK;
+
+typedef struct OS_ROBIN { /* Round Robin Control */
+ P_TCB task; /* Round Robin task */
+ U16 time; /* Round Robin switch time */
+ U16 tout; /* Round Robin timeout */
+} *P_ROBIN;
+
+typedef struct OS_XCB {
+ U8 cb_type; /* Control Block Type */
+ struct OS_TCB *p_lnk; /* Link pointer for ready/sem. wait list */
+ struct OS_TCB *p_rlnk; /* Link pointer for sem./mbx lst backwards */
+ struct OS_TCB *p_dlnk; /* Link pointer for delay list */
+ struct OS_TCB *p_blnk; /* Link pointer for delay list backwards */
+ U16 delta_time; /* Time until time out */
+} *P_XCB;
+
+typedef struct OS_MCB {
+ U8 cb_type; /* Control Block Type */
+ U8 state; /* State flag variable */
+ U8 isr_st; /* State flag variable for isr functions */
+ struct OS_TCB *p_lnk; /* Chain of tasks waiting for message */
+ U16 first; /* Index of the message list begin */
+ U16 last; /* Index of the message list end */
+ U16 count; /* Actual number of stored messages */
+ U16 size; /* Maximum number of stored messages */
+ void *msg[1]; /* FIFO for Message pointers 1st element */
+} *P_MCB;
+
+typedef struct OS_SCB {
+ U8 cb_type; /* Control Block Type */
+ U8 mask; /* Semaphore token mask */
+ U16 tokens; /* Semaphore tokens */
+ struct OS_TCB *p_lnk; /* Chain of tasks waiting for tokens */
+} *P_SCB;
+
+typedef struct OS_MUCB {
+ U8 cb_type; /* Control Block Type */
+ U8 prio; /* Owner task default priority */
+ U16 level; /* Call nesting level */
+ struct OS_TCB *p_lnk; /* Chain of tasks waiting for mutex */
+ struct OS_TCB *owner; /* Mutex owner task */
+} *P_MUCB;
+
+typedef struct OS_XTMR {
+ struct OS_TMR *next;
+ U16 tcnt;
+} *P_XTMR;
+
+typedef struct OS_TMR {
+ struct OS_TMR *next; /* Link pointer to Next timer */
+ U16 tcnt; /* Timer delay count */
+ U16 info; /* User defined call info */
+} *P_TMR;
+
+typedef struct OS_BM {
+ void *free; /* Pointer to first free memory block */
+ void *end; /* Pointer to memory block end */
+ U32 blk_size; /* Memory block size */
+} *P_BM;
+
+/* Definitions */
+#define __TRUE 1
+#define __FALSE 0
+#define NULL ((void *) 0)
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/all_includes.h Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,117 @@
+#include "mbed.h"
+#include "USBHostSerial.h"
+#include "fichier_map.h"
+#include "ident_crac.h"
+
+#include "can.h"
+#include "ident.h"
+
+#include "ktypes.h"
+
+#include "IHM.h"
+
+extern Serial pc; // tx, rx
+extern short cooXdepart,cooYdepart;
+
+extern "C" void mbed_reset();
+
+#define NOMBRE_COINS 6
+#define NOMBRE_GOBELETS 5
+#define NOMBRE_PIEDS 16
+
+
+#define VAL 2
+#define DIST_DISCONT 80 //80
+
+#define MAX_X 32
+#define MAX_Y 22
+
+#define BLEU 0
+#define ROUGE 1
+
+#define M_PI 3.14159265358979323846
+#define DELTA_ANGLE 0.006136 //2*3.14159265358979323846/1024.
+
+//#define SEUIL_DISCONTINUITE 10
+
+
+#define DEBUGING 1
+//#define COODEBUGING 1
+
+#ifdef TETE_EN_BAS
+ #define COEF_TETE_EN_BAS -1
+#else
+ #define COEF_TETE_EN_BAS 1
+#endif
+
+#ifdef DEBUGING
+ #define DEBUG_PRINTF pc.printf
+#else
+ #define DEBUG_PRINTF
+#endif
+
+#ifdef COODEBUGING
+ #define COO_PRINTF pc.printf
+#else
+ #define COO_PRINTF
+#endif
+
+
+typedef struct
+{
+char command[3] ;
+char string_character[17];
+unsigned char length_command;
+unsigned short debut;
+unsigned short fin;
+unsigned char count;
+unsigned char scan_interval;
+unsigned char number_of_scan;
+char created_command[32];
+unsigned short length_reponse;
+unsigned short number_of_full_frame;
+unsigned short size_of_incomplete_frame;
+} T_cmd;
+
+extern unsigned short angle_cartographie;
+extern short cooX_demande,cooY_demande; // coo du point a mesure dans le repere absolue de la table
+extern short cooXdepart,cooYdepart; // coo debut du match dans le repere absolue de la table
+extern short cooX_actuelle, cooY_actuelle,teta_actuelle; // coo du robot dans le repere absolue de la table
+extern short x_telemetre, y_telemetre; // coo dans le repere du telemetre
+extern double teta,teta_actuelle_rad; // angle
+extern unsigned char flag_mbed_reset;
+
+typedef enum
+{
+ BEGIN_CONNECTION,
+ WAIT_CONNECTION,
+ CONNECTION_OK,
+ TRANSITION,
+ DETECTION,
+ TELEMETRE_GOBELET_CONNU,
+ ENVOI_CAN_ECRAN,
+ ENVOI_CAN_STRAT,
+ SEND_COMMAND,
+ WAIT_ECHO_COMMAND,
+ WAIT_STATUS,
+ WAIT_ANSWER_BEGIN,
+ WAIT_TIMESTAMP,
+ WAIT_FULL_FRAME,
+ WAIT_INCOMPLETE_FRAME,
+ SEND_STATE,
+ MS2,
+ MS_ECHO,
+ BEFORE_END,
+ END,
+ END2,
+ END3,
+ RESET,
+} ETAT;
+
+extern ETAT etat_connection;
+
+void automate_connection(void);
+
+
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/fichier_map.cpp Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,66 @@
+#include "all_includes.h"
+
+
+void affiche_map_terminal(char (*ptr_map)[MAX_X])
+{
+ unsigned char i=0,j=0;
+ for(i=0;i<MAX_Y;i++)
+ {
+ for(j=0;j<MAX_X;j++)
+ {
+ DEBUG_PRINTF("%c",(ptr_map[ MAX_Y-1-i][ MAX_X-1-j])*187+32);
+ }
+ DEBUG_PRINTF("\n");
+ }
+}
+
+
+void init_map(char (*ptr_map)[MAX_X])
+{
+ unsigned char i=0;
+ for(i=1;i<MAX_X-1;i++)
+ {
+ ptr_map[00][ i]=1;
+
+ }
+ for(i=0;i<MAX_X;i++)
+ {
+ ptr_map[MAX_Y-1][ i]=1;
+ }
+ for(i=0;i<MAX_Y;i++)
+ {
+ ptr_map[ i][00]=1;
+ ptr_map[ i][MAX_X-1]=1;
+ }
+ // trou représentant le telemetre
+ ptr_map[(cooYdepart+15)/100][(cooXdepart+75)/100]=0;
+ // cercle du gateau
+ ptr_map[0][14]=0;
+ ptr_map[0][16]=0;
+ ptr_map[1][14]=1;
+ ptr_map[1][16]=1;
+ ptr_map[2][15]=1;
+
+
+}
+void vide_map(char (*ptr_map)[MAX_X])
+{
+ unsigned char i,j;
+ for(i=1;i<MAX_X-1;i++) // On garde les contours
+ {
+ for(j=1;j<MAX_Y-1;j++)// On garde les contours
+ {
+ ptr_map[ j][ i]=0;
+ }
+ }
+ // trou représentant le telemetre
+ ptr_map[(cooYdepart+15)/100][(cooXdepart+75)/100]=0;
+ // cercle du gateau
+ ptr_map[0][14]=0;
+ ptr_map[0][16]=0;
+ ptr_map[1][14]=1;
+ ptr_map[1][16]=1;
+ ptr_map[2][15]=1;
+
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fichier_map.h Wed Apr 15 06:23:18 2015 +0000 @@ -0,0 +1,9 @@ +#define MAX_X 32 + + +void affiche_map_terminal(char (*ptr_map)[MAX_X]); + +void init_map(char (*ptr_map)[MAX_X]); + +void vide_map(char (*ptr_map)[MAX_X]); +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ktypes.h Wed Apr 15 06:23:18 2015 +0000 @@ -0,0 +1,52 @@ +#ifndef __KTYPES_H__ +#define __KTYPES_H__ + +/* FILE: ktypes.h */ +/****************************************************************************************/ +/* MODULE NAME: None */ +/* */ +/* AUTHOR : Jacques-Olivier KLEIN */ +/* */ +/* EMAIL : jacques-olivier.klein@u-psud.fr */ +/* */ +/* INSTITUTION: IUT de CACHAN - 9 av. de la div. Leclerc - 94230 CACHAN */ +/* */ +/* DATE : 03/07/2012 */ +/* CPU : FREESCALE MC9S12XS128MAA */ +/* BOARD : CACHAN Xboard+MicroB12 */ +/* OS : None */ +/* */ +/* DESCRIPTION: D�finition des types de longueurs fixes */ +/****************************************************************************************/ + +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + + +typedef unsigned char UINT8; +typedef unsigned short UINT16; +typedef unsigned long UINT32; +typedef signed char SINT8; +typedef signed short SINT16; +typedef signed long SINT32; + +typedef unsigned char INT8U; +typedef unsigned short INT16U; +typedef unsigned long INT32U; +typedef signed char INT8S; +typedef signed short INT16S; +typedef signed long INT32S; + +typedef unsigned char U8; +typedef unsigned short U16; +typedef signed short S16; + +typedef volatile unsigned char VUINT8; + + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp Wed Apr 15 06:23:18 2015 +0000
@@ -0,0 +1,731 @@
+#include "mbed.h"
+#include "all_includes.h"
+#include "USBHostSerial.h"
+#include <stdio.h>
+#define RVISION 1000
+#define TETABALISE 0.785398
+
+// LED
+DigitalOut myled[4]={LED1,LED2,LED3,LED4};
+// end LED
+
+Serial pc(USBTX, USBRX); // tx, rx
+CAN can(p30,p29);
+DigitalIn pot2(p20);
+
+CANMessage msgTx; // EMISSION
+CANMessage msgRx;
+CANMessage can_MsgRx[SIZE_FIFO]; // RECEPTION
+
+Timer t;
+Timeout flipper;
+
+unsigned char flag_timeout=1; // quand 1 pas de timeout si 0 timeout
+
+void fonction_timeout()
+{
+ flag_timeout=0;
+}
+
+typedef struct{
+ short X;
+ short Y;
+ double teta;
+ short Xabs;
+ short Yabs;
+ double teta_abs;
+
+
+
+ }T_pass;
+
+T_pass passage[20];
+
+unsigned short d1=0,d2=0;
+char buffer[66],com_echo_command[16],com_status_command[4],com_echo[16],com_status[4], time_stamp_and_sum[6],vide[1],final_LF[1];
+unsigned short status=0, distance=0,old_distance=0,d=0;
+unsigned short discont_dist[VAL][2]={{0},{0}};
+signed short discont_check[VAL][2]={{0},{0}};
+double x1=0,y1=0,x2=0,y2=0;
+char variable_interupt_ecran = 0;
+char variable_interupt_strat = 0;
+char compteur_passage=0;
+unsigned short DIST=0,Centre_Y_pass=0;
+short coeff_directeur=0,old_coeff_directeur=0, Centre_X_pass=0, Gobelet_found_X=0;
+
+/*************************** coo demande pour la cartographie **************************/
+short cooX_demande=0,cooY_demande=0; // coo du point a mesure dans le repere absolue de la table en mm
+unsigned short angle_cartographie = 0; // angle demande centre sur le point demande en degre
+/***************************************************************************************/
+
+/*************************** coo de debut de match du robot **************************/
+short cooXdepart=0,cooYdepart=0; // coo debut du match dans le repere absolue de la table
+
+/***************************************************************************************/
+
+/*************************** coo actuelle du robot **************************/
+short cooX_actuelle=965, cooY_actuelle=0,teta_actuelle = 90; // coo du robot dans le repere absolue de la table
+
+/***************************************************************************************/
+
+/********************* coo des points mesure par le telemetre **************************/
+short x_telemetre=0, y_telemetre=0; // coo dans le repere du telemetre
+short x_absolu=0, y_absolu=0;
+double teta = 0,teta_actuelle_rad=90; //90 // angle
+/***************************************************************************************/
+
+
+/*
+Sensor Commands
+MDMS-Command max 32 bytes min 16 bytes
+GDGS-Command max 14 bytes min 13 bytes
+BM-Command max 4 bytes min 3 bytes
+QT-Command max 4 bytes min 3 bytes
+RS-Command max 4 bytes min 3 bytes
+TM-Command max 5 bytes min 4 bytes
+SS-Command max 10 bytes min 9 bytes
+CR-Command max 6 bytes min 5 bytes
+HS-Command max 5 bytes min 4 bytes
+DB-Command max 6 bytes min 5 bytes
+VV-Command max 4 bytes min 3 bytes
+PP-Command max 4 bytes min 3 bytes
+II Command max 4 bytes min 3 bytes
+*/
+
+T_cmd MS_all = {{"MS"},{},16,44,725,1,1,0}; // vision max du telemetre avec la resolution la plus forte
+T_cmd MS_centre_avant = {{"MS"},{},16,55,215,1,1,1}; // vision angle avant autorise
+T_cmd MS_centre_arriere = {{"MS"},{},16,55,215,1,1,1}; // vision angle arriere autorise
+
+T_cmd MS_avant_moyenne = {{"MS"},{},16,508,724,27,1,1}; // vision angle avant avec un gros cluster pour faire la detection des dangers
+T_cmd MS_arriere_moyenne = {{"MS"},{},16,508,724,27,1,1}; // vision angle avant avec un gros cluster pour faire la detection des dangers
+
+T_cmd MS_one = {{"MS"},{},16,240,240,1,1,0}; // vision cluster de 1
+T_cmd MS_one_shot = {{"MS"},{},16,384,384,1,1,0};
+
+T_cmd MS_center = {{"MS"},{},16,44,725,1,1,1};
+
+//T_cmd MS_center={{"MS"},{},3,436 ,724,1,0,1}; // 90� face avant
+
+
+ETAT etat_connection=BEGIN_CONNECTION;
+
+void create_command(T_cmd *Pcmd)
+{
+ switch(Pcmd->command[0])
+ {
+ case 'M': // manquue string characters pour l'instant
+ sprintf(Pcmd->created_command,"%s%04d%04d%02d%01d%02d\n"
+ ,Pcmd->command,Pcmd->debut,Pcmd->fin,Pcmd->count,Pcmd->scan_interval,Pcmd->number_of_scan);
+ Pcmd->number_of_full_frame=(((Pcmd->fin)-(Pcmd->debut)+1)/32);
+ Pcmd->size_of_incomplete_frame=(((Pcmd->fin)-(Pcmd->debut)+1)%32);
+ Pcmd->length_reponse=((Pcmd->length_command)+1)*2+5+10+Pcmd->number_of_full_frame*66+Pcmd->size_of_incomplete_frame+3;
+ break;
+
+ default: sprintf(Pcmd->created_command,"%s%s\n",Pcmd->command,Pcmd->string_character);
+ break;
+
+ }
+}
+
+
+
+
+
+
+int main()
+{
+ unsigned char i=0,j=0,sum;
+ unsigned long temps=0,diff_temps,old_temps;
+ short cooX=0,cooY=0,compteur_global=0;
+ double Angle=0;
+ unsigned char swap_distance[66]; //66
+ char status_buff[5],number_of_scan_remaining_buff[3],c;
+
+// cration des commande
+create_command(&MS_all);
+create_command(&MS_centre_avant);
+create_command(&MS_centre_arriere);
+create_command(&MS_avant_moyenne);
+create_command(&MS_arriere_moyenne);
+create_command(&MS_one);
+create_command(&MS_center);
+
+// wait(2);
+ USBHostSerial serial;
+ pc.baud(921600);
+
+
+// initialisation du CAN
+ can.frequency(1000000); // vitesse du bus can
+ can.attach(&can_ISR_Reader); // Fonction appeler lors de l'interruption CAN en reception
+
+// message CAN autorise a declenche l'interruption
+ CAN2_wrFilter(RECEIVE_ODOMETRIE); // message odometrie pour pouvoir mettre a jour la position du robot au moment du tir telemetre
+ CAN2_wrFilter(TELEMETRE_RTR_CARTO); // message de demande de cartographie
+ CAN2_wrFilter(RESET_TELEMETRE); // message de reset de la carte telemetre
+
+
+ DEBUG_PRINTF("Debut du programme de Bruno LARNAUDIE\r\n");
+ myled[2] = 1;
+
+ while(1)
+ {
+ myled[1] = 1;
+
+
+ switch(etat_connection)
+ {
+ case BEGIN_CONNECTION: DEBUG_PRINTF("host serial launch\n\r");
+ etat_connection=WAIT_CONNECTION;
+ break;
+
+ case WAIT_CONNECTION: DEBUG_PRINTF("wait for connection\n\r");
+ while(!serial.connect())
+ wait(1);
+ DEBUG_PRINTF("Host device connected\n\r");
+ //serial.printf("SS750000\n"); // envoi la commande au laser
+ //wait_ms(10);
+ serial.printf("RS\n");
+ while(serial.available())
+ serial.getc();
+ wait_ms(100);
+ while(serial.available())
+ serial.getc();
+ wait_ms(100);
+ while(serial.available())
+ serial.getc();
+ etat_connection=CONNECTION_OK;
+ break;
+
+ case CONNECTION_OK : DEBUG_PRINTF("state connection ok\n\r");
+ wait(1);
+ if(!serial.connected())
+ etat_connection=WAIT_CONNECTION;
+ else
+ {
+ if(serial.available()!=0)
+ {
+ DEBUG_PRINTF("Vidage de la memoire usb serial\n\r");
+ etat_connection=CONNECTION_OK;
+ while (serial.available()!=0)
+ {
+ DEBUG_PRINTF("%c",serial.getc());
+ }
+ }
+ else
+ {
+ DEBUG_PRINTF("Buffer est vide\n");
+ etat_connection=TRANSITION;
+ }
+ }
+ break;
+
+ case TRANSITION: // preparation de la commande a envoyer et calcul de la longeur de la reponse
+ DEBUG_PRINTF("Transition\n\r");
+ wait_ms(100);
+ MS_center=MS_all;
+ etat_connection=SEND_COMMAND;
+ break;
+
+ case SEND_COMMAND: // envoi de la commande
+ DEBUG_PRINTF("MS\n");
+ if(!serial.connected())
+ etat_connection=WAIT_CONNECTION;
+ else
+ {
+ DEBUG_PRINTF("command_send\n");
+ MS_center.created_command[15]=10;
+ serial.printf(MS_center.created_command); // envoi la commande au laser
+ MS_center.created_command[15]=0;
+ DEBUG_PRINTF("%s",MS_center.created_command);
+ /*flag_timeout=1;
+ flipper.attach(&fonction_timeout, 0.1); // setup flipper to call flip after 2 seconds
+ */etat_connection=WAIT_ECHO_COMMAND;
+ }
+ break;
+
+ case WAIT_ECHO_COMMAND:// attente de la reponse
+ if(!serial.connected())
+ etat_connection=WAIT_CONNECTION;
+ else
+ {
+ if(serial.available()>=(MS_center.length_command+5)) // Attend d'avoir recu les caracteres de status
+ {
+ MS_center.created_command[15]=10;
+ for(i=0;i<(MS_center.length_command);i++)
+ {
+ c=serial.getc();
+ if(MS_center.created_command[i]==c)
+ {
+ }
+ else
+ {
+ DEBUG_PRINTF("retour incorrect\n");
+ etat_connection=RESET;
+ }
+ }
+ serial.readBuf(status_buff,5);
+ if((status_buff[0]=='0')&&(status_buff[1]=='0')&&(status_buff[2]=='P')&&(status_buff[3]==10)&&(status_buff[4]==10))
+ {
+ etat_connection=WAIT_ANSWER_BEGIN;
+ status_buff[3]=0;
+ }
+ else
+ {
+ etat_connection=RESET;
+ DEBUG_PRINTF("status incorrect\n");
+ }
+ }
+ else if(flag_timeout==0)
+ {
+ flag_timeout=1;
+ DEBUG_PRINTF("TIMEOUT\n");
+ etat_connection=BEFORE_END;
+ }
+ }
+ break;
+
+
+ case WAIT_ANSWER_BEGIN:// attente de l'encapsulage des datas
+ if(!serial.connected())
+ etat_connection=WAIT_CONNECTION;
+ else
+ {
+ if(serial.available()>=(MS_center.length_command+4)) // Attend d'avoir recu les caractères de status
+ {
+ // DEBUG_PRINTF("command_echo\n");
+ for(i=0;i<(MS_center.length_command)-3;i++)
+ {
+ c=serial.getc();
+ if(MS_center.created_command[i]==c)
+ {
+ // DEBUG_PRINTF("%c",c);
+
+ }
+ else
+ {
+ etat_connection=CONNECTION_OK;
+ DEBUG_PRINTF("retour incorrect=%c\n",c);
+ }
+ }
+ serial.readBuf(number_of_scan_remaining_buff,3);
+
+ number_of_scan_remaining_buff[2]=0;
+ // DEBUG_PRINTF("scan_remaining=%s\n",number_of_scan_remaining_buff);
+ // DEBUG_PRINTF("99b et timestamp\n");
+ if(serial.available()>=4)
+ serial.readBuf(status_buff,4);
+ if(serial.available()>=6)
+ serial.readBuf(time_stamp_and_sum,6);
+ temps= (((((unsigned long)(time_stamp_and_sum[0]-0x30))<<18)&0xFC0000)
+ |((((unsigned long)(time_stamp_and_sum[1]-0x30))<<12)&0x03F000)
+ |((((unsigned long)(time_stamp_and_sum[2]-0x30))<<06)&0x000FC0)
+ |((((unsigned long)(time_stamp_and_sum[3]-0x30)))&0x00003F));
+
+ /*flipper.detach();
+ flag_timeout=1;
+ flipper.attach(&fonction_timeout, 0.2); // setup flipper to call flip after 2 seconds
+ */etat_connection=WAIT_FULL_FRAME;
+
+ }
+ else if(flag_timeout==0)
+ {
+ flag_timeout=1;
+ DEBUG_PRINTF("TIMEOUT\n");
+ etat_connection=CONNECTION_OK;
+ }
+ }
+ break;
+
+
+ case WAIT_FULL_FRAME: // attente d'une trame pleine
+
+ msgTx.id=0x315;
+ msgTx.len=8;
+ msgTx.format=CANStandard;
+ msgTx.type=CANData;
+ compteur_global=0;
+
+ for(i=0;i<MS_center.number_of_full_frame;i++)
+ {
+ //DEBUG_PRINTF("sa=%02d ",serial.available());
+ sum=0;
+ for(j=0;j<66;j=j+2)
+ {
+ while(serial.available()<2);
+ //DEBUG_PRINTF("%02d ",serial.available());
+ swap_distance[j]=serial.getc();
+ swap_distance[j+1]=serial.getc();
+
+ if(j==64)
+ {
+ if((((sum&0x3F)+0x30)==(swap_distance[j]))&&(swap_distance[j+1]==10))
+ {
+ etat_connection=WAIT_INCOMPLETE_FRAME;
+ }
+ else
+ {
+ DEBUG_PRINTF("error");
+ etat_connection=BEFORE_END;
+ }
+ if((MS_center.size_of_incomplete_frame==0)&&(i==MS_center.number_of_full_frame-1)) // envoi du dernier point si que des trames completes
+ {
+ COO_PRINTF("%+05d%+05d\n",cooX,cooY);
+ }
+ }
+ else
+ {
+ sum=sum+swap_distance[j]+swap_distance[j+1];
+ distance=(((unsigned short)(swap_distance[j]-0x30)<<6)&0xFC0)|(((unsigned short)(swap_distance[j+1]-0x30))&0x3F);
+ Angle=M_PI/2+(COEF_TETE_EN_BAS*(MS_center.debut+(j/2+i*32)*MS_center.count)-384)*DELTA_ANGLE;
+ /////////////////////////
+ if(distance<=20 || distance>=4000)
+ distance=4000;
+ /////////////////////////
+
+ cooX=(short)(cos(Angle)*distance);
+ cooY=(short)(sin(Angle)*distance);
+
+ /*msgTx.data[(compteur_global*2)%8]=(char)(cooX/10); // 40
+ msgTx.data[(compteur_global*2+1)%8]=(char)(cooY/10);// 40
+
+ compteur_global++;
+ if((((compteur_global)%4)==0)&&(compteur_global>=3))
+ {
+ can.write(msgTx);
+ //wait_ms(1);
+ }*/
+
+ if((old_distance > distance+DIST_DISCONT || old_distance+DIST_DISCONT<distance)&&(old_distance!=0))
+ {
+
+ if((old_distance+DIST_DISCONT<distance)&&(old_distance<RVISION) &&(d1==0))
+ {
+ d1=old_distance;
+ x1=(short)(old_distance*cos(Angle));
+ y1=(unsigned short)(old_distance*sin(Angle));
+ }
+
+ else if( (old_distance > (distance+DIST_DISCONT)) &&(distance<RVISION) &&(d2==0)&&(d1!=0) )
+ {
+ d2=distance;
+ x2=(short)(distance*cos(Angle));
+ y2=(unsigned short)(distance*sin(Angle));
+ }
+
+ if((d1!=0)&&(d2!=0))
+ {
+ // calcul de la distance entre 2 points avec la discontinuit� de distance et pyhtagore
+ DIST= sqrt( (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) ) ; //1.220
+
+
+ if(DIST >= 400)
+ {
+ compteur_passage++;
+
+ DEBUG_PRINTF("\n\nPASSAGE numero %d:",compteur_passage);
+ DEBUG_PRINTF("\nLargeur: %d mm",DIST);
+ DEBUG_PRINTF("\nDistance: %d mm",(d1+d2)/2);
+ DEBUG_PRINTF("\nAngle: %lf ",Angle);
+ DEBUG_PRINTF("\nx2=%lf\tx1=%lf\ty2=%lf\ty1=%lf",x2,x1,y2,y1);
+
+ teta_actuelle_rad=teta_actuelle*M_PI/180;
+
+ Centre_X_pass = (x2+x1)/2;
+ Centre_Y_pass = (y2+y1)/2;
+
+ teta = atan2((double)Centre_X_pass,(double)Centre_Y_pass);
+
+
+ DEBUG_PRINTF("\nCentre passage en X = %d\t Centre passage en Y = %d , teta = %lf\n",Centre_X_pass,Centre_Y_pass,teta);
+
+
+ DEBUG_PRINTF("\nd1= %d , d2= %d , teta= %lf, teta_actuelle= %lf",d1,d2,teta,teta_actuelle_rad);
+ x_absolu = cooX_actuelle + ((d1+d2)/2)*cos(teta+teta_actuelle_rad);
+ y_absolu = cooY_actuelle + ((d1+d2)/2)*sin(teta+teta_actuelle_rad);
+
+ passage[compteur_passage-1].X=Centre_X_pass;
+ passage[compteur_passage-1].Y=Centre_Y_pass;
+ passage[compteur_passage-1].teta=teta;
+ passage[compteur_passage-1].Xabs=x_absolu;
+ passage[compteur_passage-1].Yabs=y_absolu;
+ passage[compteur_passage-1].teta_abs=teta+teta_actuelle_rad;
+
+
+
+
+ DEBUG_PRINTF("\n xabs= %d yabs= %d\n",x_absolu,y_absolu);
+
+ }
+
+ //wait(3);
+ d1=0;
+ d2=0;
+ }
+
+ coeff_directeur = (y2-y1)/(x2-x1);
+ //DEBUG_PRINTF("\nCOEFF DIRECTEUR = %d", coeff_directeur);
+ //if((old_coeff_directeur && coeff_directeur) == 1)
+ //DEBUG_PRINTF("\rBORD\r");
+
+ }
+
+ old_coeff_directeur = coeff_directeur;
+ old_distance = distance;
+
+
+ }
+ }
+
+
+ } //DEBUG_PRINTF(status_buff);
+
+ //flipper.detach(); // setup flipper to call flip after 2 seconds
+ break;
+
+ case WAIT_INCOMPLETE_FRAME: DEBUG_PRINTF("\nWAIT_INCOMPLETE_FRAME\n");
+ // attente d'une trame non pleine
+ sum=0;
+
+ for(j=0;j<(MS_center.size_of_incomplete_frame*2)+1;j=j+2)
+ {
+ while(serial.available()<2);
+ //DEBUG_PRINTF("%02d ",serial.available());
+ swap_distance[j]=serial.getc();
+ swap_distance[j+1]=serial.getc();
+ //DEBUG_PRINTF("%02d ",j);
+ if(j==(MS_center.size_of_incomplete_frame*2))
+ {
+ while(serial.available()<1);
+ //DEBUG_PRINTF("%02d ",j);
+ swap_distance[j+2]=serial.getc();
+ //DEBUG_PRINTF("sum=%02d calcul=%02d\n",(sum&0x3F)+0x30,(((swap_distance[j]))));
+ if((((sum&0x3F)+0x30)==(swap_distance[j]))&&(swap_distance[j+1]==10)&&(swap_distance[j+2]==10))
+ {
+ //DEBUG_PRINTF("i=%02d Good",i);
+ etat_connection=WAIT_INCOMPLETE_FRAME;
+ }
+ else
+ {
+ DEBUG_PRINTF("error\n");
+ etat_connection=BEFORE_END;
+ }
+ }
+ else
+ {
+ sum=sum+swap_distance[j]+swap_distance[j+1];
+ distance=(((unsigned short)(swap_distance[j]-0x30)<<6)&0xFC0)|(((unsigned short)(swap_distance[j+1]-0x30))&0x3F);
+ Angle=M_PI/2+(COEF_TETE_EN_BAS*(MS_center.debut+(j/2+i*32)*MS_center.count)-384)*DELTA_ANGLE;
+ /////////////////////////
+ if(distance<=20 || distance>=4000)
+ distance=4000;
+ /////////////////////////
+
+ cooX=(short)(cos(Angle)*distance);
+ cooY=(short)(sin(Angle)*distance);
+
+
+ /*msgTx.data[(compteur_global*2)%8]=(char)(cooX/10); // 40
+ msgTx.data[(compteur_global*2+1)%8]=(char)(cooY/10);// 40
+
+ compteur_global++;
+ if((((compteur_global)%4)==0)&&(compteur_global>=3))
+ {
+ can.write(msgTx);
+ //wait_ms(1);
+ }
+
+ */
+
+ if((old_distance > distance+DIST_DISCONT || old_distance+DIST_DISCONT<distance)&&(old_distance!=0))
+ {
+
+ if((old_distance+DIST_DISCONT<distance)&&(old_distance<RVISION) &&(d1==0))
+ {
+ d1=old_distance;
+ x1=(short)(old_distance*cos(Angle));
+ y1=(unsigned short)(old_distance*sin(Angle));
+ }
+
+ else if( (old_distance > (distance+DIST_DISCONT)) &&(distance<RVISION) &&(d2==0)&&(d1!=0) )
+ {
+ d2=distance;
+ x2=(short)(distance*cos(Angle));
+ y2=(unsigned short)(distance*sin(Angle));
+ }
+
+ if((d1!=0)&&(d2!=0))
+ {
+ // calcul de la distance entre 2 points avec la discontinuite de distance et pyhtagore
+ DIST= sqrt( (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) ) ; //1.220
+
+
+ if(DIST >= 400)
+ {
+ compteur_passage++;
+
+ DEBUG_PRINTF("\n\nPASSAGE numero %d:",compteur_passage);
+ DEBUG_PRINTF("\nLargeur: %d mm",DIST);
+ DEBUG_PRINTF("\nDistance: %d mm",(d1+d2)/2);
+ DEBUG_PRINTF("\nAngle: %lf ",Angle);
+ DEBUG_PRINTF("\nx2=%lf\tx1=%lf\ty2=%lf\ty1=%lf",x2,x1,y2,y1);
+
+ teta_actuelle_rad=teta_actuelle*M_PI/180;
+
+ Centre_X_pass = (x2+x1)/2;
+ Centre_Y_pass = (y2+y1)/2;
+
+ teta = atan2((double)Centre_X_pass,(double)Centre_Y_pass);
+
+
+ DEBUG_PRINTF("\nCentre passage en X = %d\t Centre passage en Y = %d , teta = %lf",Centre_X_pass,Centre_Y_pass,teta);
+
+ DEBUG_PRINTF("\nd1= %d , d2= %d , teta= %lf, teta_actuelle= %lf",d1,d2,teta,teta_actuelle_rad);
+ x_absolu = cooX_actuelle + ((d1+d2)/2)*cos(teta+teta_actuelle_rad);
+ y_absolu = cooY_actuelle + ((d1+d2)/2)*sin(teta+teta_actuelle_rad);
+ DEBUG_PRINTF("\n xabs= %d yabs= %d\n",x_absolu,y_absolu);
+
+ passage[compteur_passage-1].X=Centre_X_pass;
+ passage[compteur_passage-1].Y=Centre_Y_pass;
+ passage[compteur_passage-1].teta=teta;
+ passage[compteur_passage-1].Xabs=x_absolu;
+ passage[compteur_passage-1].Yabs=y_absolu;
+ passage[compteur_passage-1].teta_abs=teta+teta_actuelle_rad;
+
+
+ }
+
+ //wait(3);
+ d1=0;
+ d2=0;
+ }
+
+ coeff_directeur = (y2-y1)/(x2-x1);
+
+
+ }
+
+ old_coeff_directeur = coeff_directeur;
+ old_distance = distance;
+
+ }
+ }
+ DEBUG_PRINTF("Fin de tir\n");
+ myled[2] = !myled[2];
+
+ etat_connection=ENVOI_CAN_STRAT;
+ break;
+
+ /* case SEND_STATE:
+ compteur_passage =0;
+
+ diff_temps=temps-old_temps;
+ old_temps=temps;
+ msgTx.id=0x400;
+ msgTx.len=2;
+ msgTx.format=CANStandard;
+ msgTx.type=CANData;
+ msgTx.data[0]=(unsigned char)(diff_temps>>8); // x0
+ msgTx.data[1]=(unsigned char)(diff_temps); // suite de x0
+ can.write(msgTx);
+ if(flag_mbed_reset==1)
+ {
+ etat_connection=RESET;
+ }
+ else
+ {
+ if(MS_center.number_of_scan==0)
+ etat_connection=WAIT_ANSWER_BEGIN;
+ else
+ etat_connection=SEND_COMMAND;
+ }
+ break;
+ */
+
+ case DETECTION:
+
+ break;
+
+
+ case ENVOI_CAN_STRAT: for(i=0;i<9;i++){
+ if((abs(TETABALISE-passage[i].teta_abs))<(abs(TETABALISE-passage[i+1].teta_abs))){
+ x_absolu=passage[i].Xabs;
+ y_absolu=passage[i].Yabs;
+ }
+ }
+
+ msgTx.id=0x315;
+ msgTx.len=4;
+ msgTx.format=CANStandard;
+ msgTx.type=CANData;
+ msgTx.data[1] = (x_absolu);
+ msgTx.data[0] = (x_absolu>>8);
+ msgTx.data[3] = (y_absolu);
+ msgTx.data[2] = (y_absolu>>8);
+
+ compteur_passage =0;
+
+ can.write(msgTx);
+ if((can.read(msgRx))&&(msgRx.id==0x130)){
+ cooX_actuelle= msgRx.data[0]||msgRx.data[1]<<8;
+ cooY_actuelle= msgRx.data[2]||msgRx.data[3]<<8;
+ }
+ variable_interupt_strat = 0;
+ msgTx.id=0x999;
+ if(flag_mbed_reset==1)
+ {
+ etat_connection=RESET;
+ }
+ else
+ {
+ if(MS_center.number_of_scan==0)
+ etat_connection=WAIT_ANSWER_BEGIN;
+ else
+ etat_connection=SEND_COMMAND;
+ }
+ break;
+
+
+
+ case MS_ECHO: DEBUG_PRINTF("MS_echo\n");
+ while(serial.available()==0);
+ while (serial.available())
+ {
+
+ DEBUG_PRINTF("%c", serial.getc());
+
+ }
+ etat_connection=BEFORE_END;
+ break;
+
+ case BEFORE_END :
+ DEBUG_PRINTF("end\n");
+ etat_connection=END;
+ break;
+
+ case END : break;
+
+ case END2 : break;
+
+ case END3 :
+ break;
+
+ case RESET: serial.printf("RS\n");
+ while(serial.available())
+ serial.getc();
+ wait_ms(100);
+ while(serial.available())
+ serial.getc();
+ mbed_reset();
+
+ break;
+
+ default:
+ DEBUG_PRINTF("default\n\r");
+ break;
+
+ }
+ myled[1] = 0;
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Wed Apr 15 06:23:18 2015 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/9ad691361fac \ No newline at end of file