Questions about porting DigiCombo.h to Leonardo

Hello guys!
Recently I have been working on a project that requires HID Touchscreen functions (compatible with Android) and I have been figuring out how to port the DigiCombo.h, a library which is capable of this but is designed to work on Digispark only, to one that can be used for Leonardo or Micro. Since it's unrealistic to redo the library work on my own, I just picked out the core part of it and tested it on Leonardo when I encountered a lot of questions. It seems that my code and Leonardo can't work properly with Android system while using the original library on Digispark is near to perfect in any situation.
Note in advance: this project may require proficiency and experience in HID, USB, multi-touch Touchscreen descriptor, and something else relevant. Also you need to have a glimpse into DigiCombo lib files (available in github) and my explanations are written in the comment sections of my code. Also(again:), it's hard to test the invisible multi-touch in Android, thus I test it with APDE (Processing for android), and the code will be given at the end.
Here is my code on Leonardo:

#include <HID.h>

#define REPORT_ID_TOUCH 0x01
#define CONTACT_COUNT_MAXIMUM 10

// copied from DigiComboC.c, maybe it isn't the problem
static const uint8_t _hidReportDescriptorTouch[] PROGMEM = {
  0x05, 0x0D,                    // USAGE_PAGE(Digitizers)
  0x09, 0x04,                    // USAGE     (Touch Screen)
  0xA1, 0x01,                    // COLLECTION(Application)
  0x85, REPORT_ID_TOUCH,         //   REPORT_ID (Touch)
  0x09, 0x55,                    //   USAGE (Contact Count Maximum)
  0x25, CONTACT_COUNT_MAXIMUM,   //   LOGICAL_MAXIMUM (CONTACT_COUNT_MAXIMUM)
  0xB1, 0x02,                    //   FEATURE (Data,Var,Abs)
  0x09, 0x54,                    //   USAGE (Contact count)
  0x95, 0x01,                    //   REPORT_COUNT(1)
  0x75, 0x08,                    //   REPORT_SIZE (8)
  0x81, 0x02,                    //   INPUT (Data,Var,Abs)
  
  0x09, 0x22,                    //   USAGE (Finger)
  0xA1, 0x02,                    //   COLLECTION (Logical)
  0x09, 0x51,                    //     USAGE (Contact Identifier)
  0x75, 0x08,                    //     REPORT_SIZE (8)
  0x95, 0x01,                    //     REPORT_COUNT (1)
  0x81, 0x02,                    //     INPUT (Data,Var,Abs)
  
  0x09, 0x42,                    //     USAGE (Tip Switch)
  0x09, 0x32,                    //     USAGE (In Range)
  0x15, 0x00,                    //     LOGICAL_MINIMUM (0)
  0x25, 0x01,                    //     LOGICAL_MAXIMUM (1)
  0x75, 0x01,                    //     REPORT_SIZE (1)
  0x95, 0x02,                    //     REPORT_COUNT(2)
  0x81, 0x02,                    //     INPUT (Data,Var,Abs)
  0x95, 0x06,                    //     REPORT_COUNT (6)
  0x81, 0x03,                    //     INPUT (Cnst,Ary,Abs)
  
  0x05, 0x01,                    //     USAGE_PAGE (Generic Desktop)
  0x09, 0x30,                    //     Usage (X)
  0x09, 0x31,                    //     Usage (Y)
  0x16, 0x00, 0x00,              //     Logical Minimum (0)
  0x26, 0x10, 0x27,              //     Logical Maximum (10000)
  0x36, 0x00, 0x00,              //     Physical Minimum (0)
  0x46, 0x10, 0x27,              //     Physical Maximum (10000)
  0x66, 0x00, 0x00,              //     UNIT (None)
  0x75, 0x10,                    //     Report Size (16),
  0x95, 0x02,                    //     Report Count (2),
  0x81, 0x02,                    //     Input (Data,Var,Abs)
  0xC0,                          //   END_COLLECTION
  0xC0,                          // END_COLLECTION
  // with this declaration a data packet must be sent as:
  // byte 1   -> "contact count"        (always == 1)    <===== Please note this! So weird! But it actually work in this library.
  // byte 2   -> "contact identifier"   (any value)
  // byte 3   -> "Tip Switch" state     (bit 0 = Tip Switch up/down, bit 1 = In Range)  <===== no idea what it means
  // byte 4,5 -> absolute X coordinate  (0...10000)
  // byte 6,7 -> absolute Y coordinate  (0...10000)
};

// initialization
void begin(void)
{
    // register as an HID device
    static HIDSubDescriptor node(_hidReportDescriptorTouch, sizeof(_hidReportDescriptorTouch));
    HID().AppendDescriptor(&node);
}

// stimulate a finger  <===== similar to DigiCombo's function: moveFinger(int, int, int)
void _move(uint8_t count, uint8_t contact_identifier, uint8_t state, uint16_t x, uint16_t y)
{
  uint8_t buffer [7];
  buffer[0] = count; // This byte is the so-called Contact Count
  buffer[1] = contact_identifier & 0xFF; // "contact identifier"
  buffer[2] = state & 0xFF; //(bit 0 = Tip Switch up/down, bit 1 = In Range)  <===== still no idea :(
  buffer[3] = x & 0xFF; // low byte x_coord
  buffer[4] = (x >> 8) & 0xFF; // high byte x_coord
  buffer[5] = y & 0xFF;// low byte y_coord
  buffer[6] = (y >> 8) & 0xFF; // high byte y_coord  <=====  send the coordinate
  HID().SendReport(REPORT_ID_TOUCH, buffer, 7);
}

void setup() {
  begin();
  delay(1000);  // seems that we must add a delay of 1000ms just as Digi_Combo::begin() in DigiCombo.cpp. Otherwise, we would miss the first Contact
}

void loop() {
// Just testing
  _move(1, 0x01, 0b11, 2000, 1000);
  delay(1000);
  _move(1, 0x02, 0b11, 1000, 2000);
  delay(1000);
  _move(1, 0x03, 0b11, 1000, 1000);
  delay(1000);
  _move(1, 0x04, 0b11, 2000, 2000);
  delay(1000);
// Things go well above. Problems come as follows when I release the touches.
  _move(4, 0x04, 0b00, 0, 0);
  delay(1000);
// It can't cancel the touch(id=4)
  _move(3, 0x03, 0b00, 0, 0);
  delay(1000);
// It can't cancel the touch(id=3) either
  _move(2, 0x02, 0b00, 0, 0);
  delay(1000);
// It cancel both touch(id=1) and touch(id=4) at a time
  _move(1, 0x01, 0b00, 0, 0);
  delay(1000);
// It cancel both touch(id=2) and touch(id=3)
  delay(1000);
}

As you can see, it's extremely weird, confusing and I have no idea what causes the problem. My code is almost copied from the library files, and it should be free from errors.
Now I have to paste some related library code for reference.

// ......
void Digi_Combo::moveFinger(uint16_t x, uint16_t y, uint8_t contactId)
{
    uint8_t id = contactId != 0xFF ? contactId : lastContactId;
    contacts[id] = 1;

    report_buffer[0] = REPORT_ID_TOUCH;
    report_buffer[1] = 1;
    report_buffer[2] = id;
    report_buffer[3] = 0b11;
    report_buffer[4] = MSB(x);
    report_buffer[5] = LSB(x);
    report_buffer[6] = MSB(y);
    report_buffer[7] = LSB(y);
    usbReportSend(REPORT_SIZE_TOUCH);
}
// ......
void Digi_Combo::release(uint8_t contactId)
{
    uint8_t id = contactId != 0xFF ? contactId : lastContactId;
    uint8_t currentlyCountContact = countContact();
    if (lastReportId == REPORT_ID_TOUCH) contacts[id] = 0;

    report_buffer[0] = lastReportId;
    report_buffer[1] = lastReportId == REPORT_ID_TOUCH ? currentlyCountContact : 0;
    report_buffer[2] = lastReportId == REPORT_ID_TOUCH ? id : 0;
    report_buffer[3] = 0;
    report_buffer[4] = 0;
    report_buffer[5] = 0;
    report_buffer[6] = 0;
    report_buffer[7] = 0;

    usbReportSend(BUFFER_SIZE);
}

For more info, you need to fetch DigiCombo.cpp, DigiCombo.h, DigiComboC.c, DigiComboC.h. I'm sorry about that.
Here is my APDE code for multi-touch testing:
SEE=====> APDE Code For Multi-touch Testing

Thanks in advance :slightly_smiling_face:

Aweful editor :rofl: This is my first post in forum

Please do not put the plain text to the code tags - as a result your message is very difficult to read.

Did you try compile them?

Not really. I just want DigiCombo.h to work on Leonardo. Maybe it's too difficult for me to understand the whole library including its usb driver part. Thus I just pick out its HID report descriptor and its data format, and then test them on Leonardo using HID.h instead.

When you try to compile, the compiler will inform you about all the errors and inconsistencies in the code. It is a point where you have to start.

I tried compiling DigiCombo for Leonardo just now. And of course it caused errors. It seems not compatible with 16MHz Avr board :frowning:

C:\Users\yaz\Documents\Arduino\libraries\DigiCombo\usbdrv/asmcommon.inc: Assembler messages:
C:\Users\yaz\Documents\Arduino\libraries\DigiCombo\usbdrv/asmcommon.inc:98: Error: constant value required
C:\Users\yaz\Documents\Arduino\libraries\DigiCombo\usbdrv/asmcommon.inc:43: Error: invalid operands (*ABS* and *UND* sections) for `<<'
C:\Users\yaz\Documents\Arduino\libraries\DigiCombo\usbdrv/asmcommon.inc:59: Error: invalid operands (*ABS* and *UND* sections) for `<<'
C:\Users\yaz\Documents\Arduino\libraries\DigiCombo\usbdrv/usbdrvasm16.inc:332: Error: invalid operands (*ABS* and *UND* sections) for `<<'

This is the highlighted error info.

It is hardly to be surprise to you, yeh?
I am not sure I fully understand what you trying to do, but usually you can't get the code from one microcontroller and just use it on another. You need a complicate task, called "porting" - rewriting all mcu-dependent parts of code from one MCU to another.

Yeah, you're right. So I give up such an idea.
I use HID.h instead, but the same principle as the DigiCombo.h: HID descriptor and data format. The problem is that its effect is slightly different from DigiCombo.h and a bit unsatisfactory.

Things go well when I try to add a new contact, but my code fails to release it.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.