diff --git a/.github/workflows/CompatHelper.yml b/.github/workflows/CompatHelper.yml
deleted file mode 100644
index cba9134..0000000
--- a/.github/workflows/CompatHelper.yml
+++ /dev/null
@@ -1,16 +0,0 @@
-name: CompatHelper
-on:
- schedule:
- - cron: 0 0 * * *
- workflow_dispatch:
-jobs:
- CompatHelper:
- runs-on: ubuntu-latest
- steps:
- - name: Pkg.add("CompatHelper")
- run: julia -e 'using Pkg; Pkg.add("CompatHelper")'
- - name: CompatHelper.main()
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- COMPATHELPER_PRIV: ${{ secrets.DOCUMENTER_KEY }}
- run: julia -e 'using CompatHelper; CompatHelper.main()'
diff --git a/.github/workflows/TagBot.yml b/.github/workflows/TagBot.yml
deleted file mode 100644
index 634f90d..0000000
--- a/.github/workflows/TagBot.yml
+++ /dev/null
@@ -1,16 +0,0 @@
-name: TagBot
-on:
- issue_comment:
- types:
- - created
- workflow_dispatch:
-jobs:
- TagBot:
- if: github.event_name == 'workflow_dispatch' || github.actor == 'JuliaTagBot'
- runs-on: ubuntu-latest
- steps:
- - uses: JuliaRegistries/TagBot@v1
- with:
- token: ${{ secrets.GITHUB_TOKEN }}
- ssh: ${{ secrets.DOCUMENTER_KEY }}
-
\ No newline at end of file
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
deleted file mode 100644
index a034182..0000000
--- a/.github/workflows/ci.yml
+++ /dev/null
@@ -1,40 +0,0 @@
-name: CI
-on:
- push:
- branches:
- - master
- tags: '*'
- pull_request:
-jobs:
- test:
- name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }}
- runs-on: ${{ matrix.os }}
- strategy:
- fail-fast: false
- matrix:
- version:
- - '1'
- os:
- - ubuntu-latest
- - macOS-latest
- - windows-latest
- arch:
- - x64
- steps:
- - uses: actions/checkout@v2
- - uses: julia-actions/setup-julia@v1
- with:
- version: ${{ matrix.version }}
- arch: ${{ matrix.arch }}
- - uses: actions/cache@v1
- env:
- cache-name: cache-artifacts
- with:
- path: ~/.julia/artifacts
- key: ${{ runner.os }}-test-${{ env.cache-name }}-${{ hashFiles('**/Project.toml') }}
- restore-keys: |
- ${{ runner.os }}-test-${{ env.cache-name }}-
- ${{ runner.os }}-test-
- ${{ runner.os }}-
- - uses: julia-actions/julia-buildpkg@latest
- - uses: julia-actions/julia-runtest@latest
\ No newline at end of file
diff --git a/Manifest.toml b/Manifest.toml
index f6d406d..ec4da10 100644
--- a/Manifest.toml
+++ b/Manifest.toml
@@ -1,197 +1,67 @@
# This file is machine-generated - editing it directly is not advised
-[[ArgTools]]
-uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f"
+julia_version = "1.12.6"
+manifest_format = "2.0"
+project_hash = "f8556de8ceff5f13bdaf89939adbdadb5282f7ec"
-[[Artifacts]]
+[[deps.Artifacts]]
uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33"
+version = "1.11.0"
-[[Base64]]
-uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
+[[deps.DataStructures]]
+deps = ["OrderedCollections"]
+git-tree-sha1 = "6fb53a69613a0b2b68a0d12671717d307ab8b24e"
+uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
+version = "0.19.5"
-[[CEnum]]
-git-tree-sha1 = "215a9aa4a1f23fbd05b92769fdd62559488d70e9"
-uuid = "fa961155-64e5-5f13-b03f-caf6b980ea82"
-version = "0.4.1"
-
-[[ColorTypes]]
-deps = ["FixedPointNumbers", "Random"]
-git-tree-sha1 = "024fe24d83e4a5bf5fc80501a314ce0d1aa35597"
-uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f"
-version = "0.11.0"
-
-[[Colors]]
-deps = ["ColorTypes", "FixedPointNumbers", "Reexport"]
-git-tree-sha1 = "417b0ed7b8b838aa6ca0a87aadf1bb9eb111ce40"
-uuid = "5ae59095-9a9b-59fe-a467-6f913c188581"
-version = "0.12.8"
-
-[[Dates]]
+[[deps.Dates]]
deps = ["Printf"]
uuid = "ade2ca70-3891-5945-98fb-dc099432e06a"
+version = "1.11.0"
-[[Downloads]]
-deps = ["ArgTools", "LibCURL", "NetworkOptions"]
-uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6"
-
-[[FixedPointNumbers]]
-deps = ["Statistics"]
-git-tree-sha1 = "335bfdceacc84c5cdf16aadc768aa5ddfc5383cc"
-uuid = "53c48c17-4a7d-5ca2-90c5-79b7896eea93"
-version = "0.8.4"
-
-[[InteractiveUtils]]
-deps = ["Markdown"]
-uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240"
-
-[[JLLWrappers]]
-deps = ["Preferences"]
-git-tree-sha1 = "642a199af8b68253517b80bd3bfd17eb4e84df6e"
+[[deps.JLLWrappers]]
+deps = ["Artifacts", "Preferences"]
+git-tree-sha1 = "7204148362dafe5fe6a273f855b8ccbe4df8173e"
uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210"
-version = "1.3.0"
-
-[[LibCURL]]
-deps = ["LibCURL_jll", "MozillaCACerts_jll"]
-uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21"
-
-[[LibCURL_jll]]
-deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"]
-uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0"
-
-[[LibGit2]]
-deps = ["Base64", "NetworkOptions", "Printf", "SHA"]
-uuid = "76f85450-5226-5b5a-8eaa-529ad045b433"
+version = "1.8.0"
-[[LibSSH2_jll]]
-deps = ["Artifacts", "Libdl", "MbedTLS_jll"]
-uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8"
-
-[[Libdl]]
+[[deps.Libdl]]
uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb"
+version = "1.11.0"
-[[LinearAlgebra]]
-deps = ["Libdl"]
-uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
-
-[[Logging]]
-uuid = "56ddb016-857b-54e1-b83d-db4d58db5568"
-
-[[Markdown]]
-deps = ["Base64"]
-uuid = "d6f4376e-aef5-505a-96c1-9c027394607a"
-
-[[MbedTLS_jll]]
-deps = ["Artifacts", "Libdl"]
-uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1"
+[[deps.NgHerb]]
+deps = ["DataStructures", "ngspice_jll"]
+path = "."
+uuid = "16d751f2-2168-46b0-9d00-9e1470832ba3"
+version = "0.2.1"
-[[MozillaCACerts_jll]]
-uuid = "14a3606d-f60d-562e-9121-12d972cd8159"
+[[deps.OrderedCollections]]
+git-tree-sha1 = "94ba93778373a53bfd5a0caaf7d809c445292ff4"
+uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d"
+version = "1.8.2"
-[[NetworkOptions]]
-uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908"
-
-[[Pkg]]
-deps = ["Artifacts", "Dates", "Downloads", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"]
-uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
-
-[[Preferences]]
+[[deps.Preferences]]
deps = ["TOML"]
-git-tree-sha1 = "ea79e4c9077208cd3bc5d29631a26bc0cff78902"
+git-tree-sha1 = "8b770b60760d4451834fe79dd483e318eee709c4"
uuid = "21216c6a-2e73-6563-6e65-726566657250"
-version = "1.2.1"
+version = "1.5.2"
-[[Printf]]
+[[deps.Printf]]
deps = ["Unicode"]
uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7"
+version = "1.11.0"
-[[REPL]]
-deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"]
-uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb"
-
-[[Random]]
-deps = ["Serialization"]
-uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
-
-[[RecipesBase]]
-git-tree-sha1 = "b3fb709f3c97bfc6e948be68beeecb55a0b340ae"
-uuid = "3cdcf5f2-1ef4-517c-9805-6587b60abb01"
-version = "1.1.1"
-
-[[Reexport]]
-git-tree-sha1 = "57d8440b0c7d98fc4f889e478e80f268d534c9d5"
-uuid = "189a3867-3050-52da-a836-e630ba90ab69"
-version = "1.0.0"
-
-[[ReplMaker]]
-deps = ["REPL", "Unicode"]
-git-tree-sha1 = "76098218397ec93b925b70ce355144d539b1a8b4"
-uuid = "b873ce64-0db9-51f5-a568-4457d8e49576"
-version = "0.2.5"
-
-[[Requires]]
-deps = ["UUIDs"]
-git-tree-sha1 = "4036a3bd08ac7e968e27c203d45f5fff15020621"
-uuid = "ae029012-a4dd-5104-9daa-d747884805df"
-version = "1.1.3"
-
-[[SHA]]
-uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce"
-
-[[SafeTestsets]]
-deps = ["Test"]
-git-tree-sha1 = "36ebc5622c82eb9324005cc75e7e2cc51181d181"
-uuid = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f"
-version = "0.0.1"
-
-[[Serialization]]
-uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b"
-
-[[Sockets]]
-uuid = "6462fe0b-24de-5631-8697-dd941f90decc"
-
-[[SparseArrays]]
-deps = ["LinearAlgebra", "Random"]
-uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
-
-[[Statistics]]
-deps = ["LinearAlgebra", "SparseArrays"]
-uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
-
-[[TOML]]
+[[deps.TOML]]
deps = ["Dates"]
uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76"
+version = "1.0.3"
-[[Tar]]
-deps = ["ArgTools", "SHA"]
-uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e"
-
-[[Test]]
-deps = ["InteractiveUtils", "Logging", "Random", "Serialization"]
-uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
-
-[[UUIDs]]
-deps = ["Random", "SHA"]
-uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"
-
-[[Unicode]]
+[[deps.Unicode]]
uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5"
+version = "1.11.0"
-[[Zlib_jll]]
-deps = ["Libdl"]
-uuid = "83775a58-1f1d-513f-b197-d71354ab007a"
-
-[[nghttp2_jll]]
-deps = ["Artifacts", "Libdl"]
-uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d"
-
-[[ngspice_jll]]
-deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
-git-tree-sha1 = "02d25c1bad237d00e23208770c48da1d46f68de1"
-repo-rev = "main"
-repo-url = "https://github.com/JuliaBinaryWrappers/ngspice_jll.jl"
+[[deps.ngspice_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl"]
+git-tree-sha1 = "58c3dc3bb44dd7e74086c6dfc9fcd69b732b5162"
uuid = "57e080ce-e004-5ece-a144-c95753423b2a"
-version = "34.0.0+1"
-
-[[p7zip_jll]]
-deps = ["Artifacts", "Libdl"]
-uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0"
+version = "41.0.0+2"
diff --git a/Project.toml b/Project.toml
index af4a47a..cc3b534 100644
--- a/Project.toml
+++ b/Project.toml
@@ -1,28 +1,13 @@
-name = "NgSpice"
-uuid = "1a64e563-3ad9-44a2-8713-a1728bea8a90"
-authors = ["Venkateshprasad Bhat"]
-version = "0.1.4"
+name = "NgHerb"
+uuid = "16d751f2-2168-46b0-9d00-9e1470832ba3"
+version = "0.2.0"
+authors = ["Chris Winstead", "Venkateshprasad Bhat"]
[deps]
-CEnum = "fa961155-64e5-5f13-b03f-caf6b980ea82"
-Colors = "5ae59095-9a9b-59fe-a467-6f913c188581"
-Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb"
-RecipesBase = "3cdcf5f2-1ef4-517c-9805-6587b60abb01"
-ReplMaker = "b873ce64-0db9-51f5-a568-4457d8e49576"
-Requires = "ae029012-a4dd-5104-9daa-d747884805df"
+DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
ngspice_jll = "57e080ce-e004-5ece-a144-c95753423b2a"
-[compat]
-CEnum = "0.4, 0.5"
-Colors = "0.12"
-RecipesBase = "1.1"
-ReplMaker = "0.2"
-Requires = "1.1"
-julia = "1.5"
-
-[extras]
-SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f"
-Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
-[targets]
-test = ["Test", "SafeTestsets"]
+[compat]
+DataStructures = "0.19.5"
+ngspice_jll = "41.0.0"
diff --git a/README.md b/README.md
index bf4c8f5..4358959 100644
--- a/README.md
+++ b/README.md
@@ -1,58 +1,101 @@
-# NgSpice
+# NgHerb.jl -- A Revision of NgSpice.jl
-[](https://JuliaComputing.github.io/NgSpice.jl/stable)
-[](https://JuliaComputing.github.io/NgSpice.jl/dev)
-[](https://github.com/JuliaComputing/NgSpice.jl/actions)
-[](https://codecov.io/gh/JuliaComputing/NgSpice.jl)
+This repository provides a Julia wrapper for `ngspice` shared C library. It's based on the
+[NgSpice.jl](https://github.com/JuliaComputing/NgSpice.jl) Julia module by Venkateshprasad Bhat.
+NgHerb.jl implements these changes:
+
+* Thread safety for `ngspice` callbacks, to resolve segfaults in Julia 1.12.6+
+* Removed unused callbacks
+* Removed some REPL and Plot features for easier maintenance
+
+NgHerb.jl has some additional streamlining compared to NgSpice.jl
+
+The main purpose of this fork is to provide a minimal `ngspice` library wrapper that works stably with more recent
+Julia versions. As of Julia 1.12.6, the upstream NgSpice.jl module is broken unless
+Julia is constrained to one thread, i.e. `julia -t 1`. NgHerb.jl tries to fix this by
+introducing a CircularBuffer to manage asynchronous output from the `ngspice`. I made a fork rather than
+mess with NgSpice.jl directly, mainly because I'm not super confident about my solution.
-This repository provides a Julia wrapper for NgSpice library.
## Usage:
In a Julia REPL,
```
-] add https://github.com/JuliaComputing/NgSpice.jl
-using NgSpice
+] add https://github.com/cjwinstead/NgHerb.jl
+using NgHerb
```
---
-To start an an interactive mode,
+Upon initialization, you shold see a startup message from the `ngspice` library, something
+like this:
+
```
-using Plots
-NgSpice.interactive()
+******
+** ngspice-46 shared library
+** Creation Date: Tue May 12 23:05:42 UTC 2026
+******
```
-- Hit `~` for initializing the NgSpice
+### Basic Functions
-Run the Ngspice simulations commands!
-For example:
-```
-source /filepath/netlist # without quotes
-display # prints all vectors and constants
-plot vector1 vector2 # plots the real part of vector by default
-```
+To load a netlist and run analyses in `ngspice`, use:
+* `NgHerb.load_netlist(String)` -- loads a netlist from a multi-line Julia String
+* `NgHerb.cmd(String)` -- run an `ngspice` command.
-*Note*: It is not necessary for `.cir` to be placed in `bin` folder as long as full path is specified.
+To retrieve data from `ngspice`, use:
-Additional to usual plot parameters, different modes of retrieval can be set with:
- `plot -x space seperated vectorlist`
- where `x` takes following modes:
+* `NgHerb.getrealvec(String)` -- get the named vector
+* `NgHerb.getmagnitudevec(String)` -- get the magnitude of a complex vector
+* `NgHerb.getphasevec(String)` -- get the phase of a complex vector (radians)
-| Modes | Description |
-|---------|-------|
-| -r, --real | Real part of vector|
-| -i, --imaginary | Imaginary part of vector |
-| -m, --magnitude | Magnitude of vector |
-| -p, --phase | Phase of vector |
----
-For a non-interactive and more Julia-like experience checkout this [tutorial](tutorials\mosfet.jl).
+```julia-repl
+julia> netlist="""
+* Demo circuit
+
+V1 1 0 DC 1
+R1 1 2 1k
+R2 2 0 2k
+
+.end
+""";
+
+julia> NgHerb.load_netlist(netlist)
+Circuit: * Demo circuit
+
+julia> NgHerb.cmd("op")
+
+Doing analysis at TEMP = 27.000000 and TNOM = 27.000000
+Using SPARSE 1.3 as Direct Linear Solver
+No. of Data Rows : 1
+
+julia> NgHerb.cmd("print all");
+
+v(1) = 1.000000e+00
+v(2) = 6.666667e-01
+v1#branch = -3.33333e-04
+
+julia> NgHerb.getrealvec("2")
+1-element Vector{Float64}:
+ 0.6666666666666666
-Additionally, to simulate a `complex_circuit.sp` file with multiple plotting statements, run
-```
-using NgSpice
-using Plots
-source_sp("path/to/the/complex_circuit.sp")
```
+
+## String Macros
+
+Some special strings are defined to conveniently interface with `ngspice`:
+
+* `ng"..."` -- shorthand for NgHerb.cmd()
+* `vec"..."` -- returns the indicated vector (with name and type)
+
+These string types all return `Vector{Float64}`:
+
+* `real"..."` -- real part of the indicated `ngspice` vector
+* `imag"..."` -- imaginary part of the indicated `ngspice` vector
+* `magnitude"..."` -- complex magnitude of the indicated vector
+* `phase"..."` -- complex phase (in degrees)
+* `dB"..."` -- magnitude in dB20
+* `i"..."` -- real-valued branch current in the indicated voltage source
+
diff --git a/inputs/RC2.net b/inputs/RC2.net
deleted file mode 100644
index e08dc85..0000000
--- a/inputs/RC2.net
+++ /dev/null
@@ -1,15 +0,0 @@
-* Spice netlister for gnetlist
-R5 n4 n5 1k
-V1 n0 0 dc 1 ac 2 pulse 0 1 10n 10n 100n 1u 2u
-R4 n3 n4 1k
-R3 n2 n3 5k
-C5 n5 0 1n
-R2 n1 n2 1K
-C4 n4 0 1n
-R1 n0 n1 1k
-C3 n3 0 1n
-C2 n2 0 1n
-C1 n1 0 1n
-I1 n5 0 DC 0.01mA
-R6 0 n5 10k
-.END
\ No newline at end of file
diff --git a/inputs/ac_ascii.cir b/inputs/ac_ascii.cir
deleted file mode 100644
index f7f14a5..0000000
--- a/inputs/ac_ascii.cir
+++ /dev/null
@@ -1,8 +0,0 @@
-* simulation of RC2
-.control
-set filetype=ascii
-ac dec 100 10k 1000k
-
-write ac_ascii.raw
-.endc
-.include RC2.net
\ No newline at end of file
diff --git a/inputs/mosfet.cir b/inputs/mosfet.cir
deleted file mode 100644
index 1d25d40..0000000
--- a/inputs/mosfet.cir
+++ /dev/null
@@ -1,23 +0,0 @@
-A Berkeley SPICE3 compatible circuit
-*
-* This circuit contains only Berkeley SPICE3 components.
-*
-* The circuit is an AC coupled transistor amplifier with
-* a sinewave input at node "1", a gain of approximately -3.9,
-* and output on node "coll".
-*
-.tran 1e-5 2e-3
-*
-vcc vcc 0 12.0
-vin 1 0 0.0 ac 1.0 sin(0 1 1k)
-ccouple 1 base 10uF
-rbias1 vcc base 100k
-rbias2 base 0 24k
-q1 coll base emit generic
-rcollector vcc coll 3.9k
-remitter emit 0 1k
-*
-.probe v(emit) v(vcc) v(1) v(base) v(coll) vcc#branch vin#branch
-.model generic npn
-*
-.end
\ No newline at end of file
diff --git a/inputs/vdiv.cir b/inputs/vdiv.cir
deleted file mode 100644
index db5ae1f..0000000
--- a/inputs/vdiv.cir
+++ /dev/null
@@ -1,5 +0,0 @@
-voltage divider netlist
-V1 in 0 1
-R1 in out 1k
-R2 out 0 2k
-.end
\ No newline at end of file
diff --git a/src/API/get_vector.jl b/src/API/get_vector.jl
index 3995d8d..ad63169 100644
--- a/src/API/get_vector.jl
+++ b/src/API/get_vector.jl
@@ -1,12 +1,13 @@
function get_vector_info(vecname, maxlen=Int(maxintfloat()))
+ GC.enable(false)
factor = 1.0
if occursin("*", vecname)
factor, vecname = split(vecname, "*")
factor = parse(Float64, factor)
end
- vec = ngGet_Vec_Info(vecname)
+ vec = ngGet_Vec_Info(vecname) # returns pVectorInfo
vec != C_NULL || throw("Vector $(vecname) not found")
- vecinfo = unsafe_load(vec)
+ vecinfo = unsafe_load(vec) # vecinfo should be a VectorInfo
vname = unsafe_string(vecinfo.name)
len = min(maxlen, vecinfo.length)
typelist = Dict(0 => "notype",
@@ -43,6 +44,7 @@ function get_vector_info(vecname, maxlen=Int(maxintfloat()))
else
error("Unknown vector type")
end
+ GC.enable(true)
end
function curplot()
@@ -97,7 +99,7 @@ function getmagnitudevec(name, maxlen=Int(maxintfloat()))
abs.(data)
end
-function getphasevec(name, maxlen=Int(maxintfloat))
+function getphasevec(name, maxlen=Int(maxintfloat()))
_, __, data = get_vector_info(name, maxlen)
angle.(data)
end
diff --git a/src/API/graphs.jl b/src/API/graphs.jl
deleted file mode 100644
index 49b020f..0000000
--- a/src/API/graphs.jl
+++ /dev/null
@@ -1,72 +0,0 @@
-using RecipesBase
-using Colors
-using .Plots
-
-struct NgSpiceGraphs end
-
-const graph = NgSpiceGraphs()
-
-# `fort` is frequency or time vector. It is the `X` axis and should always be real.
-@recipe function ng(::NgSpiceGraphs, vectype, fort, veclist, title, xlims=nothing)
- ft = getrealvec(fort)
- label := permutedims(veclist)
- grid := true
- title := "$title"
- background_color --> Colors.RGB(0.0, 0.0, 0.0)
- xguide := fort
- guide := length(veclist) > 1 ? "signals" : "signal"
- color_palette --> :default
- seriestype := :path
- overwrite_figure := false
- vec = vectype.(veclist)
- #isa(xlims, Nothing) || xlims := xlims
- ft, vec
-end
-
-# source function for sp files needs to specially process plot commands
-function source_sp(netpath)
- netlines = readlines(netpath)
- circpath = joinpath(pwd(), "net.cir")
- for l in range(1, stop=length(netlines))
- if netlines[l] == ".control"
- open(circpath, "a") do f
- for line in netlines[1:l-1]
- write(f, line*"\n")
- end
- end
- try source(circpath) catch; rm(circpath) end
- temp = l
- while netlines[temp+1] != ".endc"
- temp += 1
- try
- if occursin("plot", netlines[temp])
- _plotswitch(netlines[temp])
- else
- cmd(netlines[temp])
- end
- catch
- isfile(circpath) && rm(circpath)
- end
- end
- end
- end
- isfile(circpath) && rm(circpath)
-end
-
-function _plotswitch(pltstr)
- params = split(pltstr[6:end], " ")
- xlims = nothing
- xlim_index = findall(occursin.("xlim", params))
- length(xlim_index) == 0 || (xlim_index = xlim_index[1]; xlims = parse.(Float64, (params[xlim_index+1], params[xlim_index+2]));
- deleteat!(params, xlim_index:1:xlim_index+2))
- fort = "frequency" ∈ listcurvecs() ? "frequency" : "time"
- pushfirst!(params, fort)
- if !occursin("-", params[1]) plt = plot(graph, getrealvec, params[1], params[2:end], "Real plot", xlims)
- elseif params[1] ∈ ("--real", "-r") plt = plot(graph, getrealvec, params[2], params[3:end], "Real plot", xlims)
- elseif params[1] ∈ ("--imaginary", "-i") plt = plot(graph, getimagvec, params[2], params[3:end], "Imaginary plot", xlims)
- elseif params[1] ∈ ("--magnitude", "-m") plt = plot(graph, getmagnitudevec, params[2], params[3:end], "Magnitude plot", xlims)
- elseif params[1] ∈ ("--phase", "-p") plt = plot(graph, getphasevec, params[2], params[3:end], "Phase plot", xlims)
- else throw("$(params[1]) is not a valid plot type")
- end
- Base.display(plt)
-end
diff --git a/src/API/repl.jl b/src/API/repl.jl
deleted file mode 100644
index ec310e0..0000000
--- a/src/API/repl.jl
+++ /dev/null
@@ -1,29 +0,0 @@
-using ReplMaker
-using .Plots
-
-function _ngspice_parser(str)
- if str == "init" init()
- elseif occursin("plot", str)
- _plotswitch(str)
- else
- cmd(str)
- end
-end
-
-function _repl_parser(str)
- if occursin(".sp", str) && str[1:7] == "source "
- source_sp(str[8:end])
- else
- _ngspice_parser(str)
- end
-end
-
-interactive() = (init();
- initrepl(_repl_parser,
- prompt_text = "NgSpice> ",
- prompt_color = :yellow,
- start_key = '~',
- mode_name = "for NgSpice is",
- ))
-
-
\ No newline at end of file
diff --git a/src/API/running.jl b/src/API/running.jl
index 75237b4..935f556 100644
--- a/src/API/running.jl
+++ b/src/API/running.jl
@@ -1,34 +1,24 @@
-cmd(command) = ngSpice_Command(command)
-function init()
- pvoid = convert(Ptr{Nothing}, 0)
- ngSpice_Init(gen_psendchar(), gen_psendstat(),
- gen_pcontrolledexit(),
- gen_psenddata(),
- gen_psendinitdata(),
- gen_pbgthread(), pvoid)
- ngSpice_Init_JLExtensions(
- @cfunction(path_resolve, Cstring, (Cstring, Cstring))
- )
-
-end
-isrunning() = ngSpice_running() # always returns 0
+function cmd(command::String)
+ global quiet
+ GC.enable(false)
+ ngSpice_Command(command)
+ if !quiet
+ dumpbuffer()
+ end
+end
+precompile(cmd,(String,))
-run() = (println("Running the simulator"); cmd("run"))
-bgrun() = (println("Running the simulator in a background thread");
- cmd("bg_run"))
-set_breakpoint(bkpt::Float64) = ngSpice_SetBkpt(bkpt)
-
-stop() = (println("Stopping the simulator"); cmd("stop"))
-bghalt() = (println("Halting the simulator in a background thread");
- cmd("bg_halt"))
+function init()
+ GC.enable(false)
+ ngSpice_Init(gen_psendchar[], gen_psendstat[],
+ gen_pcontrolledexit[],
+ gen_psenddata[],
+ gen_psendinitdata[],
+ gen_pbgthread[], C_NULL)
-reset() = (println("Resetting the simulator"); cmd("reset"))
-resume() = (println("Resuming the simulator"); cmd("resume"))
+end
-alter(command::String) = cmd(string("alter ", command))
-quit() = cmd("quit")
-exit() = (println("Quitting immediately"); cmd("unset askquit"); cmd("quit"))
diff --git a/src/API/sim_utils.jl b/src/API/sim_utils.jl
index 8db6c14..a188188 100644
--- a/src/API/sim_utils.jl
+++ b/src/API/sim_utils.jl
@@ -1,17 +1,23 @@
-function load_netlist(netlist::AbstractArray{T}) where T <: AbstractString
- append!(netlist, ["C_NULL"])
- t = netlist |> ngSpice_Circ
-end
+ function load_netlist(netlist::Vector{String})
+ append!(netlist, ["C_NULL"])
+ t = netlist |> ngSpice_Circ
+ end
-function load_netlist(netlist::AbstractString)
- # The strings in Julia always use \n instead of \r \r\n
- # (even if the editor does).
- # But if the circuit-string has \r in it,
- # uncomment the following line
- # occursin("\r", netlist) && replace(netlist, "\r"=>"")
- load_netlist(split(netlist, "\n"))
+# Opted to use the "circbyline" approach here to reduce
+# memory crossover events between Julia and NgSpice.
+function load_netlist(netlist::String)
+ for line in eachsplit(netlist,"\n")
+ if contains(line,r"\w+")
+ cmd(string("circbyline ",line))
+ end
+ end
+ if !contains(lowercase(netlist),r"\.end\s*$")
+ cmd("circbyline .end")
+ end
end
+precompile(load_netlist,(String,))
+precompile(load_netlist,(Vector{String},))
-source(netpath) = cmd("source $netpath")
+source(netpath::String) = cmd("source $netpath")
display() = cmd("display")
diff --git a/src/NgHerb.jl b/src/NgHerb.jl
new file mode 100644
index 0000000..5bc2246
--- /dev/null
+++ b/src/NgHerb.jl
@@ -0,0 +1,139 @@
+__precompile__()
+module NgHerb
+
+using ngspice_jll
+export ngspice_jll
+
+using DataStructures
+
+include("interface/ngspice_common.jl")
+include("interface/callbacks.jl")
+include("interface/ngspice_api.jl")
+include("API/sim_utils.jl")
+include("API/running.jl")
+include("API/get_vector.jl")
+
+#const async_cond = Ref{Base.AsyncCondition}()
+string_buffer = CircularBuffer{UInt8}(10000)
+
+# Callback pointers
+const gen_psendchar = Ref{Ptr{Cvoid}}(C_NULL)
+const gen_pcontrolledexit = Ref{Ptr{Cvoid}}(C_NULL)
+
+const gen_psendstat = Ref{Ptr{Cvoid}}(C_NULL)
+const gen_pbgthread = Ref{Ptr{Cvoid}}(C_NULL)
+const gen_psenddata = Ref{Ptr{Cvoid}}(C_NULL)
+const gen_psendinitdata = Ref{Ptr{Cvoid}}(C_NULL)
+
+pcbvec = Vector{Ref}()
+cbvec = Vector{Function}()
+quiet = false
+
+data_pointer = Ptr{VecInfoAll}(0)
+
+function __init__()
+
+ # async_cond[] = Base.AsyncCondition()
+
+ # We will just need these callbacks:
+ gen_psendchar[] = @cfunction(sendchar, Cint, (Ptr{Cchar}, Cint, Ptr{Cvoid} ))
+ gen_pcontrolledexit[] = @cfunction(controlledexit, Cint, (Cint, Cint, Cint, Cint, Ptr{Cvoid}))
+
+ for x in (gen_psendchar, gen_pcontrolledexit)
+ push!(pcbvec,x)
+ end
+
+ for x in (sendchar,controlledexit)
+ push!(cbvec,x)
+ end
+
+
+# callback_listener()
+ init()
+end
+
+function be_quiet()
+ global quiet = true
+end
+
+
+function dumpbuffer()
+ # Dump contents from ring buffer
+ buf_str = String(collect(string_buffer))
+ empty!(string_buffer)
+
+ # Remove "stdout " from start of lines
+ io=IOBuffer()
+ for l in eachsplit(buf_str,"\n")
+ println(io,replace(l,r"^stdout "=>""))
+ end
+
+ # Print everything
+ println(String(take!(seekstart(io))))
+end
+
+
+#=
+function callback_listener()
+ @async begin
+ try
+ while isopen(async_cond[])
+ wait(async_cond[])
+ #dumpbuffer()
+ GC.enable(true)
+ end
+ catch err
+ @error "Error in AsyncCondition processing loop" exception=(err, catch_backtrace())
+ end
+ end
+end
+=#
+
+#================ Special Strings =====================#
+# ng"" sends the quoted command to the simulator
+macro ng_str(s)
+ NgHerb.cmd(s)
+end
+
+# real"" retrieves the real-valued part of the indicated vector
+macro real_str(s)
+ NgHerb.getrealvec(s)
+end
+
+# imag"" retrieves the imaginary-valued part of the indicated vector
+macro imag_str(s)
+ NgHerb.getimaginaryvec(s)
+end
+
+# i"" retrieves the current in the indicated voltage source
+macro i_str(s)
+ NgHerb.getrealvec(s*"#branch")
+end
+
+# magnitude"" retrieves the complex magnitude of the indicated vector
+macro magnitude_str(s)
+ NgHerb.getmagnitudevec(s)
+end
+
+# dB"" retrieves a magnitude vector and converts to dB20
+macro dB_str(s)
+ 20.0 .* log10.(NgHerb.getmagnitudevec(s))
+end
+
+# phase"" retrieves a phase vector and converts to degrees
+macro phase_str(s)
+ (180/π).*NgHerb.getphasevec(s)
+end
+
+# vec"" returns a vector, possibly complex
+macro vec_str(s)
+ NgHerb.getvec(s)
+end
+
+
+
+
+export @ng_str, @real_str, @imag_str, @i_str, @magnitude_str, @dB_str, @phase_str, @vec_str
+export dump_buffer,be_quiet
+
+end
diff --git a/src/NgSpice.jl b/src/NgSpice.jl
deleted file mode 100644
index b68b822..0000000
--- a/src/NgSpice.jl
+++ /dev/null
@@ -1,51 +0,0 @@
-__precompile__()
-module NgSpice
-
-using ngspice_jll
-export ngspice_jll
-
-using Requires
-
-include("interface/ctypes.jl")
-export Ctm, Ctime_t, Cclock_t
-
-include("interface/ngspice_common.jl")
-include("interface/ngspice_api.jl")
-
-export bgthreadrunning, controlledexit, #getISRCdata, detsyncdata, getVSRCdata,
- sendchar, senddata, sendstat, sendinitdata
-
-export gen_pbgthread, gen_pcontrolledexit, gen_psendchar, gen_psenddata,
- gen_psendinitdata, gen_psendstat
-
-foreach(names(@__MODULE__, all=true)) do s
- if startswith(string(s), "ng")
- @eval export $s
- end
-end #should this be replaced with aliases
-
-include("extensions.jl")
-
-include("API/get_vector.jl")
-include("API/sim_utils.jl")
-include("API/running.jl")
-
-function __init__()
- @require Plots="91a5bcdd-55d7-5caf-9e0b-520d859cae80" @eval include("API/repl.jl")
- @require Plots="91a5bcdd-55d7-5caf-9e0b-520d859cae80" @eval include("API/graphs.jl")
-
- # Ensure that NgSpice is initialized, as otherwise it's easy to get segfaults
- # because NgSpice expects a printf callback to be provided (as we do in the
- # init() method we're calling here)
- init()
-end
-
-export get_vector_info,
- curplot, listallplots, listallvecs, listcurvecs, getimagvec,
- getmagnitudevec, getphasevec, getvec, getrealvec,
- NgSpiceGraphs, graph,
- load_netlist, source, source_sp,
- bghalt, bgrun, cmd, init,
- interactive, alter
- #isrunning,
-end
diff --git a/src/extensions.jl b/src/extensions.jl
deleted file mode 100644
index f5bfb8f..0000000
--- a/src/extensions.jl
+++ /dev/null
@@ -1,30 +0,0 @@
-const JLPATH_PREFIX = "jlpkg:"
-
-function c_strdup(str)
- ptr = @ccall libngspice.tmalloc((sizeof(str)+1)::Cint)::Ptr{UInt8}
- @GC.preserve str Base.unsafe_copyto!(ptr, pointer(str), sizeof(str))
- unsafe_store!(ptr, UInt8(0), sizeof(str) + 1)
- ptr
-end
-
-function path_resolve(name::Cstring, dir::Cstring)::Cstring
- name = unsafe_string(name)
- dir = unsafe_string(dir)
-
- if startswith(name, JLPATH_PREFIX)
- path = name[sizeof(JLPATH_PREFIX)+1:end]
- components = splitpath(path)
-
- @assert components[1] != "/"
-
- pkg_path = Base.locate_package(Base.PkgId(components[1]))
- if pkg_path !== nothing
- pkg_path = realpath(joinpath(dirname(pkg_path), ".."))
- file_path = joinpath(pkg_path, components[2:end]...)
- return c_strdup(file_path)
- end
-
- return Ptr{Cchar}(-1)
- end
- return C_NULL
-end
diff --git a/src/interface/callbacks.jl b/src/interface/callbacks.jl
new file mode 100644
index 0000000..9eb635b
--- /dev/null
+++ b/src/interface/callbacks.jl
@@ -0,0 +1,21 @@
+function sendchar(_text::Ptr{Cchar}, id::Cint, userdata::Ptr{Cvoid})::Cint
+ copy_len = ccall(:strlen, Csize_t, (Ptr{Cchar},), _text)
+ for c in 1:copy_len
+ push!(string_buffer,unsafe_load(_text,c))
+ end
+ push!(string_buffer,'\n')
+
+ #ccall(:uv_async_send, Cint, (Ptr{Cvoid},), async_cond[].handle)
+ return zero(Int32)
+end
+precompile(sendchar,(Ptr{Cchar},Cint,Ptr{Cvoid}))
+
+
+
+function controlledexit(exitstatus::Cint, immediate::Cint, quitexit::Cint, id::Cint, userdata::Ptr{Cvoid})::Cint
+ quitexit == 1 && println("Returned from quit with exit status")
+ return exitstatus
+end
+
+
+
diff --git a/src/interface/ctypes.jl b/src/interface/ctypes.jl
deleted file mode 100644
index 436e6ad..0000000
--- a/src/interface/ctypes.jl
+++ /dev/null
@@ -1,7 +0,0 @@
-## TODO: pending https://github.com/JuliaLang/julia/issues/29420
-# this one is suggested in the issue, but it looks like time_t and tm are two different things?
-# const Ctime_t = Base.Libc.TmStruct
-
-const Ctm = Base.Libc.TmStruct
-const Ctime_t = UInt
-const Cclock_t = UInt
diff --git a/src/interface/ngspice_api.jl b/src/interface/ngspice_api.jl
index 8d7be04..c423295 100644
--- a/src/interface/ngspice_api.jl
+++ b/src/interface/ngspice_api.jl
@@ -2,36 +2,31 @@ function ngSpice_Init(printfcn, statfcn, ngexit, sdata, sinitdata, bgtrun, userD
ccall((:ngSpice_Init, libngspice), Cint, (Ptr{Cvoid}, Ptr{Cvoid}, Ptr{Cvoid}, Ptr{Cvoid}, Ptr{Cvoid}, Ptr{Cvoid}, Ptr{Cvoid}), printfcn, statfcn, ngexit, sdata, sinitdata, bgtrun, userData)
end
-function ngSpice_Init_JLExtensions(path_resolve)
- ret = try;
- ccall((:ngSpice_Init_JLExtensions, libngspice), Cint, (Cint, Ptr{Cvoid},),
- 1, path_resolve)
- catch e;
- @warn "Failed to initialize julia extensions. Some features may not work."
- return false
+#-----------------------------------------------------------------
+# This implementation is really worried about thread safety,
+# but maybe not altogether necessary? I assume the command
+# string will be consumed rapidly by the receiving ccall
+# and not needed again after it returns.
+function ngSpice_Command(command::String)
+ # Calculate bytes needed (including the NUL terminator)
+ byte_count = sizeof(command) + 1
+
+ # 1. Allocate raw system memory that Julia's GC will completely ignore
+ c_buffer = Libc.malloc(byte_count)
+
+ # 2. Safely copy Julia's string data into the raw system buffer
+ GC.@preserve command begin
+ src_ptr = Base.unsafe_convert(Cstring, command)
+ # Copy the characters + trailing NUL byte
+ unsafe_copyto!(convert(Ptr{UInt8}, c_buffer), convert(Ptr{UInt8}, src_ptr), byte_count)
+
+ @ccall libngspice.ngSpice_Command(c_buffer::Ptr{Cchar})::Cint
end
- if ret != 0
- error("Failed to initialize julia extensions")
- end
- return true
-end
-
-function ngSpice_Init_Sync(vsrcdat, isrcdat, syncdat, ident, userData)
- ccall((:ngSpice_Init_Sync, libngspice), Cint, (Ptr{Cvoid}, Ptr{Cvoid}, Ptr{Cvoid}, Ptr{Cint}, Ptr{Cvoid}), vsrcdat, isrcdat, syncdat, ident, userData)
-end
-
-function ngSpice_Command(command)
- ccall((:ngSpice_Command, libngspice), Cint, (Cstring,), command)
end
-function ngGet_Vec_Info(vecname)
- ccall((:ngGet_Vec_Info, libngspice), pvector_info, (Cstring,), vecname)
-end
-
-function ngSpice_Circ(circarray)
- ccall((:ngSpice_Circ, libngspice), Cint, (Ptr{Ptr{UInt8}},), circarray)
-end
+#-----------------------------------------------------------------
+# These seem safe
function ngSpice_CurPlot()
ccall((:ngSpice_CurPlot, libngspice), Ptr{UInt8}, ())
end
@@ -40,14 +35,22 @@ function ngSpice_AllPlots()
ccall((:ngSpice_AllPlots, libngspice), Ptr{Ptr{UInt8}}, ())
end
+
+#-----------------------------------------------------------------
+# These functions are potentially unsafe due to passing String
+# to Csting on foreign thread
+function ngGet_Vec_Info(vecname)
+ ccall((:ngGet_Vec_Info, libngspice), pVectorInfo, (Cstring,), vecname)
+end
+
+
function ngSpice_AllVecs(plotname)
ccall((:ngSpice_AllVecs, libngspice), Ptr{Ptr{UInt8}}, (Cstring,), plotname)
end
-function ngSpice_running()
- ccall((:ngSpice_running, libngspice), Cint, ())
-end
-function ngSpice_SetBkpt(bkpt)
- ccall((:ngSpice_SetBkpt, libngspice), Cint, (Cdouble,), bkpt)
+#-----------------------------------------------------------------
+# Is this safe?
+function ngSpice_Circ(circarray)
+ ccall((:ngSpice_Circ, libngspice), Cint, (Ptr{Ptr{UInt8}},), circarray)
end
diff --git a/src/interface/ngspice_common.jl b/src/interface/ngspice_common.jl
index 61e2fc1..b845418 100644
--- a/src/interface/ngspice_common.jl
+++ b/src/interface/ngspice_common.jl
@@ -1,4 +1,3 @@
-# Skipping MacroDefinition: IMPEXP __declspec ( dllimport )
const ngcomplex_t = Complex{Cdouble}
@@ -11,12 +10,14 @@ const VF_MINGIVEN = (1 << 5)
const VF_MAXGIVEN = (1 << 6)
const VF_PERMANENT = (1 << 7)
+
+
"""
Vector info obtained from any vector in ngspice.dll.
Allows direct access to the ngspice internal vector structure,
as defined in include/ngspice/devc.h .
"""
-struct vector_info
+struct VectorInfo
name::Cstring # Same as so_vname
type::Cint # Same as so_vtype
flags::Int16 # Flags (a combination of VF_*)
@@ -25,9 +26,9 @@ struct vector_info
length::Cint # Length of the vector
end
-const pvector_info = Ptr{vector_info}
+const pVectorInfo = Ptr{VectorInfo}
-struct vecvalues
+struct VecValues
name::Cstring # name of a specific vector
creal::Cdouble # actual data value
cimag::Cdouble # actual data value
@@ -35,17 +36,17 @@ struct vecvalues
is_complex::Cint # if the data are complex numbers
end
-const pvecvalues = Ptr{vecvalues}
+const pVecValues = Ptr{VecValues}
-struct vecvaluesall
+struct VecValuesAll
veccount::Cint # number of vectors in plot
vecindex::Cint # index of actual set of vectors. i.e. the number of accepted data point
- vecsa::pvecvalues # values of actual set of vectors, indexed from 0 to veccount - 1
- #just pvecvalues?
+ vecsa::pVecValues # values of actual set of vectors, indexed from 0 to veccount - 1
+ #just pVecValues?
end
-const pvecvaluesall = Ptr{vecvaluesall}
-struct vecinfo
+const pVecValuesAll = Ptr{VecValuesAll}
+struct VecInfo
number::Cint # number of vector, as postion in the linked list of vectors, s
name::Cstring # name of the actual vector
is_real::Cint # 1 if the actual vector has real data
@@ -53,96 +54,16 @@ struct vecinfo
pdvecscale::Ptr{Cvoid} # a void pointer to struct dvec *ds, the scale vector
end
+const pVecInfo = Ptr{VecInfo}
-const pvecinfo = Ptr{vecinfo}
-struct vecinfoall
+struct VecInfoAll
name::Cstring
title::Cstring
date::Cstring
type::Cstring
veccount::Cint
- vecs::pvecinfo
-end
-
-#const pvecinfoall = Ptr{vecinfoall}
-
-ngerrorf, bgrunningf, vecgetnum = 0, 0, 0
-function std_print(text)
- occursin("stdout", text) &&
- (println(text[8:end]); return)
- (occursin("stderr", text) && !occursin("viewport", text)) &&
- (println(text[8:end]); return)
- occursin("viewport", text) &&
- (println("\nPlotting is skipped.\n")
- ; return)
- println(text)
-end
-
-function sendchar(_text::Ptr{Cchar}, id::Cint, userdata)::Cint
- _text != C_NULL || throw("Not a valid text")
- text = unsafe_string(_text)
- std_print(text)
- occursin(r"stderr Error:"i, text) && (ngerrorf = 1)
- return 0
-end
-
-gen_psendchar() = @cfunction(sendchar, Cint, (Ptr{Cchar}, Cint, Ptr{Cvoid}))
-
-function sendstat(_text::Ptr{Cchar}, id::Cint, userdata)::Cint
- _text != C_NULL || throw("Not a valid text")
- text = unsafe_string(_text)
- std_print(text)
- return 0
-end
-
-gen_psendstat() = @cfunction(sendstat, Cint, (Ptr{Cchar}, Cint, Ptr{Cvoid}))
-
-function bgthreadrunning(run::Cint, id::Cint, userdata::Ptr{Cvoid})::Cint
- bgrunning = run
- run ? println("BG thread is not running") :
- println("BG thread is running")
- return 0
-end
-
-gen_pbgthread() = @cfunction(bgthreadrunning, Cint, (Cint, Cint, Ptr{Cvoid}))
-
-function controlledexit(exitstatus::Cint, immediate::Cint,
- quitexit::Cint, id::Cint, userdata::Ptr{Cvoid})::Cint
- quitexit == 1 && println("Returned from quit with exit status")
- immediate == 1 ? (println("Unloading NgSpice"); ngSpice_Command("quit")) :
- (println("Prepare an unload"); will_unload = 1)
- return exitstatus
-end
-
-gen_pcontrolledexit() = @cfunction(controlledexit, Cint, (Cint, Cint, Cint, Cint, Ptr{Cvoid}))
-
-function senddata(vecdata::Ptr{vecinfoall},
- id::Cint, userdata::Ptr{Cvoid})::Cint
- return 0
-end
-
-gen_psenddata() = @cfunction(senddata, Cint, (Ptr{vecinfoall}, Cint, Ptr{Cvoid}))
-
-function sendinitdata(initdata::Ptr{vecinfoall}, id::Cint, userdata::Ptr{Cvoid})
- #=
- This bit is problematic because it always returns C_NULLs even before
- `data.veccount` number of `vecinfo`s are passed.
- Even when that is handled it's o/p is always `nothing`
- and array of `nothing`s
-
- initdata == C_NULL && throw("No initialized data")
- data = unsafe_load(initdata)
- vec = unsafe_wrap(Array, data.vecs, (data.veccount, ))
- for v in vec
- v.name == C_NULL && return zero(Int32)
- vname = unsafe_string(v.name)
- vpdvec = unsafe_wrap(Array, v.pdvec, 10)
- vpdscale = unsafe_wrap(Array, v.pdvecscale, 10)
- println(vname, vpdscale, vpdvec)
- end
- =#
- return zero(Int32)
+ vecs::pVecInfo
end
+const pVecInfoAll = Ptr{VecInfoAll}
-gen_psendinitdata() = @cfunction(sendinitdata, Cint, (Ptr{vecinfoall}, Cint, Ptr{Cvoid}))
diff --git a/test/ngspice_api.jl b/test/ngspice_api.jl
deleted file mode 100644
index eb1bc1f..0000000
--- a/test/ngspice_api.jl
+++ /dev/null
@@ -1,15 +0,0 @@
-using NgSpice
-using Test
-
-rootdir = joinpath(@__DIR__, "..")
-netpath = joinpath(rootdir, "inputs", "mosfet.cir")
-
-@testset "interface" begin
- p = convert(Ptr{Nothing}, 0)
- @test ngSpice_Init(p, p, p, p, p, p, p) == 0
- @test ngSpice_Command("source $netpath") == 0
- @test ngSpice_CurPlot() != C_NULL
- @test ngSpice_Command("run") == 0
- @test typeof(ngSpice_AllPlots()) == Ptr{Ptr{UInt8}}
- @test ngSpice_running() == 0
-end
\ No newline at end of file
diff --git a/test/runtests.jl b/test/runtests.jl
deleted file mode 100644
index 56b8194..0000000
--- a/test/runtests.jl
+++ /dev/null
@@ -1,15 +0,0 @@
-using NgSpice
-using Test
-using SafeTestsets
-
-@safetestset "interface functions" begin
- include("ngspice_api.jl")
-end
-
-@testset "friend functions" begin
- include("wrapper_api.jl")
-end
-
-@safetestset "wrapper safetests" begin
- include("wrapper_safetests.jl")
-end
diff --git a/test/wrapper_api.jl b/test/wrapper_api.jl
deleted file mode 100644
index 0aedb6c..0000000
--- a/test/wrapper_api.jl
+++ /dev/null
@@ -1,34 +0,0 @@
-using NgSpice
-using Test
-
-rootdir = joinpath(@__DIR__, "..")
-netpath = joinpath(rootdir, "inputs", "mosfet.cir")
-
-@testset "initialize" begin
- init()
- @test source(netpath) == 0
- @test NgSpice.run() == 0
-end
-
-@testset "getvectors" begin
- # as this simulation runs after the one in `ngspice_api.jl`,
- # `tran2` is the current plot
- @test curplot() == "tran2"
- @test listallplots() == ["tran2", "tran1", "const"]
- @test collect(keys(listallvecs())) == collect(sort(listallplots()))
- @test listallvecs()[curplot()] == listcurvecs()
- @test getvec.(listcurvecs()) == get_vector_info.(listcurvecs())
- #listcurvecs()
- for node in split("V(1) emit coll base vcc")
- @test getvec(node)[2] == "voltage"
- end
- for branch in split("vcc#branch vin#branch")
- @test getvec(branch)[2] == "current"
- end
- @test getvec("time")[2] == "time"
-end
-
-@testset "passing circuit as an array" begin
- netlist = readlines(netpath)
- @test load_netlist(netlist) == 0
-end
diff --git a/test/wrapper_safetests.jl b/test/wrapper_safetests.jl
deleted file mode 100644
index 8cedacd..0000000
--- a/test/wrapper_safetests.jl
+++ /dev/null
@@ -1,16 +0,0 @@
-using NgSpice
-using Test
-
-NgSpice.init()
-
-nl = """
-* Diode test circuit
-V1 inp 0 DC=1 AC=1 SIN(1 1 1000)
-* Connected in forward bias:
-D1 inp 0 dmod
-.model dmod d cjo=0 m=1 rs=5000 area=1 pj=0 cjp=0 mj=0 mjsw=0 pb=1 php=1 n=2 bv=0 ibv=0 ik=0 ikr=0 is=1.0e-9 tt=0
-.save all @d1[id] @d1[cd] @d1[charge] @d1[vd]
-.END
-"""
-
-@test NgSpice.load_netlist(nl) == 0
diff --git a/tutorials/demo.jl b/tutorials/demo.jl
deleted file mode 100644
index 3e7d4d1..0000000
--- a/tutorials/demo.jl
+++ /dev/null
@@ -1,12 +0,0 @@
-# Check out mosfet.jl for more Julia-like usage
-
-import NgSpice
-n = NgSpice
-
-netpath = joinpath(@__DIR__, "..", "inputs", "ac_ascii.cir") |> normpath
-
-n.init()
-n.cmd("source $netpath")
-n.cmd("run")
-n.cmd("display")
-#n.cmd("")
diff --git a/tutorials/mosfet.jl b/tutorials/mosfet.jl
deleted file mode 100644
index d4ec770..0000000
--- a/tutorials/mosfet.jl
+++ /dev/null
@@ -1,21 +0,0 @@
-using NgSpice
-# using Plots
-n = NgSpice
-
-netpath = joinpath(@__DIR__, "..", "inputs", "mosfet.cir") |> normpath
-
-n.init()
-n.source(netpath)
-n.run()
-n.display() # Returns a dataframe of current vectors
-n.listallvecs() # Lists vectors of both active and inactive plots
-n.curplot() # Current active plot
-n.listcurvecs() # Vectors in current active plot
-
-# For plotting the signals, pass `n.graph` an object of `NgSpiceGraphs` type.
-# And then, specify the get-vector method.
-# Pass "time" or "frequency"
-# List of signals to plot
-# Finally, the title of the plot
-# plot(n.graph, n.getimagvec, "time", ["emit", "vcc"], "Simple MOSFET")
-# plot(n.graph, n.getrealvec, "time", ["emit", "vcc"], "Simple MOSFET")