nissy-fmc

A Rubik's cube FMC assistant
git clone https://git.tronto.net/nissy-fmc
Download | Log | Files | Refs | README | LICENSE

commit 5839e270c710a2349b3ef9f8891517a87852527c
parent 7f0772f4b67fcae9fea06db4033937d69e215b04
Author: Sebastiano Tronto <sebastiano@tronto.net>
Date:   Sun, 25 Jun 2023 18:57:19 +0200

FFI *seems* to be working, need to work out async stuff; added example async code

Diffstat:
MMakefile | 2+-
MTODO.md | 5++---
Mflutter/lib/main.dart | 134+++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
Mflutter/pubspec.yaml | 28+++++++++++++++++-----------
Dflutter_ffi/example/lib/main.dart | 55-------------------------------------------------------
Dflutter_ffi/example/pubspec.yaml | 28----------------------------
Mflutter_ffi/lib/nissy_flutter_ffi.dart | 48++++++++++++++++++++++++++++++++++++++++++++++++
Mflutter_ffi/pubspec.yaml | 3---
Msrc/nissy.c | 4+++-
Msrc/nissy.h | 9++++++++-
10 files changed, 169 insertions(+), 147 deletions(-)

diff --git a/Makefile b/Makefile @@ -32,7 +32,7 @@ nissy_flutter_ffi: tables cp src/* nissy_flutter_ffi/src/ cd nissy_flutter_ffi && \ flutter pub run ffigen --config ffigen.yaml - cp tables nissy_flutter_ffi/data/ + cp tables nissy_flutter/data/ nissy: clean nissy_flutter nissy_flutter_ffi diff --git a/TODO.md b/TODO.md @@ -1,6 +1,5 @@ -* Figure out FFI: long-running stuff with await? -* Read data file from flutter and pass it to C backend -* show EOs in gui (for example scramble) +* Learn async stuff +* start with example hard-coded scramble, EO only * input text box for scramble, get EOs for that * UI design * other steps diff --git a/flutter/lib/main.dart b/flutter/lib/main.dart @@ -1,70 +1,116 @@ +import 'dart:typed_data'; +import 'dart:async'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart' show rootBundle; + +import 'package:nissy_flutter_ffi/nissy_flutter_ffi.dart' as nissy_flutter_ffi; void main() { - runApp(const NissyApp()); + runApp(const MyApp()); +} + +class MyApp extends StatefulWidget { + const MyApp({super.key}); + + @override + State<MyApp> createState() => _MyAppState(); } -class NissyApp extends StatelessWidget { - const NissyApp({super.key}); +class _MyAppState extends State<MyApp> { + @override + + void initState() { + super.initState(); + } @override Widget build(BuildContext context) { + const textStyle = TextStyle(fontSize: 25); + const spacerSmall = SizedBox(height: 10); return MaterialApp( - title: 'Nissy', - theme: ThemeData( - colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue), - useMaterial3: true, + home: Scaffold( + appBar: AppBar( + title: const Text('Nissy ffi test run'), + ), + body: SingleChildScrollView( + child: Container( + padding: const EdgeInsets.all(10), + child: NissyFutureBuilder(), + ), + ), ), - home: const MyHomePage(title: 'Nissy'), ); } } -class MyHomePage extends StatefulWidget { - const MyHomePage({super.key, required this.title}); - - final String title; +class NissyFutureBuilder extends StatefulWidget { + const NissyFutureBuilder({super.key}); @override - State<MyHomePage> createState() => _MyHomePageState(); + State<NissyFutureBuilder> createState() => NissyFutureBuilderState(); } -class _MyHomePageState extends State<MyHomePage> { - int _counter = 0; - void _incrementCounter() { - setState(() { - _counter++; - }); - } +// Copied from https://api.flutter.dev/flutter/widgets/FutureBuilder-class.html +class NissyFutureBuilderState extends State<NissyFutureBuilder> { + final Future<String> _calculation = Future<String>.delayed( + const Duration(seconds: 2), + () => 'Data Loaded', + ); @override Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - backgroundColor: _counter % 3 == 0 ? - Theme.of(context).colorScheme.inversePrimary : - Theme.of(context).colorScheme.primary, - title: Text(widget.title), - ), - body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: <Widget>[ - const Text( - 'You have pushed the button this many times:', - ), - Text( - '$_counter', - style: Theme.of(context).textTheme.headlineMedium, + return DefaultTextStyle( + style: Theme.of(context).textTheme.displayMedium!, + textAlign: TextAlign.center, + child: FutureBuilder<String>( + future: _calculation, // a previously-obtained Future<String> or null + builder: (BuildContext context, AsyncSnapshot<String> snapshot) { + List<Widget> children; + if (snapshot.hasData) { + children = <Widget>[ + const Icon( + Icons.check_circle_outline, + color: Colors.green, + size: 60, + ), + Padding( + padding: const EdgeInsets.only(top: 16), + child: Text('Result: ${snapshot.data}'), + ), + ]; + } else if (snapshot.hasError) { + children = <Widget>[ + const Icon( + Icons.error_outline, + color: Colors.red, + size: 60, + ), + Padding( + padding: const EdgeInsets.only(top: 16), + child: Text('Error: ${snapshot.error}'), + ), + ]; + } else { + children = const <Widget>[ + SizedBox( + width: 60, + height: 60, + child: CircularProgressIndicator(), + ), + Padding( + padding: EdgeInsets.only(top: 16), + child: Text('Awaiting result...'), + ), + ]; + } + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: children, ), - ], - ), - ), - floatingActionButton: FloatingActionButton( - onPressed: _incrementCounter, - tooltip: 'Increment', - child: const Icon(Icons.add), + ); + }, ), ); } diff --git a/flutter/pubspec.yaml b/flutter/pubspec.yaml @@ -1,25 +1,31 @@ -name: nissy_flutter -description: Flutter UI for nissy-fmc - +name: nissy_flutter_ffi_example +description: Demonstrates how to use the nissy_flutter_ffi plugin. publish_to: 'none' # Remove this line if you wish to publish to pub.dev -version: 3.0.0 +version: 1.0.0+1 environment: - sdk: '>=3.0.1 <4.0.0' + sdk: '>=3.0.5 <4.0.0' dependencies: flutter: sdk: flutter - # The following adds the Cupertino Icons font to your application. - # Use with the CupertinoIcons class for iOS style icons. + nissy_flutter_ffi: + path: ../nissy_flutter_ffi + + ffi: ^1.0.0 + cupertino_icons: ^1.0.2 +dev_dependencies: + flutter_test: + sdk: flutter + + flutter_lints: ^2.0.0 + flutter: uses-material-design: true - # To add assets to your application, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg + assets: + - data/ diff --git a/flutter_ffi/example/lib/main.dart b/flutter_ffi/example/lib/main.dart @@ -1,55 +0,0 @@ -import 'package:flutter/material.dart'; - -import 'package:nissy_flutter_ffi/nissy_flutter_ffi.dart' as nissy_flutter_ffi; - -void main() { - runApp(const MyApp()); -} - -class MyApp extends StatefulWidget { - const MyApp({super.key}); - - @override - State<MyApp> createState() => _MyAppState(); -} - -class _MyAppState extends State<MyApp> { - @override - final response = nissy_flutter_ffi.nissy_test(); - void initState() { - super.initState(); - } - - @override - Widget build(BuildContext context) { - const textStyle = TextStyle(fontSize: 25); - const spacerSmall = SizedBox(height: 10); - return MaterialApp( - home: Scaffold( - appBar: AppBar( - title: const Text('Nissy ffi test run'), - ), - body: SingleChildScrollView( - child: Container( - padding: const EdgeInsets.all(10), - child: Column( - children: [ - const Text( - 'Calling a nissy function from nissy.h', - style: textStyle, - textAlign: TextAlign.center, - ), - spacerSmall, - Text( - 'Response: $response', - style: textStyle, - textAlign: TextAlign.center, - ), - ], - ), - ), - ), - ), - ); - } -} diff --git a/flutter_ffi/example/pubspec.yaml b/flutter_ffi/example/pubspec.yaml @@ -1,28 +0,0 @@ -name: nissy_flutter_ffi_example -description: Demonstrates how to use the nissy_flutter_ffi plugin. -publish_to: 'none' # Remove this line if you wish to publish to pub.dev - -version: 1.0.0+1 - -environment: - sdk: '>=3.0.5 <4.0.0' - -dependencies: - flutter: - sdk: flutter - - nissy_flutter_ffi: - path: ../ - - ffi: ^1.0.0 - - cupertino_icons: ^1.0.2 - -dev_dependencies: - flutter_test: - sdk: flutter - - flutter_lints: ^2.0.0 - -flutter: - uses-material-design: true diff --git a/flutter_ffi/lib/nissy_flutter_ffi.dart b/flutter_ffi/lib/nissy_flutter_ffi.dart @@ -2,11 +2,34 @@ import 'dart:async'; import 'dart:ffi'; import 'dart:io'; import 'dart:isolate'; +import 'dart:typed_data'; +import 'package:flutter/services.dart'; import 'package:ffi/ffi.dart'; import 'nissy_flutter_ffi_bindings_generated.dart'; +void nissy_init(ByteData tables) { + // Copy tables to C ffi heap, pass to actual nissy_init() + final tablesList = tables.buffer.asUint8List(); + final n = tablesList.lengthInBytes; + final tablesHeap = calloc<Char>(n); + for (var i = 0; i < n; i++) { + tablesHeap[i] = tablesList[i]; + } + _bindings.nissy_init(tablesHeap); +} + String ptrCharToString(Pointer<Char> ptr) => ptr.cast<Utf8>().toDartString(); +Pointer<Char> stringToPtrChar(String str) { + final n = str.length; + final strNative = str.toNativeUtf8().cast<Char>(); + final ptr = calloc<Char>(n+10); + for (var i = 0; i < n; i++) { + ptr[i] = strNative[i]; + } + ptr[n] = 0; + return ptr; +} String nissy_test() { final ptr = calloc<Char>(50); @@ -16,6 +39,31 @@ String nissy_test() { return str; } +List<String> nissy_eos_in(String scr, int n) { + var ret = List<String>.empty(growable: true); + + final scramble = stringToPtrChar(scr); + final eofb = stringToPtrChar('eofb'); + final uf = stringToPtrChar('uf'); + final normal = stringToPtrChar('normal'); + + print('Doing thing...'); + + var bufferPtr = calloc<Char>(5000); // hope it is enough + final nsols = _bindings.nissy_solve(eofb, uf, n, normal, scramble, bufferPtr); + ret.add(ptrCharToString(bufferPtr)); + + print('Ret 0: ' + ret[0]); + + calloc.free(bufferPtr); + calloc.free(normal); + calloc.free(uf); + calloc.free(eofb); + calloc.free(scramble); + + return ret; +} + const String _libName = 'nissy_flutter_ffi'; /// The dynamic library in which the symbols for [NissyFlutterFfiBindings] can be found. diff --git a/flutter_ffi/pubspec.yaml b/flutter_ffi/pubspec.yaml @@ -31,6 +31,3 @@ flutter: ffiPlugin: true windows: ffiPlugin: true - - assets: - - data/ diff --git a/src/nissy.c b/src/nissy.c @@ -91,7 +91,9 @@ nissy_solve(char *step, char *trans, int d, char *type, char *scramble, char *so if (!set_solutiontype(type, &st)) return 4; if (!apply_scramble(scramble, &c)) return 5; - return solve(s, t, d, st, &c, sol); + sol[0] = 'h'; sol[1] = 'e'; sol[2] = 'l'; sol[3] = 'o'; sol[5] = 0; + return 0; + //return solve(s, t, d, st, &c, sol); } void diff --git a/src/nissy.h b/src/nissy.h @@ -8,4 +8,11 @@ void nissy_init(char *); void nissy_test(char *); /* Returns 0 on success, 1-based index of bad arg on failure */ -int nissy_solve(char *s, char *trans, int d, char *type, char *scr, char *sol); +int nissy_solve( + char *step, /* "eofb" */ + char *trans, /* "uf" or similar */ + int depth, /* Number of moves */ + char *type, /* "normal" or "inverse" or "niss" */ + char *scr, /* The scramble */ + char *sol /* The solution, as a single string, \n-separated */ +);