code wiki / (root) / nx_chemical_dispenser.nx

nx_chemical_dispenser.nx source

↩ module page · 210 lines · 11361 B

1// nx_chemical_dispenser.nx -- controlled-bolus chemical output (scent / pheromone / dose). 2// 3// module: nishi-core.perception.chemical_dispenser 4// depends: nishi-core.perception.profile + nishi-core.perception.transducer_characterizer + 5// nishi-core.perception.provenance_curve_store + nishi-core.io.syscalls 6// disk_kb: 5 7// capability: PERCEPTION 8// wired_status: PARTIAL_WIRED 9// 10// MISSING_CAPABILITIES: 11// - VALVE_DRIVER_DISPATCH (control solenoid / piezo / peristaltic valve 12// via MCU GPIO + PWM; depends on nx_mcu_gpio + nx_mcu_pwm from embedded 13// substrate arc) 14// - CARTRIDGE_INVENTORY_TRACK (per-cartridge remaining mass; depletes 15// with each dispense; surfaces low-inventory alert) 16// - DISPENSE_PROFILE_LOAD (per-cartridge-lot calibrated dispense curve 17// from nx_provenance_curve_store, type DISPENSE_PROFILE) 18// - LICENSE_TAG_ENFORCE (refuse to dispense substances without 19// license/safety tag in cartridge manifest) 20// - SAFETY_INTERLOCK (refuse dispense if subject too close to source, 21// if temperature exceeds safe range, if previous dispense too recent) 22// - INTEGRATION_WITH_REACTIVE_BEHAVIOR (composes with future 23// nx_reactive_behavior so scent + audio + haptic fire as a 24// coordinated prey-flight choreography in the dog toy) 25// 26// license_tier: PUBLIC_NISHI_SUBSTRATE 27// genealogy_id: feedback-substrate-primitives-meta-not-one-off_2026 + 28// feedback-multi-species-perceptual-substrate-not-anthropocentric_2026 + 29// feedback-substrate-does-heavy-lifting-user-is-partner-not-gate + 30// reference-ingest-citation-and-license-discipline + 31// project-prey-spec-dog-toy + 32// feedback-build-intelligence-never-strip-features 33// 34// Per cardinal [[feedback-multi-species-perceptual-substrate-not-anthropocentric]]: 35// Scent is the KILLER FEATURE of the prey-spec dog toy. TV-quality audio 36// + scent absent = the dog's nose says "nothing real" and the toy fails 37// the perceptual gate. THIS primitive operates the cartridge mechanism 38// that releases a controlled bolus of species-appropriate scent at 39// substrate-determined timing (proximity-triggered prey-flight, periodic 40// "alive" pulses, calming-pheromone steady-state, etc.). 41// 42// Reuse set served by this single primitive: 43// - Prey-spec dog toy scent dispense (PRIMARY use case; rabbit / squirrel / 44// bird scent per nx_perceptual_profile target) 45// - Calming pheromone diffuser (dog separation anxiety; cat Feliway-style 46// synthetic facial pheromone substitute) 47// - Working-dog training scent dispense (controlled doses for SAR / 48// drug / explosive detection training; substrate logs doses for 49// training-record provenance) 50// - Beekeeping queen-pheromone supplementation (controlled lemongrass / 51// synthetic QMP dispensing in nuc boxes) 52// - Aquaculture chemical conditioning (controlled food-attractant or 53// stress-reduction additive dispense) 54// - Veterinary controlled medication delivery (microdose nebulization) 55// - Humane pest deterrence (species-aversive scent dispense at 56// entry points instead of poison) 57 58import "nx_syscalls.nx" 59import "nx_perceptual_profile.nx" 60import "nx_transducer_characterizer.nx" 61import "nx_provenance_curve_store.nx" 62 63// ===== Dispense mechanism sealed enum ============================= 64 65const NX_CHEM_DISP_SOLENOID_VALVE: i64 = 1 // electromagnetic pulse valve 66const NX_CHEM_DISP_PIEZO_VALVE: i64 = 2 // piezoelectric microvalve 67const NX_CHEM_DISP_PERISTALTIC_PUMP: i64 = 3 // tube-roller pump 68const NX_CHEM_DISP_ATOMIZER_PIEZO: i64 = 4 // mesh-nebulizer for fine particles 69const NX_CHEM_DISP_HEATED_RELEASE: i64 = 5 // thermal volatilization (wax-bed) 70const NX_CHEM_DISP_FAN_DIFFUSION: i64 = 6 // fan-assisted ambient diffusion 71const NX_CHEM_DISP_REFILLABLE_WICK: i64 = 7 // passive wick; rate set by air flow 72 73func nx_chem_disp_mech_name(m: i64) -> *u8 { 74 if m == NX_CHEM_DISP_SOLENOID_VALVE { return "SOLENOID_VALVE" } 75 if m == NX_CHEM_DISP_PIEZO_VALVE { return "PIEZO_VALVE" } 76 if m == NX_CHEM_DISP_PERISTALTIC_PUMP { return "PERISTALTIC_PUMP" } 77 if m == NX_CHEM_DISP_ATOMIZER_PIEZO { return "ATOMIZER_PIEZO" } 78 if m == NX_CHEM_DISP_HEATED_RELEASE { return "HEATED_RELEASE" } 79 if m == NX_CHEM_DISP_FAN_DIFFUSION { return "FAN_DIFFUSION" } 80 if m == NX_CHEM_DISP_REFILLABLE_WICK { return "REFILLABLE_WICK" } 81 return "UNKNOWN_DISP_MECHANISM" 82} 83 84// ===== Substance class sealed enum ================================ 85// 86// What KIND of substance is being dispensed. Substrate gates dispense 87// by license + safety per substance class; refuses unregistered substances. 88 89const NX_CHEM_SUBST_PREY_SCENT: i64 = 1 // rabbit / squirrel / bird / mouse 90const NX_CHEM_SUBST_CALMING_PHEROMONE: i64 = 2 // synthetic DAP, FAS, etc. 91const NX_CHEM_SUBST_TRAINING_TARGET: i64 = 3 // SAR / detection training scent 92const NX_CHEM_SUBST_QUEEN_PHEROMONE: i64 = 4 // bee 93const NX_CHEM_SUBST_FOOD_ATTRACTANT: i64 = 5 // aquaculture / wildlife monitoring 94const NX_CHEM_SUBST_AVERSIVE_SCENT: i64 = 6 // humane pest deterrence 95const NX_CHEM_SUBST_VETERINARY_MED: i64 = 7 // requires veterinary license 96const NX_CHEM_SUBST_USER_DEFINED: i64 = 8 97 98func nx_chem_subst_name(s: i64) -> *u8 { 99 if s == NX_CHEM_SUBST_PREY_SCENT { return "PREY_SCENT" } 100 if s == NX_CHEM_SUBST_CALMING_PHEROMONE { return "CALMING_PHEROMONE" } 101 if s == NX_CHEM_SUBST_TRAINING_TARGET { return "TRAINING_TARGET" } 102 if s == NX_CHEM_SUBST_QUEEN_PHEROMONE { return "QUEEN_PHEROMONE" } 103 if s == NX_CHEM_SUBST_FOOD_ATTRACTANT { return "FOOD_ATTRACTANT" } 104 if s == NX_CHEM_SUBST_AVERSIVE_SCENT { return "AVERSIVE_SCENT" } 105 if s == NX_CHEM_SUBST_VETERINARY_MED { return "VETERINARY_MED" } 106 if s == NX_CHEM_SUBST_USER_DEFINED { return "USER_DEFINED" } 107 return "UNKNOWN_SUBSTANCE" 108} 109 110// ===== Dispense verdicts ========================================== 111 112const NX_CHEM_DISP_OK: i64 = 0 113const NX_CHEM_DISP_FAIL_BAD_MECHANISM: i64 = 1 114const NX_CHEM_DISP_FAIL_BAD_SUBSTANCE: i64 = 2 115const NX_CHEM_DISP_FAIL_CARTRIDGE_EMPTY: i64 = 3 116const NX_CHEM_DISP_FAIL_CARTRIDGE_NOT_CALIBRATED: i64 = 4 // no DISPENSE_PROFILE curve 117const NX_CHEM_DISP_FAIL_LICENSE_REFUSED: i64 = 5 // substance lacks 118 // license/safety tag 119const NX_CHEM_DISP_FAIL_SAFETY_INTERLOCK: i64 = 6 // proximity / temperature / 120 // cooldown violation 121const NX_CHEM_DISP_FAIL_VALVE_STUCK: i64 = 7 // mechanical failure detected 122const NX_CHEM_DISP_FAIL_DEPENDENCY_MISSING: i64 = 8 // PARTIAL_WIRED default 123 124func nx_chem_disp_verdict_name(v: i64) -> *u8 { 125 if v == NX_CHEM_DISP_OK { return "OK" } 126 if v == NX_CHEM_DISP_FAIL_BAD_MECHANISM { return "FAIL_BAD_MECHANISM" } 127 if v == NX_CHEM_DISP_FAIL_BAD_SUBSTANCE { return "FAIL_BAD_SUBSTANCE" } 128 if v == NX_CHEM_DISP_FAIL_CARTRIDGE_EMPTY { return "FAIL_CARTRIDGE_EMPTY" } 129 if v == NX_CHEM_DISP_FAIL_CARTRIDGE_NOT_CALIBRATED { return "FAIL_CARTRIDGE_NOT_CALIBRATED" } 130 if v == NX_CHEM_DISP_FAIL_LICENSE_REFUSED { return "FAIL_LICENSE_REFUSED" } 131 if v == NX_CHEM_DISP_FAIL_SAFETY_INTERLOCK { return "FAIL_SAFETY_INTERLOCK" } 132 if v == NX_CHEM_DISP_FAIL_VALVE_STUCK { return "FAIL_VALVE_STUCK" } 133 if v == NX_CHEM_DISP_FAIL_DEPENDENCY_MISSING { return "FAIL_DEPENDENCY_MISSING" } 134 return "UNKNOWN_CHEM_DISP_VERDICT" 135} 136 137// ===== Dispense parameters struct ================================= 138// 139// Bundled per [[feedback-nishilang-16-arg-function-limit]]. 140 141struct NxChemDispenseParams { 142 mechanism: i64 // NX_CHEM_DISP_* 143 substance_class: i64 // NX_CHEM_SUBST_* 144 bolus_microliters_x10: i64 // tenth-microliters to avoid float; e.g., 5 = 0.5 μL 145 duration_ms: i64 // how long the valve stays open 146 target_species_profile: i64 // for species-appropriate substance selection 147 minimum_distance_to_subject_cm: i64 // safety interlock 148 minimum_cooldown_ms: i64 // prevent saturating air with substance 149 cartridge_serial_ptr: *u8 150 cartridge_serial_len: i64 // identifies which cartridge calibration to load 151 operator_authorized: i64 // 0/1; veterinary substances require 1 152} 153 154// ===== Top-level entry stubs ====================================== 155 156// nx_chem_dispense -- emit a controlled bolus of substance through the 157// named mechanism + cartridge. Substrate enforces license, safety, 158// cooldown, calibration; dispatches MCU control signals. 159 160func nx_chem_dispense(params_ptr: *NxChemDispenseParams) -> i64 { 161 if params_ptr == 0 as *NxChemDispenseParams { return NX_CHEM_DISP_FAIL_BAD_SUBSTANCE } 162 // PARTIAL_WIRED: valve dispatch + safety interlock + license enforce queued. 163 return NX_CHEM_DISP_FAIL_DEPENDENCY_MISSING 164} 165 166// nx_chem_dispense_cartridge_remaining_uL_x10 -- inspector: how much 167// substance is left in the cartridge (tenth-microliters)? Surfaces to 168// audit dashboard for refill alerts. 169 170func nx_chem_dispense_cartridge_remaining_uL_x10(cartridge_serial_ptr: *u8, 171 cartridge_serial_len: i64) -> i64 { 172 if cartridge_serial_len <= 0 { return -1 } 173 return -1 174} 175 176// nx_chem_dispense_register_cartridge -- caller registers a new cartridge 177// with manifest (substance + license + initial volume + safety profile). 178// Substrate refuses substances without license/safety tag per 179// [[reference-ingest-citation-and-license-discipline]]. 180 181func nx_chem_dispense_register_cartridge(cartridge_serial_ptr: *u8, cartridge_serial_len: i64, 182 substance_class: i64, 183 initial_volume_uL_x10: i64, 184 license_manifest_hash_ptr: *u8, 185 license_manifest_hash_len: i64) -> i64 { 186 if cartridge_serial_len <= 0 { return 0 } 187 if license_manifest_hash_len <= 0 { return 0 } // refuse unlicensed 188 if substance_class < NX_CHEM_SUBST_PREY_SCENT { return 0 } 189 if substance_class > NX_CHEM_SUBST_USER_DEFINED { return 0 } 190 if initial_volume_uL_x10 <= 0 { return 0 } 191 return 0 192} 193 194// nx_chem_dispense_is_safe_to_fire -- inspector: would a dispense 195// right now pass all safety interlocks (distance / temperature / 196// cooldown)? Used by nx_reactive_behavior to choreograph without 197// triggering FAIL_SAFETY_INTERLOCK mid-sequence. 198 199func nx_chem_dispense_is_safe_to_fire(cartridge_serial_ptr: *u8, cartridge_serial_len: i64, 200 current_distance_cm: i64) -> i64 { 201 if cartridge_serial_len <= 0 { return 0 } 202 if current_distance_cm < 0 { return 0 } 203 return 0 204} 205 206// nx_chem_dispense_get_last_verdict -- inspector. 207 208func nx_chem_dispense_get_last_verdict() -> i64 { 209 return NX_CHEM_DISP_FAIL_DEPENDENCY_MISSING 210}