Wrap IMAQdx functions.

Quite a few functions aren't wrapped, but the most critical ones for
vision should be.

This also fixes a couple of issues:
- nivision_arm.ini (and imaqdx_arm.ini) are now generated without need for
  running the output on the RoboRIO.
- enum values are generated even if the value is not directly specified.
This commit is contained in:
Peter Johnson
2014-12-12 22:52:31 -08:00
parent ac60198842
commit db0b421019
10 changed files with 1822 additions and 1912 deletions

View File

@@ -17,6 +17,7 @@ java_accessor_map = {
"J": "Long",
"F": "Float",
"D": "Double",
"Z": "Boolean",
}
java_size_map = {
@@ -27,6 +28,7 @@ java_size_map = {
"J": 8,
"F": 4,
"D": 8,
"Z": 1,
}
class JavaType:
@@ -66,6 +68,9 @@ java_types_map = {
("unsigned short", None): JavaType("int", "int", "jint", "I"),
("unsigned", None): JavaType("int", "int", "jint", "I"),
("unsigned int", None): JavaType("int", "int", "jint", "I"),
("uInt32", None): JavaType("int", "int", "jint", "I"),
("IMAQdxSession", None): JavaType("int", "int", "jint", "I"),
("bool32", None): JavaType("boolean", "boolean", "jboolean", "Z"),
("long", None): JavaType("long", "long", "jlong", "J"),
("unsigned long", None): JavaType("long", "long", "jlong", "J"),
("__int64", None): JavaType("long", "long", "jlong", "J"),
@@ -88,6 +93,7 @@ java_types_map = {
("short", ""): JavaType("short[]", "short[]", "jshortArray", "[S"),
("int", ""): JavaType("int[]", "int[]", "jintArray", "[I"),
("unsigned int", ""): JavaType("int[]", "int[]", "jintArray", "[I"),
("uInt32", ""): JavaType("int[]", "int[]", "jintArray", "[I"),
("long", ""): JavaType("long[]", "long[]", "jlongArray", "[J"),
("float", ""): JavaType("float[]", "float[]", "jfloatArray", "[F"),
("double", ""): JavaType("double[]", "double[]", "jdoubleArray", "[D"),
@@ -1117,6 +1123,7 @@ public class {classname} {{
#include <assert.h>
#include <jni.h>
#include <nivision.h>
#include <NIIMAQdx.h>
// throw java exception
static void throwJavaException(JNIEnv *env) {{
@@ -1130,6 +1137,18 @@ static void throwJavaException(JNIEnv *env) {{
free(full_err_msg);
}}
// throw IMAQdx java exception
static void dxthrowJavaException(JNIEnv *env, IMAQdxError err) {{
jclass je = env->FindClass("{packagepath}/VisionException");
char* err_text = (char*)malloc(200);
IMAQdxGetErrorString(err, err_text, 200);
char* full_err_msg = (char*)malloc(250);
sprintf(full_err_msg, "IMAQdxError: %d: %s", err, err_text);
free(err_text);
env->ThrowNew(je, full_err_msg);
free(full_err_msg);
}}
extern "C" {{
JNIEXPORT void JNICALL Java_{package}_{classname}__1imaqDispose(JNIEnv* , jclass , jlong addr)
@@ -1260,8 +1279,13 @@ JNIEXPORT void JNICALL Java_{package}_{classname}__1imaqDispose(JNIEnv* , jclass
continue
if vname.startswith("IMAQ_"):
vname = vname[5:]
if vname.startswith("IMAQdx"):
vname = vname[6:]
if vname[0] in "0123456789":
vname = "C" + vname
if value is None:
# auto-increment
value = "%d" % (prev_value + 1)
valuestrs.append("%s(%s),%s" % (vname, value, " // %s" % comment if comment else ""))
defined.add(vname)
value_i = int(value, 0)
@@ -1344,6 +1368,10 @@ JNIEXPORT void JNICALL Java_{package}_{classname}__1imaqDispose(JNIEnv* , jclass
functype = "STDFUNC"
rettype = c_to_jtype("void", None)
exceptioncheck = "if (rv == 0) throwJavaException(env);"
elif restype == "IMAQdxError":
functype = "STDFUNC"
rettype = c_to_jtype("void", None)
exceptioncheck = "if (rv != IMAQdxErrorSuccess) dxthrowJavaException(env, rv);"
else:
if restype[-1] == "*":
functype = "STDPTRFUNC"
@@ -1680,36 +1708,45 @@ JNIEXPORT {rettype} JNICALL Java_{package}_{classname}__1{name}({args})
def union(self, name, fields):
self.unions[name] = fields
def generate(srcdir, outdir, config_struct_path, configpath, nivisionhpath):
# read config files
config_struct = configparser.ConfigParser()
config_struct.read(config_struct_path)
config = configparser.ConfigParser()
config.read(configpath)
block_comment_exclude = set(x.strip() for x in
config.get("Block Comment", "exclude").splitlines())
def generate(srcdir, outdir, inputs):
emit = None
# open input file
inf = open(nivisionhpath)
for fname, config_struct_path, configpath in inputs:
# read config files
config_struct = configparser.ConfigParser()
config_struct.read(config_struct_path)
config = configparser.ConfigParser()
config.read(configpath)
block_comment_exclude = set(x.strip() for x in
config.get("Block Comment", "exclude").splitlines())
# prescan for undefined structures
prescan_file(inf)
inf.seek(0)
# open input file
with open(fname) as inf:
# prescan for undefined structures
prescan_file(inf)
inf.seek(0)
if emit is None:
emit = JavaEmitter(outdir, config, config_struct)
else:
emit.config = config
emit.config_struct = config_struct
# generate
parse_file(emit, inf, block_comment_exclude)
# generate
emit = JavaEmitter(outdir, config, config_struct)
parse_file(emit, inf, block_comment_exclude)
emit.finish()
if __name__ == "__main__":
if len(sys.argv) < 3:
print("Usage: gen_wrap.py <nivision.h> config_struct.ini [config.ini]")
if len(sys.argv) < 4 or ((len(sys.argv)-1) % 3) != 0:
print("Usage: gen_wrap.py <header.h config_struct.ini config.ini>...")
exit(0)
fname = sys.argv[1]
config_struct_name = sys.argv[2]
configname = "nivision_2011.ini"
if len(sys.argv) >= 4:
configname = sys.argv[3]
inputs = []
for i in range(1, len(sys.argv), 3):
fname = sys.argv[i]
config_struct_name = sys.argv[i+1]
configname = sys.argv[i+2]
inputs.append((fname, config_struct_name, configname))
generate("", "", config_struct_name, configname, fname)
generate("", "", inputs)

View File

@@ -10,16 +10,18 @@ except ImportError:
from nivision_parse import *
class StructSizerEmitter:
def __init__(self, out, config):
def __init__(self, out, config, hname):
self.out = out
self.config = config
print("""#include <stdio.h>
#include <nivision.h>
#include <stddef.h>
#include <{hname}>
int main()
{
printf("[_platform_]\\npointer=%d\\n", (int)sizeof(void*));
""", file=self.out)
{{
asm("#STRUCT_SIZER [_platform_]\\n");
asm("#STRUCT_SIZER pointer=%0\\n" : : "n"((int)sizeof(void*)));
""".format(hname=hname), file=self.out)
def finish(self):
print("}", file=self.out)
@@ -67,12 +69,13 @@ int main()
if name in opaque_structs:
return
print('printf("[{name}]\\n_SIZE_=%d\\n", (int)sizeof({name}));'.format(name=name), file=self.out)
print('asm("#STRUCT_SIZER [{name}]\\n");'.format(name=name), file=self.out)
print('asm("#STRUCT_SIZER _SIZE_=%0\\n" : : "n"((int)sizeof({name})));'.format(name=name), file=self.out)
for fname, ftype, arr, comment in fields:
if ':' in fname:
continue # can't handle bitfields
print('printf("{field}=%d\\n", (int)offsetof({name}, {field}));'.format(name=name, field=fname), file=self.out)
print('asm("#STRUCT_SIZER {field}=%0\\n" : : "n"((int)offsetof({name}, {field})));'.format(name=name, field=fname), file=self.out)
def struct(self, name, fields):
self.structunion("Structure", name, fields)
@@ -80,7 +83,7 @@ int main()
def union(self, name, fields):
self.structunion("Union", name, fields)
def generate(srcdir, configpath=None, nivisionhpath=None):
def generate(srcdir, configpath=None, hpath=None):
# read config file
config = configparser.ConfigParser()
config.read(configpath)
@@ -88,7 +91,7 @@ def generate(srcdir, configpath=None, nivisionhpath=None):
config.get("Block Comment", "exclude").splitlines())
# open input file
inf = open(nivisionhpath)
inf = open(hpath)
# prescan for undefined structures
prescan_file(inf)
@@ -96,18 +99,16 @@ def generate(srcdir, configpath=None, nivisionhpath=None):
# generate
with open("struct_sizer.c", "wt") as out:
emit = StructSizerEmitter(out, config)
emit = StructSizerEmitter(out, config, os.path.basename(hpath))
parse_file(emit, inf, block_comment_exclude)
emit.finish()
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Usage: gen_struct_sizer.py <nivision.h> [config.ini]")
if len(sys.argv) != 3:
print("Usage: gen_struct_sizer.py <header.h> <config.ini>")
exit(0)
fname = sys.argv[1]
configname = "nivision_2011.ini"
if len(sys.argv) >= 3:
configname = sys.argv[2]
configname = sys.argv[2]
generate("", configname, fname)

View File

@@ -3,9 +3,26 @@
# bindings for NIVision. At some point,
# it should be integrated into the build system.
# Assumes running from allwpilib/wpilibj/wpilibJavaJNI/nivision
# Get files that we node to generate from.
# Get structure sizes.
python gen_struct_sizer.py ../../../wpilibc/wpilibC++Devices/include/nivision.h nivision_2011.ini
arm-frc-linux-gnueabi-gcc -I../../../wpilibc/wpilibC++Devices/include -S struct_sizer.c
cat struct_sizer.s | python get_struct_size.py > nivision_arm.ini
python gen_struct_sizer.py ../../../wpilibc/wpilibC++Devices/include/NIIMAQdx.h imaqdx.ini
arm-frc-linux-gnueabi-gcc -I../../../wpilibc/wpilibC++Devices/include -S struct_sizer.c
cat struct_sizer.s | python get_struct_size.py > imaqdx_arm.ini
# Run python generator.
python gen_java.py ../../../wpilibc/wpilibC++Devices/include/nivision.h nivision_arm.ini nivision_2011.ini
python gen_java.py \
../../../wpilibc/wpilibC++Devices/include/nivision.h \
nivision_arm.ini \
nivision_2011.ini \
\
../../../wpilibc/wpilibC++Devices/include/NIIMAQdx.h \
imaqdx_arm.ini \
imaqdx.ini
# Stick generated files into appropriate places.
cp NIVision.cpp ../lib/NIVisionJNI.cpp
mkdir -p ../../wpilibJavaDevices/src/main/java/com/ni/vision

View File

@@ -0,0 +1,14 @@
from __future__ import print_function
import sys
def main():
for line in sys.stdin:
line = line.strip()
if not line.startswith("#STRUCT_SIZER"):
continue
line = line[14:]
line = line.replace("#", "")
print(line)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,81 @@
[Block Comment]
exclude=
Typedefs
Forward Declare Data Structures
Error Codes Enumeration
Callbacks
; Error Codes Enumeration
[IMAQdxError]
exclude=True
; Callbacks
[FrameDoneEventCallbackPtr]
exclude=True
[PnpEventCallbackPtr]
exclude=True
[AttributeUpdatedEventCallbackPtr]
exclude=True
; Functions
[IMAQdxSequence]
arraysize=images:count
exclude=True
[IMAQdxEnumerateCameras]
arraysize=cameraInformationArray:count
exclude=True
[IMAQdxGetImageData]
#arraysize=buffer:bufferSize
[IMAQdxEnumerateVideoModes]
arraysize=videoModeArray:count
exclude=True
[IMAQdxEnumerateAttributes]
arraysize=attributeInformationArray:count
exclude=True
[IMAQdxGetAttribute]
exclude=True
[IMAQdxSetAttribute]
# has to be manual due to "..."
exclude=True
[IMAQdxGetAttributeMinimum]
exclude=True
[IMAQdxGetAttributeMaximum]
exclude=True
[IMAQdxGetAttributeIncrement]
exclude=True
[IMAQdxEnumerateAttributeValues]
arraysize=list:size
exclude=True
[IMAQdxGetAttributeTooltip]
exclude=True
[IMAQdxGetAttributeUnits]
exclude=True
[IMAQdxRegisterFrameDoneEvent]
# callback
exclude=True
[IMAQdxRegisterPnpEvent]
# callback
exclude=True
[IMAQdxWriteMemory]
arraysize=values:count
exclude=True
[IMAQdxReadMemory]
arraysize=values:count
exclude=True
[IMAQdxGetErrorString]
exclude=True
[IMAQdxEnumerateAttributes2]
arraysize=attributeInformationArray:count
exclude=True
[IMAQdxGetAttributeDescription]
exclude=True
[IMAQdxGetAttributeDisplayName]
exclude=True
[IMAQdxDispose]
exclude=True
[IMAQdxRegisterAttributeUpdatedEvent]
# callback
exclude=True
[IMAQdxEnumerateAttributes3]
arraysize=attributeInformationArray:count
exclude=True

File diff suppressed because it is too large Load Diff

View File

@@ -7,14 +7,14 @@ __all__ = ["define_after_struct", "defined", "forward_structs", "opaque_structs"
# parser regular expressions
number_re = re.compile(r'-?[0-9]+')
constant_re = re.compile(r'[A-Z0-9_]+')
define_re = re.compile(r'^#define\s+(?P<name>(IMAQ|ERR)_[A-Z0-9_]+)\s+(?P<value>.*)')
define_re = re.compile(r'^#define\s+(?P<name>(IMAQ|ERR)[A-Z0-9_]+)\s+(?P<value>.*)')
enum_re = re.compile(r'^typedef\s+enum\s+(?P<name>[A-Za-z0-9]+)_enum\s*{')
enum_value_re = re.compile(r'^\s*(?P<name>[A-Z0-9_]+)\s*=\s*(?P<value>-?[0-9A-Fx]+)\s*,?')
enum_value_re = re.compile(r'^\s*(?P<name>[A-Za-z0-9_]+)\s*(=\s*(?P<value>-?[0-9A-Fx]+))?\s*,?')
struct_re = re.compile(r'^typedef\s+struct\s+(?P<name>[A-Za-z0-9]+)_struct\s*{')
union_re = re.compile(r'^typedef\s+union\s+(?P<name>[A-Za-z0-9]+)_union\s*{')
func_pointer_re = re.compile(r'(?P<restype>[A-Za-z0-9_*]+)\s*\(\s*[A-Za-z0-9_]*[*]\s*(?P<name>[A-Za-z0-9_]+)\s*\)\s*\((?P<params>[^)]*)\)')
func_pointer_re = re.compile(r'\s*(?P<restype>[A-Za-z0-9_*]+)\s*\(\s*[A-Za-z0-9_]*\s*[*]\s*(?P<name>[A-Za-z0-9_]+)\s*\)\s*\((?P<params>[^)]*)\)')
static_const_re = re.compile(r'^static\s+const\s+(?P<type>[A-Za-z0-9_]+)\s+(?P<name>[A-Za-z0-9_]+)\s*=\s*(?P<value>[^;]+);')
function_re = re.compile(r'^(IMAQ_FUNC\s+)?(?P<restype>(const\s+)?[A-Za-z0-9_*]+)\s+(IMAQ_STDCALL\s+)?(?P<name>[A-Za-z0-9_]+)\s*\((?P<params>[^)]*)\);')
function_re = re.compile(r'^((IMAQ|NI)_FUNC\s+)?(?P<restype>(const\s+)?[A-Za-z0-9_*]+)\s+((IMAQ_STDCALL|NI_FUNC[C]?)\s+)?(?P<name>[A-Za-z0-9_]+)\s*\((?P<params>[^)]*)\);')
# defines deferred until after structures
define_after_struct = []
@@ -216,5 +216,11 @@ def parse_file(emit, f, block_comment_exclude):
if not code or code[0] == '#':
continue
if not code or code[0] == '#':
continue
if code == 'extern "C" {' or code == "}":
continue
print("%d: Unrecognized: %s" % (lineno+1, code))