1414#include < cstdio>
1515#include < jni.h>
1616#include < pthread.h>
17+ #include " robin-hood-hashing/src/include/robin_hood.h"
1718
1819JNIEnv *env;
1920JavaVM *jvm;
2021
2122struct IOClass {
2223 IOClass (): _clazz(nullptr ), _instance(nullptr ) {}
2324
25+ virtual ~IOClass () {
26+ _clazz = nullptr ;
27+ _instance = nullptr ;
28+ }
29+
2430 bool create (const char *path) {
2531 bool result;
2632 if (_instance != nullptr ) {
27- // error: already constructed
33+ // error when already constructed
2834 result = false ;
2935 } else {
3036 _clazz = env->FindClass (path);
@@ -43,48 +49,75 @@ struct IOClass {
4349 return result;
4450 }
4551
46- bool invoke (const char *name, int value) {
52+ bool invokeIV (const char *name, int value) {
4753 bool result = false ;
4854 if (_instance != nullptr ) {
4955 jmethodID method = env->GetMethodID (_clazz, name, " (I)V" );
5056 if (method != nullptr ) {
5157 env->CallVoidMethod (_instance, method, value);
52- result = true ;
53- } else {
58+ }
59+ auto exc = env->ExceptionOccurred ();
60+ if (exc) {
5461 env->ExceptionDescribe ();
62+ env->ExceptionClear ();
63+ } else {
64+ result = (method != nullptr );
5565 }
5666 }
5767 return result;
5868 }
5969
6070 bool open (int pin) {
61- return invoke (" open" , pin);
71+ return invokeIV (" open" , pin);
6272 }
63-
73+
6474 bool write (int value) {
65- return invoke (" write" , value);
75+ return invokeIV (" write" , value);
6676 }
67-
77+
6878 private:
6979 jclass _clazz;
7080 jobject _instance;
7181};
7282
73- IOClass analogInput;
74- IOClass digitalOutput;
83+ #define CLS_IOCLASS 1
84+ robin_hood::unordered_map<int , IOClass> _ioClassMap;
85+ int _nextId = 1 ;
7586
76- static void cmd_digital_output_write (var_s *self, var_s *retval) {
77- static int value = !value;
78- digitalOutput.write (value);
87+ static int get_io_class_id (var_s *map) {
88+ int result = -1 ;
89+ if (is_map (map)) {
90+ int id = map->v .m .id ;
91+ if (id != -1 && _ioClassMap.find (id) != _ioClassMap.end ()) {
92+ result = id;
93+ }
94+ }
95+ return result;
96+ }
97+
98+ int value = 0 ;
99+ static void cmd_digital_output_write (var_s *map, var_s *retval) {
100+ value = !value;
101+ int id = get_io_class_id (map);
102+ if (id != -1 ) {
103+ _ioClassMap.at (id).write (value);
104+ } else {
105+ error (retval, " IOClass not found" );
106+ }
79107}
80108
81109static int cmd_openanaloginput (int argc, slib_par_t *params, var_t *retval) {
82110 int result;
83111 int pin = get_param_int (argc, params, 0 , 0 );
84- if (analogInput.create (" net/sourceforge/smallbasic/ioio/AnalogInput" ) &&
85- analogInput.open (pin)) {
112+ int id = ++_nextId;
113+ IOClass &input = _ioClassMap[id];
114+ if (input.create (" net/sourceforge/smallbasic/ioio/AnalogInput" ) &&
115+ input.open (pin)) {
116+ map_init_id (retval, id, CLS_IOCLASS);
117+ // v_create_func(retval, "write", cmd_digital_output_write);
86118 result = 1 ;
87119 } else {
120+ _ioClassMap.erase (id);
88121 error (retval, " openAnalogInput() failed" );
89122 result = 0 ;
90123 }
@@ -94,12 +127,15 @@ static int cmd_openanaloginput(int argc, slib_par_t *params, var_t *retval) {
94127static int cmd_opendigitaloutput (int argc, slib_par_t *params, var_t *retval) {
95128 int result;
96129 int pin = get_param_int (argc, params, 0 , 0 );
97- if (digitalOutput.create (" net/sourceforge/smallbasic/ioio/DigitalOutput" ) &&
98- digitalOutput.open (pin)) {
99- map_init (retval);
130+ int id = ++_nextId;
131+ IOClass &output = _ioClassMap[id];
132+ if (output.create (" net/sourceforge/smallbasic/ioio/DigitalOutput" ) &&
133+ output.open (pin)) {
134+ map_init_id (retval, id, CLS_IOCLASS);
100135 v_create_func (retval, " write" , cmd_digital_output_write);
101136 result = 1 ;
102137 } else {
138+ _ioClassMap.erase (id);
103139 error (retval, " openDigitalOutput() failed" );
104140 result = 0 ;
105141 }
@@ -126,7 +162,10 @@ int sblib_init(const char *sourceFile) {
126162 JavaVMInitArgs vm_args;
127163 JavaVMOption options[2 ];
128164 options[0 ].optionString = (char *)" -Djava.class.path=./target/ioio-1.0-jar-with-dependencies.jar" ;
129- options[1 ].optionString = (char *)" -Dioio.SerialPorts=ACM0" ;
165+ options[1 ].optionString = (char *)" -Dioio.SerialPorts=IOIO0" ;
166+ // options[2].optionString = "-Xdebug";
167+ // options[3].optionString = "-agentlib:jdwp=transport=dt_socket,server=y,address=5005,suspend=y";
168+ // options[2].optionString = (char *)"-Xcheck:jni";
130169 vm_args.version = JNI_VERSION_1_8;
131170 vm_args.nOptions = 2 ;
132171 vm_args.options = options;
@@ -139,9 +178,24 @@ int sblib_init(const char *sourceFile) {
139178 return result;
140179}
141180
181+ SBLIB_API void sblib_free (int cls_id, int id) {
182+ if (id != -1 ) {
183+ switch (cls_id) {
184+ case CLS_IOCLASS:
185+ _ioClassMap.erase (id);
186+ break ;
187+ }
188+ }
189+ }
190+
142191void sblib_close (void ) {
192+ if (!_ioClassMap.empty ()) {
193+ fprintf (stderr, " IOClass leak detected\n " );
194+ _ioClassMap.clear ();
195+ }
143196 jvm->DetachCurrentThread ();
144- jvm->DestroyJavaVM ();
197+ // hangs
198+ // jvm->DestroyJavaVM();
145199 env = nullptr ;
146200 jvm = nullptr ;
147201}
0 commit comments