Windows + Java

Moderator: Telldus

henrik.holmstrom
Posts: 3
Joined: Thu Jan 18, 2018 11:08 am

Windows + Java

Post by henrik.holmstrom » Thu Jan 18, 2018 11:08 am

Hej, försöker få igång rfcmd på windows och med java.
Problemet verkar var att rxtx inte ser TellStick eftersom den inte verkar dyka upp som en COM-port (TelldusSetup funkar).
Tittade lite på drivern och fick intrycket att det inte är den driver som visar TellStick som en COM-port (hittade lite info på FTDI-sajten och det fanns en drivare som visst skulle kunna göra det, men kan alldeles för lite om Windows för att veta vad man ska göra).
I enhetshanteraren ser jag de vanliga COM-portarna, TellStick syns under USB-device endast.
Finns det någon som lyckats göra ett program i Java på Windows som har något tips?

micke.prag
Site Admin
Posts: 2222
Joined: Thu Jan 18, 2018 11:08 am
Location: Lund
Contact:

Post by micke.prag » Thu Jan 18, 2018 11:08 am

Jag är själv inte speciellt bra på Java så jag får ursäkta mig om jag är ute på djupt vatten ibland.

För att komma åt TellSticken finns det två lösningar som jag ser det.
Antingen kan man anropa vårt API eller gå direkt mot FTDIs API.
Vi rekommenderar vårt API då du slipper tänka på hur protokollet till mottagarna fungerar, användarna till ditt program slipper också konfigurera vilka mottagare denne har flera gånger då detta endast görs en gång (TelldusSetup) och när vi lägger in stöd för nya mottagare får man även detta "på köpet".

Oavsett vilken lösning du väljer så behöver du komma åt en "Windows Native Library"-dll. Detta görs via JNI.
http://en.wikipedia.org/wiki/Java_Native_Interface
http://java.sun.com/j2se/1.5.0/docs/guide/jni/

När väl detta fungerar kan du anropa TellUsbD101.dll eller ftd2xx.dll beroende på vilken metod du använder.
För TellUsbD101.dll kan du titta på exemplet till Visual Basic där vi har försökt göra det så simpelt som möjligt.

Väljer du istället att gå direkt på FTDI så kan du kolla i funktionen Device::send(char* strMessage) som du hittar här
http://svn.telldus.se/filedetails.php?r ... Device.cpp

Avslutningsvis kan jag också passa på att säga att vi håller på med en port av det API som finns till Windows till Linux. Det gör att du kan komma åt TellStick på samma vis på både Windows och Linux. Det kommer även att finnas funktioner för att skicka till icke-förinställda enheter (från TelldusSetup).
När detta är klart har jag dock inget datum på.

Lycka till.
Micke Prag
Software
Telldus Technologies

flax
Posts: 10
Joined: Thu Jan 18, 2018 11:08 am

Post by flax » Thu Jan 18, 2018 11:08 am

Grundproblemet är att vare sig Sun's eller rxtx's javacomm-implementation klarar att enumerera serieportarna i systemet utan hjälp. Rxtx antar att man har serieport 1 & 2, och vet inget om eventuella usb-anslutna serieenheter. Man kan dock konfigurera rxtx med de portar den "ska" känna till genom att sätta systempropertyn gnu.io.rxtx.SerialPorts, värdet är en lista av de serieportar rxtx ska kunna hantera.

Om du sätter den propertyn så behöver du inget nativeinterface, det är s.a.s. redan inkluderat i rxtx.

Kolla på wikin under http://www.telldus.se/wiki/index.php?title=Javacomm du kan till rxtx skicka in en konfigsträng där du anger vilka serieportar rxtx "ska se". Det är samma problem som du beskriver under linux, rxtx har som default bara com0 + com1 konfigurerade (dvs /dev/ttyS0 och /dev/ttyS1)

Det du vill titta på är i Tellstick.java (i det projekt jag länkar till på wikin) och då framför allt:
// This could be set from command line also... -Dprop=value
System.setProperty("gnu.io.rxtx.SerialPorts", "/dev/ttyS0:/dev/ttyS1:/dev/tellstick");

Hojta till om något var oklart, det ska fungera på samma sätt under windows och linux, så om du bara hittar vad ditt OS tycker serieporten heter så ska det räcka med att ange det i propertyn.

En konsekvens av ovanstående blir att om man kan få två tellsticks att monteras (i linux) som /dev/tellstick0 och /dev/tellstick2, eller (i windows) som usbSerial1: och usbSerial2: (eller vad det nu kan heta) så är det en baggis att från java hantera flera sändarenheter samtidigt eftersom man då kan adressera dem med deras "namn". Har inte haft budget att leka med sådant dock. :)

Lycka till!

henrik.holmstrom
Posts: 3
Joined: Thu Jan 18, 2018 11:08 am

Post by henrik.holmstrom » Thu Jan 18, 2018 11:08 am

Tack. Har försökt lite med prop:an men har ingen aning om vad Tellstick:en/USB generellt kan tänkas heta i rxtx. Den enumereras inte om man listar alla portar.

micke.prag
Site Admin
Posts: 2222
Joined: Thu Jan 18, 2018 11:08 am
Location: Lund
Contact:

Post by micke.prag » Thu Jan 18, 2018 11:08 am

I windows ger inte TellStick en comport. Du måste använda FTDIs bibliotek så tror tyvärr inte du kommer någonvart med rxtx.
Micke Prag
Software
Telldus Technologies

flax
Posts: 10
Joined: Thu Jan 18, 2018 11:08 am

Post by flax » Thu Jan 18, 2018 11:08 am

micke.prag wrote:I windows ger inte TellStick en comport. Du måste använda FTDIs bibliotek så tror tyvärr inte du kommer någonvart med rxtx.
Sicket mög. :shock: :)
Jag trodde faktiskt att det bara skulle vara att adressera den med rätt namn. Låter som att jag har det väl förspänt på linuxsidan. :D

Jag har snokat lite på FTDI's sida, och de har ju även VCP-drivers, vet du om de fungerar med tellstick? Om ja, så borde tellsticken se ut som en vanlig comport, därefter skulle mina anvisningar i så fall stämma, med rxtx som abstraktionslager i java.

Det kan nog vara värt att försöka gå via javacomm, eftersom det är ett rätt väl beprövat bibliotek för hantering av seriella enheter.

micke.prag
Site Admin
Posts: 2222
Joined: Thu Jan 18, 2018 11:08 am
Location: Lund
Contact:

Post by micke.prag » Thu Jan 18, 2018 11:08 am

VCP rutinerna kommer inte hitta TellStick då den är programmerad att använda D2XX.

Så det bästa blir att använda vårt API vilket ändå borde bli enklare att implementera i slutändan.
Micke Prag
Software
Telldus Technologies

flax
Posts: 10
Joined: Thu Jan 18, 2018 11:08 am

Post by flax » Thu Jan 18, 2018 11:08 am

Om inte VCP-drivern fungerar så är jag rädd att jag får hålla med Micke, du får i så fall kika på att skriva en wrapper till någon av dll-drivisarna med JNI. Jag har lite erfarenhet av sådant också, men det var några år sedan jag behövde ta till sådant, så jag behöver rota rätt på var jag gömt källkoden. :)
Det har dykt upp en del verktyg sedan jag pulade med JNI också, jag har hört jniwrapper nämnas (betalprodukt, men man kan hämta hem en utvärderingslicens) http://www.teamdev.com/jniwrapper/index.jsf

Om du väljer att gå JNI-vägen så skulle jag rekommendera att inte ens försöka hantera det med javacomm utan att skriva ett abstraktionslager direkt mot DLL'en.

Jag har ändrat informationen på WIKI'n så att inte folk med Windows går i samma fälla igen. Beklagar, jag hade fått för mig att tellsticken betedde sig som en VCP-enhet.

En sak till att nämna är att om man ska gå JNI-vägen så måste man ha en C++-kompilator också. :( JNIwrapper kanske är rätt väg att gå för att kunna anropa DLL'en direkt...

micke.prag
Site Admin
Posts: 2222
Joined: Thu Jan 18, 2018 11:08 am
Location: Lund
Contact:

Post by micke.prag » Thu Jan 18, 2018 11:08 am

Jag ska titta på JNI och se vad jag kan få fram. Som sagt så är jag ju ingen expert på Java så det kanske inte går så fort...
Micke Prag
Software
Telldus Technologies

flax
Posts: 10
Joined: Thu Jan 18, 2018 11:08 am

Post by flax » Thu Jan 18, 2018 11:08 am

micke.prag wrote:Jag ska titta på JNI och se vad jag kan få fram. Som sagt så är jag ju ingen expert på Java så det kanske inte går så fort...
Som jag ser det så har man några olika vägar att välja:

(1) javacomm - kräver att enheten går att adressera som en com-port i systemet. Fungerar i Linux men inte (idag) i Windows, då tellsticken inte beter sig som en com-enhet?

(2) JNI via DLL, fungerar i Windows, behövs inte i linux. Man måste skriva ett gränssnitt mellan java och dll i C++. Java har verktyg för att skapa de headerfiler och funktionsskelett som behövs. Fördel: Man kan exponera bara de anrop som behövs. Nackdel: man måste handkoda allt innan man ens kan börja jobba på Java-nivå. Man måste dessutom se till att lösa problemet med DLL'er som anropar andra DLL'er.

(3) Använd någon jniwrapper. Man köper då en binär som klarar att utifrån konfigurationsfiler anropa utpekade DLL'er. Fördel: Man slipper koda. Nackdel: Kostar pengar, kräver konfiguration och är fortfarande en hel del jobb innan man kan börja med kodningen i Java.

(4) Skriv en miniserver i VB eller något annat som tillåter att man anropar den via något välspecat protokoll, exempelvis via socket med egendefinierat protokoll eller som en webservice. Starta som en systemtjänst och anropa via java eftersom socket/ws är väldefinierade i Java. Fördel: Borde fungera bra och man kan jobba helt i en miljö åt gången utan att behöva blanda in maskinnära anrop i onödan. Nackdel: Rätt mycket jobb, men många skulle kunna dra nytta av det.

henrik.holmstrom
Posts: 3
Joined: Thu Jan 18, 2018 11:08 am

Post by henrik.holmstrom » Thu Jan 18, 2018 11:08 am

Tack för alla tips. För att få igång det hela kör jag på en Linux-burk så länge, sen återvänder jag till Windows-problemet.
Att jag vill ha en "rå" comm-port beror på att jag vill köra samma program på linux och på windows. Att jag själv får hantera de olika devicen känns inte så jobbigt, jag tycker de ska ligga som handlers ovanpå serie-kommunikationen (alltå inte i drivaren).
Om jag fattar rätt är eran tanke att drivaren ska klara massa olika device/fabrikat och ha samma API oavsett plattform. Dvs samma sak ovanifrån betraktat men med skillnaden vad som ligger i drivaren och vad som ligger ovanför drivaren.
Troligen wrappar jag FTDI-drivaren på Windows och använder "write bytes"-metoden. Då kan jag göra ett smalt interface som i princip är endast den metoden och ha en ren comm-implementation av interfacet på linux.
Då blir resten av programmet "rent" från plattformsjox.
När (om :-) jag får ihop något vettigt postar jag det.

micke.prag
Site Admin
Posts: 2222
Joined: Thu Jan 18, 2018 11:08 am
Location: Lund
Contact:

Post by micke.prag » Thu Jan 18, 2018 11:08 am

Jag har lyckats göra ett JNI-interface till TellStick som fungerar utmärkt i Linux. Tyvärr har jag inte haft samma framgång i Windows. Ni som kanske har kompilerat liknande förr kanske kan få igång det?

http://svn.telldus.se/listing.php?repna ... dings_java_
Micke Prag
Software
Telldus Technologies

hekj
Posts: 988
Joined: Thu Jan 18, 2018 11:08 am
Location: Stockholm
Contact:

Post by hekj » Thu Jan 18, 2018 11:08 am

Följande "jniwrapper" är gratis och enkel att använda!

Java Native Access (JNA)
https://jna.dev.java.net/
Dynamically access native libraries from Java without JNI

JNA provides Java programs easy access to native shared libraries (DLLs on Windows) without writing anything but Java code—no JNI or native code is required. This functionality is comparable to Windows' Platform/Invoke and Python's ctypes. Access is dynamic at runtime without code generation.

JNA allows you to call directly into native functions using natural Java method invocation. The Java call looks just like it does in native code. Most calls require no special handling or configuration; no boilerplate or generated code is required.

The JNA library uses a small native library stub to dynamically invoke native code. The developer uses a Java interface to describe functions and structures in the target native library. This makes it quite easy to take advantage of native platform features without incurring the high overhead of configuring and building JNI code for multiple platforms.

While some attention is paid to performance, correctness and ease of use take priority.

Code: Select all

import com.sun.jna.Library;
import com.sun.jna.Native;

public class JnaDemo {

   public static String library = null;

   public interface CLibrary extends Library {

      CLibrary INSTANCE = (CLibrary)Native.loadLibrary((library), CLibrary.class);

      boolean devTurnOn(int intDeviceId);
      boolean devTurnOff(int intDeviceId);
   }

   public static void main(String[] args) {
      System.setProperty("jna.library.path", args[0]);
      String dll = args[1];
      if (dll.toLowerCase().endsWith(".dll")) {
        dll = dll.substring(0, dll.length() - 4); 
      }
      JnaDemo.library = dll;
      boolean cmdOn = args[2].equalsIgnoreCase("-on");
      int id = Integer.parseInt(args[3]);
      boolean result = false;
      if (cmdOn) { 
        System.out.print("Turning on device: ");
        result = CLibrary.INSTANCE.devTurnOn(id);
      } else {
        System.out.print("Turning off device: ");
        result = CLibrary.INSTANCE.devTurnOff(id);
      }
      System.out.println(id + " - " + (result ? "ok" : "failed"));
   }

}
java -classpath .;jna.jar JnaDemo "C:\Program Files\Telldus" TellUsbD101.dll -on 1
Turning on device: 1 - ok

java -classpath .;jna.jar JnaDemo "C:\Program Files\Telldus" TellUsbD101.dll -off 1
Turning off device: 1 - ok

micke.prag
Site Admin
Posts: 2222
Joined: Thu Jan 18, 2018 11:08 am
Location: Lund
Contact:

Post by micke.prag » Thu Jan 18, 2018 11:08 am

Detta såg trevligt ut. Det får vi ta och fixa ihop ett riktigt exempel med.
Micke Prag
Software
Telldus Technologies

gein
Posts: 437
Joined: Thu Jan 18, 2018 11:08 am

Post by gein » Thu Jan 18, 2018 11:08 am

Okej, jag gav mig på JNA men lyckas inte få det att fungera. Jag gissade att jag skulle referera till /Library/Frameworks/TelldusCore.framework/Versions/Current/Libraries/libftd2xx.0.1.4.dylib, stämmer det?

Det här felet får jag iaf:
Turning on device: Exception in thread "main" java.lang.UnsatisfiedLinkError: Unable to load library '/Library/Frameworks/TelldusCore.framework/Versions/Current/Libraries/libftd2xx.0.1.4.dylib': dlopen(/Library/Frameworks/TelldusCore.framework/Versions/Current/Libraries/libftd2xx.0.1.4.dylib, 9): no suitable image found. Did find:
/Library/Frameworks/TelldusCore.framework/Versions/Current/Libraries/libftd2xx.0.1.4.dylib: no matching architecture in universal wrapper
at com.sun.jna.NativeLibrary.loadLibrary(NativeLibrary.java:164)
at com.sun.jna.NativeLibrary.getInstance(NativeLibrary.java:237)
at com.sun.jna.Library$Handler.<init>(Library.java:140)
at com.sun.jna.Native.loadLibrary(Native.java:374)
at com.sun.jna.Native.loadLibrary(Native.java:359)
at JnaDemo$CLibrary.<clinit>(JnaDemo.java:10)
at JnaDemo.main(JnaDemo.java:29)

Post Reply