Flutter ngspice 插件

Flutter FFI 绑定 ngspice C 接口,实现一个 plugin 库:

  • 可通过 pubspec.yaml 引入
  • 上层提供 Dart API 接口
  • 底层通过 FFI 调用 C 代码

ngspice 是一个开源的电路仿真器,主要用于电子电路的分析和设计。

准备

创建项目

创建 Flutter FFI plugin 项目,

bash 复制代码
flutter create -t plugin_ffi --org cn.nebul --platforms ios,android,windows,linux,macos mozsim_ngspice

cd mozsim_ngspice/

flutter pub outdated
flutter pub upgrade --major-versions

flutter pub add ffi

获取共享库

获取 ngspice shared libs,可以找预编译库,不然就从源码编译。

1)预编译库

Windows 下载预编译库进 windows/ngspice-44.2_dll_64 目录。

bash 复制代码
$ tree windows -aF -L 2 --dirsfirst
windows
|-- ngspice-44.2_dll_64/
|                   `-- Spice64_dll/
|-- .gitignore
`-- CMakeLists.txt

2)从源码编译

bash 复制代码
# ngspice 44.2 Commit [e011d1] master
git clone -b master --depth 1 https://git.code.sf.net/p/ngspice/ngspice ngspice

# Windows
# - Building ngspice with MS Visual Studio 2022
#   - flex-bison/: https://sourceforge.net/projects/winflexbison/
#   - ngspice/visualc/sharedspice.sln: open as admin, run with ReleaseOpenMP x64

# Linux
./compile_linux_shared.sh

测试

Plugin 使用样例,

bash 复制代码
cd mozsim_ngspice/example/
flutter run

Dart 接口测试,

bash 复制代码
$ cd mozsim_ngspice/
$ dart test/mozsim_ngspice_test.dart
mozsim_ngspice_test ...
|Char| stdout Hello from ngspice
|Char| stdout Note: No compatibility mode selected!
|Char| stdout Circuit: * voltage divider netlist
|Stat| Prepare Deck
|Stat| Parse
|Char| stdout Doing analysis at TEMP = 27.000000 and TNOM = 27.000000
|Stat| Device Setup
|Char| stdout Using SPARSE 1.3 as Direct Linear Solver
|Stat| op
|Char| stdout No. of Data Rows : 1
|Char| stdout out = 6.666667e-01
|Char| stdout ngspice-44.2 done
|Char| stdout Note: 'quit' asks for resetting or detaching ngspice.dll.
|Exit| status 0 immediate false quit true
NgSpiceException: NgSpiceRequestType.command return error, ret=1
mozsim_ngspice_test done

C++ 接口测试,

powershell 复制代码
# Windows
> cd mozsim_ngspice/
> test\build\Debug\mozsim_ngspice_test.exe
mozsim_ngspice_test ...
|Char| stderr Warning: can't find the initialization file spinit.
|Char| stdout ******
|Char| stdout ** ngspice-44.2 shared library
|Char| stdout ** Creation Date: Jan 11 2025   14:16:40
|Char| stdout ******
|Char| stdout Hello from ngspice
|Char| stdout Note: No compatibility mode selected!
|Char| stdout Note: No compatibility mode selected!
|Char| stdout Circuit: * voltage divider netlist
|Stat| Prepare Deck
|Stat| Parse
|Char| stdout Doing analysis at TEMP = 27.000000 and TNOM = 27.000000
|Stat| Device Setup
|Char| stdout Using SPARSE 1.3 as Direct Linear Solver
|Stat| op
|Char| stdout No. of Data Rows : 1
|Char| stdout out = 6.666667e-01

接口

Dart 接口重生成,

bash 复制代码
# https://pub.dev/packages/ffigen
dart run ffigen --config ffigen.yaml

Dart 接口使用样例,

dart 复制代码
import 'package:mozsim_ngspice/ngspice.dart';

void main(List<String> args) async {
  print('mozsim_ngspice_test ...');
  await _main();
  // await _main();
  print('mozsim_ngspice_test done');
}

Future<void> _main() async {
  NgSpice? ngspice;
  try {
    ngspice = await NgSpice.initByLib(
      NgSpice.libPath(NgSpice.libName, 'test/build/Debug/'),
    );

    ngspice.resp.listen(_handleResponses);

    await ngspice.sendCommand('echo Hello from ngspice');

    await ngspice.sendCircs([
      '* voltage divider netlist',
      'V1 in 0 1',
      'R1 in out 1k',
      'R2 out 0 2k',
      '.end',
    ]);

    await ngspice.sendCommands(['op', 'print out']);
    await ngspice.sendCommand('quit');
  } on NgSpiceException catch (e) {
    print(e);
  } catch (e) {
    print('Caught error: $e');
  } finally {
    await ngspice?.close();
  }
}

void _handleResponses(NgSpiceResponse resp) {
  if (resp.type == NgSpiceResponseType.print) {
    final res = resp.data as String;
    print('|Char| $res');
  } else if (resp.type == NgSpiceResponseType.stat) {
    final res = resp.data as String;
    print('|Stat| $res');
  } else if (resp.type == NgSpiceResponseType.exit) {
    final (status, immediate, quit) = resp.data as (int, bool, bool);
    print('|Exit| status $status immediate $immediate quit $quit');
  }
}

参考

相关推荐
SoaringHeart12 小时前
Flutter进阶:放弃 MediaQuery.of(context) 使用 NScreenManager
前端·flutter
BG14 小时前
利用Codex GPT-5.5 基于extended_image新增图片透视变换功能
前端·flutter
帅次17 小时前
LazyColumn 懒加载、items 与 key
android·flutter·kotlin·android studio·webview
恋猫de小郭19 小时前
经典,Flutter iOS 又修复了一个构建问题,还是很抽象
android·前端·flutter
我这一生如履薄冰~20 小时前
flutter开发适配底部导航条样式
android·flutter
张风捷特烈20 小时前
状态管理大乱斗#07 | Signals 源码评析 - 暗流涌动
android·前端·flutter
Justin在掘金1 天前
Riverpod 实战指南
flutter
MonkeyKing71552 天前
Flutter Riverpod 2.x 设计思想与最佳实践
前端·flutter
梦想不只是梦与想2 天前
Flutter中 yield*关键字
flutter·生成器函数