Pseudo-Medical Monitor: Difference between revisions

From LVL1
Jump to navigation Jump to search
 
(339 intermediate revisions by the same user not shown)
Line 1: Line 1:
=Pseudo-Medical Monitor for Christmas Cheap Gift=


[[File:JAC MED MON ENHANCED.jpg]]
[[File:JAC MED MON HUGE.jpg]]


In preparation for the expected Christmas Gift availability crisis, I present the Pseudo-Gift of the season.  The time honored tradition of knockoff products hitting the market before Christmas is alive and well.  What better than a multi-property knockoff device? Star Trek / Arduino / Medical knockoff device gift for everyone.  This Pseudo-Medical Tricorder ripoff is the stocking stuffer for 2021.
= What is this device? =
This device is the ultimate Pseudo-Medical device not having any form of endorsement whatsoever!
This is NOT A VALID MEDICAL DEVICE IN ANY KNOWN UNIVERSE, ACTUAL OR FICTIONAL!!!


=Operation=
== Why make, let alone market this device? ==
This device offers several functions to the user.  The device is intended to be held by the user for self-analysis.


==Modes==
This product was part of the underground QUACK-A-THON 2025 contestIt was built as an alternate universe Hack-A-Day prize entry intended to bring mankind to its kneesAfter defeating several other malpractice devices, immediate marketing was authorized with little regard to the reality of the project.
===Passive Mode===
This device provides several passive functions when not placed in specific function modes.  The passive mode consists of a thermal image with a actual 8x8 resolution that is interpolated out to 24x24.  A distance of device from user is recorded by a time of flight laser range finderThe distance is displayed with a color bar graph.  A bar color of RED indicates the distance to user is beyond 50cm.  A bar of GREEN indicates a distance of 50cm or less.  The final BLUE bar indicates a distance of less than 25cm and invokes the EXG Sensor mode.  An Object and Ambient temperature is displayed.


[[File:JAC MED MON PASSIVE MODE.jpg]]
== How does it Pseudo do what it does? ==


===Fingerprint Mode===
This device consists of a master data collection and processing unit along with external units for specialized taskingEach External Device resides on a separate I2C bus provide through a TCA9548A I2C MUXThe external units also have a specialized embedded ATTiny85 I2C Identification Token which allows the main device to auto-configure to its attached units.
Placement of a finger on the fingerprint scanner activated this mode.  Onscreen instructions direct the user to place finger an scannerThis suspends the Passive Mode.  The onscreen instructions tell the user to keep finger on scanner until a fingerprint image is captured and displayed on the screen.  When the scanner ring is pulsing RED, a fingerprint is not displayedA GREEN ring indicates a fingerprint image has been captured and is being displayed.  Upon removal of finger from scanner, the device returns to Passive Mode.


[[File:JAC MED MON FP MODE.jpg]]
=== Main Device ===
{|class="wikitable"
!colspan="5"| Device
|-
|Device
|Name
|Notes
|Layer Diagram
|Design and Build
|-
|[[File:JAC MED MON ENHANCED.jpg|left|thumbnail|x200px]]
| Pseudo-Medical Monitor
|
* Device consists of layers of prototyping shields
* External Ports consist of pairs of RJ45 Jack
* Control Panel is attached to end of device
* An easy access analog line connector is not displayed on diagram due to lazy draftsman
|[[File:JAC_MED_MON_MAIN_DEVICE_LAYER_DIAGRAM.jpg|left|thumbnail|x200px]]
|[[Pseudo-Medical Monitor Device Design]]
|}


===Pulse Mode===
=== Main Device Monitoring Capabilities ===
Placement of a finger on the pulse sensor activates this mode.  This suspends the Passive Mode.  The sensor reads the pulse and provides a beat indicator as well as an estimate pulse rate.  Future upgrades will display the O2 Saturation level (stray diagnosis number under pulse rate).  Upon removal of finger from sensor, the device returns to Passive Mode.


[[File:JAC MED MON PULSE MODE.jpg]]
{|class="wikitable"
 
!colspan="2"| Passive Mode
===EXG Mode===
|-
When the device distance is met, or a finger is placed on the distance sensor, the EXG Mode is engaged.  This suspends the Passive Mode.  The entire screen is cleared and converted to display ~152 readings with automatic scaling to screen.  If the distance reading remains in this modes range, additional readings are made and displayed until distance criteria changes.  Upon mode change, the entire screen is redrawn and the fingerprint information is reset to not recorded.  (Finger is over distance sensor, readings are from the BioAmp EXG Pill in a black box)
|Example
 
|Description
[[File:JAC MED MON EXG MODE.jpg]]
|-
[[File:JAC MED MON BioAmp EXG Pill BOXED.jpg]]
|[[File:JAC MED MON PASSIVE MODE.jpg|thumbnail|x200px]]
 
|This device provides several passive functions when not placed in specific function modes.  The passive mode consists of a thermal image with a actual 8x8 resolution that is interpolated out to 24x24.  A distance of device from user is recorded by a time of flight laser range finder.  The distance is displayed with a color bar graph.  A bar color of RED indicates the distance to user is beyond 50cm.  A bar of GREEN indicates a distance of 50cm or less.  The final BLUE bar indicates a distance of less than 25cm and invokes the EXG Sensor mode.  An Object and Ambient temperature is displayed.
==Tests==
|-
 
!colspan="2"| Fingerprint Mode
===Eye Test===
|-
|[[File:JAC MED MON FP MODE.jpg|thumbnail|x200px]]
|Placement of a finger on the fingerprint scanner activated this mode.  Onscreen instructions direct the user to place finger an scanner.  This suspends the Passive Mode.  The onscreen instructions tell the user to keep finger on scanner until a fingerprint image is captured and displayed on the screen.  When the scanner ring is pulsing RED, a fingerprint is not displayed.  A GREEN ring indicates a fingerprint image has been captured and is being displayed.  Upon removal of finger from scanner, the device returns to Passive Mode.
|-
!colspan="2"| Pulse Mode
|-
|[[File:JAC MED MON PULSE MODE.jpg|thumbnail|x200px]]
|Placement of a finger on the pulse sensor activates this mode.  This suspends the Passive Mode.  The sensor reads the pulse and provides a beat indicator as well as an estimate pulse rate.  Future upgrades will display the O2 Saturation level (stray diagnosis number under pulse rate).  Upon removal of finger from sensor, the device returns to Passive Mode.
|-
!colspan="2"| EKG Mode
|-
|[[File:JAC MED MON EXG MODE.jpg|thumbnail|x200px]]
|When the device distance is met, or a finger is placed on the distance sensor, the EXG Mode is engaged.  This suspends the Passive Mode.  The entire screen is cleared and converted to display ~152 readings with automatic scaling to screen.  If the distance reading remains in this modes range, additional readings are made and displayed until distance criteria changes.  Upon mode change, the entire screen is redrawn and the fingerprint information is reset to not recorded.  (Finger is over distance sensor, readings are from the BioAmp EXG Pill in a black box)
|}


===Hearing Test===
== Extended Options ==


===Grip and Reflex Test===
=== External Units ===
 
===Extended EXG Tests===
 
=Design (Updated 11/05/2021)=
* Thermal Image from AMG8833 Sensor.
* Ambient and Object Temperature from MLX90614 Sensor.
* Distance of device from user via VL53L0X Laser TOF Sensor.
* Pulse Rate from MAX30102 Sensor
* Fingerprint Scan image capture from Capacitive Sensor with ID809 processing capabilities.
* ECG,EMG,EEG,EOG Function depending on where you put the electrodes!
 
==Parts List==
 
[[File:JAC MED MON ARDUINO DUE.jpg]]
* Arduino Due Generic Clone (alternative: ITEADUINO DUE)
 
[[File:JAC MED MON PROTO SHIELD.jpg]]
* Arduino Mega Prototype Shield Generic Clone (alternative: KEYESTUDIO) (EXG connector added after photo)
 
[[File:JAC MED MON ENCODERS.jpg]]
* Dual Encoder Control with LED indicators
 
[[File:JAC MED MON BioAmp EXG Pill.jpg|BioApm EXG Pill]]
*BioAmp EXG Pill [https://hackaday.io/project/178997-bioamp-exg-pill Excellent Hackaday.io Project by Deepak Khatri]
 
[[File:JAC MED MON MLX90614.jpg]]
* MLX90614 Contactless Temperature Sensor Generic Clone (alternative: )
 
[[File:JAC MED MON AMG8833.jpg]]
* AMG8833 Thermal Imager Sensor Generic Clone (alternative: TinyCircuits)
 
[[File:JAC MED MON VL53L0X.jpg]]
* VL53L0X TOF Laser Distance Sensor Generic Clone (alternative: Onyehn)
 
[[File:JAC MED MON MAX30102.jpg]]
* MAX30102 Pulse and O2 Saturation Sensor Generic Clone (alternative: MH-ET Live)
 
[[File:JAC MED MON FP SCANNER.jpg]]
* Capacitive Touch Fingerprint Scanner Generic Clone (alternative: DFROBOT)
 
[[File:JAC MED MON TFT.jpg]]
* 160x128 LCD TFT SPI 1.8" Module with SD Socket Generic Clone (alternative: Heyaodz111208)
 
[[File:JAC MED MON GRIP UNIT.jpg]]
* Grip and Reflex Sensor
** Cylinder 5x5x15 cm. 0.25 cm. thickness
** Copper Tape Hoop
** Velostat Wrap Sheet
** MPU6050 Sensor
** Vibration Motor
** Vibration Motor Control Circuit
** RJ45 Socket Breakout Board
** Momentary Push Button Switch
** Foam Wrap 0.5 cm.
 
[[File:JAC MED MON TEST UNIT.jpg]]
* Test Unit for Add-Ons
 
 
==Assemblies==
 
===Hand Held Unit===
 
[[File:JAC MED MON Hand Unit EXPLODED.jpg]]
[[File:JAC MED MON Hand Unit UNCOVERED.jpg]]
[[File:JAC MED MON Hand Unit COVERED.jpg]]
 
==Wiring==
 
===Main Shield===


{|class="wikitable"
{|class="wikitable"
!colspan="10"|Pin Mapping
!colspan="6"|  
|-
|-
|Due Pin
|Device
|Function
|Interactions
|MLX90614
|Port Description
|AMG8833
|Connection Diagram
|VL53L0X
|Design and Build
|MAX30102
|FP Scan
|TFT
|SD Socket
|EXG
|-
|-
|3
|Interrupt
|
|
|
|
|IRQ
|
|
[[File:JAC MED MON GRIP UNIT COMPLETE.jpg|left|thumbnail|x200px]]
Hand-Held Grip and Reflex Sensor
|
|
* Steady Hold
* Grip Strength
* User Response Switch
* Vibration Generation
|
|
{|class="wikitable"
!colspan="4"|Pin Mapping
|-
|Line #
|Device Signal
|Function
|-
|1
|3.3V
|Power
|-
|2
|GND
|Power
|-
|3
|MPU6050/ATTiny85 Token
|I2C-SDA
|-
|-
|4
|4
|Interrupt
|MPU6050/ATTiny85 Token
|
|I2C-SCL
|
|
|INT
|
|
|
|
|-
|-
|5
|5
|Interrupt
|MPU6050-INT
|
|GPIO
|INT
|
|
|
|
|
|-
|-
|6
|6
|Digital I/O
|Vibrating Motor I/O
|
|GPIO
|
|GPIO1
|
|
|
|
|
|-
|-
|7
|7
|Digital I/O
|Momentary Push Button
|
|GPIO
|
|XSHUT
|
|
|
|
|
|-
|-
|8
|8
|Digital I/O
|Grip Sensor
|Analog
|}
|
|
[[File:JAC MED MON HANDHELD CONNECTION DIAGRAM.jpg|left|thumbnail|x200px]]
|
|
|
[[Pseudo-Medical Monitor Hand-Held External Unit Design]]
|
|
|
|SD_CS
|
|-
|-
|9
 
|Digital I/O
|
|
[[File:JAC_MED_MON_EKG_UNIT.jpg|left|thumbnail|x200px]]
EKG-Respiration Unit
|
|
* EKG
* Breathing Sensor
* Breathing Sensor Sensitivity Adjustment
* Pacing LED
|
|
|
{|class="wikitable"
|
!colspan="4"|Pin Mapping
|RST
|
|
|-
|-
|10
|Line #
|Digital I/O
|Device Signal
|
|Function
|
|
|
|
|CS
|
|
|-
|-
|11
|1
|Digital I/O
|3.3V
|
|Power
|
|
|
|
|AO
|
|
|-
|-
|18
|2
|TX_1
|GND
|
|Power
|
|
|
|RX
|
|
|
|-
|-
|19
|3
|RX_1
|NeoPixel Controller
|
|I2C-SDA
|
|
|
|TX
|
|
|
|-
|-
|20
|4
|SDA
|NeoPixel Controller
|SDA
|I2C-SCL
|SDA
|SDA
|SDA
|
|
|
|
|-
|-
|21
|5
|SCL
|Respiration Detection
|SCL
|Analog
|SCL
|SCL
|SCL
|
|
|
|
|-
|-
|A0
|6
|
|Respiration Detection Adjust
|
|Analog
|
|
|
|
|
|
|Signal
|-
|-
|SPI
|7
|MISO
|N/C
|
|Analog
|
|
|
|
|
|SD_MISO
|
|-
|-
|SPI
|8
|MOSI
|Heart Beat Signal
|
|Analog
|
|}
|
|
|
|
|SDA
[[File:JAC_MED_MON_EKG_CONNECTION_DIAGRAM.jpg|left|thumbnail|x200px]]
|SD_MOSI
|
|
[[Pseudo-Medical Monitor EKG External Unit Design]]
|-
|-
|SPI
 
|SCK
|
|
|
|
|
[[File:JAC MED MON POLY LIAR UNIT.jpg|left|thumbnail|x200px]]
Poly-Liar Unit
|
|
|SCK
* Galvanic Skin Response Sensor
|SD_SCK
* Heart Beat Detection Sensor
* Respiration Detection Sensor
* Skin Temperature Sensor
|
|
|}
===Encoders Panel===
{|class="wikitable"
{|class="wikitable"
!colspan="4"|Pin Mapping
!colspan="4"|Pin Mapping
|-
|-
|Device
|Line #
|SIGNAL
|Device Signal
|DUE Pin
|Function  
|Function  
|-
|-
|Controls
|1
|Vin
|3.3V
|3.3V
|Power
|Power
|-
|-
|Controls
|SDA
|20
|SDA-I2C
|-
|Controls
|SCL
|21
|SCL-I2C
|-
|Controls
|INT
|2
|2
|GPIO
|-
|Controls
|GND
|GND
|GND
|Power
|Power
|}
===MIDI Shield===
{|class="wikitable"
!colspan="4"|Pin Mapping
|-
|-
|Device
|3
|SIGNAL
|Tone Controller
|DUE Pin
|I2C-SDA
|Function
|-
|-
|VS1103
|4
|Vin
|Tone Controller
|3.3V
|I2C-SCL
|Power
|-
|-
|VS1103
|5
|GND
|Respiration Detection
|GND
|Analog
|Power
|-
|-
|VS1103
|6
|TX
|Skin Temperature
|17
|Analog
|RX-Serial2
|-
|-
|VS1103
|7
|RX
|Pulse Detection
|16
|Analog
|TX-Serial2
|-
|-
|VS1103
|8
|GPIO0
|GSR Signal
|30
|Analog
|GPIO
|}
|[[File:JAC_MED_MON_POLY_LIAR_CONNECTION_DIAGRAM.jpg|left|thumbnail|x200px]]
|
[[Pseudo-Medical Monitor Poly-Liar External Unit Design]]
|-
|-
|VS1103
|
|GPIO1
[[File:JAC_MED_MON_TRACKING_GOGGLES_UNIT_WHOLE.jpg|left|thumbnail|x200px]]
|32
Tracking Goggles Unit
|GPIO
|
|-
* Eye Tracking
|VS1103
* Head Direction Tracking
|RST
|
|28
|GPIO
|-
|VS1103
|DREQ
|24
|GPIO
|-
|VS1103
|BSYNC
|26
|GPIO
|-
|VS1103
|CS
|22
|GPIO
|-
|VS1103
|SO
|SPI-HDR
|MISO
|-
|VS1103
|SI
|SPI-HDR
|MOSI
|-
|VS1103
|SCLK
|SPI-HDR
|SCK
|}
 
===Ports Shield===
 
{|class="wikitable"
{|class="wikitable"
!colspan="4"|Pin Mapping
!colspan="4"|Pin Mapping
|-
|-
|Port #
|Line #
|Line #
|DUE Pin
|Device Signal
|Function  
|Function  
|-
|-
|0
|1
|1
|3.3V
|3.3V
|Power
|Power
|-
|-
|0
|2
|2
|GND
|GND
|Power
|Power
|-
|-
|0
|3
|3
|70
|BNO055/ATTiny85 Token
|I2C-SDA
|I2C-SDA
|-
|-
|0
|4
|4
|71
|BNO055/ATTiny85 Token
|I2C-SCL
|I2C-SCL
|-
|-
|0
|5
|5
|53
|Top Sensor
|GPIO0
|Analog0
|-
|-
|0
|6
|6
|51
|Bottom Right Sensor
|GPIO1
|Analog1
|-
|-
|0
|7
|7
|49
|Bottom Left Sensor
|GPIO2
|Analog2
|-
|-
|0
|8
|8
|65/A11
|BNO055_INT
|Analog0
|Analog3
|}
|}
 
|
 
[[File:JAC_MED_MON_TRACKING_GOGGLES_CONNECTION_DIAGRAM.jpg|left|thumbnail|x200px]]
|
[[Pseudo-Medical Monitor Tracking Goggles External Unit Design]]
|-
|
Hypno Goggles Unit
|
* Goggles
* Left ATTiny85 Neopixel Token
* Right ATTiny85 Neopixel Token
* Control Box
* RJ45 Socket Breakout Board
|
|[[File:JAC_MED_MON_HYPNO_GOGGLES_CONNECTION_DIAGRAM.jpg|left|thumbnail|x200px]]
|-
|[[File:JAC_MED_MON_EEG_UNIT_WHOLE.jpg|left|thumbnail|x200px]]
EEG Unit
|
* EEG
|
{|class="wikitable"
{|class="wikitable"
!colspan="4"|Pin Mapping
!colspan="4"|Pin Mapping
|-
|-
|Port #
|Line #
|Line #
|DUE Pin
|Device Signal
|Function  
|Function  
|-
|-
|1
|1
|1
|3.3V
|3.3V
|Power
|Power
|-
|-
|1
|2
|2
|GND
|GND
|Power
|Power
|-
|-
|1
|3
|3
|70
|ATTiny85 Token
|I2C-SDA
|I2C-SDA
|-
|-
|1
|4
|4
|71
|ATTiny85 Token
|I2C-SCL
|I2C-SCL
|-
|-
|1
|5
|5
|27
|Signal 0
|GPIO0
|Analog
|-
|-
|1
|6
|6
|29
|Signal 1
|GPIO1
|Analog
|-
|-
|1
|7
|7
|31
|Signal 2
|GPIO2
|Analog
|-
|-
|1
|8
|8
|60/A6
|Singal 3
|Analog0
|Analog
|}
|[[File:JAC_MED_MON_EEG_CONNECTION_DIAGRAM.jpg|left|thumbnail|x200px]]
|
[[Pseudo-Medical Monitor EEG External Unit Design]]
|}
 
=== Test Capabilities with and without External Units ===
 
{|class="wikitable"
!colspan="2"| Test
|-
|Configuration
|Procedure
|-
!colspan="2"| Eye Test
|-
|
* Only Base Device needed.
|
Instructions for the one being tested are displayed on the unit's screen.  The one tested will be shown an "E" symbol of various sizes and orientations.  The display will be activated based on distance readings from the Base Device distance sensor.  After the display distance and time are met, the one tested will use a Rotary Encoder and Switch function, on the Control Panel, to select orientation on the "E" symbol.  The process will be repeated with success or failure counts by orientation and distance will be recorded.
|-
!colspan="2"| Hearing Test
|-
|
* Test requires earphones or headphones be plugged into Audio/MIDI shield audio jack.
* Test can use either one or two Hand Held Units or use use the switch function of the Rotary Encoders on the Control Panel.
|
Instructions for the one being tested are displayed on the unit's screen.  A series of tones of various frequencies and volumes are played to each ear in variable patterns.  Upon detection of the Tone, the tested is required to signal detection by depressing the appropriate Hand Held Unit Button of Rotary Encoder.  Tones are tested for a determined time and a timeout condition is considered to be non-detection.  Repeat of the "missed" Tones can be retested for confirmation.
|-
!colspan="2"| Grip and Reflex Test
|-
|
* Test can use of one or two Hand Held Units.
|
Instructions for the one being tested are displayed on the unit's screen.  The one tested will be asked to grip the Hand Held Units multiple times to set a baseline for grip pressure readings for each Unit used.  The one tested will then be required to register detection of the Units vibrating motor.  The operating time of the motor will be varied.  Detection of the vibration and time to detection are recorded.  Detection will be based on grip detection and Unit Button depression as instructed during test.
|-
!colspan="2"| EKG and Respiration Test A
|-
|
* Test requires EKG-Respiration Unit.
|
Instructions for the one being tested are displayed on the unit's screen.  The victim/one tested will be appropriately "Wired Up" to the device.  The sensor readings will be displayed to screen.  If the one tested has a pulse and breathing is detected, the the one tested will be considered "NOT DEAD".  If (a pulse but not breathing) or (breathing but no pulse) is detected the the one tested will be considered "NOT QUITE DEAD".  If neither pulse or breathing is detected then the one tested could simply be "PINING FOR THE FJORDS" or "NOT ALIVE" but no assertion will be made as to their death.
|-
!colspan="2"| EKG and Respiration Test B
|-
|
* Test requires EKG-Respiration Unit.
|
Instructions for the one being tested are displayed on the unit's screen.  The victim/one tested will be appropriately "Wired Up" to the device.  The sensor readings will be displayed to screen.  Regardless of the sensor readings, the NeoPixel Unit on the EKG Unit will be cycled through various colors, brightness and/or sequences.  Changes to sensor readings will then be wrecklessly assigned to conjecture as well as confession through projection interpretations.
|-
!colspan="2"| EEG Test
|-
|
* Test requires EEG Unit.
|
Instructions for the one being tested are displayed on the unit's screen.  The victim/one tested will be appropriately "Wired Up" to the device.  The sensor readings will be displayed to screen.  Regardless of the sensor readings, the NeoPixel Unit on the EEG Unit will be cycled through various colors, brightness and/or sequences.  Changes to sensor readings will then be wrecklessly assigned to conjecture as well as confession through projection interpretations.  This is a test of higher validity due to there being more lines displayed on the screen then the EKG and Respiration Tests.
|-
!colspan="2"| Poly-Liar Test
|-
|
* Test requires EKG and Respiration Unit.
* Test requires Poly-Liar Unit.
|
Instructions for the one being tested are displayed on the unit's screen.  The victim/one tested will be appropriately "Wired Up" to the device.  The sensor readings will be displayed to screen.  After a series of harmless questions are asked and answered, the one tested will be subjected to scandalous and salacious questions and accusations.  Every sensor change or stable reading will be left to predefined biased impressions and be held against the tested one's integrity.  A Tone device may sound at random causing reading changes.  These changes can be ignored or used as grounds to doubt the veracity of answers given.
|-
!colspan="2"| Eye Tracking Analyzer Test A
|-
|
* Test requires Eye Tracking Unit.
|
Instructions for the one being tested are displayed on the unit's screen.  The one being tested is warned, discouraged and berated to NOT take this test.  Eye Safety has NOT BEEN ESTABLISHED.
|-
!colspan="2"| Eye Tracking Analyzer Test B
|-
|
* Test requires Eye Tracking Unit.
|
Instructions for the one being tested are displayed on the unit's screen.  The one being tested is asked to track a moving object with their eyes only.  Movement of the head is tracked via the goggle's MPU.  The ability of the tested one to hold head still is rated.  Eye Safety has NOT BEEN ESTABLISHED.
|-
!colspan="2"|Hypno Goggles
|-
|
* Test Requires Hypno Goggles.
|
Just because you have this option doesn't mean you should use it and risk seizures.  NOT SAFE.  Don't Do This!
|}
|}


= What is behind the curtain? =
== Development and Test Units ==


{|class="wikitable"
!colspan="5"| UNITS
|-
|Device
|Name
|Notes
|Port Description
|Connection Diagram
|-
|[[File:JAC MED MON TEST UNIT.jpg|left|thumbnail|x200px]]
| Test Device for Specialized Testing
|
* Arduino Proto-Shield (pins A4 and A5 clipped)
* RJ45 Connection Box
* Wire1 Pull-Up Resistors on Wire1 I2C Bus
|
{|class="wikitable"
{|class="wikitable"
!colspan="4"|Pin Mapping
!colspan="4"|Pin Mapping
|-
|-
|Port #
|Line #
|Line #
|DUE Pin
|Device Signal
|Function  
|Function  
|-
|-
|2
|1
|1
|3.3V
|3.3V
|Power
|Power
|-
|-
|2
|2
|2
|GND
|GND
|Power
|Power
|-
|-
|2
|3
|3
|70
|Arduino DUE Wire1
|I2C-SDA
|I2C-SDA
|-
|-
|2
|4
|4
|71
|Arduino DUE Wire1
|I2C-SCL
|I2C-SCL
|-
|-
|2
|5
|5
|64/A10
|Signal 0
|Analog0
|Analog
|-
|-
|2
|6
|6
|63/A9
|Signal 1
|Analog1
|Analog
|-
|-
|2
|7
|7
|62/A8
|Signal 2
|Analog2
|Analog
|-
|-
|2
|8
|8
|61/A7
|Singal 3
|Analog3
|Analog
|}
|}
 
|[[File:JAC_MED_MON_EXTERNAL_UNIT_TESTER_CONNECTION_DIAGRAM.jpg|left|thumbnail|x200px]]
 
|-
|[[File:JAC_MED_MON_TOKEN_TEST_UNIT.jpg|left|thumbnail|x200px]]
| ATTiny85 Token Test Unit
|
* Built to Program and Test ATTiny85 Tokens
* ATTiny85 Token with Local Reset
* RJ45 Connection Box
|
{|class="wikitable"
{|class="wikitable"
!colspan="4"|Pin Mapping
!colspan="4"|Pin Mapping
|-
|-
|Port #
|Line #
|Line #
|DUE Pin
|Device Signal
|Function  
|Function  
|-
|-
|3
|1
|1
|3.3V
|3.3V
|Power
|Power
|-
|-
|3
|2
|2
|GND
|GND
Line 591: Line 511:
|-
|-
|3
|3
|3
|ATTiny85 Token
|70
|I2C-SDA
|I2C-SDA
|-
|-
|3
|4
|4
|71
|ATTiny85 Token
|I2C-SCL
|I2C-SCL
|-
|-
|3
|5
|5
|59/A5
|Signal 0
|Analog0
|N/C
|-
|-
|3
|6
|6
|58/A4
|Signal 1
|Analog1
|N/C
|-
|-
|3
|7
|7
|57/A3
|Signal 2
|Analog2
|N/C
|-
|-
|3
|8
|8
|56/A2
|Singal 3
|Analog3
|N/C
|}
|[[File:JAC_MED_MON_TOKEN_TESTER_CONNECTION_DIAGRAM.jpg|left|thumbnail|x200px]]
|}
|}


==Schematics==
== ATTiny85 Tokens ==
===Control Panel Circuit===
[[File:JAC MED MON CONTROL PANEL SCHEMATIC.jpg]]
===EXG BIO AMP Circuit used as EKG===


[[File:JAC MED MON EXG BIO AMP SCHEMATIC.jpg|800x600px]]
{|class="wikitable"
!colspan="4"| TOKENS
|-
|Device
|Name
|Notes
|Design and Build
|-
|
[[File:JAC MED MON ATTINY85 TOKEN BOX.jpg|left|thumbnail|x200px]]
|
ATTiny85 ID Token
|
* Provides a unique ID for the token
* Provides an ID for an external unit type
|rowspan="3"|
[[Pseudo-Medical Monitor ATTiny85 Token]]
|-
|
[[File:JAC MED MON TONE ATTINY85.jpg|left|thumbnail|x200px]]
|
ATTiny85 Tone Token
|
* Provides a unique ID for the token
* Provides an ID for an external unit type
* Produce Tones
|-
|
[[File:JAC MED MON NeoPixel ATTINY85.jpg|left|thumbnail|x200px]]
|
ATTiny85 Neopixel Token
|
* Provides a unique ID for the token
* Provides an ID for an external unit type
* Produce Light
|}


===Respiratory Sensor===
== 3D Printed Items ==
[[File:JAC MED MON RESPIRATORY SENSOR SCHEMATIC.jpg]]


===Vibrating Motor Circuit===
[[Pseudo Medical Monitor Device 3D Print]]
[[File:JAC MED MON VM SCHEMATIC.jpg]]


=Code (Updated 10/24/2021)=
=Video=
===Special Libraries===
[https://youtu.be/qEC1xfL9FL0 YouTube Demo Video]
<code>
<nowiki>#</nowiki>include <Adafruit_GFX.h>


<nowiki>#</nowiki>include <Adafruit_ST7735.h>
=Pseudo-Medical Monitor for Christmas Cheap Gift=


<nowiki>#</nowiki>include <Adafruit_VL53L0X.h>
[[File:JAC MED MON ENHANCED.jpg]]


<nowiki>#</nowiki>include <Adafruit_AMG88xx.h>
In preparation for the expected Christmas Gift availability crisis, I present the Pseudo-Gift of the season.  The time honored tradition of knockoff products hitting the market before Christmas is alive and wellWhat better than a multi-property knockoff device? Star Trek / Arduino / Medical knockoff device gift for everyoneThis Pseudo-Medical Tricorder ripoff is the stocking stuffer for 2021.
 
<nowiki>#</nowiki>include <MAX30105.h>
 
<nowiki>#</nowiki>include <SparkFunMLX90614.h>
 
<nowiki>#</nowiki>include <DFRobot_ID809.h>
</code>
 
===Library Modification===
<nowiki>
// In this Library : #include <SparkFunMLX90614.h>
//Change the following line in the bool IRTherm::I2CReadWord(byte reg, int16_t * dest) routine.
//
// I2C processing change needed for Arduino Due implementation
//
// Comment Out Line Below
// _i2cPort->requestFrom(_deviceAddress, (uint8_t) 3, (uint8_t) true);
 
// Add Line Below
      _i2cPort->requestFrom(_deviceAddress, (uint8_t) 3, (uint32_t)reg, (uint8_t)1, (uint8_t)true);
</nowiki>
 
===Defines - Variables - Routines===
The following code is a mixing and matching of the example code provided by the referenced Special Libraries.   
==== Includes ====
  <nowiki>
#include <Wire.h>
#include <SPI.h>
 
#include <Adafruit_GFX.h>   
#include <Adafruit_ST7735.h>
#include "Adafruit_VL53L0X.h"
#include <Adafruit_AMG88xx.h>
#include <MAX30105.h>
#include <SparkFunMLX90614.h>
#include <DFRobot_ID809.h>
#include "bmpHeader.h"
#include <SD.h>
 
#include "TFT_Stuff.h"
 
#include "HB_Stuff.h"
#include "AMG_Stuff.h"
#include "VL_Stuff.h"
#include "CT_Stuff.h"
#include "FP_Stuff.h"
#include "EXG_Stuff.h"
 
  </nowiki>
 
==== VL53L0X Sensor (VL_Stuff.h) ====
<nowiki>
#define START_DISTANCE 500
#define EXG_DISTANCE 150
 
Adafruit_VL53L0X lox = Adafruit_VL53L0X();
 
bool EXG_Mode = false;


int last_range_measurement = -1;
= Code Listing =
int VL_x_offset = 118;
int VL_y_offset = 0;
int VL_x_width = 10;
int VL_y_height = 74;


void setup_VL()
[[Pseudo-Medical Monitor Code]]
{
  lox.begin();
}
 
void VL_Reset()
{
  last_range_measurement = -1;
}
 
void range_display(int range_measurement)
{
  int box_top = VL_y_offset;
  int box_bottom = box_top + VL_y_height;
 
  int box_left = VL_x_offset;
  int box_right = box_left + VL_x_width;
 
  int box_width = VL_x_width;
  int box_height = VL_y_height;
 
  int bar_top = box_top + 1;
  int bar_bottom = box_bottom - 1;
 
  int bar_left = box_left + 1;
  int bar_right = box_right -1;
 
  int bar_width = VL_x_width - 2;
  int bar_height = VL_y_height - 2;
 
  int bar_measure;
 
  if (last_range_measurement == -1)
    {
      // Draw Box
      tft.fillRect(box_left, box_top, box_width, box_height, ST7735_BLACK);   
      tft.drawRect(box_left, box_top, box_width, box_height, ST7735_YELLOW);   
    }
 
  if (last_range_measurement != range_measurement)
    {
      tft.fillRect(bar_left, bar_top, bar_width, bar_height, ST7735_BLACK);
      if (range_measurement > START_DISTANCE)
        tft.fillRect(bar_left, bar_top, bar_width, bar_height, ST7735_RED);
      else
        {
          if (range_measurement < EXG_DISTANCE)
            {
              bar_measure = ((float)range_measurement / (float)START_DISTANCE) * bar_height;
              tft.fillRect(bar_left, bar_bottom - bar_measure, bar_width, bar_measure, ST7735_BLUE);             
            }
          else
            {
              bar_measure = ((float)range_measurement / (float)START_DISTANCE) * bar_height;
              tft.fillRect(bar_left, bar_bottom - bar_measure, bar_width, bar_measure, ST7735_GREEN);
            }
        }
    } 
 
  last_range_measurement = range_measurement;
}
 
int VL_Reading()
{
  int range_measure;
 
  VL53L0X_RangingMeasurementData_t measure;
  lox.rangingTest(&measure, false); // pass in 'true' to get debug data printout!
  if (measure.RangeStatus != 4)
    {  // phase failures have incorrect data         
      range_measure = measure.RangeMilliMeter;
    }
  else
    {
      range_measure = 9999;
    }
 
  if (range_measure < EXG_DISTANCE)
    EXG_Mode = true;
  else
    EXG_Mode = false;
 
  return(range_measure); 
}
 
void VL_Frame()
{
  int range_measure;
 
  range_measure = VL_Reading();
 
  range_display(range_measure); 
 
//  delay(100); 
}
</nowiki>
 
==== Heart Beat Sensor (HB_Stuff.h) ====
<nowiki>
 
static const unsigned char PROGMEM still_heart_logo_bmp[] =
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x0F, 0x00, 0x00, 0x67, 0x18, 0xC0, 0x00, 0xC1, 0xB0, 0x60,
0x01, 0x80, 0xE0, 0x20, 0x01, 0x00, 0xC0, 0x30, 0x01, 0x00, 0x40, 0x10, 0x01, 0x00, 0x40, 0x10,
0x01, 0x04, 0x00, 0x10, 0x01, 0x04, 0x00, 0x10, 0x01, 0x0C, 0x00, 0x30, 0x00, 0x88, 0x80, 0x20,
0x00, 0x8B, 0x80, 0x40, 0x0F, 0xF3, 0x70, 0x80, 0x00, 0x13, 0x01, 0x80, 0x00, 0x19, 0x03, 0x00,
0x00, 0x0C, 0x06, 0x00, 0x00, 0x06, 0x0C, 0x00, 0x00, 0x03, 0x18, 0x00, 0x00, 0x01, 0xB0, 0x00,
0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
 
static const unsigned char PROGMEM beat_heart_logo_bmp[] =
{
0x01, 0xF0, 0x0F, 0x80, 0x06, 0x1C, 0x38, 0x60, 0x18, 0x06, 0x60, 0x18, 0x10, 0x01, 0x80, 0x08,
0x20, 0x01, 0x80, 0x04, 0x40, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x02, 0xC0, 0x00, 0x08, 0x03,
0x80, 0x00, 0x08, 0x01, 0x80, 0x00, 0x18, 0x01, 0x80, 0x00, 0x1C, 0x01, 0x80, 0x00, 0x14, 0x00,
0x80, 0x00, 0x14, 0x00, 0x80, 0x00, 0x14, 0x00, 0x40, 0x10, 0x12, 0x00, 0x40, 0x10, 0x12, 0x00,
0x7E, 0x1F, 0x23, 0xFE, 0x03, 0x31, 0xA0, 0x04, 0x01, 0xA0, 0xA0, 0x0C, 0x00, 0xA0, 0xA0, 0x08,
0x00, 0x60, 0xE0, 0x10, 0x00, 0x20, 0x60, 0x20, 0x06, 0x00, 0x40, 0x60, 0x03, 0x00, 0x40, 0xC0,
0x01, 0x80, 0x01, 0x80, 0x00, 0xC0, 0x03, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0x30, 0x0C, 0x00,
0x00, 0x08, 0x10, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x00, 0x01, 0x80, 0x00 
};
 
MAX30105 particleSensor;
 
#define HB_INT 4
 
int HB_x_offset = 0;
int HB_y_offset = 78;
int HB_x_width = 46;
int HB_y_height = 82;
 
int HB_initialize_screen = -1;
 
void HB_Reset()
{
  HB_initialize_screen = -1; 
}
 
void setup_HB()
{
  // Initialize sensor
  if (!particleSensor.begin()) //Use default I2C port, 400kHz speed
  {
    Serial.println("MAX30105 was not found. Please check wiring/power. ");
    while (1);
  }
//  Serial.println("Place your index finger on the sensor with steady pressure.");
 
  particleSensor.setup(); //Configure sensor with default settings
  particleSensor.setPulseAmplitudeRed(0x0A); //Turn Red LED to low to indicate sensor is running
  particleSensor.setPulseAmplitudeGreen(0); //Turn off Green LED
 
}
 
 
void HB_Frame()
{
  int box_top = HB_y_offset;
  int box_bottom = box_top + HB_y_height;
 
  int box_left = HB_x_offset;
  int box_right = box_left + HB_x_width;
 
  int box_width = HB_x_width;
  int box_height = HB_y_height;
 
  const byte RATE_SIZE = 6; //Increase this for more averaging. 4 is good.
  byte rates[RATE_SIZE]; //Array of heart rates
  long pulse_ir[RATE_SIZE];
  long pulse_red[RATE_SIZE];
 
  byte rateSpot = 0;
  byte O2Spot = 0;
  long O2AVG = 0;
  long lastBeat = 0; //Time at which the last beat occurred
  float beatsPerMinute;
  int beatAvg = -1, lastAvg = 0;
  long irAVG = 0;
  long redAVG = 0;
 
  bool beatDetect = false;
  int latentBeatMax = 2;
  int latentBeat = 0;
 
  long irValue = 0;
  long redValue = 0;
  long maxValue = 0; 
  long lastValue = 0;
  long turnValue = 0;
  long lastMax = 0;
 
  int tft_HB_Screen = 0;
  int last_HB_Screen = -1;
 
  unsigned long start_time;
  unsigned long delta = 0;
  int HB_detect_threshold = 7000;
 
  // Clear rate calculating array
  for(byte x = 0; x < RATE_SIZE ; ++x)
    rates[x] = 0;
 
  if (HB_initialize_screen == -1)
    {
      tft.fillRect(box_left, box_top, box_width, box_height, ST7735_BLACK);
      tft.drawRect(box_left, box_top, box_width, box_height, ST7735_BLUE);
      tft.setTextColor(ST7735_WHITE, ST7735_BLACK);           
      tft.setCursor(box_left + 3,box_top + 4);               
      tft.println("Place ");
      tft.setCursor(box_left + 3,box_top + 16);
      tft.println("your ");           
      tft.setCursor(box_left + 3,box_top + 28);
      tft.println("finger ");           
      tft.setCursor(box_left + 3,box_top + 40);
      tft.println("on ");                       
      tft.setCursor(box_left + 3,box_top + 52);
      tft.println("sensor ");                                   
      HB_initialize_screen = 0;
      for (byte x = 0 ; x < RATE_SIZE ; x++)
        rates[x] = 0;
    }
 
  irValue = particleSensor.getIR();
  redValue = particleSensor.getRed();
 
  while(irValue > HB_detect_threshold)
    {
      irValue = particleSensor.getIR();    //Reading the IR value it will permit us to know if there's a finger on the sensor or not
      redValue = particleSensor.getRed();
     
//      Serial.print(irValue);
//      Serial.print(",");
//      Serial.print(redValue);
//      Serial.print(",");
//      Serial.print(maxValue);
//      Serial.print(",");
//      Serial.print(turnValue);
//      Serial.print(",");
//      Serial.print(lastMax);
      Serial.println();
         
      if (irValue > 7000)
        { 
          //finger is detected
          tft_HB_Screen = 1;
          if (irValue > maxValue)
            maxValue = irValue;
 
//        if ((irValue < maxValue - 200) && (irValue > lastValue + 20)) // alternate detect beat method
          if (irValue < maxValue - 200)
            {
              beatDetect = true;
              lastMax = maxValue;
              maxValue = irValue;
              turnValue = lastValue;
              latentBeat = latentBeatMax;
            }
 
          lastValue = irValue; 
         
          if (beatDetect == true)
            {
              beatDetect = false;
 
              //We sensed a beat!
              delta = millis() - lastBeat;                  //Measure duration between two beats
              lastBeat = millis();
 
              beatsPerMinute = 60 / (delta / 1000.0);          //Calculating the BPM
              lastAvg = beatAvg;           
 
              pulse_ir[O2Spot++] = irValue;
              pulse_red[O2Spot] = redValue;
/*             
              if (O2Spot == RATE_SIZE)
                {
                  for (byte x = 0; x < RATE_SIZE; ++x)
                    {
                      irAVG = irAVG + pulse_ir[x];
                      redAVG = redAVG + pulse_red[x];
                    }
                  O2AVG = ((float)irAVG / (float) redAVG) * 100;
                  tft.setCursor(box_left + 4,box_top + 56);               
                  tft.println(O2AVG);                       
                  O2Spot = 0;
                }
*/             
              if ((beatsPerMinute < 255.0) && (beatsPerMinute > 20.0))              //To calculate the average we strore some values (4) then do some math to calculate the average
                {
                  rates[rateSpot++] = (byte)beatsPerMinute; //Store this reading in the array
                  rateSpot %= RATE_SIZE; //Wrap variable
 
                  //Take average of readings
 
                  beatAvg = 0;
                  for (byte x = 0 ; x < RATE_SIZE ; x++)
                    beatAvg += rates[x];
                  beatAvg /= RATE_SIZE;
                }
            }
        }
 
 
      if (irValue < 7000)
        {      //If no finger is detected it inform the user and put the average BPM to 0 or it will be stored for the next measure
          tft_HB_Screen = 0;
          beatAvg=0;
          lastAvg = 0;
          for(byte x = 0; x < RATE_SIZE ; ++x)
            rates[x] = 0;
        }
   
      switch(tft_HB_Screen)
        {
          case 0:           
            if (last_HB_Screen != 0)
              tft.fillRect(box_left + 1, box_top + 1, box_width - 2, box_height - 2, ST7735_BLACK);             
            tft.setTextColor(ST7735_WHITE, ST7735_BLACK);           
            tft.setCursor(box_left + 3,box_top + 4);               
            tft.println("Place ");
            tft.setCursor(box_left + 3,box_top + 16);
            tft.println("your ");           
            tft.setCursor(box_left + 3,box_top + 28);
            tft.println("finger ");           
            tft.setCursor(box_left + 3,box_top + 40);
            tft.println("on ");                       
            tft.setCursor(box_left + 3,box_top + 52);
            tft.println("sensor ");                                   
            break;
          case 1:       
            if (last_HB_Screen != 1)
              tft.fillRect(box_left + 1,box_top + 1,32,33,ST7735_BLACK);
            tft.setTextColor(ST7735_WHITE, ST7735_BLACK);
            if (latentBeat == latentBeatMax) 
              {
                tft.fillRect(box_left + 1,box_top + 1, box_width - 2, 33, ST7735_BLACK);
                tft.drawBitmap(box_left + 2,box_top + 2, beat_heart_logo_bmp, 32, 32, ST7735_RED);    //Draw the second picture (bigger heart)             
              }
            if (latentBeat == 0)
              {
                tft.fillRect(box_left + 1,box_top + 1, box_width - 2, 33, ST7735_BLACK);
                tft.drawBitmap(box_left + 2, box_top + 2, still_heart_logo_bmp, 32, 32, ST7735_WHITE);      //Draw the first bmp picture (little heart)
                latentBeat = -1;
              }                                         
            if (latentBeat > 0)
              -- latentBeat;             
            if (lastAvg != beatAvg)
              {
                tft.fillRect(box_left + 1,box_top + 34 ,box_width - 2,box_height - 35, ST7735_BLACK);
                tft.setCursor(box_left + 4,box_top + 34);               
                tft.println("BPM");           
                tft.setCursor(box_left + 4,box_top + 44);               
                tft.println(beatAvg);         
                lastAvg = beatAvg;
              }
            break;
          case 2:
            tft.fillRect(box_left + 1,box_top + 2, 32, 32, ST7735_BLACK);
            tft.drawBitmap(box_left + 2,box_top + 2, beat_heart_logo_bmp, 32, 32, ST7735_RED);    //Draw the second picture (bigger heart)             
 
            tft.fillRect(box_left + 1,box_top + 34 ,box_width - 2,box_height - 35, ST7735_BLACK);
            tft.setCursor(box_left + 4,box_top + 34);               
            tft.println("BPM");           
            tft.setCursor(box_left + 4,box_top + 44);               
            tft.println(beatAvg);                     
            break; 
          case 3:
            break;   
        }
    last_HB_Screen = tft_HB_Screen;   
    delay(100);
    }
}
 
</nowiki>
 
==== Fingerprint Scanner (FP_Stuff.h) ====
<nowiki>
#define FPSerial Serial1
#define FP_INIT 3
 
DFRobot_ID809 fingerprint;
String desc;
File myFile;
 
//#define QUARTER
#ifdef  QUARTER
uint8_t data[6400];  //Quarter image
#else
uint8_t data[25600];  //Full image
#endif
 
int FP_x_offset = 46;
int FP_y_offset = 78;
int FP_x_width = 82;
int FP_y_height = 82;
 
bool fingerprint_captured = false;
bool FP_first_pass = true;
 
void setup_FP()
{
  pinMode(FP_INIT,INPUT);
  /*Init FPSerial*/
  FPSerial.begin(115200);
  /*Take FPSerial as communication port of fingerprint module */
  fingerprint.begin(FPSerial);
 
  /*Wait for Serial to open*/
  /*Test whether device can communicate properly with mainboard
    Return true or false
    */
  while(fingerprint.isConnected() == false)
  {
    Serial.println("Communication with device failed, please check connection");
    /*Get error code information */
    desc = fingerprint.getErrorDescription();
    Serial.println(desc);
    delay(1000);
  }
}
 
 
void FP_Reset()
{
  fingerprint_captured = false;
  FP_first_pass = true; 
}
 
void FP_Frame()
{
  int box_top = FP_y_offset;
  int box_bottom = box_top + FP_y_height;
 
  int box_left = FP_x_offset;
  int box_right = box_left + FP_x_width;
 
  int box_width = FP_x_width;
  int box_height = FP_y_height;
 
  int p_x, p_y, p_i, p_data, p_temp;
 
  if (FP_first_pass)
    {
      tft.drawRect(box_left, box_top, box_width, box_height, ST7735_MAGENTA);
      tft.fillRect(box_left + 1, box_top + 1, box_width - 2, box_height - 2, ST7735_BLACK);
      fingerprint.ctrlLED(/*LEDMode = */fingerprint.eBreathing, /*LEDColor = */fingerprint.eLEDRed, /*blinkCount = */0);
      tft.setCursor(box_left + 4, box_top + 4);
      tft.println("Place Finger");
      tft.setCursor(box_left + 4, box_top + 16);
      tft.println("on scanner.");     
      FP_first_pass = false;
    }
 
  if ((fingerprint.detectFinger()) && (!fingerprint_captured))
    {
      tft.setCursor(box_left + 4, box_top + 4);
      tft.println("Keep Finger ");
      tft.setCursor(box_left + 4, box_top + 16);
      tft.println("on scanner.");     
     
      fingerprint.getFingerImage(data);
      fingerprint.ctrlLED(/*LEDMode = */fingerprint.eKeepsOn, /*LEDColor = */fingerprint.eLEDGreen, /*blinkCount = */0);
      for (p_x=0; p_x < 80; ++p_x)
        for (p_y=0; p_y < 80; ++p_y)
          {
            p_temp = (p_x * 2);
            p_temp = p_temp + (p_y * 160);
            p_data = data[p_temp]/4; // image element
 
            p_temp = p_temp + 1;
            p_data = p_data + data[p_temp]/4; // image element to the right
 
            p_temp = (p_x * 2);
            p_temp = p_temp + ((p_y + 1) * 160);
            p_data = p_data + data[p_temp]/4;  // image element below
 
            p_temp = (p_x + 1) * 2;
            p_temp = p_temp + ((p_y + 1) * 160);
            p_data = p_data + data[p_temp]/4;  // image element to the right, one element down
               
            p_data = p_data/4;
            tft.drawPixel(box_left+1+p_x,box_top+1+p_y,p_data<<5);
          }       
    }
   
}
 
</nowiki>
 
==== MLX90614 Sensor Code (CT_Stuff.h) ====
<nowiki>
IRTherm therm; // Create an IRTherm object to interact with throughout
 
int last_object_measurement = -1;
int last_ambient_measurement = -1;
 
int CT_x_offset = 0;
int CT_y_offset = 0;
int CT_x_width = 44;
int CT_y_height = 74;
 
void setup_CT()
{
  if (therm.begin() == false) { // Initialize thermal IR sensor
    Serial.println("IR thermometer Failed");
    while (1);
  }
 
  therm.setUnit(TEMP_F); // Set the library's units to Farenheit
 
}
 
 
void CT_Reset()
{
  last_object_measurement = -1;
  last_ambient_measurement = -1; 
}
 
void CT_Frame()
{
  int box_top = CT_y_offset;
  int box_bottom = box_top + CT_y_height;
 
  int box_left = CT_x_offset;
  int box_right = box_left + CT_x_width;
 
  int box_width = CT_x_width;
  int box_height = CT_y_height;
 
  int ambient_x_offset = box_left + 1;
  int ambient_y_offset = box_top + 8;
  int object_x_offset = box_left + 1;
  int object_y_offset = ambient_y_offset + 20;
 
  int ambient_measurement;
  int object_measurement;
 
  if ((last_ambient_measurement == -1) && (last_object_measurement == -1))
    {
      tft.drawRect(box_left, box_top, box_width, box_height, ST7735_RED);
      tft.setCursor(ambient_x_offset, ambient_y_offset);
      tft.println("MLX90XX");
      tft.setCursor(object_x_offset, object_y_offset);
      tft.println("Object");
     
    } 
 
  therm.read();
  ambient_measurement = therm.ambient();
  object_measurement = therm.object();
 
  if ( last_ambient_measurement != ambient_measurement)
    {
      tft.setCursor(ambient_x_offset, ambient_y_offset + 8);
      tft.println(String(therm.ambient(), 2));
    }
 
  if ( last_object_measurement != object_measurement)
    { 
      tft.setCursor(object_x_offset, object_y_offset + 8);
      tft.println(String(therm.object(), 2));
    }
 
  last_ambient_measurement = ambient_measurement;
  last_object_measurement = object_measurement;     
}
 
</nowiki>
 
====AMG8833 Sensor (AMG_Stuff.h) ====
<nowiki>
//low range of the sensor (this will be blue on the screen)
#define MINTEMP 20
 
//high range of the sensor (this will be red on the screen)
#define MAXTEMP 28
 
//the colors we will be using
const uint16_t camColors[] = {0x480F,
                              0x400F, 0x400F, 0x400F, 0x4010, 0x3810, 0x3810, 0x3810, 0x3810, 0x3010, 0x3010,
                              0x3010, 0x2810, 0x2810, 0x2810, 0x2810, 0x2010, 0x2010, 0x2010, 0x1810, 0x1810,
                              0x1811, 0x1811, 0x1011, 0x1011, 0x1011, 0x0811, 0x0811, 0x0811, 0x0011, 0x0011,
                              0x0011, 0x0011, 0x0011, 0x0031, 0x0031, 0x0051, 0x0072, 0x0072, 0x0092, 0x00B2,
                              0x00B2, 0x00D2, 0x00F2, 0x00F2, 0x0112, 0x0132, 0x0152, 0x0152, 0x0172, 0x0192,
                              0x0192, 0x01B2, 0x01D2, 0x01F3, 0x01F3, 0x0213, 0x0233, 0x0253, 0x0253, 0x0273,
                              0x0293, 0x02B3, 0x02D3, 0x02D3, 0x02F3, 0x0313, 0x0333, 0x0333, 0x0353, 0x0373,
                              0x0394, 0x03B4, 0x03D4, 0x03D4, 0x03F4, 0x0414, 0x0434, 0x0454, 0x0474, 0x0474,
                              0x0494, 0x04B4, 0x04D4, 0x04F4, 0x0514, 0x0534, 0x0534, 0x0554, 0x0554, 0x0574,
                              0x0574, 0x0573, 0x0573, 0x0573, 0x0572, 0x0572, 0x0572, 0x0571, 0x0591, 0x0591,
                              0x0590, 0x0590, 0x058F, 0x058F, 0x058F, 0x058E, 0x05AE, 0x05AE, 0x05AD, 0x05AD,
                              0x05AD, 0x05AC, 0x05AC, 0x05AB, 0x05CB, 0x05CB, 0x05CA, 0x05CA, 0x05CA, 0x05C9,
                              0x05C9, 0x05C8, 0x05E8, 0x05E8, 0x05E7, 0x05E7, 0x05E6, 0x05E6, 0x05E6, 0x05E5,
                              0x05E5, 0x0604, 0x0604, 0x0604, 0x0603, 0x0603, 0x0602, 0x0602, 0x0601, 0x0621,
                              0x0621, 0x0620, 0x0620, 0x0620, 0x0620, 0x0E20, 0x0E20, 0x0E40, 0x1640, 0x1640,
                              0x1E40, 0x1E40, 0x2640, 0x2640, 0x2E40, 0x2E60, 0x3660, 0x3660, 0x3E60, 0x3E60,
                              0x3E60, 0x4660, 0x4660, 0x4E60, 0x4E80, 0x5680, 0x5680, 0x5E80, 0x5E80, 0x6680,
                              0x6680, 0x6E80, 0x6EA0, 0x76A0, 0x76A0, 0x7EA0, 0x7EA0, 0x86A0, 0x86A0, 0x8EA0,
                              0x8EC0, 0x96C0, 0x96C0, 0x9EC0, 0x9EC0, 0xA6C0, 0xAEC0, 0xAEC0, 0xB6E0, 0xB6E0,
                              0xBEE0, 0xBEE0, 0xC6E0, 0xC6E0, 0xCEE0, 0xCEE0, 0xD6E0, 0xD700, 0xDF00, 0xDEE0,
                              0xDEC0, 0xDEA0, 0xDE80, 0xDE80, 0xE660, 0xE640, 0xE620, 0xE600, 0xE5E0, 0xE5C0,
                              0xE5A0, 0xE580, 0xE560, 0xE540, 0xE520, 0xE500, 0xE4E0, 0xE4C0, 0xE4A0, 0xE480,
                              0xE460, 0xEC40, 0xEC20, 0xEC00, 0xEBE0, 0xEBC0, 0xEBA0, 0xEB80, 0xEB60, 0xEB40,
                              0xEB20, 0xEB00, 0xEAE0, 0xEAC0, 0xEAA0, 0xEA80, 0xEA60, 0xEA40, 0xF220, 0xF200,
                              0xF1E0, 0xF1C0, 0xF1A0, 0xF180, 0xF160, 0xF140, 0xF100, 0xF0E0, 0xF0C0, 0xF0A0,
                              0xF080, 0xF060, 0xF040, 0xF020, 0xF800,
                            };
 
Adafruit_AMG88xx amg;
unsigned long delayTime;
 
#define AMG_COLS 8
#define AMG_ROWS 8
float pixels[AMG_COLS * AMG_ROWS];
 
#define INTERPOLATED_COLS 24
#define INTERPOLATED_ROWS 24
 
 
float get_point(float *p, uint8_t rows, uint8_t cols, int8_t x, int8_t y);
void set_point(float *p, uint8_t rows, uint8_t cols, int8_t x, int8_t y, float f);
void get_adjacents_1d(float *src, float *dest, uint8_t rows, uint8_t cols, int8_t x, int8_t y);
void get_adjacents_2d(float *src, float *dest, uint8_t rows, uint8_t cols, int8_t x, int8_t y);
float cubicInterpolate(float p[], float x);
float bicubicInterpolate(float p[], float x, float y);
void interpolate_image(float *src, uint8_t src_rows, uint8_t src_cols,
                      float *dest, uint8_t dest_rows, uint8_t dest_cols);
 
void setup_AMG()
{
  if (!amg.begin())
    {
      Serial.println("Could not find a valid AMG88xx sensor, check wiring!");
      while (1) { delay(1); }
    }
  //  Serial.println("-- Thermal Camera Test --");
}
 
void AMG_Reset()
{
 
}
 
void drawpixels(int x_offset, int y_offset, float *p, uint8_t rows, uint8_t cols, uint8_t boxWidth, uint8_t boxHeight)
{
  int colorTemp;
//  int x_offset = 4, y_offset = 0;
 
  for (int y = 0; y < rows; y++)
  {
    for (int x = 0; x < cols; x++)
    {
      float val = get_point(p, rows, cols, x, y);
      if (val >= MAXTEMP) colorTemp = MAXTEMP;
      else if (val <= MINTEMP) colorTemp = MINTEMP;
      else colorTemp = val;
 
      uint8_t colorIndex = map(colorTemp, MINTEMP, MAXTEMP, 0, 255);
      colorIndex = constrain(colorIndex, 0, 255);
      //draw the pixels!
      uint16_t color;
      color = val * 2;
      tft.fillRect(x_offset + (boxWidth * x), y_offset + (((rows-1)  - y) * boxHeight), boxWidth, boxHeight, camColors[colorIndex]);
    }
  }
}
 
int AMG_x_offset = 44;
int AMG_y_offset = 0;
int AMG_x_width = 74;
int AMG_y_height = 74;
 
 
void AMG_Frame()
{
 
  int AMG_box_top = AMG_y_offset;
  int AMG_box_left = AMG_x_offset;
  int AMG_box_bottom = AMG_box_top + AMG_y_height;
  int AMG_box_right = AMG_box_left + AMG_x_width;
  int AMG_box_width = AMG_x_width;
  int AMG_box_height = AMG_y_height;
  int AMG_frame_left = AMG_box_left + 1;
  int AMG_frame_top = AMG_box_top + 1;
 
  int box_size = 3;
 
  //read all the pixels
  amg.readPixels(pixels);
  float dest_2d[INTERPOLATED_ROWS * INTERPOLATED_COLS];
  int32_t t = millis();
  interpolate_image(pixels, AMG_ROWS, AMG_COLS, dest_2d, INTERPOLATED_ROWS, INTERPOLATED_COLS);
//  Serial.print("Interpolation took "); Serial.print(millis() - t); Serial.println(" ms");
//  uint16_t boxsize = min(tft.width() / INTERPOLATED_COLS, tft.height() / INTERPOLATED_COLS);
  tft.drawRect(AMG_box_left, AMG_box_top, AMG_box_width, AMG_box_height, ST7735_ORANGE);
  drawpixels(AMG_frame_left,AMG_frame_top,dest_2d, INTERPOLATED_ROWS, INTERPOLATED_COLS, box_size, box_size); 
}
 
</nowiki>
 
==== BioAmp EXG (EXG_Stuff.h) ====
<nowiki>
#define EXG_SAMPLE_SIZE 155
#define EXG_PIN A0
 
int EXG_x_offset = 0;
int EXG_y_offset = 0;
int EXG_x_width = 128;
int EXG_y_height = 160;
 
void EXG_Frame()
 
  int box_top = EXG_y_offset;
  int box_bottom = box_top + EXG_y_height;
 
  int box_left = EXG_x_offset;
  int box_right = box_left + EXG_x_width;
 
  int box_width = EXG_x_width;
  int box_height = EXG_y_height;
 
  tft.fillRect(box_left, box_top, box_width, box_height, ST7735_WHITE);
  tft.drawRect(box_left+1, box_top+1, box_width-3, box_height-3, ST7735_BLACK);
 
}
 
void EXG_Display_Data(int * EXG_data)
{
  int box_top = EXG_y_offset;
  int box_bottom = box_top + EXG_y_height;
 
  int box_left = EXG_x_offset;
  int box_right = box_left + EXG_x_width;
 
  int box_width = EXG_x_width;
  int box_height = EXG_y_height;
 
  int max_value = -5000;
  int min_value = 5000;
  int data_point1,data_point2;
 
  tft.fillRect(box_left+2, box_top+2, box_width-5, box_height-5, ST7735_WHITE);
 
  for(int x=0;x<EXG_SAMPLE_SIZE; ++x)
    {
      if (EXG_data[x] > max_value)
        max_value = EXG_data[x];
      if (EXG_data[x] < min_value)
        min_value = EXG_data[x];       
    }
  for(int x=0;x<EXG_SAMPLE_SIZE-1; ++x)
  {
    data_point1 = map(EXG_data[x],min_value,max_value,2,124);
    data_point2 = map(EXG_data[x+1],min_value,max_value,2,124);
    tft.drawLine(data_point1,x+2,data_point2,x+3,ST7735_RED);
    Serial.println(data_point1);
  }
   
}
 
void EXG_Collect()
{
  int EXG_Delay = 30; 
  int EXG_data[EXG_SAMPLE_SIZE];
 
  for(int x=0;x<EXG_SAMPLE_SIZE; ++x)
    {
      EXG_data[x] = analogRead(EXG_PIN);
      delay(EXG_Delay);
    }
 
  EXG_Display_Data(EXG_data);
 
}
 
 
void EXG_Demo()
{
  EXG_Frame();
  while(1)
    {
      EXG_Collect();     
    }
}
</nowiki>
 
==== Core ====
<nowiki>
void setup()
{
  Wire.begin();
  Serial.begin(115200);
 
  Serial.println("SETUP - Begin");
  Serial.println("TFT");
  setup_TFT();
  Serial.println("CT");
  setup_CT();
  Serial.println("AMG");
  setup_AMG();
  Serial.println("VL");
  setup_VL(); 
  Serial.println("HB");
  setup_HB();
  Serial.println("FP");
  setup_FP();
  Serial.println("SETUP - End");
}
 
void loop()
{
 
  VL_Frame();
  AMG_Frame();
  CT_Frame();
  FP_Frame();
  HB_Frame();
 
  if (EXG_Mode)
    {
      EXG_Frame();
      while(EXG_Mode)
        {
          EXG_Collect();
          VL_Reading();
        }
      TFT_Reset();
      VL_Reset();
      AMG_Reset();
      CT_Reset();
      FP_Reset(); 
      HB_Reset();
    } 
}
</nowiki>
 
=Video=
[https://youtu.be/qEC1xfL9FL0 YouTube Demo Video]


=Return to Index=
=Return to Index=


[[JAC Projects|The JAC Project Index]]
[[JAC Projects|The JAC Project Index]]

Latest revision as of 17:03, 11 December 2021

What is this device?

This device is the ultimate Pseudo-Medical device not having any form of endorsement whatsoever! This is NOT A VALID MEDICAL DEVICE IN ANY KNOWN UNIVERSE, ACTUAL OR FICTIONAL!!!

Why make, let alone market this device?

This product was part of the underground QUACK-A-THON 2025 contest. It was built as an alternate universe Hack-A-Day prize entry intended to bring mankind to its knees. After defeating several other malpractice devices, immediate marketing was authorized with little regard to the reality of the project.

How does it Pseudo do what it does?

This device consists of a master data collection and processing unit along with external units for specialized tasking. Each External Device resides on a separate I2C bus provide through a TCA9548A I2C MUX. The external units also have a specialized embedded ATTiny85 I2C Identification Token which allows the main device to auto-configure to its attached units.

Main Device

Device
Device Name Notes Layer Diagram Design and Build
Pseudo-Medical Monitor
  • Device consists of layers of prototyping shields
  • External Ports consist of pairs of RJ45 Jack
  • Control Panel is attached to end of device
  • An easy access analog line connector is not displayed on diagram due to lazy draftsman
Pseudo-Medical Monitor Device Design

Main Device Monitoring Capabilities

Passive Mode
Example Description
This device provides several passive functions when not placed in specific function modes. The passive mode consists of a thermal image with a actual 8x8 resolution that is interpolated out to 24x24. A distance of device from user is recorded by a time of flight laser range finder. The distance is displayed with a color bar graph. A bar color of RED indicates the distance to user is beyond 50cm. A bar of GREEN indicates a distance of 50cm or less. The final BLUE bar indicates a distance of less than 25cm and invokes the EXG Sensor mode. An Object and Ambient temperature is displayed.
Fingerprint Mode
Placement of a finger on the fingerprint scanner activated this mode. Onscreen instructions direct the user to place finger an scanner. This suspends the Passive Mode. The onscreen instructions tell the user to keep finger on scanner until a fingerprint image is captured and displayed on the screen. When the scanner ring is pulsing RED, a fingerprint is not displayed. A GREEN ring indicates a fingerprint image has been captured and is being displayed. Upon removal of finger from scanner, the device returns to Passive Mode.
Pulse Mode
Placement of a finger on the pulse sensor activates this mode. This suspends the Passive Mode. The sensor reads the pulse and provides a beat indicator as well as an estimate pulse rate. Future upgrades will display the O2 Saturation level (stray diagnosis number under pulse rate). Upon removal of finger from sensor, the device returns to Passive Mode.
EKG Mode
When the device distance is met, or a finger is placed on the distance sensor, the EXG Mode is engaged. This suspends the Passive Mode. The entire screen is cleared and converted to display ~152 readings with automatic scaling to screen. If the distance reading remains in this modes range, additional readings are made and displayed until distance criteria changes. Upon mode change, the entire screen is redrawn and the fingerprint information is reset to not recorded. (Finger is over distance sensor, readings are from the BioAmp EXG Pill in a black box)

Extended Options

External Units

Device Interactions Port Description Connection Diagram Design and Build

Hand-Held Grip and Reflex Sensor

  • Steady Hold
  • Grip Strength
  • User Response Switch
  • Vibration Generation
Pin Mapping
Line # Device Signal Function
1 3.3V Power
2 GND Power
3 MPU6050/ATTiny85 Token I2C-SDA
4 MPU6050/ATTiny85 Token I2C-SCL
5 MPU6050-INT GPIO
6 Vibrating Motor I/O GPIO
7 Momentary Push Button GPIO
8 Grip Sensor Analog

Pseudo-Medical Monitor Hand-Held External Unit Design

EKG-Respiration Unit

  • EKG
  • Breathing Sensor
  • Breathing Sensor Sensitivity Adjustment
  • Pacing LED
Pin Mapping
Line # Device Signal Function
1 3.3V Power
2 GND Power
3 NeoPixel Controller I2C-SDA
4 NeoPixel Controller I2C-SCL
5 Respiration Detection Analog
6 Respiration Detection Adjust Analog
7 N/C Analog
8 Heart Beat Signal Analog

Pseudo-Medical Monitor EKG External Unit Design

Poly-Liar Unit

  • Galvanic Skin Response Sensor
  • Heart Beat Detection Sensor
  • Respiration Detection Sensor
  • Skin Temperature Sensor
Pin Mapping
Line # Device Signal Function
1 3.3V Power
2 GND Power
3 Tone Controller I2C-SDA
4 Tone Controller I2C-SCL
5 Respiration Detection Analog
6 Skin Temperature Analog
7 Pulse Detection Analog
8 GSR Signal Analog

Pseudo-Medical Monitor Poly-Liar External Unit Design

Tracking Goggles Unit

  • Eye Tracking
  • Head Direction Tracking
Pin Mapping
Line # Device Signal Function
1 3.3V Power
2 GND Power
3 BNO055/ATTiny85 Token I2C-SDA
4 BNO055/ATTiny85 Token I2C-SCL
5 Top Sensor Analog0
6 Bottom Right Sensor Analog1
7 Bottom Left Sensor Analog2
8 BNO055_INT Analog3

Pseudo-Medical Monitor Tracking Goggles External Unit Design

Hypno Goggles Unit

  • Goggles
  • Left ATTiny85 Neopixel Token
  • Right ATTiny85 Neopixel Token
  • Control Box
  • RJ45 Socket Breakout Board

EEG Unit

  • EEG
Pin Mapping
Line # Device Signal Function
1 3.3V Power
2 GND Power
3 ATTiny85 Token I2C-SDA
4 ATTiny85 Token I2C-SCL
5 Signal 0 Analog
6 Signal 1 Analog
7 Signal 2 Analog
8 Singal 3 Analog

Pseudo-Medical Monitor EEG External Unit Design

Test Capabilities with and without External Units

Test
Configuration Procedure
Eye Test
  • Only Base Device needed.

Instructions for the one being tested are displayed on the unit's screen. The one tested will be shown an "E" symbol of various sizes and orientations. The display will be activated based on distance readings from the Base Device distance sensor. After the display distance and time are met, the one tested will use a Rotary Encoder and Switch function, on the Control Panel, to select orientation on the "E" symbol. The process will be repeated with success or failure counts by orientation and distance will be recorded.

Hearing Test
  • Test requires earphones or headphones be plugged into Audio/MIDI shield audio jack.
  • Test can use either one or two Hand Held Units or use use the switch function of the Rotary Encoders on the Control Panel.

Instructions for the one being tested are displayed on the unit's screen. A series of tones of various frequencies and volumes are played to each ear in variable patterns. Upon detection of the Tone, the tested is required to signal detection by depressing the appropriate Hand Held Unit Button of Rotary Encoder. Tones are tested for a determined time and a timeout condition is considered to be non-detection. Repeat of the "missed" Tones can be retested for confirmation.

Grip and Reflex Test
  • Test can use of one or two Hand Held Units.

Instructions for the one being tested are displayed on the unit's screen. The one tested will be asked to grip the Hand Held Units multiple times to set a baseline for grip pressure readings for each Unit used. The one tested will then be required to register detection of the Units vibrating motor. The operating time of the motor will be varied. Detection of the vibration and time to detection are recorded. Detection will be based on grip detection and Unit Button depression as instructed during test.

EKG and Respiration Test A
  • Test requires EKG-Respiration Unit.

Instructions for the one being tested are displayed on the unit's screen. The victim/one tested will be appropriately "Wired Up" to the device. The sensor readings will be displayed to screen. If the one tested has a pulse and breathing is detected, the the one tested will be considered "NOT DEAD". If (a pulse but not breathing) or (breathing but no pulse) is detected the the one tested will be considered "NOT QUITE DEAD". If neither pulse or breathing is detected then the one tested could simply be "PINING FOR THE FJORDS" or "NOT ALIVE" but no assertion will be made as to their death.

EKG and Respiration Test B
  • Test requires EKG-Respiration Unit.

Instructions for the one being tested are displayed on the unit's screen. The victim/one tested will be appropriately "Wired Up" to the device. The sensor readings will be displayed to screen. Regardless of the sensor readings, the NeoPixel Unit on the EKG Unit will be cycled through various colors, brightness and/or sequences. Changes to sensor readings will then be wrecklessly assigned to conjecture as well as confession through projection interpretations.

EEG Test
  • Test requires EEG Unit.

Instructions for the one being tested are displayed on the unit's screen. The victim/one tested will be appropriately "Wired Up" to the device. The sensor readings will be displayed to screen. Regardless of the sensor readings, the NeoPixel Unit on the EEG Unit will be cycled through various colors, brightness and/or sequences. Changes to sensor readings will then be wrecklessly assigned to conjecture as well as confession through projection interpretations. This is a test of higher validity due to there being more lines displayed on the screen then the EKG and Respiration Tests.

Poly-Liar Test
  • Test requires EKG and Respiration Unit.
  • Test requires Poly-Liar Unit.

Instructions for the one being tested are displayed on the unit's screen. The victim/one tested will be appropriately "Wired Up" to the device. The sensor readings will be displayed to screen. After a series of harmless questions are asked and answered, the one tested will be subjected to scandalous and salacious questions and accusations. Every sensor change or stable reading will be left to predefined biased impressions and be held against the tested one's integrity. A Tone device may sound at random causing reading changes. These changes can be ignored or used as grounds to doubt the veracity of answers given.

Eye Tracking Analyzer Test A
  • Test requires Eye Tracking Unit.

Instructions for the one being tested are displayed on the unit's screen. The one being tested is warned, discouraged and berated to NOT take this test. Eye Safety has NOT BEEN ESTABLISHED.

Eye Tracking Analyzer Test B
  • Test requires Eye Tracking Unit.

Instructions for the one being tested are displayed on the unit's screen. The one being tested is asked to track a moving object with their eyes only. Movement of the head is tracked via the goggle's MPU. The ability of the tested one to hold head still is rated. Eye Safety has NOT BEEN ESTABLISHED.

Hypno Goggles
  • Test Requires Hypno Goggles.

Just because you have this option doesn't mean you should use it and risk seizures. NOT SAFE. Don't Do This!

What is behind the curtain?

Development and Test Units

UNITS
Device Name Notes Port Description Connection Diagram
Test Device for Specialized Testing
  • Arduino Proto-Shield (pins A4 and A5 clipped)
  • RJ45 Connection Box
  • Wire1 Pull-Up Resistors on Wire1 I2C Bus
Pin Mapping
Line # Device Signal Function
1 3.3V Power
2 GND Power
3 Arduino DUE Wire1 I2C-SDA
4 Arduino DUE Wire1 I2C-SCL
5 Signal 0 Analog
6 Signal 1 Analog
7 Signal 2 Analog
8 Singal 3 Analog
ATTiny85 Token Test Unit
  • Built to Program and Test ATTiny85 Tokens
  • ATTiny85 Token with Local Reset
  • RJ45 Connection Box
Pin Mapping
Line # Device Signal Function
1 3.3V Power
2 GND Power
3 ATTiny85 Token I2C-SDA
4 ATTiny85 Token I2C-SCL
5 Signal 0 N/C
6 Signal 1 N/C
7 Signal 2 N/C
8 Singal 3 N/C

ATTiny85 Tokens

TOKENS
Device Name Notes Design and Build

ATTiny85 ID Token

  • Provides a unique ID for the token
  • Provides an ID for an external unit type
Pseudo-Medical Monitor ATTiny85 Token

ATTiny85 Tone Token

  • Provides a unique ID for the token
  • Provides an ID for an external unit type
  • Produce Tones

ATTiny85 Neopixel Token

  • Provides a unique ID for the token
  • Provides an ID for an external unit type
  • Produce Light

3D Printed Items

Pseudo Medical Monitor Device 3D Print

Video

YouTube Demo Video

Pseudo-Medical Monitor for Christmas Cheap Gift

In preparation for the expected Christmas Gift availability crisis, I present the Pseudo-Gift of the season. The time honored tradition of knockoff products hitting the market before Christmas is alive and well. What better than a multi-property knockoff device? Star Trek / Arduino / Medical knockoff device gift for everyone. This Pseudo-Medical Tricorder ripoff is the stocking stuffer for 2021.

Code Listing

Pseudo-Medical Monitor Code

Return to Index

The JAC Project Index