CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

some characters get lost with usb_put_packet

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
sinaloe



Joined: 24 Apr 2015
Posts: 3

View user's profile Send private message

some characters get lost with usb_put_packet
PostPosted: Sun Apr 26, 2015 6:24 am     Reply with quote

Hello.

I use the ex_usb_keyboard example as basis to use my Pic 18F4550 as HID device to write into a text editor on the connected PC. The Pic is connected to a Bluetooth module which gets characters one by one.
The Pic blinks for every character as expected but once in a while a character is not written to the text editor.

Here is my header file:
Code:

#ifndef __EX_USB_COMMON_H__
#define __EX_USB_COMMON_H__

//#define USB_ISR_POLLING

#include <18F4550.h>
#fuses HSPLL,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL5,CPUDIV1,VREGEN
#use delay(clock=48000000)

//leds ordered from bottom to top
#DEFINE LED1 PIN_A5  //green
#define LED2 PIN_B4  //yellow
#define LED3 PIN_A4  //red
#define STATUS_LED PIN_D7  //red
#define LEDS_OFF()   LED_OFF(LED1); LED_OFF(LED2); LED_OFF(LED3); LED_OFF(STATUS_LED)

//see section below labeled USB_CABLE_IS_ATTACHED
#define PIN_USB_SENSE   PIN_B0

#use rs232(baud=19200,parity=N,xmit=PIN_B3,rcv=PIN_B2,bits=8)

#ifndef LEDS_OFF
#define LEDS_OFF()
#endif

#define USB_CABLE_IS_ATTACHED() input(PIN_USB_SENSE)

#ifndef LED_ON
#define LED_ON(x) output_high(x)
#endif

#ifndef LED_OFF
#define LED_OFF(x) output_low(x)
#endif


And here the important parts of the source file:

Code:

#include <bt_hid_device.h>

/////////////////////////////////////////////////////////////////////////////
//
// Include the CCS USB Libraries.  See the comments at the top of these
// files for more information
//
/////////////////////////////////////////////////////////////////////////////
#include <pic18_usb.h>           //Microchip PIC18Fxx5x hardware layer for usb.c
#include <usb_desc_keyboard.h>   //USB Configuration and Device descriptors for this UBS device
#include <usb.c>                 //handles usb setup tokens and get descriptor reports

int altgr = 0;

/////////////////////////////////////////////////////////////////////////////
//
// usb_debug_task()
//
// When called periodically, displays debugging information over serial
// to display enumeration and connection states.  Also lights LED2 and LED3
// based upon enumeration and connection status.
//
/////////////////////////////////////////////////////////////////////////////
void usb_debug_task(void)
{
   static int8 last_connected;
   static int8 last_enumerated;
   int8 new_connected;
   int8 new_enumerated;

   new_connected=usb_attached();
   new_enumerated=usb_enumerated();

   if (new_connected)
      LED_ON(LED2);
   else
      LED_OFF(LED2);

   if (new_enumerated)
      LED_ON(LED3);
   else
      LED_OFF(LED3);

   last_connected=new_connected;
   last_enumerated=new_enumerated;
}

typedef enum
{
   KB_MODIFIER_LEFT_CTRL = 1,
   KB_MODIFIER_LEFT_SHIFT = 2,
   KB_MODIFIER_LEFT_ALT = 4,
   KB_MODIFIER_LEFT_GUI = 8,
   KB_MODIFIER_RIGHT_CTRL = 16,
   KB_MODIFIER_RIGHT_SHIFT = 32,
   KB_MODIFIER_RIGHT_ALT = 64, // Alt Gr
   KB_MODIFIER_RIGHT_GUI = 128
} kb_modifier_t;

typedef enum
{
   USB_KBD_SCANCODE_ESC = 0x29,
   USB_KBD_SCANCODE_CAPS_LOC = 0x39,
   USB_KBD_SCANCODE_F1 = 0x3A, //F2 is 0x3B, F3 is 0x3C, etc.  this is valid up to F12
   USB_KBD_SCANCODE_PRTSC = 0x46,
   USB_KBD_SCANCODE_SCROLL_LOCK = 0x47,
   USB_KBD_SCANCODE_PAUSE = 0x48,
   USB_KBD_SCANCODE_INS = 0x49,
   USB_KBD_SCANCODE_HOME = 0x4A,
   USB_KBD_SCANCODE_PG_UP = 0x4B,
   USB_KBD_SCANCODE_DEL = 0x4C,
   USB_KBD_SCANCODE_END = 0x4D,
   USB_KBD_SCANCODE_PG_DN = 0x4E,
   USB_KBD_SCANCODE_RIGHT = 0x4F,
   USB_KBD_SCANCODE_LEFT = 0x50,
   USB_KBD_SCANCODE_DOWN = 0x51,
   USB_KBD_SCANCODE_UP = 0x52,
   USB_KBD_SCANCODE_NUM_LOCK = 0x53,
   USB_KBD_SCANCODE_WIN_MENU = 0x65,
   USB_KBD_SCANCODE_F13 = 0x68,   //F14 is 0x69, F15 is 0x6A, etc.  this is valid up to F24
   USB_KBD_SCANCODE_HELP = 0x75,
   USB_KBD_SCANCODE_UNDO = 0x7A,
   USB_KBD_SCANCODE_CUT = 0x7B,
   USB_KBD_SCANCODE_COPY = 0x7C,
   USB_KBD_SCANCODE_PASTE = 0x7D,
   USB_KBD_SCANCODE_MUTE = 0x7F,
   USB_KBD_SCANCODE_VOL_UP = 0x80,
   USB_KBD_SCANCODE_VOL_DOWN = 0x81
} kb_scancode_t;

unsigned int16 scancodeEN(char c)
{
   unsigned int16 shift = 0;
   
   if ((c>='A')&&(c<='Z'))
   {
      c = tolower(c);
      shift = 0x100;
   }
   if ((c>='a')&&(c<='z'))
   {
      return(((c-='a')+4)|shift);
   }
   if ((c>='1')&&(c<='9'))
   {
      return((c-='0')+0x1D);
   }
   switch(c)
   {
      case '!':   return(0x11E);
      case '@':   return(0x11F);
      case '#':   return(0x120);
      case '$':   return(0x121);
      case '%':   return(0x122);
      case '^':   return(0x123);
      case '&':   return(0x124);
      case '*':   return(0x125);
      case '(':   return(0x126);
      case ')':   return(0x127);
      case '0':   return(0x27);
      case '\n':  return(0x28);  //enter
      case '\r':  return(0x28);  //enter
      case '\b':  return(0x2A);  //backspace
      case '\t':  return(0x2B);  //tab
      case ' ':   return(0x2C);  //space
      case '_':   return(0x12D);
      case '-':   return(0x2D);
      case '+':   return(0x12E);
      case '=':   return(0x2E);
      case '{':   return(0x12F);
      case '[':   return(0x2F);
      case '}':   return(0x130);
      case ']':   return(0x30);
      case '|':   return(0x131);
      case '\\':   return(0x31);
      case ':':   return(0x133);
      case ';':   return(0x33);
      case '"':   return(0x134);
      case '\'':   return(0x34);
      case '~':   return(0x135);
      case '`':   return(0x35);
      case '<':   return(0x136);
      case ',':   return(0x36);
      case '>':   return(0x137);
      case '.':   return(0x37);
      case '?':   return(0x138);
      case '/':   return(0x38);
   }
}

unsigned int16 scancodeFR(char c)
{
   ...
}


unsigned int16 scancodeDE(char c)
{
   ...
}

void main(void)
{
   unsigned int8 tx_msg[7];
   unsigned int16 scancode;
   
   //HW_INIT()
   LED_ON(LED1);
   LED_OFF(LED2);
   LED_OFF(LED3);
 
   usb_init_cs();

   long timeout;
     
   while (TRUE)
   {
      usb_task();
      usb_debug_task();
     
      if (usb_enumerated())
      {
         memset(tx_msg, 0x00, sizeof(tx_msg));

         timeout=0;

         while(!kbhit()&&(++timeout<50000));

         if (kbhit())
         {     
            LED_ON(STATUS_LED);
           
            if(input(PIN_D4)) scancode = scancodeDE(fgetc());
            if(input(PIN_D5)) scancode = scancodeEN(fgetc());
            if(input(PIN_D6)) scancode = scancodeFR(fgetc());
           
            if (bit_test(scancode, 8)) // Is bit 8 set? -> press shift
               tx_msg[0] = KB_MODIFIER_LEFT_SHIFT;
           
            if(altgr) // press Alt Gr if needed
            {
               tx_msg[0] = KB_MODIFIER_RIGHT_ALT;
               altgr = 0;
            }
           
            tx_msg[2] = scancode;
           
            LED_OFF(STATUS_LED);
         }
         usb_put_packet(1, tx_msg, sizeof(tx_msg), USB_DTS_TOGGLE);
      }
   }
}


Thanks in advance.

Best regards
Susanne
Ttelmah



Joined: 11 Mar 2010
Posts: 19499

View user's profile Send private message

PostPosted: Sun Apr 26, 2015 12:49 pm     Reply with quote

There is a potential problem with the way you sit and wait for kbhit.

If usb_task is not called at reasonable intervals things can/will go wrong.

To get really reliable USB, I never wait for more than a very few mSec anywhere in the code. Instead have an iinterrupt based timer for your timeout, and keep looping round the outer loop, rather than sitting in the wait.

In fact I don't see anywhere in the code, anything to increment timeout, so while waiting usb_task will never be called. Look at the warning in usb.h.
sinaloe



Joined: 24 Apr 2015
Posts: 3

View user's profile Send private message

PostPosted: Sat May 09, 2015 2:57 am     Reply with quote

Hello.

I am now using now the int_rda interrupt to read the data written by my serial bluetooth module.

Code:

#include <bt_hid_device.h>

/////////////////////////////////////////////////////////////////////////////
//
// Include the CCS USB Libraries.  See the comments at the top of these
// files for more information
//
/////////////////////////////////////////////////////////////////////////////
#include <pic18_usb.h>           //Microchip PIC18Fxx5x hardware layer for usb.c
#include <usb_desc_keyboard.h>   //USB Configuration and Device descriptors for this UBS device
#include <usb.c>                 //handles usb setup tokens and get descriptor reports

int altgr = 0;
char chr=0;
unsigned int8 tx_msg[7];

/////////////////////////////////////////////////////////////////////////////
//
// usb_debug_task()
//
// When called periodically, displays debugging information over serial
// to display enumeration and connection states.  Also lights LED2 and LED3
// based upon enumeration and connection status.
//
/////////////////////////////////////////////////////////////////////////////
void usb_debug_task(void)
{
   static int8 last_connected;
   static int8 last_enumerated;
   int8 new_connected;
   int8 new_enumerated;

   new_connected=usb_attached();
   new_enumerated=usb_enumerated();

   if (new_connected)
      LED_ON(LED2);
   else
      LED_OFF(LED2);

   if (new_enumerated)
      LED_ON(LED3);
   else
      LED_OFF(LED3);

   last_connected=new_connected;
   last_enumerated=new_enumerated;
}

typedef enum
{
   KB_MODIFIER_LEFT_CTRL = 1,
   KB_MODIFIER_LEFT_SHIFT = 2,
   KB_MODIFIER_LEFT_ALT = 4,
   KB_MODIFIER_LEFT_GUI = 8,
   KB_MODIFIER_RIGHT_CTRL = 16,
   KB_MODIFIER_RIGHT_SHIFT = 32,
   KB_MODIFIER_RIGHT_ALT = 64, // Alt Gr
   KB_MODIFIER_RIGHT_GUI = 128
} kb_modifier_t;

typedef enum
{
   USB_KBD_SCANCODE_ESC = 0x29,
   USB_KBD_SCANCODE_CAPS_LOC = 0x39,
   USB_KBD_SCANCODE_F1 = 0x3A, //F2 is 0x3B, F3 is 0x3C, etc.  this is valid up to F12
   USB_KBD_SCANCODE_PRTSC = 0x46,
   USB_KBD_SCANCODE_SCROLL_LOCK = 0x47,
   USB_KBD_SCANCODE_PAUSE = 0x48,
   USB_KBD_SCANCODE_INS = 0x49,
   USB_KBD_SCANCODE_HOME = 0x4A,
   USB_KBD_SCANCODE_PG_UP = 0x4B,
   USB_KBD_SCANCODE_DEL = 0x4C,
   USB_KBD_SCANCODE_END = 0x4D,
   USB_KBD_SCANCODE_PG_DN = 0x4E,
   USB_KBD_SCANCODE_RIGHT = 0x4F,
   USB_KBD_SCANCODE_LEFT = 0x50,
   USB_KBD_SCANCODE_DOWN = 0x51,
   USB_KBD_SCANCODE_UP = 0x52,
   USB_KBD_SCANCODE_NUM_LOCK = 0x53,
   USB_KBD_SCANCODE_WIN_MENU = 0x65,
   USB_KBD_SCANCODE_F13 = 0x68,   //F14 is 0x69, F15 is 0x6A, etc.  this is valid up to F24
   USB_KBD_SCANCODE_HELP = 0x75,
   USB_KBD_SCANCODE_UNDO = 0x7A,
   USB_KBD_SCANCODE_CUT = 0x7B,
   USB_KBD_SCANCODE_COPY = 0x7C,
   USB_KBD_SCANCODE_PASTE = 0x7D,
   USB_KBD_SCANCODE_MUTE = 0x7F,
   USB_KBD_SCANCODE_VOL_UP = 0x80,
   USB_KBD_SCANCODE_VOL_DOWN = 0x81
} kb_scancode_t;

// convert ascii character to USB HID Keyboard scancode.
// realize that there is no difference between 'A'/'a' or '1'/'!', they
// have the same scancode.  in order to differentiate between these the SHIFT
// modifier has to be set (see kb_modifier_t).
// see kb_scancode_t for other scancodes that are not ascii.
// bit8 will be set if shift needs to be set (for upper case chars or '!' vs '1')
unsigned int16 scancodeEN(char c)
{
   unsigned int16 shift = 0;
   
   if ((c>='A')&&(c<='Z'))
   {
      c = tolower(c);
      shift = 0x100;
   }
   if ((c>='a')&&(c<='z'))
   {
      return(((c-='a')+4)|shift);
   }
   if ((c>='1')&&(c<='9'))
   {
      return((c-='0')+0x1D);
   }
   switch(c)
   {
      case '[':   return(0x2F);
      case ')':   return(0x127);
      case '>':   return(0x137);
      case '<':   return(0x136);
      case '!':   return(0x11E);
      case '@':   return(0x11F);
      case '#':   return(0x120);
      case '$':   return(0x121);
      case '%':   return(0x122);
      case '^':   return(0x123);
      case '&':   return(0x124);
      case '*':   return(0x125);
      case '(':   return(0x126);
     
      case '0':   return(0x27);
      case '\n':  return(0x28);  //enter
      case '\r':  return(0x28);  //enter
      case '\b':  return(0x2A);  //backspace
      case '\t':  return(0x2B);  //tab
      case ' ':   return(0x2C);  //space
      case '_':   return(0x12D);
      case '-':   return(0x2D);
      case '+':   return(0x12E);
      case '=':   return(0x2E);
      case '{':   return(0x12F);
     
      case '}':   return(0x130);
      case ']':   return(0x30);
      case '|':   return(0x131);
      case '\\':   return(0x31);
      case ':':   return(0x133);
      case ';':   return(0x33);
      case '"':   return(0x134);
      case '\'':   return(0x34);
      case '~':   return(0x135);
      case '`':   return(0x35);
     
      case ',':   return(0x36);
     
      case '.':   return(0x37);
      case '?':   return(0x138);
      case '/':   return(0x38);
   }
}

#INT_RDA
void uart_handler(void)
{
      chr=getc();
}

//-

void usb_keyboard_task()
{
   
   unsigned int16 scancode;

   
   if (usb_tbe(1))
   {
      tx_msg[0] = 0x00;
      tx_msg[2] = 0x00;
     
      if (chr!=0)
      {     
         LED_ON(STATUS_LED);
         
         scancode = scancodeEN(chr);
           
         if (bit_test(scancode, 8)) // Is bit 8 set? -> press shift
            tx_msg[0] = KB_MODIFIER_LEFT_SHIFT;
           
         if(altgr) // press Alt Gr if needed
         {
            tx_msg[0] = KB_MODIFIER_RIGHT_ALT;
            altgr = 0;
         }
           
         tx_msg[2] = scancode;
         LED_OFF(STATUS_LED);
         
      }
   
     usb_put_packet(1, tx_msg, sizeof(tx_msg), USB_DTS_TOGGLE);
     
      chr = 0;
   }
}

void main(void)
{
   LED_ON(LED1);
   LED_OFF(LED2);
   LED_OFF(LED3);
 
   usb_init_cs();

   enable_interrupts(GLOBAL);
   enable_interrupts(INT_RDA);

   memset(tx_msg, 0x00, sizeof(tx_msg));

   while (TRUE)
   {
      usb_task();
     
      if (usb_enumerated())
      {
         usb_keyboard_task();   
      }
   }
}


The header file is still the same as in my first post.
I also tried to use usb_init() to get rid of the usb_task() but I still lose characters. I reduced the speed of character sending to one character per 400ms.
Ttelmah



Joined: 11 Mar 2010
Posts: 19499

View user's profile Send private message

PostPosted: Sat May 09, 2015 7:28 am     Reply with quote

Using usb_init, rather than init_cs, does not get rid of the need to occasionally call the task.
What it does is reduce how often this needs to happen. With cs, you really need to call it at an interval perhaps no longer then 10mSec. With the standard init, task still does some extra housekeeping, and still must occur at intervals, but the interval can be much longer.
What you have now is much better.

However there is a piece missing from your keyboard handler.
USB keyboard devices, are _required_ to receive status data from the PC. Note _required_. The PC will send this at intervals. Your task does not handle this, so the input buffer will overflow.

Look at the example keyboard handler. Note that if anything is received from the USB, it gets the packet. It just writes it into the variable 'leds' and then ignores this. You need something similar.

Other thing, move your chr=0, to the line after you convert the scancode.
Otherwise a character typed while the USB data is being written, will be lost.
sinaloe



Joined: 24 Apr 2015
Posts: 3

View user's profile Send private message

PostPosted: Tue May 12, 2015 10:00 am     Reply with quote

Thanks a lot for your help! It works!
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group