1 /*********************************************************************
   2     FileName:           USB_MZ.c
   3     Dependencies:       See #includes
   4     Processor:          PIC32MZ2048EFH100
   5     Hardware:           MainBrain MZ
   6     Complier:           XC32 4.40
   7     Author:             Larry Knight 2023
   8 
   9     Software License Agreement:
  10         This software is licensed under the Apache License Agreement
  11 
  12     Description:
  13         Enumerates as a High Speed interface class device,
  14         Uses Microsoft OS Descriptors to load a Winusb driver,
  15         Endpoint 1 is the receiving endpoint,
  16         Endpoint 2 is the transmitting endpoint,
  17         Host application sends commands to the device, 
  18         Device responds to the commands by sending requested data to the Host
  19 
  20     Device Interface GUID:
  21         2b8a8216-c82a-4a91-a8bc-a12129d2d70b
  22 
  23     References:        
  24         https://techcommunity.microsoft.com/t5/microsoft-usb-blog/how-does-usb-stack-enumerate-a-device/ba-p/270685#_Configuration_Descriptor_Request
  25 
  26     Registry Stuff:
  27         HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\usbflags\120900010200
  28         HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB\VID_1209&PID_0001\MainBrain_MZ
  29 
  30     Change History:
  31         Basic framework completed 06/16/2024
  32 
  33 /***********************************************************************/
  34 
  35 #include <xc.h>
  36 #include <string.h>
  37 #include <stdbool.h>
  38 #include "MainBrain.h"
  39 #include <proc/p32mz2048efh100.h>
  40 bool isConnected = false;
  41 const uint8_t seqSize = 16;
  42 
  43 union
  44 {
  45     float fval;
  46     uint8_t bytes[4];
  47 } converter;
  48 
  49 typedef struct
  50 {
  51     volatile unsigned char bmRequestType;
  52     volatile unsigned char bRequest;
  53     volatile unsigned short wValue;
  54     volatile unsigned short wIndex;
  55     volatile unsigned short wLength;
  56 } USB_TRANSACTION;
  57 
  58 USB_TRANSACTION USB_transaction;
  59 
  60 USB_ENDPOINT EP[3];
  61 
  62 uint8_t device_descriptor[] = 
  63 {
  64     /* Descriptor Length                        */ 0x12, //Size of this descriptor in bytes
  65     /* DescriptorType: DEVICE                   */ 0x01,
  66     /* bcdUSB (ver 2.0)                         */ 0x00,0x02,
  67     /* bDeviceClass                             */ 0x00,
  68     /* bDeviceSubClass                          */ 0x00,
  69     /* bDeviceProtocol                          */ 0x00,
  70     /* bMaxPacketSize0                          */ 0x40, //0x40 for High Speed USB
  71     /* idVendor                                 */ 0x09,0x12, /*VID */
  72     /* idProduct                                */ 0x01,0x00, 
  73     /* bcdDevice                                */ 0x00,0x02, 
  74     /* iManufacturer                            */ 0x01,
  75     /* iProduct                                 */ 0x02,
  76     /* iSerialNumber                            */ 0x02, 
  77     /* bNumConfigurations                       */ 0x01
  78 };
  79 
  80 uint8_t config_descriptor[] = 
  81 {
  82     // Configuration Descriptor
  83     0x09,                       //Descriptor size in bytes
  84     0x02,                       //Descriptor type
  85     0x20,0x00,                  //Total length of data
  86     0x01,                       //Number of interfaces
  87     0x01,                       //Index value of this configuration
  88     0x00,                       //Configuration string index
  89     0xc0,                       // Attributes, see usb_device.h
  90     0x32,                       // Max power consumption (2X mA)
  91                                                         
  92     // Interface Descriptor
  93     0x09,                       // Size of this descriptor in bytes
  94     0x04,                       // INTERFACE descriptor type
  95     0x00,                       // Interface Number
  96     0x00,                       // Alternate Setting Number
  97     0x02,                       // Number of endpoints in this intf
  98     0x00,                       // Class code
  99     0x00,                       // Subclass code
 100     0x00,                       // Protocol code
 101     0x00,                       // Interface string index
 102     
 103     // Endpoint Descriptor
 104     //EP01 OUT
 105     0x07,                       //Size of this descriptor in bytes
 106     0x05,                       //Endpoint Descriptor
 107     0x01,                       //EndpointAddress
 108     0x02,                       //Attributes
 109     0x40,0x00,                  //size
 110     0x00,                       //Interval   
 111     //EP02 IN                      
 112     0x07,                       //Size of this descriptor in bytes
 113     0x05,                       //Endpoint Descriptor
 114     0x82,                       //EndpointAddress
 115     0x02,                       //Attributes
 116     0x40,0x00,                  //size
 117     0x00                        //Interval
 118 };
 119 
 120 uint8_t device_qualifier[] = 
 121 {
 122     0x0a,                       //Size of this descriptor in bytes
 123     0x06,                       //Descriptor type (0x06)
 124     0x00, 0x02,                 //BCD - USB version number (Must be 0x200 or higher)
 125     0xff,                       //Class Code
 126     0xff,                       //Subclass Code
 127     0xff,                       //Protocol
 128     0x40,                       //bMaxPacketSize0
 129     0x01,                       //bNumConfigurations
 130     0x00                        //Reserved
 131 };
 132 
 133 uint8_t MSOSDescriptor[] =
 134 {   
 135     //bLength - length of this descriptor in bytes
 136     0x0b,                           
 137     //bDescriptorType - "string"
 138     0x03,                           
 139     //qwSignature - special values that specifies the OS descriptor spec version that this firmware implements
 140     'M',0,'S',0,'F',0,'T',0,'1',0,'0',0,'0',0,
 141     //bMS_VendorCode - defines the "GET_MS_DESCRIPTOR" bRequest literal value
 142     0xee,
 143     //bFlags
 144     //a new flags field has been added to the Microsoft OS string descriptor that can be used to indicate support for the ContainerID descriptor
 145     //Bit 1 of this field is used to indicate support for the ContainerID descriptor
 146     0x00                            
 147 };    
 148 
 149 //Extended Compatability ID Feature Descriptor
 150 uint8_t ExtCompatIDFeatureDescriptor[] =
 151 {
 152     0x28, 0x00, 0x00, 0x00,                             /* dwLength Length of this descriptor */
 153     0x00, 0x01,                                         /* bcdVersion = Version 1.0 */
 154     0x04, 0x00,                                         /* wIndex = 0x0004 */
 155     0x01,                                               /* bCount = 1 */
 156     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,           /* Reserved */
 157     0x00,                                               /* Interface number = 0 */
 158     0x01,                                               /* Reserved */
 159     0x57, 0x49, 0x4E, 0x55, 0x53, 0x42, 0x00, 0x00,     /* compatibleID */ //WINUSB
 160     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,     /* subCompatibleID */
 161     0x00, 0x00, 0x00, 0x00, 0x00, 0x00                  /* Reserved */
 162 };
 163     
 164 uint8_t ExtPropertyFeatureDescriptor[] =
 165 {
 166     //----------Header Section--------------
 167     0x8e, 0x00, 0x00, 0x00,                             //dwLength (4 bytes)
 168     0x00, 0x01,                                         //bcdVersion = 1.00
 169     0x05, 0x00,                                         //wIndex
 170     0x01, 0x00,                                         //wCount - 0x0001 "Property Sections" implemented in this descriptor
 171     //----------Property Section 1----------
 172     0x84, 0x00, 0x00, 0x00,                             //dwSize - 132 bytes in this Property Section
 173     0x01,0x00, 0x00, 0x00,                              //dwPropertyDataType (Unicode string)
 174     0x28, 0x00,                                         //wPropertyNameLength - 40 bytes in the bPropertyName field
 175     'D', 0, 'e', 0, 'v', 0, 'i', 0, 'c', 0, 'e', 0, 'I', 0, 'n', 0, 't', 0, 'e', 0, 'r', 0, 'f', 0, 'a', 0, 'c', 0,
 176         'e', 0, 'G', 0, 'U', 0, 'I', 0, 'D', 0,  0x00, 0x00,  //bPropertyName - "DeviceInterfaceGUID"
 177     0x4e, 0x00, 0x00, 0x00,                             //dwPropertyDataLength - 78 bytes in the bPropertyData field (GUID value in UNICODE formatted string, with braces and dashes)
 178     //Device Interface GUID
 179     //{2b8a8216-c82a-4a91-a8bc-a12129d2d70b}
 180     '{', 0, '2', 0, 'b', 0, '8', 0, 'a', 0, '8', 0, '2', 0, '1', 0, '6', 0, '-', 0, 'c', 0, '8', 0, '2', 0, 'a', 0, 
 181         '-', 0, '4', 0, 'a', 0, '9', 0, '1', 0, '-', 0, 'a', 0, '8', 0, 'b', 0, 'c', 0, '-', 0, 'a', 0, '1', 0, '2', 
 182         0, '1', 0, '2', 0, '9', 0, 'd', 0, '2', 0, 'd', 0, '7', 0, '0', 0, 'b', 0, '}', 0, 0x00, 0x00
 183     //{57c3b8e0-852f-11d0-bf32-00a0c90ab50f}
 184     //'{', 0, '5', 0, '7', 0, 'c', 0, '3', 0, 'b', 0, '8', 0, 'e', 0, '0', 0, '-', 0, '8', 0, '5', 0, '2', 0, 'f', 0, 
 185     //    '-', 0, '1', 0, '1', 0, 'd', 0, '0', 0, '-', 0, 'b', 0, 'f', 0, '3', 0, '2', 0, '-', 0, '0', 0, '0', 0, 'a', 
 186      //   0, '0', 0, 'c', 0, '9', 0, '0', 0, 'a', 0, 'b', 0, '5', 0, '0', 0, 'f', 0, '}', 0, 0x00, 0x00
 187 };    
 188 
 189 //Language - 0x0409 - English
 190 uint8_t string0[] =  {4, 0x03, 0x09, 0x04};
 191 
 192 //iManufacturer
 193 uint8_t string1[] = {28, 3, 'A', 0, 'n', 0, 't', 0, 'i', 0, 'm', 0, 'a', 0, 't', 0, 't', 0, 'e', 0, 'r', 0, '.', 0, 'm', 0, 'e', 0};   
 194 
 195 //iProduct      
 196 uint8_t string2[] = {26, 3, 'M', 0, 'a', 0, 'i', 0, 'n', 0, 'B', 0, 'r', 0, 'a', 0, 'i', 0, 'n', 0, ' ', 0, 'M', 0, 'Z', 0};
 197  
 198 //iSerialNumber 
 199 uint8_t string3[] = {10, 3, '0', 0, '0', 0, '0', 0, '1', 0};
 200 
 201 void EP0_control_transaction(void);
 202 void USB_queue_EP0(uint8_t *buffer, int size, int max_size);
 203 void EP0_RX(int length);
 204 void EP0_TX(void);
 205 void Host_CMDs(void);
 206 
 207 int EP1_RX(void);
 208 int EP2_TX(volatile uint8_t *tx_buffer);
 209 int EP0_Wait_TXRDY(void);
 210 int EP2_Wait_TXRDY(void);
 211 volatile uint8_t usbAddress;
 212 volatile bool SetAddress = true;
 213 volatile uint8_t USBState;
 214 volatile uint8_t DeviceState;
 215 
 216 void USB_init(void)
 217 {
 218     //Disable the module
 219     USBCSR0bits.SOFTCONN = 0;     
 220 
 221     //Set the initial state of the device
 222     USBState = DETACHED;
 223     DeviceState = DISCONNECTED;
 224     
 225     //disable while module is setup
 226     USBCSR0bits.SOFTCONN = 0;   
 227     
 228     //EP 1
 229     //These bits select which endpoint registers are accessed through addresses 0x3010-0x301F
 230     USBCSR3bits.ENDPOINT = 1;
 231 
 232     //RX
 233     USBOTGbits.RXFIFOSZ = 0x06;
 234     USBIENCSR1bits.RXMAXP = 64;
 235     USBIENCSR3bits.RXFIFOSZ = 0x09;
 236     USBFIFOAbits.RXFIFOAD = 0x0280;
 237     USBIENCSR3bits.PROTOCOL = 0x02;
 238     USBIENCSR3bits.TEP = 0x01;
 239     USBIENCSR1bits.FLUSH = 1;
 240     
 241     
 242     //TX
 243     USBOTGbits.TXFIFOSZ = 0x06;
 244     USBIENCSR0bits.TXMAXP = 64;
 245     USBIENCSR3bits.TXFIFOSZ = 0x09;
 246     USBFIFOAbits.TXFIFOAD = 0x0080;
 247     USBIENCSR2bits.PROTOCOL = 0x02;
 248     USBIENCSR2bits.TEP = 0x02;
 249     USBIENCSR0bits.FLUSH = 1;
 250 
 251     //Endpoint 1 is RX
 252     USBE1CSR0bits.MODE = 0;
 253     
 254     //Endpoint 2 is TX
 255     USBE2CSR0bits.MODE = 1;
 256     
 257     // Set endpoint 0 buffer to 64 bytes (multiples of 8).
 258     USBE0CSR0bits.TXMAXP = 64; 
 259 
 260     //Clear the address
 261     usbAddress = 0;                
 262     USBCSR0bits.FUNC = 0;   
 263     
 264     //VBUS Monitoring ON
 265     USBCRCONbits.VBUSMONEN = 1;
 266     
 267     //Enable the reset interrupt
 268     USBCSR2bits.RESETIE = 1;    
 269     
 270     //Enable the USB interrupt
 271     IEC4bits.USBIE = 1;    
 272     
 273     //Enable USB module interrupt
 274     USBCRCONbits.USBIE = 1;     
 275     
 276     //Clear the USB interrupt flag.
 277     IFS4bits.USBIF = 0;         
 278     
 279     //USB Interrupt Priority 7
 280     //Must be 7. Cannot use any other priority.
 281     //Internally, the USB hardware expects SRS context switching 
 282     //to avoid stack usage ? that?s why priority of 7 is required 
 283     IPC33bits.USBIP = 7;        
 284     IPC33bits.USBIS = 3; 
 285     
 286     //See DISNYET (same bit as PIDERR)
 287     USBE1CSR1bits.PIDERR = 1;   
 288 
 289     //Enable High Speed (480Mbps) USB mode
 290     USBCSR0bits.HSEN = 1;      
 291     
 292     //Enable the module
 293     USBCSR0bits.SOFTCONN = 1;     
 294 }
 295 
 296 //USB
 297 void __attribute__((vector(_USB_VECTOR), interrupt(ipl7srs), nomips16)) USB_handler()
 298 {       
 299     //Reset
 300     if(USBCSR2bits.RESETIF)
 301     {
 302         USBState = DETACHED;
 303         
 304         // 1 = Endpoint is TX
 305         USBE1CSR0bits.MODE = 1;     
 306         
 307         // Set endpoint 0 buffer to 64 bytes (multiples of 8)
 308         USBE0CSR0bits.TXMAXP = 64; 
 309         
 310         // Endpoint 0 Operating Speed Control bits
 311         USBE0CSR2bits.SPEED = 1;
 312         
 313         // Endpoint 1: TX Endpoint Operating Speed Control bits - High speed        
 314         USBE1CSR2bits.SPEED = 1;        
 315         
 316         // Endpoint 1 - Maximum TX Payload Per Transaction Control bits
 317         USBE1CSR0bits.TXMAXP = 64;
 318         
 319         // Endpoint 1 - TX Endpoint Protocol Control bits 
 320         USBE1CSR2bits.PROTOCOL = 2; 
 321 
 322         //PROTOCOL<1:0>: RX/TX Endpoint Protocol Control bits 
 323         //11 = Interrupt
 324         //10 = Bulk
 325         //01 = Isochronous
 326         //00 = Control
 327         
 328         USBCSR1bits.EP1TXIE = 1;    // Endpoint 1 TX interrupt enable
 329         USBCSR2bits.EP1RXIE = 1;    // Endpoint 1 RX interrupt enable
 330                     
 331         USBCSR2bits.RESETIF = 0;
 332     }
 333     
 334     /* Endpoint 0 Interrupt Handler */
 335     if(USBCSR0bits.EP0IF == 1)
 336     { 
 337         // Do we need the set the USB address?
 338         if (SetAddress == true)
 339         {
 340             //This sets a limit of 127
 341             USBCSR0bits.FUNC = usbAddress & 0x7F;
 342             SetAddress = false;
 343         }
 344         
 345         if(USBE0CSR0bits.RXRDY)
 346         {
 347             EP0_RX(USBE0CSR2bits.RXCNT);
 348             
 349             USB_transaction.bmRequestType = EP[0].rx_buffer[0];
 350             USB_transaction.bRequest = EP[0].rx_buffer[1];
 351             USB_transaction.wValue = (int)(EP[0].rx_buffer[3] << 8) | EP[0].rx_buffer[2];
 352             USB_transaction.wIndex = (int)(EP[0].rx_buffer[5] << 8) | EP[0].rx_buffer[4];
 353             USB_transaction.wLength = (int)(EP[0].rx_buffer[7] << 8) | EP[0].rx_buffer[6];
 354             
 355             EP0_control_transaction();
 356             
 357             // End of Data Control bit (Device mode) 
 358             if (USB_transaction.wLength == 0)
 359             {
 360                 USBE0CSR0bits.DATAEND = 1; 
 361             }
 362         }
 363                 
 364         if (USBE0CSR0bits.SETEND) 
 365         {
 366             USBE0CSR0bits.SETENDC = 1;
 367         }
 368         
 369         // Clear the USB EndPoint 0 Interrupt Flag.
 370         USBCSR0bits.EP0IF = 0;  
 371     }
 372     
 373     //Endpoint 1 Interrupt Handler
 374     if(USBCSR1bits.EP1RXIF == 1)
 375     { 
 376         EP1_RX();
 377                 
 378         Host_CMDs();
 379         
 380         USBCSR1bits.EP1RXIF = 0;
 381     }
 382 
 383     IFS4bits.USBIF = 0;   
 384 }
 385 
 386 void Host_CMDs()
 387 {
 388   uint8_t test;
 389   uint8_t SeqNum;
 390   
 391   switch (EP[1].rx_buffer[0])
 392   {
 393       //connected
 394       case 0x00:
 395           if(EP[1].rx_buffer[1] == 0x02)
 396           {
 397               Beep();
 398               DeviceState = CONNECTED;
 399           }
 400           
 401           if(EP[1].rx_buffer[1] == 0x05)
 402           {
 403               DeviceState = DISCONNECTED;
 404           }
 405         break;
 406           
 407       //Data check
 408       case 0x01:
 409           EP[2].tx_buffer[0] = 0x55;
 410           EP2_TX(EP[2].tx_buffer);
 411         break;
 412         
 413       //Send Message
 414       case 0x02:
 415         strcpy(myStr, "USB - Test");
 416           
 417         //set message pending
 418         Message = 1;
 419         break;
 420         
 421       //Back light
 422       case 0x03:
 423         Backlight_Control(EP[1].rx_buffer[1]); 
 424         break;
 425         
 426         //Beep the buzzer
 427       case 0x04:
 428         Beep(); 
 429         break;
 430         
 431       case 0x05:
 432         
 433           break;
 434           
 435         //Send a Directive
 436       case 0x07:
 437           //set the board address
 438             current_board_address = EP[1].rx_buffer[1];
 439             
 440             //calculate SRAM address from board number
 441             int a = current_board_address * 0x400;
 442             
 443             //set the directive
 444             REN70V05_WR(a, EP[1].rx_buffer[2]);
 445             
 446             //write speed data to SRAM
 447             REN70V05_WR((a + 23), EP[1].rx_buffer[3]);
 448             REN70V05_WR((a + 24), EP[1].rx_buffer[4]);
 449             
 450             //Write the direction data
 451             REN70V05_WR(a + 25, EP[1].rx_buffer[5]);
 452             
 453             //Set directive as active
 454             requestDirective = true;
 455         break;
 456         
 457         //Get board info
 458       case 0x08:
 459             //set the board address
 460             current_board_address = EP[1].rx_buffer[1];
 461 
 462             //calculate SRAM address
 463             a = current_board_address * 0x400;
 464             
 465             //get the data from SRAM and load it into USB buffer
 466             for(int i=1;i<24;i++)
 467             {
 468                 EP[2].tx_buffer[i + 9] = REN70V05_RD(a + i);
 469             }
 470             
 471             //and writes it to the TX buffer    
 472              EP2_TX(EP[2].tx_buffer);  
 473 
 474             //Get board info
 475             getBoardInfo = true;
 476           
 477             screen = BOARD_SCREEN;
 478             NeedsRefresh = true;
 479            
 480           break;
 481         //Get board data
 482       case 0x09:
 483             //set the board address
 484             current_board_address = EP[1].rx_buffer[1];
 485 
 486             //calculate SRAM address
 487             a = current_board_address * 0x400;
 488             
 489 //          //Set the directive     
 490 //          REN70V05_WR(a, 5);
 491 //          
 492 //          //Position
 493 //          EP[2].tx_buffer[26] = REN70V05_RD(a + 26);  
 494 //          EP[2].tx_buffer[27] = REN70V05_RD(a + 27);  
 495 //          EP[2].tx_buffer[28] = REN70V05_RD(a + 28);  
 496 //          EP[2].tx_buffer[29] = REN70V05_RD(a + 29);  
 497 //      
 498             requestDirective = true;
 499             
 500             //Send data to the host     
 501              EP2_TX(EP[2].tx_buffer);  
 502           break;
 503 
 504       case 0x0a:
 505 
 506         break;
 507 
 508         case 0x0b:
 509             
 510             break;
 511             
 512       //This is where we send the full 64 bytes of data whenever the 
 513       //Host requests it
 514       case 0x64:                
 515         //ADC Data
 516         //Current
 517         ADC0_result = ADC0_result * 0.00161172 * 342;
 518         converter.fval = ADC0_result;
 519 
 520         EP[2].tx_buffer[3] = converter.bytes[0];
 521         EP[2].tx_buffer[2] = converter.bytes[1];
 522         EP[2].tx_buffer[1] = converter.bytes[2];
 523         EP[2].tx_buffer[0] = converter.bytes[3];
 524 
 525         //4095 = 3.3v  3.3 / 4095 = 0.000805861v per ADC bit 6/3 = 2
 526         //so 3.0V = 24V input
 527         ADC6_result = (ADC6_result * 0.000805861 * 7.56) + 0.7;
 528           
 529         //voltage 
 530         converter.fval = ADC6_result;
 531         
 532         EP[2].tx_buffer[7] = converter.bytes[0];          
 533         EP[2].tx_buffer[6] = converter.bytes[1];
 534         EP[2].tx_buffer[5] = converter.bytes[2];          
 535         EP[2].tx_buffer[4] = converter.bytes[3];
 536         
 537         //set the board address
 538         current_board_address = EP[1].rx_buffer[1];
 539 
 540         //position counter
 541         a = current_board_address * 0x400;
 542 
 543         
 544 //      //get the data from USB buffer and fill SRAM
 545 //      for(int i=23;i<65;i++)
 546 //      {
 547 //          REN70V05_WR(a + i, EP[1].rx_buffer[i]);
 548 //      }
 549         
 550 //      //fill the buffer to send to the host
 551 //      for(int i=8;i<65;i++)
 552 //      {
 553 //          EP[2].tx_buffer[i] = REN70V05_RD(a + i);
 554 //      }
 555 
 556         //any memory access has to check for another request in process
 557         if(IO_Locked == false)
 558         {
 559             //Position
 560             EP[2].tx_buffer[26] = REN70V05_RD(a+26);    
 561             EP[2].tx_buffer[27] = REN70V05_RD(a+27);    
 562             EP[2].tx_buffer[28] = REN70V05_RD(a+28);    
 563             EP[2].tx_buffer[29] = REN70V05_RD(a+29);    
 564             EP[2].tx_buffer[30] = REN70V05_RD(a+30);    
 565             EP[2].tx_buffer[31] = REN70V05_RD(a+31);    
 566         
 567             //write speed data to SRAM
 568             REN70V05_WR((a + 23), EP[1].rx_buffer[3]);
 569             REN70V05_WR((a + 24), EP[1].rx_buffer[4]);
 570 
 571 //          //Direction
 572 //          REN70V05_WR((a + 25), EP[1].rx_buffer[5]);
 573 //          
 574             //set the directive
 575             REN70V05_WR(a, 5);
 576 
 577             //Set directive as active
 578             requestDirective = true;
 579         }
 580         
 581         //Send data to the host 
 582          EP2_TX(EP[2].tx_buffer);  
 583         
 584         break;
 585     case 0x65:
 586             USB_init();
 587             break;
 588   default:
 589       //default
 590       break;    
 591   }
 592     updated = true;
 593 }
 594 
 595 //DEBUG
 596 void dumpMem(void)
 597 {
 598     //Command
 599     REN70V05_RD((((current_board_address) - 1) * 0x400) + 0);
 600     Binary2ASCIIHex(mdata_70V05);
 601     WriteChar(40, 10, 'M', black, white);
 602     WriteChar(55, 10, d_hex[1], black, white);
 603     WriteChar(70, 10, d_hex[0], black, white);
 604 
 605     //Command from USB
 606     WriteChar(140, 10, 'U', black, white);
 607     Binary2ASCIIHex(EP[1].rx_buffer[0]);
 608     WriteChar(155, 10, d_hex[1], black, white);
 609     WriteChar(170, 10, d_hex[0], black, white);
 610 
 611     //Board Address
 612     REN70V05_RD((((current_board_address) - 1) * 0x400) + 1);
 613     Binary2ASCIIHex(mdata_70V05);
 614     WriteChar(40, 30, d_hex[1], black, white);
 615     WriteChar(55, 30, d_hex[0], black, white);
 616 
 617     //Data 1 lo-byte
 618     REN70V05_RD((((current_board_address) - 1) * 0x400) + 2);
 619     Binary2ASCIIHex(mdata_70V05);
 620     WriteChar(70, 50, d_hex[1], black, white);
 621     WriteChar(85, 50, d_hex[0], black, white);
 622 
 623     //Data 1 hi-byte
 624     REN70V05_RD((((current_board_address) - 1) * 0x400) + 3);
 625     Binary2ASCIIHex(mdata_70V05);
 626     WriteChar(40, 50, d_hex[1], black, white);
 627     WriteChar(55, 50, d_hex[0], black, white);
 628 
 629     //Data 2 lo-byte
 630     REN70V05_RD((((current_board_address) - 1) * 0x400) + 4);
 631     Binary2ASCIIHex(mdata_70V05);
 632     WriteChar(70, 70, d_hex[1], black, white);
 633     WriteChar(85, 70, d_hex[0], black, white);  
 634     
 635     //Data 2 hi-byte
 636     REN70V05_RD((((current_board_address) - 1) * 0x400) + 5);
 637     Binary2ASCIIHex(mdata_70V05);
 638     WriteChar(40, 70, d_hex[1], black, white);
 639     WriteChar(55, 70, d_hex[0], black, white);  
 640     
 641     //Sub-Command
 642     REN70V05_RD((((current_board_address) - 1) * 0x400) + 6);
 643     Binary2ASCIIHex(mdata_70V05);
 644     WriteChar(40, 90, d_hex[1], black, white);
 645     WriteChar(55, 90, d_hex[0], black, white);  
 646 }
 647 
 648 int EP2_TX(volatile uint8_t* tx_buffer)
 649 {
 650     int cnt = 0;
 651     
 652     //Load the data to TX in array
 653     EP[2].tx_num_bytes = 64;
 654     
 655     for (cnt = 0; cnt < 64; cnt++)
 656     {
 657         EP[2].tx_buffer[cnt] = tx_buffer[cnt];
 658     }       
 659         
 660     //a pointer
 661     uint8_t *FIFO_buffer;
 662 
 663     //load the pointer with the address of the TX buffer
 664     FIFO_buffer = (uint8_t *)&USBFIFO2;
 665     
 666     //return if the TX buffer is empty
 667     if (EP2_Wait_TXRDY())
 668     {
 669         return 0;
 670     }
 671     
 672     //reset cnt
 673     cnt = 0;
 674     
 675     //send data until the TX buffer is empty
 676     while (cnt < EP[2].tx_num_bytes)
 677     {
 678         *FIFO_buffer = EP[2].tx_buffer[cnt]; // Send the bytes
 679 
 680         cnt++;
 681         
 682         // Have we sent 64 bytes?
 683         if ((cnt > 0) && (cnt % 64 == 0))
 684         {
 685             //Set TXRDY and wait for it to be cleared before sending any more bytes
 686             USBE2CSR0bits.TXPKTRDY = 1;            
 687             if(EP2_Wait_TXRDY())
 688             {
 689                 return 0;
 690             }            
 691         }
 692     }
 693 
 694     USBE2CSR0bits.TXPKTRDY = 1;            
 695 }
 696 
 697 int EP1_RX()
 698 {
 699     unsigned char *FIFO_buffer;
 700     int cnt;
 701     int rx_bytes;
 702     //get the number of bytes received
 703     rx_bytes = USBE1CSR2bits.RXCNT;
 704     
 705     //USB FIFO Data Register 1
 706     FIFO_buffer = (unsigned char *)&USBFIFO1; 
 707     
 708     //load the array with the bytes in the buffer
 709     for(cnt = 0; cnt < rx_bytes; cnt++)
 710     {
 711         EP[1].rx_buffer[cnt] = *(FIFO_buffer + (cnt & 3));
 712     }
 713     
 714     //unload the RX FIFO
 715     USBE1CSR1bits.RXPKTRDY = 0;
 716 
 717     return rx_bytes;
 718 }
 719 
 720 void EP0_control_transaction()
 721 {
 722     uint16_t length;
 723 
 724     if ((USB_transaction.bmRequestType == 0xC0) && (USB_transaction.wIndex == 0x04))
 725     {
 726        length = USB_transaction.wLength;
 727        if (length > sizeof(ExtCompatIDFeatureDescriptor))
 728        {
 729            length = sizeof(ExtCompatIDFeatureDescriptor);
 730        }
 731        
 732        USB_queue_EP0(ExtCompatIDFeatureDescriptor, sizeof(ExtCompatIDFeatureDescriptor), length); 
 733        
 734        return;
 735     }
 736     
 737     //Class specific, device to host, interface target
 738     if(USB_transaction.bmRequestType == 0xc1)    
 739     {
 740         //Check if the host is requesting an MS feature descriptor
 741         if(USB_transaction.bRequest == 0xee)
 742         {
 743             //Figure out which descriptor is being requested
 744             if(USB_transaction.wIndex == 0x05)    
 745             {
 746                 //Determine number of bytes to send to host 
 747                 //Lesser of: requested amount, or total size of the descriptor
 748                 length = sizeof(ExtPropertyFeatureDescriptor);
 749                 if(USB_transaction.wLength < length)
 750                 {
 751                     length = USB_transaction.wLength;
 752                 }
 753                 
 754                 USB_queue_EP0(ExtPropertyFeatureDescriptor, sizeof(ExtPropertyFeatureDescriptor), length);  
 755                         
 756                 USBE0CSR0bits.TXRDY = 1;    
 757                 
 758                 return;
 759             }
 760         }
 761     }
 762     
 763     // We're not going to bother with whether bmRequestType is IN or OUT for the most part
 764     switch (USB_transaction.bRequest)
 765     {
 766         case 0xC:
 767         {
 768             USBE0CSR0bits.STALL = 1;
 769             break;
 770             
 771         }
 772         case 0x0: 
 773         {
 774             if (USB_transaction.bmRequestType == 0x80) // Get status
 775                 USB_queue_EP0(device_descriptor, 0, 0);
 776             if (USB_transaction.bmRequestType == 0x00) // Select function
 777                 USB_queue_EP0(device_descriptor, 0, 0);
 778             break;            
 779         }
 780         
 781         //Set USB address
 782         case 0x5: 
 783         {
 784             USBE0CSR0bits.RXRDYC = 1;
 785             usbAddress = EP[0].rx_buffer[2];
 786 
 787             SetAddress = true;
 788             break;
 789         }
 790         
 791         //added by chatgpt
 792         case 0xEE:  // Microsoft OS Descriptor request
 793         {
 794             if (USB_transaction.bmRequestType == 0xC0) // Vendor-specific request
 795             {
 796                 USB_queue_EP0(MSOSDescriptor, sizeof(MSOSDescriptor), USB_transaction.wLength);
 797             }
 798             break;
 799         }
 800         
 801         //Get descriptor
 802         case 0x6: 
 803         {
 804             switch (USB_transaction.wValue >> 8)
 805             {
 806                 //Device descriptor
 807                 case 0x1: 
 808                 {
 809                     USB_queue_EP0(device_descriptor, sizeof(device_descriptor), USB_transaction.wLength);                             
 810                     break;
 811                 }
 812                 
 813                 //Configuration descriptor
 814                 case 0x2: 
 815                 {
 816                     USB_queue_EP0(config_descriptor, sizeof(config_descriptor), USB_transaction.wLength);
 817                     break;
 818                 }
 819                 
 820                 //String descriptors
 821                 case 0x3: 
 822                 {          
 823                     switch (USB_transaction.wValue & 0xff)
 824                     {
 825                         //String 0 - Language ID
 826                         case 0x0: 
 827                         {
 828                             USB_queue_EP0(string0, sizeof(string0), USB_transaction.wLength);
 829                             break;
 830                         }
 831                         //String 1 - iManufacturer
 832                         case 0x1: 
 833                         {
 834                             USB_queue_EP0(string1, sizeof(string1), USB_transaction.wLength);                           
 835                             break;
 836                         }
 837                         //String 2 - iProduct
 838                         case 0x2: 
 839                         {
 840                             USB_queue_EP0(string2, sizeof(string2), USB_transaction.wLength);
 841                             break;
 842                         }
 843                         //String 3 - iSerialNumber
 844                         case 0x3: 
 845                         {
 846                             USB_queue_EP0(string3, sizeof(string3), USB_transaction.wLength);
 847                             break;
 848                         }
 849                         //MS OS Descriptor Query
 850                         case 0xee:
 851                         {
 852                             USB_queue_EP0(MSOSDescriptor, sizeof(MSOSDescriptor), USB_transaction.wLength);
 853                             break;
 854                         }                       
 855                         break;
 856                     }  
 857                     break;
 858                 }
 859                 
 860                 case 0x04: // Extended Compatibility ID Feature Descriptor
 861                 if (USB_transaction.wIndex == 0x0004)
 862                 {
 863                     USB_queue_EP0(ExtCompatIDFeatureDescriptor, sizeof(ExtCompatIDFeatureDescriptor), USB_transaction.wLength);
 864                 }
 865                 break;
 866                 
 867                 case 0x05: // Extended Properties Feature Descriptor
 868                 if (USB_transaction.wIndex == 0x0005)
 869                 {
 870                     USB_queue_EP0(ExtPropertyFeatureDescriptor, sizeof(ExtPropertyFeatureDescriptor), USB_transaction.wLength);
 871                 }
 872                 break;
 873 
 874             //Device Qualifier
 875                 case 0x6: 
 876                 {          
 877                     USB_queue_EP0(device_qualifier, sizeof(device_qualifier), USB_transaction.wLength);
 878                     break;
 879                 }                        
 880             }
 881             break;
 882         }
 883         
 884         // Set configuration
 885         case 0x9: 
 886         {
 887             //Enumeration complete!
 888             USBState = ATTACHED;
 889             break;
 890         }
 891         
 892         default: 
 893         {
 894             USBE0CSR0bits.STALL = 1;
 895             break;
 896         }  
 897     }
 898 }
 899 
 900 //USB_queue_EP0(config_descriptor, sizeof(config_descriptor), USB_transaction.wLength);
 901 void USB_queue_EP0(uint8_t *buffer, int size, int max_size)
 902 {
 903     int cnt;
 904     
 905     if (max_size < size)
 906         size = max_size;
 907     
 908     EP[0].tx_num_bytes = size;
 909     
 910     for (cnt = 0; cnt < size; cnt++)
 911     {
 912         EP[0].tx_buffer[cnt] = buffer[cnt];
 913     }       
 914     
 915     EP0_TX();
 916 }
 917 
 918 /* Non-blocking EP0_TX */
 919 void EP0_TX()
 920 {
 921     static int ep0_tx_cnt = 0;
 922     uint8_t *FIFO_buffer = (uint8_t *)&USBFIFO0;
 923 
 924     while ((ep0_tx_cnt < EP[0].tx_num_bytes) && !USBE0CSR0bits.TXRDY)
 925     {
 926         *FIFO_buffer = EP[0].tx_buffer[ep0_tx_cnt++];
 927         if ((ep0_tx_cnt % 64) == 0)
 928         {
 929             USBE0CSR0bits.TXRDY = 1;
 930             return; // Exit; next chunk will be sent in next ISR
 931         }
 932     }
 933 
 934     // Final chunk
 935     if (ep0_tx_cnt >= EP[0].tx_num_bytes)
 936     {
 937         USBE0CSR0bits.TXRDY = 1;
 938         ep0_tx_cnt = 0; // Reset for next transfer
 939     }
 940 
 941 }
 942 
 943 void EP0_RX(int length)
 944 {
 945     int cnt;
 946     uint8_t *FIFO_buffer;
 947     
 948     // Store number of bytes received
 949     EP[0].rx_num_bytes = USBE0CSR2bits.RXCNT;
 950     
 951     // Get 8-bit pointer to USB FIFO for endpoint 0
 952     FIFO_buffer = (uint8_t *)&USBFIFO0;
 953     
 954     for(cnt = 0; cnt < length; cnt++)
 955     {
 956         // Read in one byte at a time
 957         EP[0].rx_buffer[cnt] = *(FIFO_buffer + (cnt & 3));
 958     }
 959      
 960     USBE0CSR0bits.RXRDYC = 1;
 961 }
 962 
 963 int EP0_Wait_TXRDY()
 964 {
 965     int timeout;
 966     
 967     timeout = 0;
 968     
 969     while (USBE0CSR0bits.TXRDY)
 970     {
 971         timeout++;
 972         
 973         if (timeout > 5000)
 974         {
 975             return 1;
 976         }
 977     };
 978     
 979     return 0;
 980 }
 981 
 982 
 983 
 984 
 985 //int EP2_Wait_TXRDY(void)
 986 //{
 987 //    // Wait until the TX FIFO is empty before loading new data
 988 //    while (USBE2CSR0bits.FIFONE)
 989 //    ; // spin
 990 //
 991 //    // Set TXPKTRDY to indicate the packet is ready to send
 992 //    USBE2CSR0bits.TXPKTRDY = 1;
 993 //
 994 //    // Optionally, wait until the hardware clears TXPKTRDY
 995 //    while (USBE2CSR0bits.TXPKTRDY)
 996 //      ; // spin until packet has been sent
 997 //}
 998 
 999 
1000 
1001 int EP2_Wait_TXRDY()
1002 {
1003     int timeout;
1004     
1005     timeout = 0;
1006     
1007     while (USBE1CSR0bits.TXPKTRDY)
1008     {
1009         timeout++;
1010         
1011         if (timeout > 5000)
1012         {
1013             return 1;
1014         }
1015     };
1016     
1017     return 0;
1018 }
1019 
1020 void setTime(void)
1021 {
1022     //Unlock the registers
1023     RTCCONbits.RTCWREN = 1;
1024     
1025 //    //24 to 12 hour conversion
1026 //    if(EP[1].rx_buffer[1] > 12)
1027 //    {
1028 //        Binary2ASCIIBCD(EP[1].rx_buffer[1] - 12);
1029 //    }
1030 //    else
1031 //    {
1032         Binary2ASCIIBCD(EP[1].rx_buffer[1]);
1033 //    }
1034         
1035     RTCTIMEbits.HR10 = d1;
1036     RTCTIMEbits.HR01 = d0;
1037     
1038     hchar = hchar + 20;
1039     Binary2ASCIIBCD(EP[1].rx_buffer[2]);
1040 //    WriteChar(hchar, vchar, d1, 0x0);
1041 //    WriteChar(hchar, vchar, d0, 0x0);
1042    
1043     RTCTIMEbits.MIN10 = d1;
1044     RTCTIMEbits.MIN01 = d0;
1045 
1046     hchar = hchar + 20;
1047     Binary2ASCIIBCD(EP[1].rx_buffer[3]);
1048 //    WriteChar(hchar, vchar, d1, 0x0);
1049 //    WriteChar(hchar, vchar, d0, 0x0);
1050    
1051     
1052     RTCTIMEbits.SEC10 = d1;
1053     RTCTIMEbits.SEC01 = d0;    
1054 
1055     //Re-lock the registers
1056     RTCCONbits.RTCWREN = 0;
1057 }
1058 
1059 void SRAM2USB(void)
1060 {
1061     //Get Board Address
1062     current_board_address = EP[1].rx_buffer[1];
1063 
1064     for(int i=4;i<=63;i++)
1065     {
1066         EP[2].tx_buffer[i] = REN70V05_RD((((current_board_address) - 1) * 0x400) + i);
1067     }
1068 }
1069 
1070 void BoardData2SRAM(void)
1071 {
1072     //Get Board Address
1073     current_board_address = EP[1].rx_buffer[1];
1074     
1075     for(int i=0;i<=63;i++)
1076     {
1077         REN70V05_WR(((((current_board_address) - 1) * 0x400) + i), EP[1].rx_buffer[i]);
1078     }
1079     
1080     //dumpMem();
1081 }
1082 
1083 void USB2SRAM(void)
1084 {
1085     //Get Board Address
1086     current_board_address = EP[1].rx_buffer[1];
1087     
1088     for(int i=0;i<064;i++)
1089     {
1090         REN70V05_WR(((((current_board_address) - 1) * 0x400) + i), EP[1].rx_buffer[i]);
1091     }
1092 }