[Python/ctypes] Probleem met aanspreken external API

Pagina: 1
Acties:

Vraag


Acties:
  • 0 Henk 'm!

  • Chaot
  • Registratie: November 2001
  • Laatst online: 30-09 22:13
Voor een paar meettoestellen in mijn labo's (Omicron LT STM voor de geïnteresseerden) ben ik aan het proberen met python te praten tegen de meegeleverde software, om zo extra functies te krijgen. Dit wordt gedaan met behulp van een remote API die bij de software inbegrepen is.

Vroeger deed ik dat met een oude versie van LabVIEW die we hebben, maar onlangs hebben we tweede machine gekocht, en nu is de software 64 bit ipv 32 bit. Aangezien een nieuwe versie van LabVIEW duur is, en ik een deel functies van SciPy in de toekomst wil gebruiken, ben ik nu dus aan het proberen om alles met Python op te lossen.

Voor een hele hoop functies is iemand al zo vriendelijk geweest om ze te implementeren in Python, en de code is toegankelijk op pypi.org. Het programa heet Mate-for-Dummies, en ik maak er zeer dankbaar gebruik van. https://pypi.org/project/MATE-for-Dummies/

De code is niet gedocumenteerd, maar voor de meeste functies snap ik hoe hij werkt, en kan ik zelf opties toevoegen/veranderen. Echter is er voor mij een belangrijke functie waarbij ik vastzit.

In theorie kan ik additionele experimentele parameters declareren naar de Omicron software, en hun waardes van tijd tot tijd doorsturen, zodat de Omicron software alles samen opslaat. Om dit te doen heeft de is er de functie addForeignParameter. addForeign parameter is een functie die vier waardes ald input gebuikt. Voorbeeld uit de handleiding:
code:
1
 STM_Spectroscopy.addForeignParameter("My_Parameter","double","volt",0.0)


Andere functies die al geïmplementeerd zijn in Mate-for-Dummies gebruiken echter maar één parameter:
code:
1
 GapVoltage.min("Voltage")


In theorie, om de functies aan te roepen met behulp van de API moet je callFunctionByDesc() gebruiken. Om deze callFunctionByDesc() aan te roepen is ctypes nodig, aangezien de API in C++ geschreven is. callFunctionByDesc() heeft drie inputs:
  1. De functie die je wil gebruiken
  2. De datastructuur waar een eventuele data return in gezet wordt
  3. De datastructuur waar de parameters voor de functie in worden meegeven
Mijn probleem zit bij item 3. Wanneer er slechts één waarde voor de functie is, is er een vaste datastructuur, die gemakkelijk in ctypes is te declareren, om door te geven. Wanneer je verschillende waardes moet doorgeven specifieerd de handleiding een andere datastructuur die ik maar niet aan de praat krijg met behulp van Python/Ctypes:
Afbeeldingslocatie: https://tweakers.net/i/AyP624zPOM0wajTBM0CMRTGleuk=/f/image/hBUV7E9FpEuz5kK91aFUVgqo.png

Problematisch voor mij is dat deze constructie blijkbaar ook voor hun niet gemakkelijk te declareren is in C.

Ik heb al vanalle varianten geprobeerd van pointers door te geven van structuren, maar elke keer krijg ik een weinig behulpzame error terug:
The addressed object rejected the call to the function. This can have a number of reasons.
De datastructuur die op dit moment enkel werkt voor length = 1:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
def flat_values(self, string_length, array_length, length):
        pack = 4 * (1 + int(self.machine == 34404))

        class RealArray(ctypes.Structure):
            _pack_ = pack
            _fields_ = [('length', ctypes.c_int),
                        ('values', ctypes.c_double * array_length)]

        class FlatValue(ctypes.Structure):
            _pack_ = pack
            _fields_ = [('type', ctypes.c_int),
                        ('boolean', ctypes.c_int),
                        ('integer', ctypes.c_int),
                        ('enumeration', ctypes.c_int),
                        ('real', ctypes.c_double),
                        ('string', ctypes.POINTER(ctypes.POINTER(self.String))),
                        ('pairX', ctypes.c_double),
                        ('pairY', ctypes.c_double),
                        ('realArray',
                         ctypes.POINTER(ctypes.POINTER(RealArray)))]

        class FlatValues(ctypes.Structure):
            _fields_ = [('length', ctypes.c_int),
                        ('values', FlatValue * length)]

        flat_values = FlatValues(length)
        
        for i in range(length):
            o = flat_values.values[i]
            o.string = ctypes.pointer(ctypes.
                                      pointer(self.String(string_length)))
            o.realArray = ctypes.pointer(ctypes.
                                         pointer(RealArray(array_length)))
            
            
            flat_values.values[i] = o
        return flat_values

(En ja, alle varianten die ik geprobeerd heb geven ergere errors terug dan de structuur die al in Mate-for-Dummies zit. De maintainer kent duidelijk meet van programmeren dan ik.)

Hoe het in LabVIEW werkt voor de geïnteresseerde:
Afbeeldingslocatie: https://tweakers.net/i/Dfw4EIqA-JJSrV55_4XsBfufP9Q=/234x176/filters:strip_exif()/f/image/IuEBLicNtK7QJkhf6mFoCAJI.png?f=fotoalbum_medium

Heeft iemand een idee hoe ik de datastructuur van LabVIEW kan imiteren met ctypes?

Dit is de eerste keer dat ik een topic open in Softwareontwikkeling. Ik heb geprobeerd volledig te zijn, maar als extra info gewenst is, laat maar weten.