3

My Delphi XE7 project needs to communicate with the FTDI FT311 Android Accessory Chip. They helpfully provide an Android demo that includes their JAVA driver FT311I2CInterface.java(shown later in this post). Presuming that I needed to convert this file to OP I followed the instructions for using the Java2OP.exe command line tool making the necessary path addition to point to the JDK (which seems to get installed by XE7) SET PATH=%PATH%;C:\Program Files\Java\jdk1.7.0_25\bin

With everything in the same folder I ran the tool with:

java2op.exe  -unit FT311I2CInterface.java

received no errors and obtained an output file FT311I2CInterface.java.pas. However this output file has an empty class in it as follows:

{*******************************************************}
{                                                       }
{           CodeGear Delphi Runtime Library             }
{ Copyright(c) 2014 Embarcadero Technologies, Inc.      }
{                                                       }
{*******************************************************}

unit FT311I2CInterface.java;

interface

uses
  Androidapi.JNIBridge;

type
// ===== Forward declarations =====


// ===== Interface declarations =====

implementation

procedure RegisterTypes;
begin
end;

initialization
  RegisterTypes;
end.

Can anyone suggest what I am doing wrong please?

The original JAVA file as supplied is as follows:

//User must modify the below package with their package name
package com.I2CDemo; 
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

import android.app.Activity;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.usb.UsbAccessory;
import android.hardware.usb.UsbManager;
import android.os.Handler;
import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.util.Log;
import android.widget.Toast;


/******************************FT311 GPIO interface class******************************************/
public class FT311I2CInterface extends Activity
{

    private static final String ACTION_USB_PERMISSION =    "com.I2CDemo.USB_PERMISSION";
    public UsbManager usbmanager;
    public UsbAccessory usbaccessory;
    public PendingIntent mPermissionIntent;
    public ParcelFileDescriptor filedescriptor;
    public FileInputStream inputstream;
    public FileOutputStream outputstream;
    public boolean mPermissionRequestPending = false;
    public boolean READ_ENABLE = true;
    public boolean accessory_attached = false;
    public handler_thread handlerThread;

    private byte [] usbdata; 
    private byte [] writeusbdata;
    private int readcount;
    private byte status;
    private byte  maxnumbytes = 60;
    public boolean datareceived = false;


    public Context global_context;

    public static String ManufacturerString = "mManufacturer=FTDI";
    public static String ModelString = "mModel=FTDII2CDemo";
    public static String VersionString = "mVersion=1.0";    

        /*constructor*/
     public FT311I2CInterface(Context context){
            super();
            global_context = context;
            /*shall we start a thread here or what*/
            usbdata = new byte[64]; 
            writeusbdata = new byte[64];

            /***********************USB handling******************************************/

            usbmanager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
           // Log.d("LED", "usbmanager" +usbmanager);
            mPermissionIntent = PendingIntent.getBroadcast(context, 0, new Intent(ACTION_USB_PERMISSION), 0);
            IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
           filter.addAction(UsbManager.ACTION_USB_ACCESSORY_DETACHED);
           context.registerReceiver(mUsbReceiver, filter);

           inputstream = null;
           outputstream = null;
        }

        /*reset method*/
        public void Reset()
        {
            /*create the packet*/
            writeusbdata[0] = 0x34;
            writeusbdata[1] = 0x00;
            writeusbdata[2] = 0x00;
            writeusbdata[3] = 0x00;
            writeusbdata[4] = 0x00;

            /*send the packet over the USB*/
            SendPacket(5);
        }


        /*SetFrequency*/
        public void SetFrequency(byte freq)
        {
            /*check for maximum and minimum freq*/
            if(freq > 92)
                freq = 92;

            if (freq < 23)
                freq = 23;

            /*create the packet*/
            writeusbdata[0] = 0x31;
            switch(freq)
            {
            case 23:
                writeusbdata[1] = 10;
                break;
            case 44:
                writeusbdata[1] = 21;
                break;
            case 60:
                writeusbdata[1] = 30;
                break;
            default:
                writeusbdata[1] = 56;
                break;
            }
            writeusbdata[2] = 0x00;
            writeusbdata[3] = 0x00;
            writeusbdata[4] = 0x00;

            /*send the packet over the USB*/
            SendPacket(5);
        }


        /*write data*/
        public byte WriteData(byte i2cDeviceAddress,byte transferOptions,
                             byte numBytes, byte[] buffer, 
                             byte [] actualNumBytes)
        {

            status = 0x01; /*error by default*/
            /*
             * if num bytes are more than maximum limit
             */
            if(numBytes < 1){

                actualNumBytes[0] = (byte)0x00;
                /*return the status with the error in the command*/
                return status;
            }

            /*check for maximum limit*/
            if(numBytes > maxnumbytes){
                numBytes = maxnumbytes;

            }


            /*prepare the packet to be sent*/
            for(int count = 0;count<numBytes;count++)
            {

                writeusbdata[4+count] = (byte)buffer[count];

            }

            /*prepare the usbpacket*/
            writeusbdata[0] = 0x32;
            writeusbdata[1] = i2cDeviceAddress;
            writeusbdata[2] = transferOptions;
            writeusbdata[3] = numBytes;

            SendPacket((int)(numBytes+4));

            datareceived = false;
            /*wait while the data is received*/
            /*FIXME, may be create a thread to wait on , but any
             * way has to wait in while loop
             */
            while(true){

                if(datareceived == true){
                    break;
                }
            }

            /*by default it error*/
            status = 0x01;
            /*check for the received data*/
            if(usbdata[0] == 0x32)
            {
                /*check for return error status*/
                status = usbdata[1];


                /*updated the written bytes*/
                actualNumBytes[0] = usbdata[3];
            }
            datareceived = false;
            return status;
        }

        /*read data*/
        public byte ReadData(byte i2cDeviceAddress,byte transferOptions,
                              byte numBytes, byte[] readBuffer,
                              byte [] actualNumBytes)
        {
                status = 0x01; /*error by default*/

                /*should be at least one byte to read*/
                if(numBytes < 1){
                    return status;
                }

                /*check for max limit*/
                if(numBytes > maxnumbytes){
                    numBytes = maxnumbytes;
                }


                /*prepare the packet to send this command*/
                writeusbdata[0] = 0x33; /*read data command*/
                writeusbdata[1] = i2cDeviceAddress; /*device address*/
                writeusbdata[2] = transferOptions; /*transfer options*/
                writeusbdata[3] = numBytes; /*number of bytes*/


                /*send the data on USB bus*/
                SendPacket(4);

                datareceived = false;
                /*wait for data to arrive*/
                while(true)
                {
                    if(datareceived == true){
                        break;
                    }
                }





                /*check the received data*/
                if(usbdata[0] == 0x33)
                {
                    /*check the return status*/
                    status = usbdata[1];

                    /*check the received data length*/
                    numBytes = usbdata[3];
                    if(numBytes > maxnumbytes){
                        numBytes = maxnumbytes;
                    }

                    for(int count = 0; count<numBytes;count++)
                    {
                        readBuffer[count] = usbdata[4+count];
                    }
                    /*update the actual number of bytes*/
                    actualNumBytes[0] = numBytes;
                    datareceived = false;
                }
            return status;
        }


        /*method to send on USB*/
        private void SendPacket(int numBytes)
        {


            try {
                if(outputstream != null){
                    outputstream.write(writeusbdata, 0,numBytes);
                }
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

        }




        /*resume accessory*/
        public void ResumeAccessory()
        {
            // Intent intent = getIntent();
            if (inputstream != null && outputstream != null) {
                return;
            }

            UsbAccessory[] accessories = usbmanager.getAccessoryList();
            if(accessories != null)
            {
                Toast.makeText(global_context, "Accessory Attached", Toast.LENGTH_SHORT).show();
            }
            else
            {
                accessory_attached = false;
                return;
            }

            UsbAccessory accessory = (accessories == null ? null : accessories[0]);
            if (accessory != null) {
                if( -1 == accessory.toString().indexOf(ManufacturerString))
                {
                    Toast.makeText(global_context, "Manufacturer is not matched!", Toast.LENGTH_SHORT).show();
                    return;
                }

                if( -1 == accessory.toString().indexOf(ModelString))
                {
                    Toast.makeText(global_context, "Model is not matched!", Toast.LENGTH_SHORT).show();
                    return;
                }

                if( -1 == accessory.toString().indexOf(VersionString))
                {
                    Toast.makeText(global_context, "Version is not matched!", Toast.LENGTH_SHORT).show();
                    return;
                }

                Toast.makeText(global_context, "Manufacturer, Model & Version are matched!", Toast.LENGTH_SHORT).show();
                accessory_attached = true;

                if (usbmanager.hasPermission(accessory)) {
                    OpenAccessory(accessory);
                } 
                else
                {
                    synchronized (mUsbReceiver) {
                        if (!mPermissionRequestPending) {
                            Toast.makeText(global_context, "Request USB Permission", Toast.LENGTH_SHORT).show();
                            usbmanager.requestPermission(accessory,
                                    mPermissionIntent);
                            mPermissionRequestPending = true;
                        }
                }
            }
            } else {}

        }

        /*destroy accessory*/
        public void DestroyAccessory(){
            global_context.unregisterReceiver(mUsbReceiver);
            if(accessory_attached == true)
            {
                READ_ENABLE = false;
                byte i2cDeviceAddress = 1;
                byte transferOptions = bOption.START_BIT;
                byte numBytes = 2;
                byte [] actualNumBytes = new byte[1];
                byte [] readBuffer = new byte[60];
                //byte deviceAddress = 1;
                readBuffer[0] = 1;

                ReadData(i2cDeviceAddress,transferOptions,
                          numBytes, readBuffer,
                          actualNumBytes);
                try{Thread.sleep(10);}
                catch(Exception e){}
            }
            CloseAccessory();
        }



/*********************helper routines*************************************************/     

        public void OpenAccessory(UsbAccessory accessory)
        {
            filedescriptor = usbmanager.openAccessory(accessory);
            if(filedescriptor != null){
                usbaccessory = accessory;
                FileDescriptor fd = filedescriptor.getFileDescriptor();
                inputstream = new FileInputStream(fd);
                outputstream = new FileOutputStream(fd);
                /*check if any of them are null*/
                if(inputstream == null || outputstream==null){
                    return;
                }
            }

            handlerThread = new handler_thread(inputstream);
            handlerThread.start();
        }

        private void CloseAccessory()
        {
            try{
                if(filedescriptor != null)
                    filedescriptor.close();

            }catch (IOException e){}

            try {
                if(inputstream != null)
                        inputstream.close();
            } catch(IOException e){}

            try {
                if(outputstream != null)
                        outputstream.close();

            }catch(IOException e){}
            /*FIXME, add the notfication also to close the application*/

            filedescriptor = null;
            inputstream = null;
            outputstream = null;

            System.exit(0);
        }


        /***********USB broadcast receiver*******************************************/
        private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() 
        {
            @Override
            public void onReceive(Context context, Intent intent) 
            {
                String action = intent.getAction();
                if (ACTION_USB_PERMISSION.equals(action)) 
                {
                    synchronized (this)
                    {
                        UsbAccessory accessory = (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
                        if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false))
                        {
                            Toast.makeText(global_context, "Allow USB Permission", Toast.LENGTH_SHORT).show();
                            OpenAccessory(accessory);
                        } 
                        else 
                        {
                            Toast.makeText(global_context, "Deny USB Permission", Toast.LENGTH_SHORT).show();
                            Log.d("LED", "permission denied for accessory "+ accessory);

                        }
                        mPermissionRequestPending = false;
                    }
                } 
                else if (UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(action)) 
                {
                        CloseAccessory();
                }else
                {
                    Log.d("LED", "....");
                }
            }   
        };


        /*usb input data handler*/
        private class handler_thread  extends Thread {
            FileInputStream instream;

            handler_thread(FileInputStream stream ){
                instream = stream;
            }

            public void run()
            {

                while(READ_ENABLE == true)
                {
                    try
                    {
                        /*dont overwrite the previous buffer*/
                        if((instream != null) && (datareceived==false))
                        {
                            readcount = instream.read(usbdata,0,64);
                            if(readcount > 0)
                            {
                                datareceived = true;
                                /*send only when you find something*/   
                            }
                        }
                    }catch (IOException e){}
                }
            }
        }



    }
1

3 Answers 3

2

I am a beginner with Android and I am also trying to interface the FT311. I will share my experience with Java2OP but I am not yet able to get the usbAccessory in Delphi XE7

UsbManager := TJUsbManager.Wrap(SharedActivityContext.getSystemService(TJContext.JavaClass.USB_SERVICE));
    AccessoryList := UsbManager.getAccessoryList();
    if ( AccessoryList <> nil ) then begin
        if ( AccessoryList.Length > 0 ) then begin
            Accessory := AccessoryList.Items[0];  <<<<<<< raise an illegal instruction , access violation..
        end;
    end;

I had many troubles to use java2op but Here are the steps I follow After googling (sorry I don't remember the urls)

  1. create a .jar file with eclipse ADT containing the class you need (I use FT311GPIOInterface.java from the FT31 demo project supplyed by FTDI). It is not as easy because you have to split the demo app into a "android project library" (the one which will produce the .jar) and an "android project" the UI of the demo app. The .jar is build when you build and run the demo app (not when you build the android project library). If you want to test your .jar with the UI app, you have to copy the .jar into the UI app in the directory Libs and then deploy it on the android device I am new to eclipse, there is probably a better way to do it but ... I saw other way to produce the .jar file See brian long web site for another way to

  2. Java2op : It works on a clean XP windows : I use a virtual machine, no delphi XE installed, with java jdk1.7.0_25, java2op installed, no android SDK.

my jar is ft311lib.jar

java2op -jar ft311lib.jar -unit com.poco.ft311lib

this produce com.poco.ft311lib.pas

Hope this help

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks Domido, it is good that we are both trying to achieve similar things. You show how to obtain the FT311 as an Accessory but get an AV. I got further than this but could not create input and output Java buffers, so I've switched like you to trying to use the supplied class (for me FT311I2CInterface.java). Since I posted here I have had success with Java2Pas, a 50GBP paid-for tool which has given me a Delphi interface unit now. Did you have any success calling your unit generated by java2op? Would you like to collaborate on this? I have some example files that I can exchange with you.
1

According the linked documentation about this command line tool, I would do the following:

  • create a src/ folder and put FT311I2CInterface.java in it.
  • run java2op.exe with those args:

    java2op.exe -source src/ -unit Android.JNI.FT311I2C

Expected output :

Android.JNI.FT311I2C.pas

The -unit arg specify the output.

The -source arg specify the input (in your case you need a java source file)

3 Comments

Thanks but that didn't do it (I get an error log) so at the end of that documentation link it shows a simple example "java2op.exe -classes android.animation.* -unit hope". When I try this I get the same empty output file with a structure but no classes and no error.
This works for extracting from the Android API and creates a file 'Android.Hardware.USB.pas' - "Java2OP.exe -classes android.hardware android.hardware.usb.* -unit Android.Hardware.USB". So far, only this Android extraction seems to work for me.
Maybe try to put the java file here : src/com/I2CDemo/FT311I2CInterface.java so that the directory hierarchy reflect the java package. (and use the same command line : java2op.exe -source src/ -unit Android.JNI.FT311I2C )
1

Java2OP.exe ... is a command-line tool that you can use to generate Delphi native bridge files from Java libraries (JAR or class files).

I suggest to check if you used the tool correctly:

java2op.exe  -unit FT311I2CInterface.java

According to the documentation, -unit specifies File name of the output unit, not the input file. It also says

You must specify at least one input option that indicates what content you want to include in the output Delphi native bridge file.

Try instead:

java2op.exe  -source .

1 Comment

I've tried that and I get a doclava.log error "Command: javadoc -J-Xmx1024m -encoding "UTF-8" -sourcepath "C:\Art_soft\Java2OP\src" -subpackages -classpath "C:\Art_soft\Java2OP\android-19.jar" -bootclasspath "C:\Art_soft\Java2OP\android-19.jar" -docletpath "C:\Art_soft\Java2OP\doclava.jar" -doclet com.google.doclava.Doclava -nodocs -public -apixml "C:\Art_soft\Java2OP\temp.xml" Output: javadoc: error - Illegal package name: "C:\Art_soft\Java2OP\android-19.jar" 1 error"

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.