ardera / flutter-pi

A light-weight Flutter Engine Embedder for Linux Embedded that runs without X11 or Wayland.
MIT License
1.64k stars 162 forks source link

Get the app directory? #167

Closed pezi closed 3 years ago

pezi commented 3 years ago

Is there a way for a flutter app running under flutter-pi to get the the app directory? e.g.

/home/pi/my_apps_flutter_assets
ardera commented 3 years ago

Not that I know of. Though if you're not afraid of some hacking, you can maybe get it from Platform.executableArguments in combination with Directory.current.

What do you want to use the path for?

pezi commented 3 years ago

I need the app data directory for finding the native library of my Dart package dart_periphery inside the asset folder. Loading a native library fom the pub cache is a little tricky. All solutions, which I found, try to analyse the .package file, which contains the absolute path of the package lib directory. But this method will not work for the flutter_pi environment.

The user can provide an absolute path

setCustomLibrary(String absolutePath) 

for the native library. But for the future, I will try to provide a more simple solution - add the needed native lib inside the asset folder and dart_periphery will do the rest.

I played around - this solution works for me - (more checks should be done)

final dylib = DynamicLibrary.open('libc.so.6');
typedef A = Int32 Function();
typedef B = int Function();
var getpid = dylib.lookup<NativeFunction<A>>('getpid').asFunction<B>();
   // example CLI: flutter-pi pi/flutter_asset
   //   /proc/PID/cmdline -> list of '\0' terminated C-Strings
   // 00000000  66 6c 75 74 74 65 72 2d  70 69 00 70 69 2f 66 6c  |flutter-pi.pi/fl|
   // 00000010  75 74 74 65 72 5f 61 73  73 65 74 73 2f 00        |utter_assets/.|
    var cmd = File('/proc/${getpid()}/cmdline').readAsBytesSync();
    var arg = '';
    for (var i = 0; i < cmd.length; ++i) {
      // find end of first argument (flutter-pi) 
      if (cmd.elementAt(i) == 0) {
        var k = 0;
        //  find end of second argument - asset directory
        for (k = i + 1; k < cmd.length; ++k) {
          if (cmd.elementAt(k) == 0) {
            break;
          }
        }
        arg = String.fromCharCodes(Uint8List.sublistView(cmd, i + 1, k));
        break;
      }
    }
    var separator = '';
    if (!arg.startsWith('/')) {
      separator = '/';
    }
    var dir = Directory.current.path + separator + arg;
    print(dir);
/home/pi/flutter_assets
ardera commented 3 years ago

Yeah that's probably the best way to do it for now. You could also statically link flutter-pi with the dart-periphery library if you want to or specify LD_LIBRARY_PATH=./my-asset-bundle when invoking flutter-pi so you can load the library without the path, just by the name.

What components of dart periphery are you using? (so gpio, i2c, so on)

pezi commented 3 years ago

For a private project I built a CO2 traffic light written in Java running on a PI with following I2C sensor combination: SGP30 (CO2) and BME280 (temperature, humidity and pressure) with 3 GPIO controlled leds and a SPI waveshare ePaper display.

The HW works fine, but I was not really happy with the code, which relies on the massive use of JNI (Java Native Interface) to include the SGP30 sensor and the ePaper display.

During my research for a better solution I found follwing interesting projects: dizero and java-periphery

On the other hand I started to learn Flutter/Dart. Learning by doing now I am rewriting the CO2 traffic light as a Flutter App. "Das Pferd von hinten aufzäumend" - put the cart before the horse I started with the c-periphery Dart HW port...

For clarification: for the Flutter/flutter-pi project the ePaper display was exchanged by a UPERFECT 7 Zoll Portable Touchscreen Monitor, 1024 x 600

ardera commented 3 years ago

That's a cool project! I've actually thought about adding e-paper support for flutter-pi, but I'm not sure that'll work 😄 I understand your pain with JNI, I know some people who were dealing with it and they all would love to never do it again.

Although, why does dart periphery need a native lib in the first place? Can't you interface c-periphery directly? (Or maybe even interface the kernel devices directly, as flutter_gpiod, linux_spidev and linux_serial do)

pezi commented 3 years ago

I've actually thought about adding e-paper support for flutter-pi, but I'm not sure that'll work There a are ony few affordable e-papers with a "standard" interface like SPI.

I own a waveshare 4.2'' bi-color (black/red) e-paper module with 400x300 pixles. Works fine - but e.g. the output font must be selected with care - most fonts looks without dithering ugly on a 400x300 display. Therefore I think the usage of this kind of display is limited to nice demo images of the manufacturer or images, created knowing the limitations of the HW.

your pain with JNI, I know some people who were dealing with it and they all would love to never do it again.

As a Java developer I should clarify my problems with JNI:

On the other hand, companies like Sensirion provides maintained repositories. Looking at this BME280 sensor code, the calculation is somtimes complex... hopefully there is no calulation error inside the code introducted by the C to Java/Dart code migration. For a medical or a rocket science project I would use JNI/JNA/FFI to include the latest offical C-lib of the manufacturer.

Can't you interface c-periphery directly?

I reviewed the code with my acutal knowledge and the abilities of the new FFI dart lib. I can remove the C-glue libraray using only FFI. I started this job yesterday.

At the beginning of the project my knowlege was limited and the influence of my Java/JNI experience was to strong 😄

ardera commented 3 years ago

There a are ony few affordable e-papers with a "standard" interface like SPI. I own a waveshare 4.2'' bi-color (black/red) e-paper module with 400x300 pixles. Works fine - but e.g. the output font must be selected with care - most fonts looks without dithering ugly on a 400x300 display. Therefore I think the usage of this kind of display is limited to nice demo images of the manufacturer or images, created knowing the limitations of the HW.

True, I still want to try it though. Flutter has some accessibility stuff you can turn on that may help, for example high contrast fonts. Something like Floyd-Steinberg dithering should be easy to implement (just hard to do it fast) or maybe something fancy like gradient based dithering.

As a Java developer I should clarify my problems with JNI:

  • the method signature created by jnih is annoying long - this complicates any kind of refactoring
/*
 * Class:     at_treedb_hardware_sensor_SGP30
 * Method:    _sgp30_measure_raw_blocking_read
 * Signature: ()J
 */
JNIEXPORT jlong JNICALL Java_at_treedb_hardware_sensor_SGP30__1sgp30_1measure_1raw_1blocking_1read
  (JNIEnv *, jobject);
  • most native sensor libraries drag their own helper libs for I2C etc.

Wow, yeah that's a long method name. Even for Java standards. 😄

  • for many devices, most form China, the C code has only developement quality: many TODOs, tons of out commented code parts. etc

Yeah I know what you mean, that's embedded for you, I guess ;)

I reviewed the code with my acutal knowledge and the abilities of the new FFI dart lib. I can remove the C-glue libraray using only FFI. I started this job yesterday.

At the beginning of the project my knowlege was limited and the influence of my Java/JNI experience was to strong 😄

Ah cool! IMO the dart FFI is pretty easy to get used to. Just a little annoying when the API you want to interface has different ABIs depending on architecture, like libc for example.