xlab / c-for-go

Automatic C-Go Bindings Generator for Go Programming Language
https://c.for-go.com
MIT License
1.48k stars 117 forks source link

NIDAQmx #11

Closed 5k3105 closed 7 years ago

5k3105 commented 7 years ago

Hi,

I am not very experienced with C. I was wondering if you could give me some instruction on what I am doing wrong please?

My repo is: https://github.com/5k3105/NIDAQmx

error:

processing nidaqmx.yml ⠸[ERR] NIDAQmx.h:85:29: unexpected identifier int64, expected one of ['(', ')', ',', ':', ';', '=', '[', '{', _Bool, _Complex, _Noreturn, _Static_assert, asm, auto, char, const, double, enum, extern, float, inline, int, long, register, restrict, short, signed, static, struct, typedef, typedefname, typeof, union, unsigned, void, volatile]

Thanks

cznic commented 7 years ago

FWIW, adding -ccdefs solves the problem here (Linux):

jnml@4670:~/src/github.com/5k3105/NIDAQmx$ cgogen nidaqmx.yml 
  processing nidaqmx.yml ⠙[ERR] NIDAQmx.h:85:29: unexpected identifier int64, expected one of ['(', ')', ',', ':', ';', '=', '[', '{', _Bool, _Complex, _Noreturn, _Static_assert, asm, auto, char, const, double, enum, extern, float, inline, int, long, register, restrict, short, signed, static, struct, typedef, typedefname, typeof, union, unsigned, void, volatile]
jnml@4670:~/src/github.com/5k3105/NIDAQmx$ cgogen -ccdefs nidaqmx.yml 
  processing nidaqmx.yml done.
jnml@4670:~/src/github.com/5k3105/NIDAQmx$ ll nidaqmx
celkem 196
-rw-rw-r-- 1 jnml jnml    277 lis 19 01:29 cgo_helpers.h
-rw-rw-r-- 1 jnml jnml 187050 lis 19 01:29 const.go
-rw-rw-r-- 1 jnml jnml    294 lis 19 01:29 doc.go
-rw-rw-r-- 1 jnml jnml    302 lis 19 01:29 nidaqmx.go
jnml@4670:~/src/github.com/5k3105/NIDAQmx$ 
5k3105 commented 7 years ago

Did not work for me. Gave same error. Win7. I have TDM-GCC64 installed.

cgogen -ccdefs C:\goworksp\src\local\NIDAQmx\nidaqmx.yml

Thank you for responding

cznic commented 7 years ago

Sorry to hear that it did not help. Possibly related cznic/cc#58 which has a pending PR cznic/cc#60.

xlab commented 7 years ago

@5k3105 Hi! A really quick fix would be to define __linux__ so the header won't be relying on compiler-specific types. Borrowing all compiler defines for this case is like using a sledgehammer for cracking nuts.

PARSER: 
  SourcesPaths: ["NIDAQmx.h"]
  Defines:
    __linux__: 1

Please close the issue if this helps. @cznic probably right, borrowing defines from compiler not yet available on windows.

xlab commented 7 years ago

@5k3105 also, your translator rules look messed up a bit, check out these:

TRANSLATOR: 
  ConstRules: 
    defines: expand
  Rules: 
    global: 
      - {action: accept, from: "^DAQmx"}
      - {action: replace, from: "^DAQmx"}
      - {transform: export}
    post-global: 
      - {action: replace, from: _$}
      - {load: snakecase}

works beautifully

5k3105 commented 7 years ago

Wow guys! Thanks a lot! Generated this time :+1:

I'll let you know how it tests monday - thanks so much :)

5k3105 commented 7 years ago

Hi,

package main

import (
    "fmt"
    "local/nidaqmx"
)

const DAQMX_DEVICE_NAME = "cDAQ9181-184F222"

func main() {

fmt.Println(nidaqmx.SelfTestDevice(DAQMX_DEVICE_NAME))

}

I get:

λ go build main.go
# local/NIDAQmx
In file included from ..\NIDAQmx\cgo_helpers.go:9:0:
./NIDAQmx.h:85:10: error: unknown type name '__int64'
  typedef __int64            int64;
          ^
./NIDAQmx.h:93:29: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'uInt64'
  typedef unsigned __int64   uInt64;
                             ^
In file included from ..\NIDAQmx\cgo_helpers.go:9:0:
./NIDAQmx.h:2652:145: error: unknown type name 'uInt64'
 int32 __CFUNC     DAQmxCfgSampClkTiming          (TaskHandle taskHandle, const char source[], float64 rate, int32 activeEdge, int32 sampleMode, uInt64 sampsPerChan);
                                                                                                                                                 ^
./NIDAQmx.h:2654:92: error: unknown type name 'uInt64'
 int32 __CFUNC     DAQmxCfgHandshakingTiming      (TaskHandle taskHandle, int32 sampleMode, uInt64 sampsPerChan);
                                                                                            ^
./NIDAQmx.h:2656:102: error: unknown type name 'uInt64'
 int32 __CFUNC     DAQmxCfgBurstHandshakingTimingImportClock(TaskHandle taskHandle, int32 sampleMode, uInt64 sampsPerChan, float64 sampleClkRate, const char sampleClkSrc[], int32 sampleClkActiveEdge, int32 pauseWhen, int32 readyEventActiveLevel);
                                                                                                      ^
./NIDAQmx.h:2658:102: error: unknown type name 'uInt64'
 int32 __CFUNC     DAQmxCfgBurstHandshakingTimingExportClock(TaskHandle taskHandle, int32 sampleMode, uInt64 sampsPerChan, float64 sampleClkRate, const char sampleClkOutpTerm[], int32 sampleClkPulsePolarity, int32 pauseWhen, int32 readyEventActiveLevel);
                                                                                                      ^
./NIDAQmx.h:2659:151: error: unknown type name 'uInt64'
 int32 __CFUNC     DAQmxCfgChangeDetectionTiming  (TaskHandle taskHandle, const char risingEdgeChan[], const char fallingEdgeChan[], int32 sampleMode, uInt64 sampsPerChan);
                                                                                                                                                       ^
./NIDAQmx.h:2661:92: error: unknown type name 'uInt64'
 int32 __CFUNC     DAQmxCfgImplicitTiming         (TaskHandle taskHandle, int32 sampleMode, uInt64 sampsPerChan);
                                                                                            ^
./NIDAQmx.h:2663:145: error: unknown type name 'uInt64'
 int32 __CFUNC     DAQmxCfgPipelinedSampClkTiming (TaskHandle taskHandle, const char source[], float64 rate, int32 activeEdge, int32 sampleMode, uInt64 sampsPerChan);
                                                                                                                                                 ^
./NIDAQmx.h:6228:66: error: unknown type name 'uInt64'
 int32 __CFUNC DAQmxGetLoggingSampsPerFile(TaskHandle taskHandle, uInt64 *data);
                                                                  ^
./NIDAQmx.h:6229:66: error: unknown type name 'uInt64'
 int32 __CFUNC DAQmxSetLoggingSampsPerFile(TaskHandle taskHandle, uInt64 data);
                                                                  ^
./NIDAQmx.h:6236:75: error: unknown type name 'uInt64'
 int32 __CFUNC DAQmxGetLoggingFilePreallocationSize(TaskHandle taskHandle, uInt64 *data);
                                                                           ^
./NIDAQmx.h:6237:75: error: unknown type name 'uInt64'
 int32 __CFUNC DAQmxSetLoggingFilePreallocationSize(TaskHandle taskHandle, uInt64 data);
                                                                           ^
./NIDAQmx.h:6240:62: error: unknown type name 'uInt64'
 int32 __CFUNC DAQmxGetReadCurrReadPos(TaskHandle taskHandle, uInt64 *data);
                                                              ^
./NIDAQmx.h:6244:75: error: unknown type name 'uInt64'
 int32 __CFUNC DAQmxGetReadTotalSampPerChanAcquired(TaskHandle taskHandle, uInt64 *data);
                                                                           ^
./NIDAQmx.h:6485:67: error: unknown type name 'uInt64'
 int32 __CFUNC DAQmxGetSampQuantSampPerChan(TaskHandle taskHandle, uInt64 *data);
                                                                   ^
./NIDAQmx.h:6486:67: error: unknown type name 'uInt64'
 int32 __CFUNC DAQmxSetSampQuantSampPerChan(TaskHandle taskHandle, uInt64 data);
                                                                   ^
./NIDAQmx.h:7297:64: error: unknown type name 'uInt64'
 int32 __CFUNC DAQmxGetWriteCurrWritePos(TaskHandle taskHandle, uInt64 *data);
                                                                ^
./NIDAQmx.h:7325:77: error: unknown type name 'uInt64'
 int32 __CFUNC DAQmxGetWriteTotalSampPerChanGenerated(TaskHandle taskHandle, uInt64 *data);
xlab commented 7 years ago

@5k3105 these are 100% C-related problems, I mean they arise because your C compiler can't compile the header given the defines you have during the compilation. I think you have to define something, there is two options:

1) Run go install this way: CGO_CFLAGS="-D__linux__=1" go install 2) Add platform-specific FlagGroups to cgogen config (see https://github.com/xlab/cgogen/wiki/Generator-config-section#flaggroups)

xlab commented 7 years ago

@5k3105 There are some bad news by the way. There is a lot, A LOT of methods that use ... variadic argument lists that are not supported in CGO. Normally there is two options to handle them: 1) ignore, 2) write a wrapper. Given their count, 2) is out of question, and 1) is probably too.

So for now, the quickest way to deal with it is to ignore:

      - {action: ignore, from: "^DAQmxGet"}
      - {action: ignore, from: "^DAQmxCreate"}
      - {action: ignore, from: "^DAQmxSet"}

You may add rules explicitly for variadic methods only, this should help you to get things working at least for anything else.

Note that ... variadics are not supported, but wrapper auto-generation can be done, this is scheduled on January holidays I guess. You can track progress in https://github.com/xlab/cgogen/issues/9

5k3105 commented 7 years ago
C:\goworksp\src\local\telem
λ set CGO_CFLAGS="-D__linux__=1"

C:\goworksp\src\local\telem
λ go install
# local/NIDAQmx
gcc: error: "-D__linux__=1": Invalid argument
C:\goworksp\src\local\telem
λ set CGO_CFLAGS="-D__linux__"

C:\goworksp\src\local\telem
λ go install
# local/NIDAQmx
gcc: error: "-D__linux__": Invalid argument

These are the only calls I will use right now:

nidaqmx.SelfTestDevice() // int32 __CFUNC     DAQmxSelfTestDevice            (const char deviceName[]);

nidaqmx.CreateTask() // int32 __CFUNC     DAQmxCreateTask                (const char taskName[], TaskHandle *taskHandle);

nidaqmx.CreateAIThrmcplChan() // int32 __CFUNC     DAQmxCreateAIThrmcplChan       (TaskHandle taskHandle, const char physicalChannel[], const char nameToAssignToChannel[], float64 minVal, float64 maxVal, int32 units, int32 thermocoupleType, int32 cjcSource, float64 cjcVal, const char cjcChannel[]);

nidaqmx.ValDegC
nidaqmx.ValTTypeTC
nidaqmx.ValBuiltIn
nidaqmx.ValGroupByScanNumber

nidaqmx.StartTask() // int32 __CFUNC     DAQmxStartTask                 (TaskHandle taskHandle);

nidaqmx.ReadAnalogF64() // int32 __CFUNC     DAQmxReadAnalogF64             (TaskHandle taskHandle, int32 numSampsPerChan, float64 timeout, bool32 fillMode, float64 readArray[], uInt32 arraySizeInSamps, int32 *sampsPerChanRead, bool32 *reserved);

nidaqmx.StopTask() // int32 __CFUNC     DAQmxStopTask                  (TaskHandle taskHandle);

nidaqmx.ClearTask() // int32 __CFUNC     DAQmxClearTask                 (TaskHandle taskHandle);
5k3105 commented 7 years ago

Ok, I think the env var took.

5k3105 commented 7 years ago

Using:

GENERATOR: 
  PackageName: nidaqmx
  PackageDescription: "Package nidaqmx provides Go bindings for National Instruments NIDAQmx"
  PackageLicense: "THE AUTOGENERATED LICENSE. ALL THE RIGHTS ARE RESERVED BY ROBOTS."
  Includes: ["NIDAQmx.h"]

PARSER: 
  SourcesPaths: ["NIDAQmx.h"]
  Defines:
    __linux__: 1

TRANSLATOR: 
  ConstRules: 
    defines: expand
  Rules: 
    global: 
      - {action: ignore, from: "^DAQmxGet"}
      - {action: ignore, from: "^DAQmxCreate"}
      - {action: ignore, from: "^DAQmxSet"}
      - {action: accept, from: "^DAQmx"}
      - {action: replace, from: "^DAQmx"}
      - {transform: export}
    post-global: 
      - {action: replace, from: _$}
      - {load: snakecase}

Lots of lines like this:

C:\Users\clott\AppData\Local\Temp\go-build291329218\local\NIDAQmx\_obj\nidaqmx.cgo2.o:nidaqmx.cgo2.c:(.text+0x1673d): undefined reference to `DAQmxStartNewFile'
C:\Users\clott\AppData\Local\Temp\go-build291329218\local\NIDAQmx\_obj\nidaqmx.cgo2.o:nidaqmx.cgo2.c:(.text+0x16793): undefined reference to `DAQmxStartTask'
C:\Users\clott\AppData\Local\Temp\go-build291329218\local\NIDAQmx\_obj\nidaqmx.cgo2.o:nidaqmx.cgo2.c:(.text+0x167e9): undefined reference to `DAQmxStopTask'
C:\Users\clott\AppData\Local\Temp\go-build291329218\local\NIDAQmx\_obj\nidaqmx.cgo2.o:nidaqmx.cgo2.c:(.text+0x16846): undefined reference to `DAQmxSwitchCloseRelays'
C:\Users\clott\AppData\Local\Temp\go-build291329218\local\NIDAQmx\_obj\nidaqmx.cgo2.o:nidaqmx.cgo2.c:(.text+0x168ae): undefined reference to `DAQmxSwitchConnect'
C:\Users\clott\AppData\Local\Temp\go-build291329218\local\NIDAQmx\_obj\nidaqmx.cgo2.o:nidaqmx.cgo2.c:(.text+0x1690b): undefined reference to `DAQmxSwitchConnectMulti'
C:\Users\clott\AppData\Local\Temp\go-build291329218\local\NIDAQmx\_obj\nidaqmx.cgo2.o:nidaqmx.cgo2.c:(.text+0x16969): undefined reference to `DAQmxSwitchCreateScanList'
C:\Users\clott\AppData\Local\Temp\go-build291329218\local\NIDAQmx\_obj\nidaqmx.cgo2.o:nidaqmx.cgo2.c:(.text+0x169d1): undefined reference to `DAQmxSwitchDisconnect'
C:\Users\clott\AppData\Local\Temp\go-build291329218\local\NIDAQmx\_obj\nidaqmx.cgo2.o:nidaqmx.cgo2.c:(.text+0x16a2e): undefined reference to `DAQmxSwitchDisconnectAll'
C:\Users\clott\AppData\Local\Temp\go-build291329218\local\NIDAQmx\_obj\nidaqmx.cgo2.o:nidaqmx.cgo2.c:(.text+0x16a8b): undefined reference to `DAQmxSwitchDisconnectMulti'
C:\Users\clott\AppData\Local\Temp\go-build291329218\local\NIDAQmx\_obj\nidaqmx.cgo2.o:nidaqmx.cgo2.c:(.text+0x16b06): undefined reference to `DAQmxSwitchFindPath'
C:\Users\clott\AppData\Local\Temp\go-build291329218\local\NIDAQmx\_obj\nidaqmx.cgo2.o:nidaqmx.cgo2.c:(.text+0x16b79): undefined reference to `DAQmxSwitchGetMultiRelayCount'
C:\Users\clott\AppData\Local\Temp\go-build291329218\local\NIDAQmx\_obj\nidaqmx.cgo2.o:nidaqmx.cgo2.c:(.text+0x16bec): undefined reference to `DAQmxSwitchGetMultiRelayPos'
C:\Users\clott\AppData\Local\Temp\go-build291329218\local\NIDAQmx\_obj\nidaqmx.cgo2.o:nidaqmx.cgo2.c:(.text+0x16c4a): undefined reference to `DAQmxSwitchGetSingleRelayCount'
C:\Users\clott\AppData\Local\Temp\go-build291329218\local\NIDAQmx\_obj\nidaqmx.cgo2.o:nidaqmx.cgo2.c:(.text+0x16ca8): undefined reference to `DAQmxSwitchGetSingleRelayPos'
C:\Users\clott\AppData\Local\Temp\go-build291329218\local\NIDAQmx\_obj\nidaqmx.cgo2.o:nidaqmx.cgo2.c:(.text+0x16d05): undefined reference to `DAQmxSwitchOpenRelays'
C:\Users\clott\AppData\Local\Temp\go-build291329218\local\NIDAQmx\_obj\nidaqmx.cgo2.o:nidaqmx.cgo2.c:(.text+0x16d63): undefined reference to `DAQmxSwitchSetTopologyAndReset'
C:\Users\clott\AppData\Local\Temp\go-build291329218\local\NIDAQmx\_obj\nidaqmx.cgo2.o:nidaqmx.cgo2.c:(.text+0x16db9): undefined reference to `DAQmxSwitchWaitForSettling'
C:\Users\clott\AppData\Local\Temp\go-build291329218\local\NIDAQmx\_obj\nidaqmx.cgo2.o:nidaqmx.cgo2.c:(.text+0x16e16): undefined reference to `DAQmxTaskControl'
C:\Users\clott\AppData\Local\Temp\go-build291329218\local\NIDAQmx\_obj\nidaqmx.cgo2.o:nidaqmx.cgo2.c:(.text+0x16e6c): undefined reference to `DAQmxTristateOutputTerm'
C:\Users\clott\AppData\Local\Temp\go-build291329218\local\NIDAQmx\_obj\nidaqmx.cgo2.o:nidaqmx.cgo2.c:(.text+0x16ec2): undefined reference to `DAQmxUnreserveNetworkDevice'
C:\Users\clott\AppData\Local\Temp\go-build291329218\local\NIDAQmx\_obj\nidaqmx.cgo2.o:nidaqmx.cgo2.c:(.text+0x16f30): undefined reference to `DAQmxWaitForNextSampleClock'
C:\Users\clott\AppData\Local\Temp\go-build291329218\local\NIDAQmx\_obj\nidaqmx.cgo2.o:nidaqmx.cgo2.c:(.text+0x16f93): undefined reference to `DAQmxWaitUntilTaskDone'
C:\Users\clott\AppData\Local\Temp\go-build291329218\local\NIDAQmx\_obj\nidaqmx.cgo2.o:nidaqmx.cgo2.c:(.text+0x1703a): undefined reference to `DAQmxWriteAnalogF64'
C:\Users\clott\AppData\Local\Temp\go-build291329218\local\NIDAQmx\_obj\nidaqmx.cgo2.o:nidaqmx.cgo2.c:(.text+0x170be): undefined reference to `DAQmxWriteAnalogScalarF64'
C:\Users\clott\AppData\Local\Temp\go-build291329218\local\NIDAQmx\_obj\nidaqmx.cgo2.o:nidaqmx.cgo2.c:(.text+0x17165): undefined reference to `DAQmxWriteBinaryI16'
C:\Users\clott\AppData\Local\Temp\go-build291329218\local\NIDAQmx\_obj\nidaqmx.cgo2.o:nidaqmx.cgo2.c:(.text+0x1720c): undefined reference to `DAQmxWriteBinaryI32'
C:\Users\clott\AppData\Local\Temp\go-build291329218\local\NIDAQmx\_obj\nidaqmx.cgo2.o:nidaqmx.cgo2.c:(.text+0x172b3): undefined reference to `DAQmxWriteBinaryU16'
C:\Users\clott\AppData\Local\Temp\go-build291329218\local\NIDAQmx\_obj\nidaqmx.cgo2.o:nidaqmx.cgo2.c:(.text+0x1735a): undefined reference to `DAQmxWriteBinaryU32'
C:\Users\clott\AppData\Local\Temp\go-build291329218\local\NIDAQmx\_obj\nidaqmx.cgo2.o:nidaqmx.cgo2.c:(.text+0x17413): undefined reference to `DAQmxWriteCtrFreq'
C:\Users\clott\AppData\Local\Temp\go-build291329218\local\NIDAQmx\_obj\nidaqmx.cgo2.o:nidaqmx.cgo2.c:(.text+0x174a7): undefined reference to `DAQmxWriteCtrFreqScalar'
C:\Users\clott\AppData\Local\Temp\go-build291329218\local\NIDAQmx\_obj\nidaqmx.cgo2.o:nidaqmx.cgo2.c:(.text+0x17560): undefined reference to `DAQmxWriteCtrTicks'
C:\Users\clott\AppData\Local\Temp\go-build291329218\local\NIDAQmx\_obj\nidaqmx.cgo2.o:nidaqmx.cgo2.c:(.text+0x175eb): undefined reference to `DAQmxWriteCtrTicksScalar'
C:\Users\clott\AppData\Local\Temp\go-build291329218\local\NIDAQmx\_obj\nidaqmx.cgo2.o:nidaqmx.cgo2.c:(.text+0x176a4): undefined reference to `DAQmxWriteCtrTime'
C:\Users\clott\AppData\Local\Temp\go-build291329218\local\NIDAQmx\_obj\nidaqmx.cgo2.o:nidaqmx.cgo2.c:(.text+0x17738): undefined reference to `DAQmxWriteCtrTimeScalar'
C:\Users\clott\AppData\Local\Temp\go-build291329218\local\NIDAQmx\_obj\nidaqmx.cgo2.o:nidaqmx.cgo2.c:(.text+0x177df): undefined reference to `DAQmxWriteDigitalLines'
C:\Users\clott\AppData\Local\Temp\go-build291329218\local\NIDAQmx\_obj\nidaqmx.cgo2.o:nidaqmx.cgo2.c:(.text+0x17861): undefined reference to `DAQmxWriteDigitalScalarU32'
C:\Users\clott\AppData\Local\Temp\go-build291329218\local\NIDAQmx\_obj\nidaqmx.cgo2.o:nidaqmx.cgo2.c:(.text+0x17908): undefined reference to `DAQmxWriteDigitalU16'
C:\Users\clott\AppData\Local\Temp\go-build291329218\local\NIDAQmx\_obj\nidaqmx.cgo2.o:nidaqmx.cgo2.c:(.text+0x179af): undefined reference to `DAQmxWriteDigitalU32'
C:\Users\clott\AppData\Local\Temp\go-build291329218\local\NIDAQmx\_obj\nidaqmx.cgo2.o:nidaqmx.cgo2.c:(.text+0x17a56): undefined reference to `DAQmxWriteDigitalU8'
C:\Users\clott\AppData\Local\Temp\go-build291329218\local\NIDAQmx\_obj\nidaqmx.cgo2.o:nidaqmx.cgo2.c:(.text+0x17af2): undefined reference to `DAQmxWriteRaw'
C:\Users\clott\AppData\Local\Temp\go-build291329218\local\NIDAQmx\_obj\nidaqmx.cgo2.o:nidaqmx.cgo2.c:(.text+0x17b65): undefined reference to `DAQmxWriteToTEDSFromArray'
C:\Users\clott\AppData\Local\Temp\go-build291329218\local\NIDAQmx\_obj\nidaqmx.cgo2.o:nidaqmx.cgo2.c:(.text+0x17bcd): undefined reference to `DAQmxWriteToTEDSFromFile'
C:\Users\clott\AppData\Local\Temp\go-build291329218\local\NIDAQmx\_obj\nidaqmx.cgo2.o:nidaqmx.cgo2.c:(.text+0x17c2e): undefined reference to `DAQmxXSeriesCalAdjust'
collect2.exe: error: ld returned 1 exit status
xlab commented 7 years ago

@5k3105 Yeah, sure, you should link against a library. You're pretty close. Depending on the environment, you must link against .dll, .so or .dylib

If you library is located under name libnidaqmx.so in /usr/local/lib then specify CGO_LDFLAGS="-L/usr/local/lib -lnidaqmx" I hope you see the pattern in these.

Another option is to fill the FlagGroups in generator's config that will specify LDFLAGS for your platform, there are many other options but they're much more advanced (and time consuming).

TIP! If you have pkg-config installed, you can take advantage of that, see example: https://github.com/xlab/vorbis-go/blob/master/vorbis.yml#L6

UPD: oops, you're under Windows, so just locate the library on your disk and paste the path of directory to -L flag and the mingw64 compatible lib name to -l.

5k3105 commented 7 years ago

@xlab Thank you for all your help!

λ go install
# local/NIDAQmx
..\NIDAQmx\const.go:2067: ReadWaitMode redeclared in this block
        previous declaration at ..\NIDAQmx\const.go:1519
..\NIDAQmx\const.go:2441: ValPulseTime redeclared in this block
        previous declaration at ..\NIDAQmx\const.go:2417
..\NIDAQmx\const.go:2445: ValPulseTicks redeclared in this block
        previous declaration at ..\NIDAQmx\const.go:2419

I was initially going to just delete these extra lines but it turns out they are indeed redeclared but with different values sometimes. So I just put a '2' behind the second instances of these and it stopped complaining.

My CGO_LDFLAGS looks like this: -L/goworksp/src/local/NIDAQmx -lnicaiu

But I get:

λ go install
# local/telem
C:\Go\pkg\tool\windows_amd64\link.exe: running gcc failed: exit status 1
C:/TDM-GCC-64/bin/../lib/gcc/x86_64-w64-mingw32/5.1.0/../../../../x86_64-w64-mingw32/bin/ld.exe: cannot find -lnicaiu
collect2.exe: error: ld returned 1 exit status

I feel like I've tried every permutation of the above. It's a .dll file - "nicaiu.dll" (from the Windows/Wow64 folder on the target machine) I copied and placed in the nidaqmx folder. I found an old post refering to this:

http://forums.ni.com/t5/Multifunction-DAQ/How-Can-I-Use-The-NI-DAQmx-ANSI-C-Function-Library-With-GCC-on/td-p/195781

and

http://forums.ni.com/t5/Multifunction-DAQ/Howto-use-NIDAQmx-with-mingw-gcc-3-4-2/td-p/294361

Funny thing is, even when I remove the '-lnicaiu' from the flags: CGO_LDFLAGS =-L/goworksp/src/local/NIDAQmx

It still responds with cannot find -lnicaiu:

λ go install
# local/telem
C:\Go\pkg\tool\windows_amd64\link.exe: running gcc failed: exit status 1
C:/TDM-GCC-64/bin/../lib/gcc/x86_64-w64-mingw32/5.1.0/../../../../x86_64-w64-mingw32/bin/ld.exe: cannot find -lnicaiu
collect2.exe: error: ld returned 1 exit status
xlab commented 7 years ago

That's strange indeed, ld must always be capable of finding nicaiu.dll in paths defined by -L. :(

5k3105 commented 7 years ago

In the second link it mentioned:

Qt 4.7 with included mingw can use NIDAQmx.lib "as is" with LIBS += "\NIDAQmx.lib" statement in pro file.

Not sure what this means but I gave qt a try:

λ go install
# local/telem
C:\Go\pkg\tool\windows_amd64\link.exe: running gcc failed: exit status 1
C:/Qt/Qt5.7.0/Tools/mingw530_32/bin/../lib/gcc/i686-w64-mingw32/5.3.0/../../../../i686-w64-mingw32/bin/ld.exe: unrecognised emulation mode: i386pep
Supported emulations: i386pe
collect2.exe: error: ld returned 1 exit status
xlab commented 7 years ago

You're going too deeply in the rabbit hole. I think it's pretty solvable with plain MinGW64 + msys shell, with clean env variables. Just clean the mess.

5k3105 commented 7 years ago

Hi,

Got it to compile! (complete go build log at bottom)

host link: "gcc" "-m64" "-gdwarf-2" "-mconsole" "-o" "C:\\msys64\\tmp\\go-build984789194\\local\\telem\\_obj\\exe\\a.out.exe" "C:\\msys64\\tmp\\go-link-612005067\\go.o" "C:\\msys64\\tmp\\go-link-612005067\\000000.o" "C:\\msys64\\tmp\\go-link-612005067\\000001.o" "-L\\\\goworksp\\\\src\\\\local\\\\NIDAQmx" "-lnicaiu" "-g" "-O2" "-lmsvcrt" "-lm" "-mthreads" "-lwinmm" "-lws2_32" "-lntdll" "-ladvapi32" "-lkernel32"

Meaningful line:

"-L\\\\goworksp\\\\src\\\\local\\\\NIDAQmx"

Which I could not get to change through any of my env vars (.profile, .bash_profile, windows env vars). It should be /c/goworksp/src/local/NIDAQmx. Since it was missing the c, it couldn't find the .dll. Wound up putting dll in /c/usr/local/lib and it compiled.

So :) thank you!

I now have two problems. The SelfTestDevice which takes a string and returns an int (error code) is coming back with 'Device identifier is invalid.' Pretty sure this is the correct string I am sending it since I am just translating some python over - so same device name. Is there any way that string (const char deviceName[]) could get changed?

I am wondering if the way I changed the constants may be disturbing things (https://github.com/xlab/cgogen/issues/11#issuecomment-262314019). I just did a search and replace on the names but any of the functions using the old names will surely take the first value and not the second value I renamed to 'value2'.

Second - nidaqmx.CreateTask() // int32 __CFUNC DAQmxCreateTask (const char taskName[], TaskHandle *taskHandle);

This is the first function used in the code. It does not have a variadic argument but is also not generated because it starts with 'Create'. So there is a way I can include that single function? (- {action: accept, from: "^DAQmxCreateTask"}):

  Rules: 
    global: 
      - {action: accept, from: "^DAQmxCreateTask"}
      - {action: ignore, from: "^DAQmxGet"}
      - {action: ignore, from: "^DAQmxCreate"}
      - {action: ignore, from: "^DAQmxSet"}
      - {action: accept, from: "^DAQmx"}
      - {action: replace, from: "^DAQmx"}
      - {transform: export}

go build log:

clott@N-04711 MINGW64 /c/goworksp/src/local/telem
$ go build -v -x -ldflags "-L /c/goworksp/src/local/NIDAQmx -v"
WORK=C:\msys64\tmp\go-build984789194
local/telem
mkdir -p $WORK\local\telem\_obj\
mkdir -p $WORK\local\telem\_obj\exe\
cd C:\goworksp\src\local\telem
"C:\\Go\\pkg\\tool\\windows_amd64\\compile.exe" -o "C:\\msys64\\tmp\\go-build984789194\\local\\telem.a" -trimpath "C:\\msys64\\tmp\\go-build984789194" -p main -complete -buildid 6c79789db6d79a20215dc936c2f622a43fbe87f4 -D _/C_/goworksp/src/local/telem -I "C:\\msys64\\tmp\\go-build984789194" -I "C:\\goworksp\\pkg\\windows_amd64" -pack "C:\\goworksp\\src\\local\\telem\\main.go"
cd .
"C:\\Go\\pkg\\tool\\windows_amd64\\link.exe" -o "C:\\msys64\\tmp\\go-build984789194\\local\\telem\\_obj\\exe\\a.out.exe" -L "C:\\msys64\\tmp\\go-build984789194" -L "C:\\goworksp\\pkg\\windows_amd64" -extld=gcc -buildmode=exe -buildid=6c79789db6d79a20215dc936c2f622a43fbe87f4 -L /c/goworksp/src/local/NIDAQmx -v "C:\\msys64\\tmp\\go-build984789194\\local\\telem.a"
# local/telem
HEADER = -H10 -T0x401000 -D0x0 -R0x1000
searching for runtime.a in $WORK\runtime.a
searching for runtime.a in C:\goworksp\pkg\windows_amd64\runtime.a
searching for runtime.a in \c\goworksp\src\local\NIDAQmx\runtime.a
searching for runtime.a in C:\Go\pkg\windows_amd64\runtime.a
 0.00 deadcode
 0.02 pclntab=285276 bytes, funcdata total 44156 bytes
 0.02 dodata
 0.02 reloc
 0.03 reloc
 0.03 asmb
 0.03 codeblk
 0.04 datblk
 0.04 sym
 0.04 dwarf
 0.04 headr
 0.04 symsize = 0
host link: "gcc" "-m64" "-gdwarf-2" "-mconsole" "-o" "C:\\msys64\\tmp\\go-build984789194\\local\\telem\\_obj\\exe\\a.out.exe" "C:\\msys64\\tmp\\go-link-612005067\\go.o" "C:\\msys64\\tmp\\go-link-612005067\\000000.o" "C:\\msys64\\tmp\\go-link-612005067\\000001.o" "-L\\\\goworksp\\\\src\\\\local\\\\NIDAQmx" "-lnicaiu" "-g" "-O2" "-lmsvcrt" "-lm" "-mthreads" "-lwinmm" "-lws2_32" "-lntdll" "-ladvapi32" "-lkernel32"
C:\Go\pkg\tool\windows_amd64\link.exe: running gcc failed: exit status 1
C:/TDM-GCC-64/bin/../lib/gcc/x86_64-w64-mingw32/5.1.0/../../../../x86_64-w64-mingw32/bin/ld.exe: cannot find -lnicaiu
collect2.exe: error: ld returned 1 exit status
xlab commented 7 years ago

Regarding strings: you need to form an 0-ending string like "hello\x00" otherwise you hand a full memory chunk to C land, and it reads your passwords from a browser tab here too.

Take these snippets:

var end = "\x00"
var endChar byte = '\x00'

func safeString(s string) string {
    if len(s) == 0 {
        return end
    }
    if s[len(s)-1] != endChar {
        return s + end
    }
    return s
}

func safeStrings(list []string) []string {
    for i := range list {
        list[i] = safeString(list[i])
    }
    return list
}
xlab commented 7 years ago

@5k3105 About the ignore case:

      - {action: ignore, from: "^DAQmxCreate[^T]+"}

You can use regexp to just ignore functions that are not DAQmxCreateT* (I checked, there is no ... in DAQmxCreateT* functions).

I probably need to add respect of the filters order, so you could override "^DAQmxCreate" with "^DAQmxCreateTask" by placing it below, but it's technically harder than 1 hour so I postpone that change. To be specific, this particular function needs to learn how to respect the order of rules https://github.com/xlab/cgogen/blob/master/translator/translator.go#L912-L926 but currently it operates on separate maps and can't tell if accept rules are below ignore rules in the config.

Glad you got that working. Be careful with strings.

5k3105 commented 7 years ago

Hi,

I don't understand why TaskHandle passed into DAQmxCreateTask as *taskHandle is represented in go as []unsafe.Pointer.

This is my code:

var th unsafe.Pointer

nidaqmx.CreateTask("task1", &th) 

nidaqmx.CreateAIThrmcplChan(th, safeString(DAQMX_DEVICE_NAME + "/ai1"), safeString("T0 - LiDAR box right side"), -60.0, 100.0, nidaqmx.ValDegC, nidaqmx.ValTTypeTC, nidaqmx.ValBuiltIn, 25.0, safeString(" "))

TaskHandle (https://github.com/5k3105/NIDAQmx/blob/master/NIDAQmx.h#L99):

typedef void* TaskHandle;

CreateTask (https://github.com/5k3105/NIDAQmx/blob/master/NIDAQmx.h#L2510):

int32 __CFUNC DAQmxCreateTask (const char taskName[], TaskHandle *taskHandle);

CreateAIThrmcplChan:

int32 __CFUNC     DAQmxCreateAIThrmcplChan       (TaskHandle taskHandle, const char physicalChannel[], const char nameToAssignToChannel[], float64 minVal, float64 maxVal, int32 units, int32 thermocoupleType, int32 cjcSource, float64 cjcVal, const char cjcChannel[]);

generated go:

// CreateTask function as declared in nidaqmx\NIDAQmx.h:2510
func CreateTask(TaskName string, TaskHandle []unsafe.Pointer) int32 {
    cTaskName, _ := unpackPCharString(TaskName)
    cTaskHandle, _ := (*unsafe.Pointer)(unsafe.Pointer((*sliceHeader)(unsafe.Pointer(&TaskHandle)).Data)), cgoAllocsUnknown
    __ret := C.DAQmxCreateTask(cTaskName, cTaskHandle)
    __v := (int32)(__ret)
    return __v
}
// CreateAIThrmcplChan function as declared in nidaqmx\NIDAQmx.h:2547
func CreateAIThrmcplChan(TaskHandle unsafe.Pointer, PhysicalChannel string, NameToAssignToChannel string, MinVal float64, MaxVal float64, Units int32, ThermocoupleType int32, CjcSource int32, CjcVal float64, CjcChannel string) int32 {
    cTaskHandle, _ := (unsafe.Pointer)(TaskHandle), cgoAllocsUnknown
    cPhysicalChannel, _ := unpackPCharString(PhysicalChannel)
    cNameToAssignToChannel, _ := unpackPCharString(NameToAssignToChannel)
    cMinVal, _ := (C.float64)(MinVal), cgoAllocsUnknown
    cMaxVal, _ := (C.float64)(MaxVal), cgoAllocsUnknown
    cUnits, _ := (C.int32)(Units), cgoAllocsUnknown
    cThermocoupleType, _ := (C.int32)(ThermocoupleType), cgoAllocsUnknown
    cCjcSource, _ := (C.int32)(CjcSource), cgoAllocsUnknown
    cCjcVal, _ := (C.float64)(CjcVal), cgoAllocsUnknown
    cCjcChannel, _ := unpackPCharString(CjcChannel)
    __ret := C.DAQmxCreateAIThrmcplChan(cTaskHandle, cPhysicalChannel, cNameToAssignToChannel, cMinVal, cMaxVal, cUnits, cThermocoupleType, cCjcSource, cCjcVal, cCjcChannel)
    __v := (int32)(__ret)
    return __v
}
xlab commented 7 years ago

@5k3105 That's because in C there is no difference between an array and a pointer without some context (like length), this is indistinguishable by translator.

So cgogen assumes by default that every function argument or struct field being a pointer means it's a slice (and that's correct). And return values are assumed to be pointers (just more likely return a pointer rather than an array, due to unknown length). But there is a legitimate way to change this because of convenience of pointer types (as opposed to slices).

Please check out the docs about this behaviour and how to deal with it using PtrTips: https://github.com/xlab/cgogen/wiki/Translator-config-section#ptrtips

thus you can override the default behaviour for all by providing a line that covers everything. And work out the cases when you actually have slices, not pointers. Or maybe make a rule making every first argument of any function be always a pointer, useful for receivers. By the way, you can find a plenty of legit examples here: https://github.com/xlab/cgogen/wiki/Examples

For particular example, a typical PtrTip section: https://github.com/xlab/android-go/blob/master/gles2.yml#L26-L39

5k3105 commented 7 years ago

Ok, I will take a look at that.

I will do this temporarily then:

var ths []unsafe.Pointer

nidaqmx.CreateTask("task1", ths)

th := ths[0]

nidaqmx.CreateAIThrmcplChan(th, safeString(DAQMX_DEVICE_NAME + "/ai1"), safeString("T0 - LiDAR box right side"), -60.0, 100.0, nidaqmx.ValDegC, nidaqmx.ValTTypeTC, nidaqmx.ValBuiltIn, 25.0, safeString(" "))

and I will test:

  PtrTips:
    function:
      - {target: ^DAQmxCreateTask$, tips: [0,ref]}
xlab commented 7 years ago

@5k3105

nidaqmx.CreateTask("task1", ths)

you forgot safeString or \x00 in string.

5k3105 commented 7 years ago

Thank you ;)

5k3105 commented 7 years ago

Hi,

I went ahead and updated the yml and generated the lib again, but instead of giving

TaskHandle *unsafe.Pointer in CreateTask, it gave TaskHandle unsafe.Pointer

So I changed it in the file to *unsafe.Pointer (which is probably wrong, right?).

It did compile but I get nothing in response to ReadAnalogF64 so I imagine this is wrong?

Later I ran into:

func ReadAnalogF64(TaskHandle unsafe.Pointer, NumSampsPerChan int32, Timeout float64, FillMode uint32, ReadArray []float64, ArraySizeInSamps uint32, SampsPerChanRead []int32, Reserved []uint32) int32 {

SampsPerChanRead needed to be *int32 so I updated the yml:

  PtrTips:
    function:
      - {target: ^DAQmxCreateTask$, tips: [0,ref]}
      - {target: ^DAQmxReadAnalogF64$, tips: [0, 0, 0, 0, 0, 0, ref, ref]}
5k3105 commented 7 years ago

Another point that might be making things misbehave:

For ReadAnalogF64, parameter ReadArray size is dependent on the following parameter called ArraySizeInSamps.

Since ReadArray expects a slice in Go, I can't:

var readarray [16]float64

when ArraySizeInSamps = 16

In the other code I look at the array size is statically defined before it's use:

data = numpy.zeros((1000,), dtype=numpy.float64)

DAQmxReadAnalogF64(taskHandle,1000,10.0,DAQmx_Val_GroupByChannel,data,1000,byref(read),None)

or in C:

 float64     data[1000];

DAQmxReadAnalogF64(taskHandle,1000,10.0,DAQmx_Val_GroupByChannel,data,1000,&read,NULL)

(examples from: https://pythonhosted.org/PyDAQmx/usage.html)

5k3105 commented 7 years ago

Hi,

I also get

Error -200492 Reserved parameter must be NULL.

for the last parameter of DAQmxReadAnalogF64. I have tried to put nil there and also

var reserved uint32
reserved = 0

f64 := nidaqmx.ReadAnalogF64(th, 1, 100.0, nidaqmx.ValGroupByScanNumber, readarray, 16, &samplesperchanread, &reserved)

which gives me the error as well.

How do I specify a C NULL in Go when it expects a *uint32 ?

xlab commented 7 years ago

How do I specify a C NULL

As usual really, nil. Instead:

, &reserved)

do:

, nil)
5k3105 commented 7 years ago

Hi. Thank you for your help.

original error code was:

Error -200492 Reserved parameter must be NULL.

after the change to nil for 'reserved' parameter, error code is:

Error -200230 NULL pointer was passed for a required parameter.

I think this now refers to the 'readarray' parameter.

(TaskHandle taskHandle, int32 numSampsPerChan, float64 timeout, bool32 fillMode, float64 readArray[], uInt32 arraySizeInSamps, int32 *sampsPerChanRead, bool32 *reserved)

5k3105 commented 7 years ago

Hi,

Do you know of any way I can fix this:

..\NidaqMonitor\nidaqMonitor.go:57: cannot use readarray (type [16]float64) as type []float64 in argument to nidaqmx.ReadAnalogF64

xlab commented 7 years ago

Use arr = make([]float64, 16) instead of [16]float64. That seems to be a Go error.

By the way, as the issue is resolved, I propose to move the discussion to email (max@kc.vc)