├── Documentation
├── GlobalTracker_FAQs
│ └── README.md
├── Hardware_Overview
│ ├── ARTEMIS_PINS.md
│ └── README.md
└── Message_Format
│ └── README.md
├── Hardware
├── Artemis_Global_Tracker.brd
├── Artemis_Global_Tracker.sch
├── New_Parts.lbr
├── Production
│ ├── Artemis_Global_Tracker-Panel.GBL
│ ├── Artemis_Global_Tracker-Panel.GBO
│ ├── Artemis_Global_Tracker-Panel.GBP
│ ├── Artemis_Global_Tracker-Panel.GBS
│ ├── Artemis_Global_Tracker-Panel.GKO
│ ├── Artemis_Global_Tracker-Panel.GTL
│ ├── Artemis_Global_Tracker-Panel.GTO
│ ├── Artemis_Global_Tracker-Panel.GTP
│ ├── Artemis_Global_Tracker-Panel.GTS
│ ├── Artemis_Global_Tracker-Panel.TXT
│ ├── Artemis_Global_Tracker-Panel.b#1
│ ├── Artemis_Global_Tracker-Panel.brd
│ ├── Artemis_Global_Tracker-Panel.zip
│ └── Artemis_Global_Tracker.dru
└── Schematic.pdf
├── LICENSE.md
├── README.md
├── Software
├── README.md
└── examples
│ ├── Example10_BasicSend
│ └── Example10_BasicSend.ino
│ ├── Example11_Ring
│ └── Example11_Ring.ino
│ ├── Example12_TestLowPower
│ └── Example12_TestLowPower.ino
│ ├── Example13_GeofenceAlert
│ └── Example13_GeofenceAlert.ino
│ ├── Example14_SimpleTracker
│ └── Example14_SimpleTracker.ino
│ ├── Example15_BetterTracker
│ ├── Example15_BetterTracker.ino
│ ├── Tracker_EEPROM_Functions.ino
│ └── Tracker_EEPROM_Storage.h
│ ├── Example16_GlobalTracker
│ ├── Example16_GlobalTracker.ino
│ ├── Tracker_BattV.ino
│ ├── Tracker_Callbacks.ino
│ ├── Tracker_Message_Fields.h
│ ├── Tracker_Message_Fields.ino
│ ├── Tracker_User_Functions.ino
│ └── Tracker_printf_Support.ino
│ ├── Example17_ProductionTest
│ └── Example17_ProductionTest.ino
│ ├── Example18_ProductionTestPart2
│ └── Example18_ProductionTestPart2.ino
│ ├── Example19_SerialTerminal
│ └── Example19_SerialTerminal.ino
│ ├── Example1_Blink
│ └── Example1_Blink.ino
│ ├── Example20_GNSS_ModuleInfo
│ └── Example20_GNSS_ModuleInfo.ino
│ ├── Example21_IridiumSerialAndPowerTest
│ └── Example21_IridiumSerialAndPowerTest.ino
│ ├── Example2_BusVoltage
│ └── Example2_BusVoltage.ino
│ ├── Example3_PHT
│ └── Example3_PHT.ino
│ ├── Example4_ExternalPHT
│ └── Example4_ExternalPHT.ino
│ ├── Example5_GNSS
│ └── Example5_GNSS.ino
│ ├── Example6_Geofence
│ └── Example6_Geofence.ino
│ ├── Example7_GetIMEI
│ └── Example7_GetIMEI.ino
│ ├── Example8_CheckCSQ
│ └── Example8_CheckCSQ.ino
│ ├── Example9_GetTime
│ └── Example9_GetTime.ino
│ └── README.md
├── Tools
├── Artemis_Global_Tracker_Configuration_Tool
│ ├── AGTCT.py
│ ├── Windows_64-bit
│ │ ├── AGTCT.exe
│ │ ├── default.pkl
│ │ ├── empty.pkl
│ │ └── mapper.pkl
│ ├── default.pkl
│ ├── empty.pkl
│ └── mapper.pkl
├── Artemis_Global_Tracker_Mapping_Tools
│ ├── Artemis_Global_Tracker_CSV_DateTime.py
│ ├── Artemis_Global_Tracker_DateTime_CSV_to_KML.py
│ ├── Artemis_Global_Tracker_GMail_Downloader.py
│ ├── Artemis_Global_Tracker_Mapper.py
│ ├── Artemis_Global_Tracker_Message_Translator.py
│ ├── Artemis_Global_Tracker_Stitcher.py
│ ├── Flight_Simulator.py
│ └── map_image_blank.png
└── README.md
├── binaries
├── Example14_SimpleTracker
│ └── Example14_SimpleTracker.ino.bin
├── Example15_BetterTracker
│ └── Example15_BetterTracker.ino.bin
├── Example16_GlobalTracker
│ └── Example16_GlobalTracker.ino.bin
├── Example17_ProductionTest
│ └── Example17_ProductionTest.ino.bin
├── Example18_ProductionTestPart2
│ └── Example18_ProductionTestPart2.ino.bin
├── Example19_SerialTerminal
│ └── Example19_SerialTerminal.ino.bin
├── Example1_Blink
│ └── Example1_Blink.ino.bin
├── Example21_IridiumSerialAndPowerTest
│ └── Example21_IridiumSerialAndPowerTest.ino.bin
├── Example5_GNSS
│ └── Example5_GNSS.ino.bin
├── Example7_GetIMEI
│ └── Example7_GetIMEI.ino.bin
├── Example9_GetTime
│ └── Example9_GetTime.ino.bin
└── README.md
└── img
├── 16469-Artemis_Global_Tracker-02.jpg
├── 16469-Artemis_Global_Tracker-04.jpg
├── 9603N.JPG
├── AGTCT1.PNG
├── AGTCT10.PNG
├── AGTCT11.PNG
├── AGTCT12.PNG
├── AGTCT13.PNG
├── AGTCT14.PNG
├── AGTCT2.PNG
├── AGTCT3.PNG
├── AGTCT4.PNG
├── AGTCT5.PNG
├── AGTCT6.PNG
├── AGTCT7.PNG
├── AGTCT8.PNG
├── AGTCT9.PNG
├── Artemis.JPG
├── Bottom.JPG
├── Bus_V.JPG
├── Config.JPG
├── Delivery_Group.PNG
├── Dimensions.png
├── GPS_EN.JPG
├── Google_Earth.JPG
├── LTC3225.JPG
├── LiPo.JPG
├── Mapper.JPG
├── PHT.JPG
├── Pins.JPG
├── Power_Select.JPG
├── Quickstart1.PNG
├── Quickstart2.PNG
├── Quickstart3.PNG
├── Quickstart4.PNG
├── Quickstart5.PNG
├── Qwiic.JPG
├── RF.JPG
├── Reg.JPG
├── Reg_EN.JPG
├── Top.JPG
├── Tracker_with_Internet.JPG
├── USB.JPG
├── VBCKP.JPG
├── ZOE-M8Q_Mask.JPG
├── ZOE-M8Q_Paste.JPG
├── ZOE-M8Q_Placed.JPG
└── ZOE.JPG
/Documentation/Hardware_Overview/ARTEMIS_PINS.md:
--------------------------------------------------------------------------------
1 | # Artemis Global Tracker: Artemis Pad Allocation
2 |
3 | | Module Pad No. | Name | Pin | Allocation |
4 | |---|---|---|---|
5 | | 1 | GND | | Power Ground |
6 | | 2 | GPIO20 | SWDCK | JTAG single wire clock |
7 | | 3 | GPIO49 | RX0 | Bootload RX pin for serial bootloading |
8 | | 4 | GPIO39 | ~D39 | Qwiic SCL |
9 | | 5 | GPIO40 | D40 | Qwiic SDA |
10 | | 6 | GPIO9 | D9 | ZOE-M8Q SDA |
11 | | 7 | BOOT | | Bootload. Hold pin high during reset to initiate bootloader |
12 | | 8 | GPIO10 | D10 | ZOE-M8Q PIO14 (Geofence Alert) |
13 | | 9 | GPIO48 | TX0 | Bootload TX pin for serial bootloading |
14 | | 10 | GPIO21 | SWDIO | JTAG single wire I/O |
15 | | 11 | GPIO8 | D8 | ZOE-M8Q SCL |
16 | | 12 | GPIO5 | ~D5 | SPI SCK or GPIO |
17 | | 13 | GPIO7 | ~D7 | SPI MOSI or GPIO |
18 | | 14 | GPIO35 | ~AD35 | SPI CS(1) or GPIO |
19 | | 15 | GPIO4 | ~D4 | SPI CS(2) or GPIO |
20 | | 16 | GPIO24 | ~D24 | Iridium 9603N TX(In) |
21 | | 17 | GPIO22 | ~D22 | AD4210 ON |
22 | | 18 | GPIO23 | ~D23 | N/C |
23 | | 19 | GPIO27 | ~D27 | LTC3225 SHDN |
24 | | 20 | GPIO14 | D14 | N/C |
25 | | 21 | GPIO28 | ~D28 | LTC3225 PGOOD |
26 | | 22 | GND | | Power |
27 | | 23 | GPIO6 | ~D6 | SPI MISO or GPIO |
28 | | 24 | GPIO32 | ~AD32 | N/C |
29 | | 25 | GPIO25 | ~D25 | Iridium 9603N RX(Out) |
30 | | 26 | GPIO12 | ~AD12 | N/C |
31 | | 27 | GPIO26 | ~D26 | GPS_EN |
32 | | 28 | GPIO13 | ~AD13 | Bus Voltage Measure |
33 | | 29 | GPIO15 | D15 | N/C |
34 | | 30 | GPIO33 | ~AD33/SWO | JTAG SWO |
35 | | 31 | GPIO34 | AD34 | Bus Voltage Measure Enable |
36 | | 32 | GPIO11 | ~AD11 | N/C |
37 | | 33 | GPIO29 | ~AD29 | N/C |
38 | | 34 | XO | | 32kHz Xtal Connection for external 32.768kHz RTC crystal |
39 | | 35 | XI | | 32kHz Xtal Connection for external 32.768kHz RTC crystal |
40 | | 36 | VDD | | Power |
41 | | 37 | VDD | | Power |
42 | | 38 | GND | | Power |
43 | | 39 | GND | | Power |
44 | | 40 | GPIO19 | ~D19 | White LED |
45 | | 41 | GPIO18 | ~D18 | Iridium 9603N Network Available |
46 | | 42 | GPIO16 | AD16 | N/C |
47 | | 43 | GPIO17 | D17 | Iridium 9603N ON/OFF |
48 | | 44 | GPIO31 | ~AD31 | N/C |
49 | | 45 | GPIO41 | D41 | Iridium 9603N Ring Indicator |
50 | | 46 | GPIO45 | ~D45 | N/C |
51 | | 47 | GND | | Power |
52 | | 48 | GPIO2 | D2 | N/C |
53 | | 49 | GPIO1 | D1 | N/C |
54 | | 50 | nRESET | | System Reset Pull pin low to reset system |
55 | | 51 | GPIO0 | D0 | N/C |
56 | | 52 | GPIO43 | ~D43 | N/C |
57 | | 53 | GPIO42 | ~D42 | N/C |
58 | | 54 | GPIO3 | D3 | N/C |
59 | | 55 | GPIO36 | D36 | N/C |
60 | | 56 | GPIO38 | D38 | N/C |
61 | | 57 | GPIO37 | ~D37 | N/C |
62 | | 58 | GPIO44 | ~D44 | N/C |
63 | | 59 | GND | | Power |
64 |
--------------------------------------------------------------------------------
/Documentation/Hardware_Overview/README.md:
--------------------------------------------------------------------------------
1 | # Artemis Global Tracker: Hardware Overview
2 |
3 | The Artemis Global Tracker is an open source satellite tracker utilising the [SparkFun Artemis module](https://www.sparkfun.com/products/15484),
4 | [Iridium 9603N satellite transceiver](https://www.iridium.com/products/iridium-9603/) and [u-blox ZOE-M8Q GNSS
5 | ](https://www.u-blox.com/en/product/zoe-m8-series).
6 |
7 | The hardware design is based extensively on the:
8 | - [SparkFun Artemis module](https://www.sparkfun.com/products/15484)
9 | - [SparkFun Thing Plus - Artemis](https://www.sparkfun.com/products/15574) battery charging circuit and USB-C interface
10 | - [SparkFun Qwiic Iridium 9603N](https://www.sparkfun.com/products/16394) Iridium 9603N, LTC3225 supercapacitor charger and ADM4210 inrush current circuit
11 | - [SparkFun GPS Breakout - ZOE-M8Q](https://www.sparkfun.com/products/15193) ZOE connections and backup battery circuit
12 |
13 | The design also makes use of the:
14 | - [Skyworks AS179-92LF GaAs RF Switch](https://www.skyworksinc.com/products/switches/as179-92lf)
15 | - [Maxtena M1600HCT-P-SMA antenna](https://www.maxtena.com/products/f-gps/m1600hct-p-sma/) which is tuned for Iridium, GPS and GLONASS
16 | - [Available from SparkFun](https://www.sparkfun.com/products/16838)
17 | - [TE / MEAS Switzerland MS8607](https://www.te.com/usa-en/product-CAT-BLPS0018.html) combined pressure, humidity and temperature sensor
18 |
19 | The full schematic for the tracker can be found [here](../../Hardware/Schematic.pdf)
20 |
21 | Additional information can be found in the [FAQs](../GlobalTracker_FAQs/README.md)
22 |
23 | ## The Artemis Module
24 |
25 | The heart of the tracker is, of course, the most excellent Artemis module from SparkFun. The pad allocation is defined [here](../Hardware_Overview/ARTEMIS_PINS.md).
26 |
27 | 
28 |
29 | ## Power Options
30 |
31 | The tracker can be powered from:
32 | - the USB-C interface
33 | - a LiPo battery (recharged via the USB-C interface)
34 | - an external solar panel or battery pack (6V maximum)
35 |
36 | 3 x Energizer™ Ultimate Lithium AA or AAA cells are recommended as they will work down to -40C
37 |
38 | Low-forward-voltage diodes isolate the power sources from each other. You can have the USB, LiPo and external cells connected simultaneously, it will do no harm.
39 | The tracker will preferentially draw power from USB if it is connected.
40 |
41 | If the USB is disconnected, the tracker will preferentially draw power from the external cells. If you have the external cells connected, you may as well disconnect the LiPo.
42 |
43 | 
44 |
45 | J4 (VBUS -> VIN) can be used to measure the current draw or to connect a power switch after you open the MEAS split pad.
46 |
47 | ## USB Interface
48 |
49 | The USB interface is taken directly from the [SparkFun Thing Plus - Artemis](https://www.sparkfun.com/products/15574).
50 |
51 | 
52 |
53 | ## LiPo Charger
54 |
55 | The LiPo charger circuit is taken directly from the [SparkFun Thing Plus - Artemis](https://www.sparkfun.com/products/15574).
56 |
57 | 
58 |
59 | ## 3.3V Regulator
60 |
61 | 3.3V power for the tracker is regulated by an AP2112K regulator. Its 50uA quiescent current draw means it can be powered continuously without
62 | depleting the batteries during sleep.
63 |
64 | 
65 |
66 | If you want to completely disable the regulator to minimise the current draw, you can do so by opening the 3.3V_EN split pad. The EN pin can then be used to enable/disable the regulator.
67 | Pull EN low to disable the regulator, pull it up to VIN to enable it. EN could also be driven by a logic signal from an external timer circuit.
68 |
69 | 
70 |
71 | ## ZOE-M8Q
72 |
73 | GNSS data is provided by the u-blox ZOE-M8Q as used on the [SparkFun GPS Breakout - ZOE-M8Q](https://www.sparkfun.com/products/15193).
74 |
75 | Connection to the Artemis is via I2C port 1. The serial and safeboot pins are available on test pads to allow the ZOE firmware to be updated.
76 |
77 | Geofence alerts from the ZOE can be produced on PIO14, which is connected to Artemis pin D10.
78 |
79 | 
80 |
81 | Back-up power for the ZOE is drawn preferentially from the 3.3V rail, but there is a small back-up battery too to keep the ZOE's clock running
82 | when all other power sources have been disconnected. The battery recharges only when USB power is connected (to help minimise the 3.3V current
83 | draw during sleep).
84 |
85 | 
86 |
87 | 3.3V power for the ZOE is switched via a FET. The same switched power also feeds the antenna switch when the GNSS is in use.
88 |
89 | 
90 |
91 | ## Iridium 9603N
92 |
93 | The tracker uses the same Iridium 9603N transceiver as the [SparkFun Qwiic Iridium 9603N](https://www.sparkfun.com/products/16394).
94 |
95 | 
96 |
97 | Power for the 9603N is provided by the same LTC3225 supercapacitor charger and ADM4210 in-rush current limit circuit as used by the Qwiic Iridium.
98 |
99 | 
100 |
101 | The LTC3225 charge current is adjustable up to a maximum of 150mA. When set to the full 150mA, the LTC3225 can match the 145mA average current
102 | drawn by the 9603N during transmit. This means that 1 Farad supercapacitors are adequate as they only need to hold enough charge to meet the
103 | 9603N's 1.3A peak current draw during the very brief (8.3ms) transmit bursts.
104 |
105 | If you want to power the Global Tracker from a low current source, e.g. solar panels, the charge current can be reduced to 60mA by
106 | changing the **Charge Current** jumper link. The 60mA charge current is enough to offset the 9603N's 39mA average current draw during receive,
107 | but bigger supercapacitors are needed to deliver the average current draw during a complete receive/transmit cycle.
108 | So, if you do change the charge current to 60mA, you will also need to solder additional 10 Farad supercapacitors on to
109 | the rear of the PCB using the solder pads provided.
110 |
111 | ## Antenna Switch
112 |
113 | The ZOE and Iridium 9603N share the antenna via a [Skyworks AS179-92LF GaAs RF Switch](https://www.skyworksinc.com/products/switches/as179-92lf).
114 |
115 | Care needs to be taken that the 3.3V GNSS and 5.3V 9603N are not powered up simultaneously as _bad things might happen to the AS179_.
116 |
117 | 
118 |
119 | ## Pressure, Humidity and Temperature Sensor
120 |
121 | Pressure, humidity and temperature readings are provided by a [TE / MEAS Switzerland MS8607](https://www.te.com/usa-en/product-CAT-BLPS0018.html) combined sensor.
122 | The MS8607 shares I2C port 1 with the ZOE.
123 |
124 | The sensor will provide pressure readings as low as 10mbar which is equivalent to an altitude of approximately 31,000m.
125 |
126 | 
127 |
128 | ## I/O Pins
129 |
130 | The Artemis' SPI and I2C (port 1) pins are broken out on pin headers so the user can connect external peripherals.
131 |
132 | 
133 |
134 | I2C port 4 is broken out on a standard SparkFun Qwiic connector.
135 |
136 | 
137 |
138 | ## Bus Voltage
139 |
140 | The bus voltage (from the USB, LiPo or external cells) can be measured via the Artemis pin AD13. A simple two resistor divider divides the bus voltage by three.
141 | Power to the resistor divider is switched by an N-FET so the power draw can be minimised during sleep.
142 |
143 | 
144 |
--------------------------------------------------------------------------------
/Hardware/Production/Artemis_Global_Tracker-Panel.GBP:
--------------------------------------------------------------------------------
1 | G04 EAGLE Gerber RS-274X export*
2 | G75*
3 | %MOMM*%
4 | %FSLAX34Y34*%
5 | %LPD*%
6 | %INSolderpaste Bottom*%
7 | %IPPOS*%
8 | %AMOC8*
9 | 5,1,8,0,0,1.08239X$1,22.5*%
10 | G01*
11 |
12 |
13 | M02*
14 |
--------------------------------------------------------------------------------
/Hardware/Production/Artemis_Global_Tracker-Panel.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/Hardware/Production/Artemis_Global_Tracker-Panel.zip
--------------------------------------------------------------------------------
/Hardware/Production/Artemis_Global_Tracker.dru:
--------------------------------------------------------------------------------
1 | description[en] = SparkFun 2 Layer Design Rule Checks - STANDARD/TIGHT/FAB-LIMIT\n
\nThese rules have been curated by SparkFuns DFM commitee. After doing much research, communicating with our multiple fab houses, and getting quotes of various designs, we have compiled three DRU files. \n
\nSTANDARD: This is more of a "best case scenario" set of limitations. If your design has the space, and/or you have the time to work within these parameters, please do. Larger trace width and clearance makes for easier visual inspection of the PCB while troubleshooting (useful in production and to the end user). It also allows for better ability to hack a trace (if you are crazy enough to scrape away the mask and solder to a trace). Another thing to keep in mind is that more metal is just more robust. \n
\nTIGHT: This is where cost comes into play. We have found that most fab houses begin to add extra charges when you go smaller than these specs. In some cases, going to less than 15 mil trace can increase the cost by 10%. (This is why we have set the min drill on this DRU to 15 mil) Same story for traces thinner than 7 mil. To avoid those extra charges, then stay within the rules of this DRU.\n
\nFAB-LIMIT: These set of rules are at the very limit of most fab houses capabilities. You will pay more for these specs, and it should be used on designs that have a darned good reason to need 4 mil vias and 4 mil traces.\n
\n**NOTE Clearance, Distance, Sizes, and Restring are all set to different limits in each of these three DRU files. Please compare the files within the CAM job editor window of eagle to see all the numbers.\n
\n***NOTE, Please set your Net Classes to default (0mil for all settings), so that it won't effect the DRC when you run it with these settings.
2 | layerSetup = (1*16)
3 | mtCopper = 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm
4 | mtIsolate = 1.5mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm
5 | mdWireWire = 4mil
6 | mdWirePad = 4mil
7 | mdWireVia = 4mil
8 | mdPadPad = 4mil
9 | mdPadVia = 4mil
10 | mdViaVia = 4mil
11 | mdSmdPad = 4mil
12 | mdSmdVia = 4mil
13 | mdSmdSmd = 4mil
14 | mdViaViaSameLayer = 8mil
15 | mnLayersViaInSmd = 2
16 | mdCopperDimension = 4mil
17 | mdDrill = 4mil
18 | mdSmdStop = 0mil
19 | msWidth = 4mil
20 | msDrill = 6mil
21 | msMicroVia = 9.99mm
22 | msBlindViaRatio = 0.500000
23 | rvPadTop = 0.250000
24 | rvPadInner = 0.250000
25 | rvPadBottom = 0.250000
26 | rvViaOuter = 0.250000
27 | rvViaInner = 0.250000
28 | rvMicroViaOuter = 0.250000
29 | rvMicroViaInner = 0.250000
30 | rlMinPadTop = 5mil
31 | rlMaxPadTop = 20mil
32 | rlMinPadInner = 6mil
33 | rlMaxPadInner = 20mil
34 | rlMinPadBottom = 5mil
35 | rlMaxPadBottom = 20mil
36 | rlMinViaOuter = 5mil
37 | rlMaxViaOuter = 20mil
38 | rlMinViaInner = 6mil
39 | rlMaxViaInner = 20mil
40 | rlMinMicroViaOuter = 4mil
41 | rlMaxMicroViaOuter = 20mil
42 | rlMinMicroViaInner = 4mil
43 | rlMaxMicroViaInner = 20mil
44 | psTop = -1
45 | psBottom = -1
46 | psFirst = -1
47 | psElongationLong = 100
48 | psElongationOffset = 100
49 | mvStopFrame = 1.000000
50 | mvCreamFrame = 0.000000
51 | mlMinStopFrame = 4mil
52 | mlMaxStopFrame = 4mil
53 | mlMinCreamFrame = 0mil
54 | mlMaxCreamFrame = 0mil
55 | mlViaStopLimit = 25mil
56 | srRoundness = 0.000000
57 | srMinRoundness = 0mil
58 | srMaxRoundness = 0mil
59 | slThermalIsolate = 10mil
60 | slThermalsForVias = 0
61 | dpMaxLengthDifference = 10mm
62 | dpGapFactor = 2.500000
63 | checkAngle = 1
64 | checkFont = 1
65 | checkRestrict = 1
66 | checkStop = 0
67 | checkValues = 0
68 | checkNames = 1
69 | checkWireStubs = 1
70 | checkPolygonWidth = 0
71 | useDiameter = 13
72 | maxErrors = 50
73 |
--------------------------------------------------------------------------------
/Hardware/Schematic.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/Hardware/Schematic.pdf
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | SparkFun License Information
2 | ============================
3 |
4 | SparkFun uses two different licenses for our files — one for hardware and one for code.
5 |
6 | Hardware
7 | ---------
8 |
9 | **SparkFun hardware is released under [Creative Commons Share-alike 4.0 International](http://creativecommons.org/licenses/by-sa/4.0/).**
10 |
11 | Note: This is a human-readable summary of (and not a substitute for) the [license](http://creativecommons.org/licenses/by-sa/4.0/legalcode).
12 |
13 | You are free to:
14 |
15 | Share — copy and redistribute the material in any medium or format
16 | Adapt — remix, transform, and build upon the material
17 | for any purpose, even commercially.
18 | The licensor cannot revoke these freedoms as long as you follow the license terms.
19 | Under the following terms:
20 |
21 | Attribution — You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use.
22 | ShareAlike — If you remix, transform, or build upon the material, you must distribute your contributions under the same license as the original.
23 | No additional restrictions — You may not apply legal terms or technological measures that legally restrict others from doing anything the license permits.
24 | Notices:
25 |
26 | You do not have to comply with the license for elements of the material in the public domain or where your use is permitted by an applicable exception or limitation.
27 | No warranties are given. The license may not give you all of the permissions necessary for your intended use. For example, other rights such as publicity, privacy, or moral rights may limit how you use the material.
28 |
29 |
30 | Code
31 | --------
32 |
33 | **SparkFun code, firmware, and software is released under the MIT License(http://opensource.org/licenses/MIT).**
34 |
35 | The MIT License (MIT)
36 |
37 | Copyright (c) 2020 SparkFun Electronics
38 |
39 | Permission is hereby granted, free of charge, to any person obtaining a copy
40 | of this software and associated documentation files (the "Software"), to deal
41 | in the Software without restriction, including without limitation the rights
42 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
43 | copies of the Software, and to permit persons to whom the Software is
44 | furnished to do so, subject to the following conditions:
45 |
46 | The above copyright notice and this permission notice shall be included in all
47 | copies or substantial portions of the Software.
48 |
49 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
50 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
51 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
52 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
53 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
54 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
55 | SOFTWARE.
56 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Artemis Global Tracker
2 |
3 | An open source global satellite tracker utilising the [SparkFun Artemis module](https://www.sparkfun.com/products/15484),
4 | [Iridium 9603N satellite transceiver](https://www.iridium.com/products/iridium-9603/) and [u-blox ZOE-M8Q GNSS](https://www.u-blox.com/en/product/zoe-m8-series).
5 |
6 | [](https://www.sparkfun.com/products/16469)
7 |
8 | [*SparkX Artemis Global Tracker (SPX-16469)*](https://www.sparkfun.com/products/16469)
9 |
10 | [](https://www.sparkfun.com/products/16469)
11 |
12 | [*SparkX Artemis Global Tracker (SPX-16469)*](https://www.sparkfun.com/products/16469)
13 |
14 | ## Retired Product
15 |
16 | The SparkX Artemis Global Tracker (SPX-16469) has been replaced by the [SparkFun Artemis Global Tracker (WRL-18712)](https://www.sparkfun.com/products/18712).
17 |
18 | ## Repository Contents
19 |
20 | - **/Documentation** - Documentation for the hardware and the full GlobalTracker example
21 | - **/Hardware** - Eagle PCB, SCH and LBR design files
22 | - **/Software** - Arduino examples
23 | - **/Tools** - Tools to help: configure the full GlobalTracker example via USB or remotely via Iridium messaging; and track and map its position
24 | - **/binaries** - binary files for the examples which you can upload using the [Artemis Firmware Upload GUI](https://github.com/sparkfun/Artemis-Firmware-Upload-GUI) instead of the Arduino IDE
25 | - **LICENSE.md** contains the licence information
26 |
27 | ## Documentation
28 |
29 | - [Hardware overview](Documentation/Hardware_Overview/README.md): an overview of the hardware
30 | - The Artemis pin allocation is summarised [here](Documentation/Hardware_Overview/ARTEMIS_PINS.md)
31 | - [Message Format](Documentation/Message_Format/README.md): a definition of the message format and fields (both binary and text) for the full GlobalTracker example
32 | - [GlobalTracker FAQs](Documentation/GlobalTracker_FAQs/README.md): information to help you operate and configure the AGT
33 |
34 | ## License Information
35 |
36 | This product is _**open source**_!
37 |
38 | Please review the LICENSE.md file for license information.
39 |
40 | If you have any questions or concerns on licensing, please contact technical support on our [SparkFun forums](https://forum.sparkfun.com/viewforum.php?f=123).
41 |
42 | Distributed as-is; no warranty is given.
43 |
44 | - Your friends at SparkFun.
45 |
--------------------------------------------------------------------------------
/Software/README.md:
--------------------------------------------------------------------------------
1 | # Artemis Global Tracker: Software
2 |
3 | ## Repository Contents
4 | - **/examples** - examples showing how to use all of the features of the Tracker
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Software/examples/Example10_BasicSend/Example10_BasicSend.ino:
--------------------------------------------------------------------------------
1 | /*
2 | Artemis Global Tracker
3 | Example: Basic Send
4 |
5 | Written by Paul Clark (PaulZC)
6 | September 7th 2021
7 |
8 | ** Updated for v2.1.0 of the Apollo3 core / Artemis board package **
9 | ** (At the time of writing, v2.1.1 of the core conatins a feature which makes communication with the u-blox GNSS problematic. Be sure to use v2.1.0) **
10 |
11 | ** Set the Board to "RedBoard Artemis ATP" **
12 | ** (The Artemis Module does not have a Wire port defined, which prevents the IridiumSBD library from compiling) **
13 |
14 | This example powers up the Iridium 9603N and
15 | sends a "Hello, world!" message from the satellite modem.
16 | If you have activated your account and have credits, this message
17 | should arrive at the endpoints (delivery group) you have configured
18 | (email address or HTTP POST).
19 |
20 | You will need to install version 3.0.5 of the Iridium SBD I2C library
21 | before this example will run successfully:
22 | https://github.com/sparkfun/SparkFun_IridiumSBD_I2C_Arduino_Library
23 | (Available through the Arduino Library Manager: search for IridiumSBDi2c)
24 |
25 | Power for the 9603N is provided by the LTC3225 super capacitor charger.
26 | D27 needs to be pulled high to enable the charger.
27 | The LTC3225 PGOOD signal is connected to D28.
28 |
29 | Power for the 9603N is switched by the ADM4210 inrush current limiter.
30 | D22 needs to be pulled high to enable power for the 9603N.
31 |
32 | The 9603N itself is enabled via its ON/OFF (SLEEP) pin which is connected
33 | to D17. Pull high - via the IridiumSBD library - to enable the 9603N.
34 |
35 | The 9603N's Network Available signal is conected to D18,
36 | so let's configure D18 as an input.
37 |
38 | The 9603N's Ring Indicator is conected to D41,
39 | so let's configure D41 as an input.
40 |
41 | To prevent bad tings happening to the AS179 RF antenna switch,
42 | D26 needs to be pulled high to disable the GNSS power.
43 |
44 | */
45 |
46 | // Artemis Tracker pin definitions
47 | #define spiCS1 4 // D4 can be used as an SPI chip select or as a general purpose IO pin
48 | #define geofencePin 10 // Input for the ZOE-M8Q's PIO14 (geofence) pin
49 | #define busVoltagePin 13 // Bus voltage divided by 3 (Analog in)
50 | #define iridiumSleep 17 // Iridium 9603N ON/OFF (sleep) pin: pull high to enable the 9603N
51 | #define iridiumNA 18 // Input for the Iridium 9603N Network Available
52 | #define LED 19 // White LED
53 | #define iridiumPwrEN 22 // ADM4210 ON: pull high to enable power for the Iridium 9603N
54 | #define gnssEN 26 // GNSS Enable: pull low to enable power for the GNSS (via Q2)
55 | #define superCapChgEN 27 // LTC3225 super capacitor charger: pull high to enable the super capacitor charger
56 | #define superCapPGOOD 28 // Input for the LTC3225 super capacitor charger PGOOD signal
57 | #define busVoltageMonEN 34 // Bus voltage monitor enable: pull high to enable bus voltage monitoring (via Q4 and Q3)
58 | #define spiCS2 35 // D35 can be used as an SPI chip select or as a general purpose IO pin
59 | #define iridiumRI 41 // Input for the Iridium 9603N Ring Indicator
60 | // Make sure you do not have gnssEN and iridiumPwrEN enabled at the same time!
61 | // If you do, bad things might happen to the AS179 RF switch!
62 |
63 | // We use Serial1 to communicate with the Iridium modem. Serial1 on the ATP uses pin 24 for TX and 25 for RX. AGT uses the same pins.
64 |
65 | #include //http://librarymanager/All#IridiumSBDI2C
66 | #define DIAGNOSTICS false // Change this to true to see IridiumSBD diagnostics
67 | // Declare the IridiumSBD object (including the sleep (ON/OFF) and Ring Indicator pins)
68 | IridiumSBD modem(Serial1, iridiumSleep, iridiumRI);
69 |
70 | void gnssON(void) // Enable power for the GNSS
71 | {
72 | am_hal_gpio_pincfg_t pinCfg = g_AM_HAL_GPIO_OUTPUT; // Begin by making the gnssEN pin an open-drain output
73 | pinCfg.eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_OPENDRAIN;
74 | pin_config(PinName(gnssEN), pinCfg);
75 | delay(1);
76 |
77 | digitalWrite(gnssEN, LOW); // Enable GNSS power (HIGH = disable; LOW = enable)
78 | }
79 |
80 | void gnssOFF(void) // Disable power for the GNSS
81 | {
82 | am_hal_gpio_pincfg_t pinCfg = g_AM_HAL_GPIO_OUTPUT; // Begin by making the gnssEN pin an open-drain output
83 | pinCfg.eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_OPENDRAIN;
84 | pin_config(PinName(gnssEN), pinCfg);
85 | delay(1);
86 |
87 | digitalWrite(gnssEN, HIGH); // Disable GNSS power (HIGH = disable; LOW = enable)
88 | }
89 |
90 | // Overwrite the IridiumSBD beginSerialPort function - a fix for https://github.com/sparkfun/Arduino_Apollo3/issues/423
91 | void IridiumSBD::beginSerialPort() // Start the serial port connected to the satellite modem
92 | {
93 | diagprint(F("custom IridiumSBD::beginSerialPort\r\n"));
94 |
95 | // Configure the standard ATP pins for UART1 TX and RX - endSerialPort may have disabled the RX pin
96 |
97 | am_hal_gpio_pincfg_t pinConfigTx = g_AM_BSP_GPIO_COM_UART_TX;
98 | pinConfigTx.uFuncSel = AM_HAL_PIN_24_UART1TX;
99 | pin_config(D24, pinConfigTx);
100 |
101 | am_hal_gpio_pincfg_t pinConfigRx = g_AM_BSP_GPIO_COM_UART_RX;
102 | pinConfigRx.uFuncSel = AM_HAL_PIN_25_UART1RX;
103 | pinConfigRx.ePullup = AM_HAL_GPIO_PIN_PULLUP_WEAK; // Put a weak pull-up on the Rx pin
104 | pin_config(D25, pinConfigRx);
105 |
106 | Serial1.begin(19200);
107 | }
108 |
109 | // Overwrite the IridiumSBD endSerialPort function - a fix for https://github.com/sparkfun/Arduino_Apollo3/issues/423
110 | void IridiumSBD::endSerialPort()
111 | {
112 | diagprint(F("custom IridiumSBD::endSerialPort\r\n"));
113 |
114 | // Disable the Serial1 RX pin to avoid the code hang
115 | am_hal_gpio_pinconfig(PinName(D25), g_AM_HAL_GPIO_DISABLE);
116 | }
117 |
118 | void setup()
119 | {
120 | int signalQuality = -1;
121 | int err;
122 |
123 | pinMode(LED, OUTPUT); // Make the LED pin an output
124 |
125 | gnssOFF(); // Disable power for the GNSS
126 | pinMode(geofencePin, INPUT); // Configure the geofence pin as an input
127 |
128 | pinMode(iridiumPwrEN, OUTPUT); // Configure the Iridium Power Pin (connected to the ADM4210 ON pin)
129 | digitalWrite(iridiumPwrEN, LOW); // Disable Iridium Power (HIGH = enable; LOW = disable)
130 | pinMode(superCapChgEN, OUTPUT); // Configure the super capacitor charger enable pin (connected to LTC3225 !SHDN)
131 | digitalWrite(superCapChgEN, LOW); // Disable the super capacitor charger (HIGH = enable; LOW = disable)
132 | pinMode(iridiumSleep, OUTPUT); // Iridium 9603N On/Off (Sleep) pin
133 | digitalWrite(iridiumSleep, LOW); // Put the Iridium 9603N to sleep (HIGH = on; LOW = off/sleep)
134 | pinMode(iridiumRI, INPUT); // Configure the Iridium Ring Indicator as an input
135 | pinMode(iridiumNA, INPUT); // Configure the Iridium Network Available as an input
136 | pinMode(superCapPGOOD, INPUT); // Configure the super capacitor charger PGOOD input
137 |
138 | // Make sure the Serial1 RX pin is disabled to prevent the power-on glitch on the modem's RX(OUT) pin
139 | // causing problems with v2.1.0 of the Apollo3 core. Requires v3.0.5 of IridiumSBDi2c.
140 | modem.endSerialPort();
141 |
142 | // Start the console serial port
143 | Serial.begin(115200);
144 | while (!Serial) // Wait for the user to open the serial monitor
145 | ;
146 | delay(100);
147 | Serial.println();
148 | Serial.println();
149 | Serial.println(F("Artemis Global Tracker"));
150 | Serial.println(F("Example: Basic Send"));
151 | Serial.println();
152 |
153 | //empty the serial buffer
154 | while(Serial.available() > 0)
155 | Serial.read();
156 |
157 | //wait for the user to press any key before beginning
158 | Serial.println(F("Please check that the Serial Monitor is set to 115200 Baud"));
159 | Serial.println(F("and that the line ending is set to Newline."));
160 | Serial.println(F("Then click Send to start the example."));
161 | Serial.println();
162 | while(Serial.available() == 0)
163 | ;
164 |
165 | // Enable the supercapacitor charger
166 | Serial.println(F("Enabling the supercapacitor charger..."));
167 | digitalWrite(superCapChgEN, HIGH); // Enable the super capacitor charger
168 | delay(1000);
169 |
170 | // Wait for the supercapacitor charger PGOOD signal to go high
171 | while (digitalRead(superCapPGOOD) == false)
172 | {
173 | Serial.println(F("Waiting for supercapacitors to charge..."));
174 | delay(1000);
175 | }
176 | Serial.println(F("Supercapacitors charged!"));
177 |
178 | // Enable power for the 9603N
179 | Serial.println(F("Enabling 9603N power..."));
180 | digitalWrite(iridiumPwrEN, HIGH); // Enable Iridium Power
181 | delay(1000);
182 |
183 | // If we're powering the device by USB, tell the library to
184 | // relax timing constraints waiting for the supercap to recharge.
185 | modem.setPowerProfile(IridiumSBD::USB_POWER_PROFILE);
186 |
187 | // Begin satellite modem operation
188 | // Also begin the serial port connected to the satellite modem via IridiumSBD::beginSerialPort
189 | Serial.println(F("Starting modem..."));
190 | err = modem.begin();
191 | if (err != ISBD_SUCCESS)
192 | {
193 | Serial.print(F("Begin failed: error "));
194 | Serial.println(err);
195 | if (err == ISBD_NO_MODEM_DETECTED)
196 | Serial.println(F("No modem detected: check wiring."));
197 | return;
198 | }
199 |
200 | // Test the signal quality.
201 | // This returns a number between 0 and 5.
202 | // 2 or better is preferred.
203 | err = modem.getSignalQuality(signalQuality);
204 | if (err != ISBD_SUCCESS)
205 | {
206 | Serial.print(F("SignalQuality failed: error "));
207 | Serial.println(err);
208 | return;
209 | }
210 |
211 | Serial.print(F("On a scale of 0 to 5, signal quality is currently "));
212 | Serial.print(signalQuality);
213 | Serial.println(F("."));
214 |
215 | // Send the message
216 | Serial.println(F("Trying to send the message. This might take several minutes."));
217 | err = modem.sendSBDText("Hello, world!");
218 | if (err != ISBD_SUCCESS)
219 | {
220 | Serial.print(F("sendSBDText failed: error "));
221 | Serial.println(err);
222 | if (err == ISBD_SENDRECEIVE_TIMEOUT)
223 | Serial.println(F("Try again with a better view of the sky."));
224 | }
225 | else
226 | {
227 | Serial.println(F("Hey, it worked!"));
228 | }
229 |
230 | // Clear the Mobile Originated message buffer
231 | Serial.println(F("Clearing the MO buffer."));
232 | err = modem.clearBuffers(ISBD_CLEAR_MO); // Clear MO buffer
233 | if (err != ISBD_SUCCESS)
234 | {
235 | Serial.print(F("clearBuffers failed: error "));
236 | Serial.println(err);
237 | }
238 |
239 | // Power down the modem
240 | // Also disable the Serial1 RX pin via IridiumSBD::endSerialPort
241 | Serial.println(F("Putting the 9603N to sleep."));
242 | err = modem.sleep();
243 | if (err != ISBD_SUCCESS)
244 | {
245 | Serial.print(F("sleep failed: error "));
246 | Serial.println(err);
247 | }
248 |
249 | // Disable 9603N power
250 | Serial.println(F("Disabling 9603N power..."));
251 | digitalWrite(iridiumPwrEN, LOW); // Disable Iridium Power
252 |
253 | // Disable the supercapacitor charger
254 | Serial.println(F("Disabling the supercapacitor charger..."));
255 | digitalWrite(superCapChgEN, LOW); // Disable the super capacitor charger
256 |
257 | Serial.println(F("Done!"));
258 | }
259 |
260 | void loop()
261 | {
262 | }
263 |
264 | #if DIAGNOSTICS
265 | void ISBDConsoleCallback(IridiumSBD *device, char c)
266 | {
267 | Serial.write(c);
268 | }
269 |
270 | void ISBDDiagsCallback(IridiumSBD *device, char c)
271 | {
272 | Serial.write(c);
273 | }
274 | #endif
275 |
--------------------------------------------------------------------------------
/Software/examples/Example13_GeofenceAlert/Example13_GeofenceAlert.ino:
--------------------------------------------------------------------------------
1 | /*
2 | Artemis Global Tracker
3 | Example: Geofence Alert
4 |
5 | Written by Paul Clark (PaulZC)
6 | August 7th 2021
7 |
8 | ** Updated for v2.1.0 of the Apollo3 core / Artemis board package **
9 | ** (At the time of writing, v2.1.1 of the core conatins a feature which makes communication with the u-blox GNSS problematic. Be sure to use v2.1.0) **
10 |
11 | ** Set the Board to "RedBoard Artemis ATP" **
12 | ** (The Artemis Module does not have a Wire port defined, which prevents the GNSS library from compiling) **
13 |
14 | This example powers up the ZOE-M8Q and reads the fix.
15 | Once a valid 3D fix has been found, the code reads the latitude and longitude.
16 | The code then sets a geofence around that position with a radius of 100m with 95% confidence.
17 | The Artemis then goes into deep sleep to save current but will be woken up whenever the geofence
18 | pin changes state. The LED is illuminated when the tracker is inside the geofence.
19 |
20 | Once the geofence has been set, you can test the code by disconnecting the antenna.
21 | After a few seconds the geofence status will go to "unknown" and the LED will go out.
22 |
23 | This example also engages the ZOE's Power Save Mode.
24 | ** When it is able to ** the ZOE will approximately halve its current draw.
25 |
26 | You will need to install the SparkFun u-blox library before this example
27 | will run successfully:
28 | https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library
29 |
30 | The ZOE-M8Q shares I2C Port 1 with the MS8607: SCL = D8; SDA = D9
31 |
32 | Power for the ZOE is switched via Q2.
33 | D26 needs to be pulled low to enable the GNSS power.
34 |
35 | The ZOE's PIO14 pin (geofence signal) is conected to D10,
36 | so let's configure D10 as an input.
37 |
38 | To prevent bad tings happening to the AS179 RF antenna switch,
39 | D27 and D22 should also be pulled low to disable the 5.3V rail.
40 |
41 | */
42 |
43 | // Artemis Tracker pin definitions
44 | #define spiCS1 4 // D4 can be used as an SPI chip select or as a general purpose IO pin
45 | #define geofencePin 10 // Input for the ZOE-M8Q's PIO14 (geofence) pin
46 | #define busVoltagePin 13 // Bus voltage divided by 3 (Analog in)
47 | #define iridiumSleep 17 // Iridium 9603N ON/OFF (sleep) pin: pull high to enable the 9603N
48 | #define iridiumNA 18 // Input for the Iridium 9603N Network Available
49 | #define LED 19 // White LED
50 | #define iridiumPwrEN 22 // ADM4210 ON: pull high to enable power for the Iridium 9603N
51 | #define gnssEN 26 // GNSS Enable: pull low to enable power for the GNSS (via Q2)
52 | #define superCapChgEN 27 // LTC3225 super capacitor charger: pull high to enable the super capacitor charger
53 | #define superCapPGOOD 28 // Input for the LTC3225 super capacitor charger PGOOD signal
54 | #define busVoltageMonEN 34 // Bus voltage monitor enable: pull high to enable bus voltage monitoring (via Q4 and Q3)
55 | #define spiCS2 35 // D35 can be used as an SPI chip select or as a general purpose IO pin
56 | #define iridiumRI 41 // Input for the Iridium 9603N Ring Indicator
57 | // Make sure you do not have gnssEN and iridiumPwrEN enabled at the same time!
58 | // If you do, bad things might happen to the AS179 RF switch!
59 |
60 | #include // Needed for I2C
61 | const byte PIN_AGTWIRE_SCL = 8;
62 | const byte PIN_AGTWIRE_SDA = 9;
63 | TwoWire agtWire(PIN_AGTWIRE_SDA, PIN_AGTWIRE_SCL); //Create an I2C port using pads 8 (SCL) and 9 (SDA)
64 |
65 | #include "SparkFun_u-blox_GNSS_Arduino_Library.h" //http://librarymanager/All#SparkFun_u-blox_GNSS
66 | SFE_UBLOX_GNSS myGNSS;
67 |
68 | // geofencePin Interrupt Service Routine
69 | // (Always keep ISRs as short as possible, don't do anything clever in them,
70 | // and always use volatile variables if the main loop needs to access them too.)
71 | void geofenceISR(void)
72 | {
73 | digitalWrite(LED, !digitalRead(geofencePin)); // Update the LED
74 | }
75 |
76 | void gnssON(void) // Enable power for the GNSS
77 | {
78 | am_hal_gpio_pincfg_t pinCfg = g_AM_HAL_GPIO_OUTPUT; // Begin by making the gnssEN pin an open-drain output
79 | pinCfg.eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_OPENDRAIN;
80 | pin_config(PinName(gnssEN), pinCfg);
81 | delay(1);
82 |
83 | digitalWrite(gnssEN, LOW); // Enable GNSS power (HIGH = disable; LOW = enable)
84 | }
85 |
86 | void gnssOFF(void) // Disable power for the GNSS
87 | {
88 | am_hal_gpio_pincfg_t pinCfg = g_AM_HAL_GPIO_OUTPUT; // Begin by making the gnssEN pin an open-drain output
89 | pinCfg.eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_OPENDRAIN;
90 | pin_config(PinName(gnssEN), pinCfg);
91 | delay(1);
92 |
93 | digitalWrite(gnssEN, HIGH); // Disable GNSS power (HIGH = disable; LOW = enable)
94 | }
95 |
96 | void setup()
97 | {
98 | pinMode(LED, OUTPUT);
99 |
100 | pinMode(iridiumPwrEN, OUTPUT); // Configure the Iridium Power Pin (connected to the ADM4210 ON pin)
101 | digitalWrite(iridiumPwrEN, LOW); // Disable Iridium Power
102 | pinMode(superCapChgEN, OUTPUT); // Configure the super capacitor charger enable pin (connected to LTC3225 !SHDN)
103 | digitalWrite(superCapChgEN, LOW); // Disable the super capacitor charger
104 |
105 | gnssOFF(); // Disable power for the GNSS
106 | pinMode(geofencePin, INPUT); // Configure the geofence pin as an input
107 |
108 | // Call geofenceISR whenever geofencePin changes state
109 | // Note that in v2.1.0 of the core, this causes an immediate interrupt
110 | attachInterrupt(geofencePin, geofenceISR, CHANGE);
111 |
112 | // Set up the I2C pins
113 | agtWire.begin();
114 | agtWire.setClock(100000); // Use 100kHz for best performance
115 | setAGTWirePullups(0); // Remove the pull-ups from the I2C pins (internal to the Artemis) for best performance
116 |
117 | // Start the console serial port
118 | Serial.begin(115200);
119 | delay(1000); // Wait for the user to open the serial monitor (extend this delay if you need more time)
120 | Serial.println();
121 | Serial.println();
122 | Serial.println(F("Artemis Global Tracker"));
123 | Serial.println(F("Example: Geofence Alert"));
124 | Serial.println();
125 |
126 | gnssON(); // Enable power for the GNSS
127 | delay(1000); // Let the ZOE power up
128 |
129 | if (myGNSS.begin(agtWire) == false) //Connect to the u-blox module using agtWire
130 | {
131 | Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
132 | while (1);
133 | }
134 |
135 | //myGNSS.enableDebugging(); // Enable debug messages
136 | myGNSS.setI2COutput(COM_TYPE_UBX); // Limit I2C output to UBX (disable the NMEA noise)
137 |
138 | Serial.println(F("Waiting for a 3D fix..."));
139 |
140 | byte fixType = 0;
141 |
142 | while (fixType != 3) // Wait for a 3D fix
143 | {
144 | fixType = myGNSS.getFixType(); // Get the fix type
145 | Serial.print(F("Fix: "));
146 | Serial.print(fixType);
147 | if(fixType == 0) Serial.print(F(" = No fix"));
148 | else if(fixType == 1) Serial.print(F(" = Dead reckoning"));
149 | else if(fixType == 2) Serial.print(F(" = 2D"));
150 | else if(fixType == 3) Serial.print(F(" = 3D"));
151 | else if(fixType == 4) Serial.print(F(" = GNSS + Dead reckoning"));
152 | Serial.println();
153 | delay(1000);
154 | }
155 |
156 | Serial.println(F("3D fix found! Setting the geofence..."));
157 |
158 | long latitude = myGNSS.getLatitude(); // Get the latitude in degrees * 10^-7
159 | Serial.print(F("Lat: "));
160 | Serial.print(latitude);
161 |
162 | long longitude = myGNSS.getLongitude(); // Get the longitude in degrees * 10^-7
163 | Serial.print(F(" Long: "));
164 | Serial.println(longitude);
165 |
166 | uint32_t radius = 10000; // Set the radius to 100m (radius is in m * 10^-2 i.e. cm)
167 | byte confidence = 2; // Set the confidence level: 0=none, 1=68%, 2=95%, 3=99.7%, 4=99.99%
168 | byte pinPolarity = 0; // Set the PIO pin polarity: 0 = low means inside, 1 = low means outside (or unknown)
169 | byte pin = 14; // ZOE-M8Q PIO14 is connected to the geofencePin
170 |
171 | //myGNSS.clearGeofences();// Clear all existing geofences.
172 |
173 | // It is possible to define up to four geofences.
174 | // Call addGeofence up to four times to define them.
175 | // The geofencePin will indicate the combined state of all active geofences.
176 | myGNSS.addGeofence(latitude, longitude, radius, confidence, pinPolarity, pin); // Add the geofence
177 |
178 | delay(1000); // Let the geofence do its thing
179 |
180 | Serial.println(F("The LED will be lit while the tracker is inside the geofence."));
181 |
182 | digitalWrite(LED, !digitalRead(geofencePin)); // Update the LED.
183 |
184 | // Put the ZOE-M8Q into power save mode
185 | if (myGNSS.powerSaveMode() == true)
186 | {
187 | Serial.println(F("GNSS Power Save Mode enabled."));
188 | }
189 | else
190 | {
191 | Serial.println(F("***!!! GNSS Power Save Mode may have FAILED !!!***"));
192 | }
193 |
194 | Serial.println(F("Going into deep sleep..."));
195 | Serial.println();
196 |
197 | Serial.flush(); // Wait for serial data to be sent so the Serial.end doesn't cause problems
198 |
199 | // Code taken (mostly) from Apollo3 Example6_Low_Power_Alarm
200 |
201 | // Disable UART
202 | Serial.end();
203 |
204 | // Disable ADC
205 | powerControlADC(false);
206 |
207 | // Force the peripherals off
208 | am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM0);
209 | am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM1);
210 | am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM2);
211 | am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM3);
212 | am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM4);
213 | am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM5);
214 | am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_ADC);
215 | am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_UART0);
216 | am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_UART1);
217 |
218 | // Disable all unused pins - including UART0 TX (48) and RX (49)
219 | const int pinsToDisable[] = {0,1,2,11,12,14,15,16,20,21,29,31,32,36,37,38,42,43,44,45,48,49,-1};
220 | for (int x = 0; pinsToDisable[x] >= 0; x++)
221 | {
222 | am_hal_gpio_pinconfig(pinsToDisable[x], g_AM_HAL_GPIO_DISABLE);
223 | }
224 |
225 | //Power down CACHE, flashand SRAM
226 | am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_ALL); // Power down all flash and cache
227 | am_hal_pwrctrl_memory_deepsleep_retain(AM_HAL_PWRCTRL_MEM_SRAM_384K); // Retain all SRAM (0.6 uA)
228 |
229 | // Keep the 32kHz clock running for RTC
230 | am_hal_stimer_config(AM_HAL_STIMER_CFG_CLEAR | AM_HAL_STIMER_CFG_FREEZE);
231 | am_hal_stimer_config(AM_HAL_STIMER_XTAL_32KHZ);
232 | }
233 |
234 | void loop()
235 | {
236 | // Go to Deep Sleep.
237 | am_hal_sysctrl_sleep(AM_HAL_SYSCTRL_SLEEP_DEEP);
238 | }
239 |
240 | void setAGTWirePullups(uint32_t i2cBusPullUps)
241 | {
242 | //Change SCL and SDA pull-ups manually using pin_config
243 | am_hal_gpio_pincfg_t sclPinCfg = g_AM_BSP_GPIO_IOM1_SCL;
244 | am_hal_gpio_pincfg_t sdaPinCfg = g_AM_BSP_GPIO_IOM1_SDA;
245 |
246 | if (i2cBusPullUps == 0)
247 | {
248 | sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_NONE; // No pull-ups
249 | sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_NONE;
250 | }
251 | else if (i2cBusPullUps == 1)
252 | {
253 | sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_1_5K; // Use 1K5 pull-ups
254 | sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_1_5K;
255 | }
256 | else if (i2cBusPullUps == 6)
257 | {
258 | sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_6K; // Use 6K pull-ups
259 | sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_6K;
260 | }
261 | else if (i2cBusPullUps == 12)
262 | {
263 | sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_12K; // Use 12K pull-ups
264 | sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_12K;
265 | }
266 | else
267 | {
268 | sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_24K; // Use 24K pull-ups
269 | sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_24K;
270 | }
271 |
272 | pin_config(PinName(PIN_AGTWIRE_SCL), sclPinCfg);
273 | pin_config(PinName(PIN_AGTWIRE_SDA), sdaPinCfg);
274 | }
275 |
--------------------------------------------------------------------------------
/Software/examples/Example15_BetterTracker/Tracker_EEPROM_Functions.ino:
--------------------------------------------------------------------------------
1 | // Artemis Global Tracker: BetterTracker EEPROM storage
2 |
3 | // These functions provide a robust way of storing the SOURCE, DEST and TXINT variables in non-volatile "EEPROM" (Flash)
4 |
5 | #include "Tracker_EEPROM_Storage.h"
6 |
7 | byte calculateEEPROMchecksumA() // Calculate the RFC 1145 Checksum A for the EEPROM data
8 | {
9 | uint32_t csuma = 0;
10 | for (uint16_t x = LOC_STX; x < (LOC_ETX + LEN_ETX); x += 1) // Calculate a sum of every byte from STX to ETX
11 | {
12 | csuma = csuma + EEPROM.read(x);
13 | }
14 | return ((byte)(csuma & 0x000000ff));
15 | }
16 |
17 | byte calculateEEPROMchecksumB() // Calculate the RFC 1145 Checksum B for the EEPROM data
18 | {
19 | uint32_t csuma = 0;
20 | uint32_t csumb = 0;
21 | for (uint16_t x = LOC_STX; x < (LOC_ETX + LEN_ETX); x += 1) // Calculate a sum of sums for every byte from STX to ETX
22 | {
23 | csuma = csuma + EEPROM.read(x);
24 | csumb = csumb + csuma;
25 | }
26 | return ((byte)(csumb & 0x000000ff));
27 | }
28 |
29 | bool checkEEPROM(trackerSettings *myTrackerSettings)
30 | // Checks if EEPROM data is valid (i.e. has been initialised) by checking that the STX, ETX and the two checksum bytes are valid
31 | {
32 | byte stx;
33 | byte etx;
34 | EEPROM.get(LOC_STX, stx);
35 | EEPROM.get(LOC_ETX, etx);
36 | byte eeprom_csuma;
37 | byte eeprom_csumb;
38 | EEPROM.get(LOC_CSUMA, eeprom_csuma);
39 | EEPROM.get(LOC_CSUMB, eeprom_csumb);
40 | byte csuma = calculateEEPROMchecksumA();
41 | byte csumb = calculateEEPROMchecksumB();
42 | bool result = true;
43 | result = result && ((stx == myTrackerSettings->STX) && (etx == myTrackerSettings->ETX)); // Check that EEPROM STX and ETX match the values in RAM
44 | result = result && ((csuma == eeprom_csuma) && (csumb == eeprom_csumb)); // Check that the EEPROM checksums are valid
45 | result = result && ((stx == DEF_STX) && (etx == DEF_ETX)); // Check that EEPROM STX and ETX are actually STX and ETX (not zero!)
46 | return (result);
47 | }
48 |
49 | void updateEEPROMchecksum() // Update the two EEPROM checksum bytes
50 | {
51 | byte csuma = calculateEEPROMchecksumA();
52 | byte csumb = calculateEEPROMchecksumB();
53 | EEPROM.write(LOC_CSUMA, csuma);
54 | EEPROM.write(LOC_CSUMB, csumb);
55 | }
56 |
57 | void initTrackerSettings(trackerSettings *myTrackerSettings) // Initialises the trackerSettings in RAM with the default values
58 | {
59 | myTrackerSettings->STX = DEF_STX;
60 | myTrackerSettings->SOURCE = DEF_SOURCE;
61 | myTrackerSettings->DEST = DEF_DEST;
62 | myTrackerSettings->TXINT = (volatile uint16_t)DEF_TXINT;
63 | myTrackerSettings->ETX = DEF_ETX;
64 | }
65 |
66 | void putTrackerSettings(trackerSettings *myTrackerSettings) // Write the trackerSettings from RAM into EEPROM
67 | {
68 | EEPROM.erase(); // Erase any old data first
69 | EEPROM.put(LOC_STX, myTrackerSettings->STX);
70 | EEPROM.put(LOC_SOURCE, myTrackerSettings->SOURCE);
71 | EEPROM.put(LOC_DEST, myTrackerSettings->DEST);
72 | EEPROM.put(LOC_TXINT, (uint16_t)myTrackerSettings->TXINT);
73 | EEPROM.put(LOC_ETX, myTrackerSettings->ETX);
74 | updateEEPROMchecksum();
75 | }
76 |
77 | void updateTrackerSettings(trackerSettings *myTrackerSettings) // Update any changed trackerSettings in EEPROM
78 | {
79 | EEPROM.update(LOC_STX, myTrackerSettings->STX);
80 | EEPROM.update(LOC_SOURCE, myTrackerSettings->SOURCE);
81 | EEPROM.update(LOC_DEST, myTrackerSettings->DEST);
82 | EEPROM.update(LOC_TXINT, (uint16_t)myTrackerSettings->TXINT);
83 | EEPROM.update(LOC_ETX, myTrackerSettings->ETX);
84 | updateEEPROMchecksum();
85 | }
86 |
87 | void getTrackerSettings(trackerSettings *myTrackerSettings) // Read the trackerSettings from EEPROM into RAM
88 | {
89 | EEPROM.get(LOC_STX, myTrackerSettings->STX);
90 | EEPROM.get(LOC_SOURCE, myTrackerSettings->SOURCE);
91 | EEPROM.get(LOC_DEST, myTrackerSettings->DEST);
92 |
93 | uint16_t tempUint16;
94 | EEPROM.get(LOC_TXINT, tempUint16);
95 | myTrackerSettings->TXINT = (volatile uint16_t)tempUint16;
96 |
97 | EEPROM.get(LOC_ETX, myTrackerSettings->ETX);
98 | }
99 |
--------------------------------------------------------------------------------
/Software/examples/Example15_BetterTracker/Tracker_EEPROM_Storage.h:
--------------------------------------------------------------------------------
1 | // Artemis Global Tracker: BetterTracker EEPROM storage
2 |
3 | #ifndef TrackerEEPROM
4 | #define TrackerEEPROM
5 |
6 | // Data type storage lengths when stored in EEPROM
7 | #define LEN_BYTE 1
8 | #define LEN_INT16 2
9 | #define LEN_INT32 4
10 | #define LEN_FLOAT 4
11 |
12 | // Define the storage lengths for the message fields that will be stored in EEPROM
13 | #define LEN_STX LEN_BYTE // STX is byte
14 | #define LEN_SOURCE LEN_INT32 // SOURCE is uint32
15 | #define LEN_DEST LEN_INT32 // DEST is uint32
16 | #define LEN_TXINT LEN_INT16 // TXINT is uint16
17 | #define LEN_ETX LEN_BYTE // ETX is byte
18 | #define LEN_CSUMA LEN_BYTE // ChecksumA is byte
19 | #define LEN_CSUMB LEN_BYTE // ChecksumB is byte
20 |
21 | // Define the storage locations for each message field that will be stored in EEPROM
22 | #define LOC_STX 0 // Change this if you want the data to be stored higher up in the EEPROM
23 | #define LOC_SOURCE LOC_STX + LEN_STX
24 | #define LOC_DEST LOC_SOURCE + LEN_SOURCE
25 | #define LOC_TXINT LOC_DEST + LEN_DEST
26 | #define LOC_ETX LOC_TXINT + LEN_TXINT
27 | #define LOC_CSUMA LOC_ETX + LEN_ETX
28 | #define LOC_CSUMB LOC_CSUMA + LEN_CSUMA
29 |
30 | // Define the default value for each message field
31 | #define DEF_STX 0x02
32 | #define DEF_ETX 0x03
33 |
34 | // Define the struct for the tracker settings (stored in RAM and copied to or loaded from EEPROM)
35 | // myTrackerSettings.TXINT is accessed by the rtc ISR and so needs to be volatile
36 | typedef struct
37 | {
38 | byte STX; // 0x02 - when written to EEPROM, helps indicate if EEPROM contains valid data
39 | uint32_t SOURCE; // The tracker's RockBLOCK serial number
40 | uint32_t DEST; // The destination RockBLOCK serial number for message forwarding
41 | volatile uint16_t TXINT; // The message transmit interval in minutes
42 | byte ETX; // 0x03 - when written to EEPROM, helps indicate if EEPROM contains valid data
43 | } trackerSettings;
44 |
45 | #endif
46 |
--------------------------------------------------------------------------------
/Software/examples/Example16_GlobalTracker/Tracker_BattV.ino:
--------------------------------------------------------------------------------
1 | // Artemis Global Tracker: battery voltage definitions and functions
2 |
3 | // We check if the battery voltage is low in several places. This function simplifies that and
4 | // lets us define a single "low voltage" to cause the tracker to go to sleep: 20 * 10mV less than LOWBATT
5 | bool battVlow ()
6 | {
7 | if (myTrackerSettings.BATTV.the_data < (myTrackerSettings.LOWBATT.the_data - 20))
8 | return (true);
9 | else
10 | return (false);
11 | }
12 |
13 | // Get the battery (bus) voltage
14 | // Enable the bus voltage monitor
15 | // Read the bus voltage and store it in vbat
16 | // Disable the bus voltage monitor to save power
17 | // Converts the analogread into V * 10^-2, compensating for
18 | // the voltage divider (/3) and the Apollo voltage reference (2.0V)
19 | // Include a correction factor of 1.09 to correct for the divider impedance
20 | void get_vbat()
21 | {
22 | digitalWrite(busVoltageMonEN, HIGH); // Enable the bus voltage monitor
23 | analogReadResolution(14); //Set resolution to 14 bit
24 | delay(10); // Let the voltage settle
25 | myTrackerSettings.BATTV.the_data = ((uint16_t)analogRead(busVoltagePin)) * 109 * 3 * 2 / 16384; // Convert into V * 10^-2
26 | digitalWrite(busVoltageMonEN, LOW); // Disable the bus voltage monitor
27 | }
28 |
--------------------------------------------------------------------------------
/Software/examples/Example16_GlobalTracker/Tracker_Callbacks.ino:
--------------------------------------------------------------------------------
1 | // Artemis Global Tracker: IridiumSBD Callbacks
2 |
3 | // IridiumSBD Callback - this code is called while the 9603N is trying to transmit
4 | bool ISBDCallback()
5 | {
6 | // Flash the LED at 4 Hz
7 | if ((millis() / 250) % 2 == 1) {
8 | digitalWrite(LED, HIGH);
9 | }
10 | else {
11 | digitalWrite(LED, LOW);
12 | }
13 |
14 | // Check the battery voltage now we are drawing current for the 9603
15 | // If voltage is low, stop Iridium send
16 | get_vbat(); // Read the battery (bus) voltage
17 | if ((myTrackerSettings.BATTV.the_data < (myTrackerSettings.LOWBATT.the_data - 200))) {
18 | Serial.print("*** LOW VOLTAGE (ISBDCallback) ");
19 | Serial.print((((float)myTrackerSettings.BATTV.the_data)/100.0),2);
20 | Serial.println("V ***");
21 | return false; // Returning false causes IridiumSBD to terminate
22 | }
23 | else {
24 | return true;
25 | }
26 | } // End of ISBDCallback()
27 |
28 | #if DIAGNOSTICS
29 | void ISBDConsoleCallback(IridiumSBD *device, char c)
30 | {
31 | Serial.write(c);
32 | }
33 |
34 | void ISBDDiagsCallback(IridiumSBD *device, char c)
35 | {
36 | Serial.write(c);
37 | }
38 | #endif
39 |
--------------------------------------------------------------------------------
/Software/examples/Example16_GlobalTracker/Tracker_User_Functions.ino:
--------------------------------------------------------------------------------
1 | // Artemis Global Tracker: User Functions
2 |
3 | // Add your own code to these functions to return USERVAL's or execute USERFUNC's
4 |
5 | void USER_FUNC_1()
6 | {
7 | debugPrintln(F("Executing USERFUNC1..."));
8 | // Add your own code here - it will be executed when the Tracker receives a "USERFUNC1" (0x58) message field
9 | }
10 |
11 | void USER_FUNC_2()
12 | {
13 | debugPrintln(F("Executing USERFUNC2..."));
14 | // Add your own code here - it will be executed when the Tracker receives a "USERFUNC2" (0x59) message field
15 | }
16 |
17 | void USER_FUNC_3()
18 | {
19 | debugPrintln(F("Executing USERFUNC3..."));
20 | // Add your own code here - it will be executed when the Tracker receives a "USERFUNC3" (0x5a) message field
21 | }
22 |
23 | void USER_FUNC_4()
24 | {
25 | debugPrintln(F("Executing USERFUNC4..."));
26 | // Add your own code here - it will be executed when the Tracker receives a "USERFUNC4" (0x5b) message field
27 | }
28 |
29 | void USER_FUNC_5(uint16_t myVar)
30 | {
31 | debugPrintln(F("Executing USERFUNC5..."));
32 | // Add your own code here - it will be executed when the Tracker receives a "USERFUNC5" (0x5c) message field
33 | }
34 |
35 | void USER_FUNC_6(uint16_t myVar)
36 | {
37 | debugPrintln(F("Executing USERFUNC6..."));
38 | // Add your own code here - it will be executed when the Tracker receives a "USERFUNC6" (0x5d) message field
39 | }
40 |
41 | void USER_FUNC_7(uint32_t myVar)
42 | {
43 | debugPrintln(F("Executing USERFUNC7..."));
44 | // Add your own code here - it will be executed when the Tracker receives a "USERFUNC7" (0x5e) message field
45 | }
46 |
47 | void USER_FUNC_8(uint32_t myVar)
48 | {
49 | debugPrintln(F("Executing USERFUNC8..."));
50 | // Add your own code here - it will be executed when the Tracker receives a "USERFUNC8" (0x5f) message field
51 | }
52 |
53 | byte USER_VAL_1()
54 | {
55 | // Add your own code here - e.g. read an external sensor. The return value will be sent as a "USERVAL1" (0x20) message field
56 | byte retVal; // The return value.
57 | retVal = 1; // Set retVal to 1 for testing - delete this line if you add your own code
58 | return (retVal);
59 | }
60 |
61 | byte USER_VAL_2()
62 | {
63 | // Add your own code here - e.g. read an external sensor. The return value will be sent as a "USERVAL2" (0x21) message field
64 | byte retVal; // The return value.
65 | retVal = 2; // Set retVal to 2 for testing - delete this line if you add your own code
66 | return (retVal);
67 | }
68 |
69 | uint16_t USER_VAL_3()
70 | {
71 | // Add your own code here - e.g. read an external sensor. The return value will be sent as a "USERVAL3" (0x22) message field
72 | uint16_t retVal; // The return value.
73 | retVal = 3; // Set retVal to 3 for testing - delete this line if you add your own code
74 | return (retVal);
75 | }
76 | uint16_t USER_VAL_4()
77 | {
78 | // Add your own code here - e.g. read an external sensor. The return value will be sent as a "USERVAL4" (0x23) message field
79 | uint16_t retVal; // The return value.
80 | retVal = 4; // Set retVal to 4 for testing - delete this line if you add your own code
81 | return (retVal);
82 | }
83 |
84 | uint32_t USER_VAL_5()
85 | {
86 | // Add your own code here - e.g. read an external sensor. The return value will be sent as a "USERVAL5" (0x24) message field
87 | uint32_t retVal; // The return value.
88 | retVal = 5; // Set retVal to 5 for testing - delete this line if you add your own code
89 | return (retVal);
90 | }
91 |
92 | uint32_t USER_VAL_6()
93 | {
94 | // Add your own code here - e.g. read an external sensor. The return value will be sent as a "USERVAL6" (0x25) message field
95 | uint32_t retVal; // The return value.
96 | retVal = 6; // Set retVal to 6 for testing - delete this line if you add your own code
97 | return (retVal);
98 | }
99 |
100 | float USER_VAL_7()
101 | {
102 | // Add your own code here - e.g. read an external sensor. The return value will be sent as a "USERVAL7" (0x26) message field
103 | float retVal; // The return value.
104 | retVal = 7.0; // Set retVal to 7.0 for testing - delete this line if you add your own code
105 | return (retVal);
106 | }
107 |
108 | float USER_VAL_8()
109 | {
110 | // Add your own code here - e.g. read an external sensor. The return value will be sent as a "USERVAL8" (0x27) message field
111 | float retVal; // The return value.
112 | retVal = 8.0E8; // Set retVal to 8.0E8 for testing - delete this line if you add your own code
113 | return (retVal);
114 | }
115 |
116 | void ALARM_FUNC(uint8_t alarmType)
117 | {
118 | debugPrintln(F("Executing ALARM_FUNC ..."));
119 | // Add your own code to be executed when an alarm is set off.
120 | }
121 |
--------------------------------------------------------------------------------
/Software/examples/Example16_GlobalTracker/Tracker_printf_Support.ino:
--------------------------------------------------------------------------------
1 | // Artemis Global Tracker: printf Support
2 |
3 | //*****************************************************************************
4 | //
5 | // Divide an unsigned 32-bit value by 10.
6 | //
7 | // Note: Adapted from Ch10 of Hackers Delight (hackersdelight.org).
8 | //
9 | //*****************************************************************************
10 | static uint64_t divu64_10(uint64_t ui64Val)
11 | {
12 | uint64_t q64, r64;
13 | uint32_t q32, r32, ui32Val;
14 |
15 | //
16 | // If a 32-bit value, use the more optimal 32-bit routine.
17 | //
18 | if ( ui64Val >> 32 )
19 | {
20 | q64 = (ui64Val>>1) + (ui64Val>>2);
21 | q64 += (q64 >> 4);
22 | q64 += (q64 >> 8);
23 | q64 += (q64 >> 16);
24 | q64 += (q64 >> 32);
25 | q64 >>= 3;
26 | r64 = ui64Val - q64*10;
27 | return q64 + ((r64 + 6) >> 4);
28 | }
29 | else
30 | {
31 | ui32Val = (uint32_t)(ui64Val & 0xffffffff);
32 | q32 = (ui32Val>>1) + (ui32Val>>2);
33 | q32 += (q32 >> 4);
34 | q32 += (q32 >> 8);
35 | q32 += (q32 >> 16);
36 | q32 >>= 3;
37 | r32 = ui32Val - q32*10;
38 | return (uint64_t)(q32 + ((r32 + 6) >> 4));
39 | }
40 | }
41 |
42 | //*****************************************************************************
43 | //
44 | // Converts ui64Val to a string.
45 | // Note: pcBuf[] must be sized for a minimum of 21 characters.
46 | //
47 | // Returns the number of decimal digits in the string.
48 | //
49 | // NOTE: If pcBuf is NULL, will compute a return ui64Val only (no chars
50 | // written).
51 | //
52 | //*****************************************************************************
53 | static int uint64_to_str(uint64_t ui64Val, char *pcBuf)
54 | {
55 | char tbuf[25];
56 | int ix = 0, iNumDig = 0;
57 | unsigned uMod;
58 | uint64_t u64Tmp;
59 |
60 | do
61 | {
62 | //
63 | // Divide by 10
64 | //
65 | u64Tmp = divu64_10(ui64Val);
66 |
67 | //
68 | // Get modulus
69 | //
70 | uMod = ui64Val - (u64Tmp * 10);
71 |
72 | tbuf[ix++] = uMod + '0';
73 | ui64Val = u64Tmp;
74 | } while ( ui64Val );
75 |
76 | //
77 | // Save the total number of digits
78 | //
79 | iNumDig = ix;
80 |
81 | //
82 | // Now, reverse the buffer when saving to the caller's buffer.
83 | //
84 | if ( pcBuf )
85 | {
86 | while ( ix-- )
87 | {
88 | *pcBuf++ = tbuf[ix];
89 | }
90 |
91 | //
92 | // Terminate the caller's buffer
93 | //
94 | *pcBuf = 0x00;
95 | }
96 |
97 | return iNumDig;
98 | }
99 |
100 | //*****************************************************************************
101 | //
102 | // Float to ASCII text. A basic implementation for providing support for
103 | // single-precision %f.
104 | //
105 | // param
106 | // fValue = Float value to be converted.
107 | // pcBuf = Buffer to place string AND input of buffer size.
108 | // iPrecision = Desired number of decimal places.
109 | // bufSize = The size (in bytes) of the buffer.
110 | // The recommended size is at least 16 bytes.
111 | //
112 | // This function performs a basic translation of a floating point single
113 | // precision value to a string.
114 | //
115 | // return Number of chars printed to the buffer.
116 | //
117 | //*****************************************************************************
118 | #define OLA_FTOA_ERR_VAL_TOO_SMALL -1
119 | #define OLA_FTOA_ERR_VAL_TOO_LARGE -2
120 | #define OLA_FTOA_ERR_BUFSIZE -3
121 |
122 | typedef union
123 | {
124 | int32_t I32;
125 | float F;
126 | } ola_i32fl_t;
127 |
128 | static int ftoa(float fValue, char *pcBuf, int iPrecision, int bufSize)
129 | {
130 | ola_i32fl_t unFloatValue;
131 | int iExp2, iBufSize;
132 | int32_t i32Significand, i32IntPart, i32FracPart;
133 | char *pcBufInitial, *pcBuftmp;
134 |
135 | iBufSize = bufSize; // *(uint32_t*)pcBuf;
136 | if (iBufSize < 4)
137 | {
138 | return OLA_FTOA_ERR_BUFSIZE;
139 | }
140 |
141 | if (fValue == 0.0f)
142 | {
143 | // "0.0"
144 | *(uint32_t*)pcBuf = 0x00 << 24 | ('0' << 16) | ('.' << 8) | ('0' << 0);
145 | return 3;
146 | }
147 |
148 | pcBufInitial = pcBuf;
149 |
150 | unFloatValue.F = fValue;
151 |
152 | iExp2 = ((unFloatValue.I32 >> 23) & 0x000000FF) - 127;
153 | i32Significand = (unFloatValue.I32 & 0x00FFFFFF) | 0x00800000;
154 | i32FracPart = 0;
155 | i32IntPart = 0;
156 |
157 | if (iExp2 >= 31)
158 | {
159 | return OLA_FTOA_ERR_VAL_TOO_LARGE;
160 | }
161 | else if (iExp2 < -23)
162 | {
163 | return OLA_FTOA_ERR_VAL_TOO_SMALL;
164 | }
165 | else if (iExp2 >= 23)
166 | {
167 | i32IntPart = i32Significand << (iExp2 - 23);
168 | }
169 | else if (iExp2 >= 0)
170 | {
171 | i32IntPart = i32Significand >> (23 - iExp2);
172 | i32FracPart = (i32Significand << (iExp2 + 1)) & 0x00FFFFFF;
173 | }
174 | else // if (iExp2 < 0)
175 | {
176 | i32FracPart = (i32Significand & 0x00FFFFFF) >> -(iExp2 + 1);
177 | }
178 |
179 | if (unFloatValue.I32 < 0)
180 | {
181 | *pcBuf++ = '-';
182 | }
183 |
184 | if (i32IntPart == 0)
185 | {
186 | *pcBuf++ = '0';
187 | }
188 | else
189 | {
190 | if (i32IntPart > 0)
191 | {
192 | uint64_to_str(i32IntPart, pcBuf);
193 | }
194 | else
195 | {
196 | *pcBuf++ = '-';
197 | uint64_to_str(-i32IntPart, pcBuf);
198 | }
199 | while (*pcBuf) // Get to end of new string
200 | {
201 | pcBuf++;
202 | }
203 | }
204 |
205 | //
206 | // Now, begin the fractional part
207 | //
208 | *pcBuf++ = '.';
209 |
210 | if (i32FracPart == 0)
211 | {
212 | *pcBuf++ = '0';
213 | }
214 | else
215 | {
216 | int jx, iMax;
217 |
218 | iMax = iBufSize - (pcBuf - pcBufInitial) - 1;
219 | iMax = (iMax > iPrecision) ? iPrecision : iMax;
220 |
221 | for (jx = 0; jx < iMax; jx++)
222 | {
223 | i32FracPart *= 10;
224 | *pcBuf++ = (i32FracPart >> 24) + '0';
225 | i32FracPart &= 0x00FFFFFF;
226 | }
227 |
228 | //
229 | // Per the printf spec, the number of digits printed to the right of the
230 | // decimal point (i.e. iPrecision) should be rounded.
231 | // Some examples:
232 | // Value iPrecision Formatted value
233 | // 1.36399 Unspecified (6) 1.363990
234 | // 1.36399 3 1.364
235 | // 1.36399 4 1.3640
236 | // 1.36399 5 1.36399
237 | // 1.363994 Unspecified (6) 1.363994
238 | // 1.363994 3 1.364
239 | // 1.363994 4 1.3640
240 | // 1.363994 5 1.36399
241 | // 1.363995 Unspecified (6) 1.363995
242 | // 1.363995 3 1.364
243 | // 1.363995 4 1.3640
244 | // 1.363995 5 1.36400
245 | // 1.996 Unspecified (6) 1.996000
246 | // 1.996 2 2.00
247 | // 1.996 3 1.996
248 | // 1.996 4 1.9960
249 | //
250 | // To determine whether to round up, we'll look at what the next
251 | // decimal value would have been.
252 | //
253 | if ( ((i32FracPart * 10) >> 24) >= 5 )
254 | {
255 | //
256 | // Yes, we need to round up.
257 | // Go back through the string and make adjustments as necessary.
258 | //
259 | pcBuftmp = pcBuf - 1;
260 | while ( pcBuftmp >= pcBufInitial )
261 | {
262 | if ( *pcBuftmp == '.' )
263 | {
264 | }
265 | else if ( *pcBuftmp == '9' )
266 | {
267 | *pcBuftmp = '0';
268 | }
269 | else
270 | {
271 | *pcBuftmp += 1;
272 | break;
273 | }
274 | pcBuftmp--;
275 | }
276 | }
277 | }
278 |
279 | //
280 | // Terminate the string and we're done
281 | //
282 | *pcBuf = 0x00;
283 |
284 | return (pcBuf - pcBufInitial);
285 | } // ftoa()
286 |
--------------------------------------------------------------------------------
/Software/examples/Example1_Blink/Example1_Blink.ino:
--------------------------------------------------------------------------------
1 | /*
2 | Artemis Global Tracker
3 | Example: Blink
4 |
5 | Written by Paul Clark (PaulZC)
6 | August 7th 2021
7 |
8 | Flashes the white LED on the Artemis Tracker
9 | The LED is connected to D19
10 |
11 | ** Updated for v2.1.0 of the Apollo3 core / Artemis board package **
12 | ** Set the Board to "RedBoard Artemis ATP" **
13 |
14 | If this example runs successfully, you can (hopefully) be confident that:
15 | The 3.3V regulator is working correctly
16 | (The green POWER LED should be lit up)
17 | (Measure the voltage between the 3,3V and GND pads to be sure)
18 | The Artemis is alive and kicking
19 | The CH340E USB to serial interface is working
20 | (You should see the yellow and green LEDs next to the CH340E blink
21 | when the sketch uploads.)
22 | The white LED is working
23 | The reset switch is working
24 | */
25 |
26 | // Artemis Tracker pin definitions
27 | #define spiCS1 4 // D4 can be used as an SPI chip select or as a general purpose IO pin
28 | #define geofencePin 10 // Input for the ZOE-M8Q's PIO14 (geofence) pin
29 | #define busVoltagePin 13 // Bus voltage divided by 3 (Analog in)
30 | #define iridiumSleep 17 // Iridium 9603N ON/OFF (sleep) pin: pull high to enable the 9603N
31 | #define iridiumNA 18 // Input for the Iridium 9603N Network Available
32 | #define LED 19 // White LED
33 | #define iridiumPwrEN 22 // ADM4210 ON: pull high to enable power for the Iridium 9603N
34 | #define gnssEN 26 // GNSS Enable: pull low to enable power for the GNSS (via Q2)
35 | #define superCapChgEN 27 // LTC3225 super capacitor charger: pull high to enable the super capacitor charger
36 | #define superCapPGOOD 28 // Input for the LTC3225 super capacitor charger PGOOD signal
37 | #define busVoltageMonEN 34 // Bus voltage monitor enable: pull high to enable bus voltage monitoring (via Q4 and Q3)
38 | #define spiCS2 35 // D35 can be used as an SPI chip select or as a general purpose IO pin
39 | #define iridiumRI 41 // Input for the Iridium 9603N Ring Indicator
40 | // Make sure you do not have gnssEN and iridiumPwrEN enabled at the same time!
41 | // If you do, bad things might happen to the AS179 RF switch!
42 |
43 | void gnssON(void) // Enable power for the GNSS
44 | {
45 | am_hal_gpio_pincfg_t pinCfg = g_AM_HAL_GPIO_OUTPUT; // Begin by making the gnssEN pin an open-drain output
46 | pinCfg.eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_OPENDRAIN;
47 | pin_config(PinName(gnssEN), pinCfg);
48 | delay(1);
49 |
50 | digitalWrite(gnssEN, LOW); // Enable GNSS power (HIGH = disable; LOW = enable)
51 | }
52 |
53 | void gnssOFF(void) // Disable power for the GNSS
54 | {
55 | am_hal_gpio_pincfg_t pinCfg = g_AM_HAL_GPIO_OUTPUT; // Begin by making the gnssEN pin an open-drain output
56 | pinCfg.eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_OPENDRAIN;
57 | pin_config(PinName(gnssEN), pinCfg);
58 | delay(1);
59 |
60 | digitalWrite(gnssEN, HIGH); // Disable GNSS power (HIGH = disable; LOW = enable)
61 | }
62 |
63 | void setup()
64 | {
65 | // Configure the I/O pins
66 | pinMode(LED, OUTPUT);
67 |
68 | pinMode(iridiumPwrEN, OUTPUT); // Configure the Iridium Power Pin (connected to the ADM4210 ON pin)
69 | digitalWrite(iridiumPwrEN, LOW); // Disable Iridium Power
70 | pinMode(superCapChgEN, OUTPUT); // Configure the super capacitor charger enable pin (connected to LTC3225 !SHDN)
71 | digitalWrite(superCapChgEN, LOW); // Disable the super capacitor charger
72 | gnssOFF(); // Disable power for the GNSS
73 |
74 | // Start the console serial port
75 | Serial.begin(115200);
76 | while (!Serial) // Wait for the user to open the serial monitor
77 | ;
78 | delay(100);
79 | Serial.println();
80 | Serial.println();
81 | Serial.println(F("Artemis Global Tracker"));
82 | Serial.println(F("Example: Blink"));
83 | Serial.println();
84 |
85 | //empty the serial buffer
86 | while(Serial.available() > 0)
87 | Serial.read();
88 |
89 | //wait for the user to press any key before beginning
90 | Serial.println(F("Please check that the Serial Monitor is set to 115200 Baud"));
91 | Serial.println(F("and that the line ending is set to Newline."));
92 | Serial.println(F("Then click Send to start the example."));
93 | Serial.println();
94 | while(Serial.available() == 0)
95 | ;
96 |
97 | }
98 |
99 | void loop()
100 | {
101 | digitalWrite(LED, LOW);
102 | delay(1000);
103 | digitalWrite(LED, HIGH);
104 | delay(1000);
105 | Serial.println(F("Press the RESET button to restart the example"));
106 | }
107 |
--------------------------------------------------------------------------------
/Software/examples/Example21_IridiumSerialAndPowerTest/Example21_IridiumSerialAndPowerTest.ino:
--------------------------------------------------------------------------------
1 | /*
2 | Artemis Global Tracker
3 | Example: Iridium Serial and Power Test
4 |
5 | Written by Paul Clark (PaulZC)
6 | September 7th 2021
7 |
8 | ** Updated for v2.1.0 of the Apollo3 core / Artemis board package **
9 | ** (At the time of writing, v2.1.1 of the core conatins a feature which makes communication with the u-blox GNSS problematic. Be sure to use v2.1.0) **
10 |
11 | ** Set the Board to "RedBoard Artemis ATP" **
12 | ** (The Artemis Module does not have a Wire port defined, which prevents the IridiumSBD library from compiling) **
13 |
14 | Version 2.1 of the Apollo3 core contains an interesting bug: the Artemis will hang if the Serial1 RX pin is held low
15 | for more than ~9.5 bit periods:
16 | https://github.com/sparkfun/Arduino_Apollo3/issues/423
17 | https://github.com/sparkfun/Arduino_Apollo3/issues/349
18 | On the AGT, the Iridium modem is connected to Serial1. When we power-down the modem, we need to disable the RX pin
19 | to prevent the Artemis from hanging. We do this via customised (overwritten) versions of IridiumSBD::beginSerialPort and
20 | IridiumSBD::endSerialPort.
21 |
22 | You will need to install version 3.0.5 of the Iridium SBD I2C library
23 | before this example will run successfully:
24 | https://github.com/sparkfun/SparkFun_IridiumSBD_I2C_Arduino_Library
25 | (Available through the Arduino Library Manager: search for IridiumSBDi2c)
26 |
27 | Power for the 9603N is provided by the LTC3225 super capacitor charger.
28 | D27 needs to be pulled high to enable the charger.
29 | The LTC3225 PGOOD signal is connected to D28.
30 |
31 | Power for the 9603N is switched by the ADM4210 inrush current limiter.
32 | D22 needs to be pulled high to enable power for the 9603N.
33 |
34 | The 9603N itself is enabled via its ON/OFF (SLEEP) pin which is connected
35 | to D17. Pull high - via the IridiumSBD library - to enable the 9603N.
36 |
37 | The 9603N's Network Available signal is conected to D18,
38 | so let's configure D18 as an input.
39 |
40 | The 9603N's Ring Indicator is conected to D41,
41 | so let's configure D41 as an input.
42 |
43 | To prevent bad tings happening to the AS179 RF antenna switch,
44 | D26 needs to be pulled high to disable the GNSS power.
45 |
46 | */
47 |
48 | // Artemis Tracker pin definitions
49 | #define spiCS1 4 // D4 can be used as an SPI chip select or as a general purpose IO pin
50 | #define geofencePin 10 // Input for the ZOE-M8Q's PIO14 (geofence) pin
51 | #define busVoltagePin 13 // Bus voltage divided by 3 (Analog in)
52 | #define iridiumSleep 17 // Iridium 9603N ON/OFF (sleep) pin: pull high to enable the 9603N
53 | #define iridiumNA 18 // Input for the Iridium 9603N Network Available
54 | #define LED 19 // White LED
55 | #define iridiumPwrEN 22 // ADM4210 ON: pull high to enable power for the Iridium 9603N
56 | #define gnssEN 26 // GNSS Enable: pull low to enable power for the GNSS (via Q2)
57 | #define superCapChgEN 27 // LTC3225 super capacitor charger: pull high to enable the super capacitor charger
58 | #define superCapPGOOD 28 // Input for the LTC3225 super capacitor charger PGOOD signal
59 | #define busVoltageMonEN 34 // Bus voltage monitor enable: pull high to enable bus voltage monitoring (via Q4 and Q3)
60 | #define spiCS2 35 // D35 can be used as an SPI chip select or as a general purpose IO pin
61 | #define iridiumRI 41 // Input for the Iridium 9603N Ring Indicator
62 | // Make sure you do not have gnssEN and iridiumPwrEN enabled at the same time!
63 | // If you do, bad things might happen to the AS179 RF switch!
64 |
65 | // We use Serial1 to communicate with the Iridium modem. Serial1 on the ATP uses pin 24 for TX and 25 for RX. AGT uses the same pins.
66 |
67 | #include //http://librarymanager/All#IridiumSBDI2C
68 | #define DIAGNOSTICS false // Change this to true to see IridiumSBD diagnostics
69 | // Declare the IridiumSBD object (including the sleep (ON/OFF) and Ring Indicator pins)
70 | IridiumSBD modem(Serial1, iridiumSleep, iridiumRI);
71 |
72 | void gnssON(void) // Enable power for the GNSS
73 | {
74 | am_hal_gpio_pincfg_t pinCfg = g_AM_HAL_GPIO_OUTPUT; // Begin by making the gnssEN pin an open-drain output
75 | pinCfg.eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_OPENDRAIN;
76 | pin_config(PinName(gnssEN), pinCfg);
77 | delay(1);
78 |
79 | digitalWrite(gnssEN, LOW); // Enable GNSS power (HIGH = disable; LOW = enable)
80 | }
81 |
82 | void gnssOFF(void) // Disable power for the GNSS
83 | {
84 | am_hal_gpio_pincfg_t pinCfg = g_AM_HAL_GPIO_OUTPUT; // Begin by making the gnssEN pin an open-drain output
85 | pinCfg.eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_OPENDRAIN;
86 | pin_config(PinName(gnssEN), pinCfg);
87 | delay(1);
88 |
89 | digitalWrite(gnssEN, HIGH); // Disable GNSS power (HIGH = disable; LOW = enable)
90 | }
91 |
92 | // Overwrite the IridiumSBD beginSerialPort function - a fix for https://github.com/sparkfun/Arduino_Apollo3/issues/423
93 | void IridiumSBD::beginSerialPort() // Start the serial port connected to the satellite modem
94 | {
95 | diagprint(F("custom IridiumSBD::beginSerialPort\r\n"));
96 |
97 | // Configure the standard ATP pins for UART1 TX and RX - endSerialPort may have disabled the RX pin
98 |
99 | am_hal_gpio_pincfg_t pinConfigTx = g_AM_BSP_GPIO_COM_UART_TX;
100 | pinConfigTx.uFuncSel = AM_HAL_PIN_24_UART1TX;
101 | pin_config(D24, pinConfigTx);
102 |
103 | am_hal_gpio_pincfg_t pinConfigRx = g_AM_BSP_GPIO_COM_UART_RX;
104 | pinConfigRx.uFuncSel = AM_HAL_PIN_25_UART1RX;
105 | pinConfigRx.ePullup = AM_HAL_GPIO_PIN_PULLUP_WEAK; // Put a weak pull-up on the Rx pin
106 | pin_config(D25, pinConfigRx);
107 |
108 | Serial1.begin(19200);
109 | }
110 |
111 | // Overwrite the IridiumSBD endSerialPort function - a fix for https://github.com/sparkfun/Arduino_Apollo3/issues/423
112 | void IridiumSBD::endSerialPort()
113 | {
114 | diagprint(F("custom IridiumSBD::endSerialPort\r\n"));
115 |
116 | // Disable the Serial1 RX pin to avoid the code hang
117 | am_hal_gpio_pinconfig(PinName(D25), g_AM_HAL_GPIO_DISABLE);
118 | }
119 |
120 | void setup()
121 | {
122 | pinMode(LED, OUTPUT); // Make the LED pin an output
123 |
124 | gnssOFF(); // Disable power for the GNSS
125 | pinMode(geofencePin, INPUT); // Configure the geofence pin as an input
126 |
127 | pinMode(iridiumPwrEN, OUTPUT); // Configure the Iridium Power Pin (connected to the ADM4210 ON pin)
128 | digitalWrite(iridiumPwrEN, LOW); // Disable Iridium Power (HIGH = enable; LOW = disable)
129 | pinMode(superCapChgEN, OUTPUT); // Configure the super capacitor charger enable pin (connected to LTC3225 !SHDN)
130 | digitalWrite(superCapChgEN, LOW); // Disable the super capacitor charger (HIGH = enable; LOW = disable)
131 | pinMode(iridiumSleep, OUTPUT); // Iridium 9603N On/Off (Sleep) pin
132 | digitalWrite(iridiumSleep, LOW); // Put the Iridium 9603N to sleep (HIGH = on; LOW = off/sleep)
133 | pinMode(iridiumRI, INPUT); // Configure the Iridium Ring Indicator as an input
134 | pinMode(iridiumNA, INPUT); // Configure the Iridium Network Available as an input
135 | pinMode(superCapPGOOD, INPUT); // Configure the super capacitor charger PGOOD input
136 |
137 | // Make sure the Serial1 RX pin is disabled to prevent the power-on glitch on the modem's RX(OUT) pin
138 | // causing problems with v2.1.0 of the Apollo3 core. Requires v3.0.5 of IridiumSBDi2c.
139 | modem.endSerialPort();
140 |
141 | // Start the console serial port
142 | Serial.begin(115200);
143 | while (!Serial) // Wait for the user to open the serial monitor
144 | ;
145 | delay(100);
146 | Serial.println();
147 | Serial.println();
148 | Serial.println(F("Artemis Global Tracker"));
149 | Serial.println(F("Example: Iridium Serial and Power Test"));
150 | Serial.println();
151 |
152 | //empty the serial buffer
153 | while(Serial.available() > 0)
154 | Serial.read();
155 |
156 | //wait for the user to press any key before beginning
157 | Serial.println(F("Please check that the Serial Monitor is set to 115200 Baud"));
158 | Serial.println(F("and that the line ending is set to Newline."));
159 | Serial.println(F("Then click Send to start the example."));
160 | Serial.println();
161 | while(Serial.available() == 0)
162 | ;
163 |
164 | // Enable the supercapacitor charger
165 | Serial.println(F("Enabling the supercapacitor charger..."));
166 | digitalWrite(superCapChgEN, HIGH); // Enable the super capacitor charger
167 | delay(1000);
168 |
169 | // Wait for the supercapacitor charger PGOOD signal to go high
170 | while (digitalRead(superCapPGOOD) == false)
171 | {
172 | Serial.println(F("Waiting for supercapacitors to charge..."));
173 | delay(1000);
174 | }
175 | Serial.println(F("Supercapacitors charged!"));
176 |
177 | }
178 |
179 | void loop()
180 | {
181 | // Enable power for the 9603N
182 | Serial.println(F("Enabling 9603N power..."));
183 | digitalWrite(iridiumPwrEN, HIGH); // Enable Iridium Power
184 | delay(1000);
185 |
186 | // Begin satellite modem operation
187 | // Also begin the serial port connected to the satellite modem via IridiumSBD::beginSerialPort
188 | Serial.println(F("Starting modem..."));
189 | int err = modem.begin();
190 | if (err != ISBD_SUCCESS)
191 | {
192 | Serial.print(F("Begin failed: error "));
193 | Serial.println(err);
194 | if (err == ISBD_NO_MODEM_DETECTED)
195 | Serial.println(F("No modem detected: check wiring."));
196 | return;
197 | }
198 |
199 | // Get the IMEI
200 | char IMEI[16];
201 | err = modem.getIMEI(IMEI, sizeof(IMEI));
202 | if (err != ISBD_SUCCESS)
203 | {
204 | Serial.print(F("getIMEI failed: error "));
205 | Serial.println(err);
206 | return;
207 | }
208 | Serial.print(F("IMEI is "));
209 | Serial.print(IMEI);
210 | Serial.println(F("."));
211 |
212 | // Power down the modem
213 | // Also disable the Serial1 RX pin via IridiumSBD::endSerialPort
214 | Serial.println(F("Putting the 9603N to sleep."));
215 | err = modem.sleep();
216 | if (err != ISBD_SUCCESS)
217 | {
218 | Serial.print(F("sleep failed: error "));
219 | Serial.println(err);
220 | }
221 |
222 | // Disable 9603N power
223 | Serial.println(F("Disabling 9603N power..."));
224 | Serial.flush();
225 | digitalWrite(iridiumPwrEN, LOW); // Disable Iridium Power
226 |
227 | Serial.println();
228 | Serial.print(F("Test passed! Waiting for 10 seconds"));
229 | for (int i = 0; i < 10; i++)
230 | {
231 | Serial.print(F("."));
232 | delay(1000);
233 | }
234 | Serial.println();
235 | }
236 |
237 | #if DIAGNOSTICS
238 | void ISBDConsoleCallback(IridiumSBD *device, char c)
239 | {
240 | Serial.write(c);
241 | }
242 |
243 | void ISBDDiagsCallback(IridiumSBD *device, char c)
244 | {
245 | Serial.write(c);
246 | }
247 | #endif
248 |
--------------------------------------------------------------------------------
/Software/examples/Example2_BusVoltage/Example2_BusVoltage.ino:
--------------------------------------------------------------------------------
1 | /*
2 | Artemis Global Tracker
3 | Example: Bus Voltage
4 |
5 | Written by Paul Clark (PaulZC)
6 | August 7th 2021
7 |
8 | ** Updated for v2.1.0 of the Apollo3 core / Artemis board package **
9 | ** Set the Board to "RedBoard Artemis ATP" **
10 |
11 | Based on the Artemis analogRead example
12 | By: Nathan Seidle
13 | SparkFun Electronics
14 | License: MIT. See license file for more information but you can
15 | basically do whatever you want with this code.
16 |
17 | Enables the bus voltage measurement circuit and reports the voltage
18 |
19 | If this example runs successfully, you can (hopefully) be confident that:
20 | The bus voltage measurement circuit is working
21 |
22 | Setting pin D34 high enables the bus voltage measurement circuit (via Q3 and Q4)
23 | The voltage on pin AD13 is the bus voltage divided by 3
24 | The Apollo3 internal ADC VADCREF is set to 2.0 Volts
25 | This example sets the analogReadResolution to 14-bits (16384)
26 | So, to convert the analogRead into Volts, we multiply by: 3.0 * 1.09 * 2.0 / 16384.0
27 | (The 1.09 is a correction factor for the divider source impedance)
28 | */
29 |
30 | // Artemis Tracker pin definitions
31 | #define spiCS1 4 // D4 can be used as an SPI chip select or as a general purpose IO pin
32 | #define geofencePin 10 // Input for the ZOE-M8Q's PIO14 (geofence) pin
33 | #define busVoltagePin 13 // Bus voltage divided by 3 (Analog in)
34 | #define iridiumSleep 17 // Iridium 9603N ON/OFF (sleep) pin: pull high to enable the 9603N
35 | #define iridiumNA 18 // Input for the Iridium 9603N Network Available
36 | #define LED 19 // White LED
37 | #define iridiumPwrEN 22 // ADM4210 ON: pull high to enable power for the Iridium 9603N
38 | #define gnssEN 26 // GNSS Enable: pull low to enable power for the GNSS (via Q2)
39 | #define superCapChgEN 27 // LTC3225 super capacitor charger: pull high to enable the super capacitor charger
40 | #define superCapPGOOD 28 // Input for the LTC3225 super capacitor charger PGOOD signal
41 | #define busVoltageMonEN 34 // Bus voltage monitor enable: pull high to enable bus voltage monitoring (via Q4 and Q3)
42 | #define spiCS2 35 // D35 can be used as an SPI chip select or as a general purpose IO pin
43 | #define iridiumRI 41 // Input for the Iridium 9603N Ring Indicator
44 | // Make sure you do not have gnssEN and iridiumPwrEN enabled at the same time!
45 | // If you do, bad things might happen to the AS179 RF switch!
46 |
47 | void gnssON(void) // Enable power for the GNSS
48 | {
49 | am_hal_gpio_pincfg_t pinCfg = g_AM_HAL_GPIO_OUTPUT; // Begin by making the gnssEN pin an open-drain output
50 | pinCfg.eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_OPENDRAIN;
51 | pin_config(PinName(gnssEN), pinCfg);
52 | delay(1);
53 |
54 | digitalWrite(gnssEN, LOW); // Enable GNSS power (HIGH = disable; LOW = enable)
55 | }
56 |
57 | void gnssOFF(void) // Disable power for the GNSS
58 | {
59 | am_hal_gpio_pincfg_t pinCfg = g_AM_HAL_GPIO_OUTPUT; // Begin by making the gnssEN pin an open-drain output
60 | pinCfg.eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_OPENDRAIN;
61 | pin_config(PinName(gnssEN), pinCfg);
62 | delay(1);
63 |
64 | digitalWrite(gnssEN, HIGH); // Disable GNSS power (HIGH = disable; LOW = enable)
65 | }
66 |
67 | void setup()
68 | {
69 | // Configure the I/O pins
70 | pinMode(LED, OUTPUT);
71 |
72 | pinMode(iridiumPwrEN, OUTPUT); // Configure the Iridium Power Pin (connected to the ADM4210 ON pin)
73 | digitalWrite(iridiumPwrEN, LOW); // Disable Iridium Power
74 | pinMode(superCapChgEN, OUTPUT); // Configure the super capacitor charger enable pin (connected to LTC3225 !SHDN)
75 | digitalWrite(superCapChgEN, LOW); // Disable the super capacitor charger
76 | gnssOFF(); // Disable power for the GNSS
77 |
78 | pinMode(busVoltageMonEN, OUTPUT); // Make the Bus Voltage Monitor Enable an output
79 | digitalWrite(busVoltageMonEN, HIGH); // Set it high to enable the measurement
80 | //digitalWrite(busVoltageMonEN, LOW); // Set it low to disable the measurement (busV should be ~zero)
81 |
82 | analogReadResolution(14); //Set resolution to 14 bit
83 |
84 | // Start the console serial port
85 | Serial.begin(115200);
86 | while (!Serial) // Wait for the user to open the serial monitor
87 | ;
88 | delay(100);
89 | Serial.println();
90 | Serial.println();
91 | Serial.println(F("Artemis Global Tracker"));
92 | Serial.println(F("Example: Bus Voltage"));
93 | Serial.println();
94 |
95 | //empty the serial buffer
96 | while(Serial.available() > 0)
97 | Serial.read();
98 |
99 | //wait for the user to press any key before beginning
100 | Serial.println(F("Please check that the Serial Monitor is set to 115200 Baud"));
101 | Serial.println(F("and that the line ending is set to Newline."));
102 | Serial.println(F("Then click Send to start the example."));
103 | Serial.println();
104 | while(Serial.available() == 0)
105 | ;
106 |
107 | }
108 |
109 | void loop()
110 | {
111 | digitalWrite(LED, LOW);
112 |
113 | int busV3 = analogRead(busVoltagePin); //Automatically sets pin to analog input
114 | Serial.print(F("busV/3: "));
115 | Serial.print(busV3);
116 |
117 | float busV = (float)busV3 * 3.0 * 1.09 * 2.0 / 16384.0; //Convert 1/3 busV to busV (correction factor 1.09)
118 | Serial.print(F(" busV: "));
119 | Serial.print(busV, 2);
120 | Serial.print(F("V"));
121 |
122 | //TODO enable battload
123 | int div3 = analogReadVCCDiv3(); //Read VCC across a 1/3 resistor divider
124 | Serial.print(F(" VCC/3: "));
125 | Serial.print(div3);
126 |
127 | float vcc = (float)div3 * 3.0 * 2.0 / 16384.0; //Convert 1/3 VCC to VCC
128 | Serial.print(F(" VCC: "));
129 | Serial.print(vcc, 2);
130 | Serial.print(F("V"));
131 |
132 | float internalTemp = getTempDegC(); // Read internal temperature sensor
133 | Serial.print(F(" internalTemp: "));
134 | Serial.print(internalTemp, 2);
135 |
136 | int vss = analogReadVSS(); //Read internal VSS (should be 0)
137 | Serial.print(F(" VSS: "));
138 | Serial.print(vss);
139 |
140 | Serial.println();
141 |
142 | digitalWrite(LED, HIGH);
143 | delay(1000);
144 | }
145 |
--------------------------------------------------------------------------------
/Software/examples/Example3_PHT/Example3_PHT.ino:
--------------------------------------------------------------------------------
1 | /*
2 | Artemis Global Tracker
3 | Example: Pressure, Humidity, Temperature
4 |
5 | Written by Paul Clark (PaulZC)
6 | August 7th 2021
7 |
8 | ** Updated for v2.1.0 of the Apollo3 core / Artemis board package **
9 | ** Set the Board to "RedBoard Artemis ATP" **
10 |
11 | ** (The Artemis Module does not have a Wire port defined, which prevents the MS8607 library from compiling) **
12 |
13 | This example reads the pressure, humidity and temperature from the on-board MS8607 sensor.
14 |
15 | You will also need to install the Qwiic_PHT_MS8607_Library:
16 | https://github.com/sparkfun/SparkFun_PHT_MS8607_Arduino_Library
17 | (Available through the Arduino Library Manager: search for SparkFun MS8607)
18 |
19 | Basic information on how to install an Arduino library is available here:
20 | https://learn.sparkfun.com/tutorials/installing-an-arduino-library
21 |
22 | The MS8607 is connected to I2C Port 1: SCL = D8; SDA = D9
23 |
24 | */
25 |
26 | // Artemis Tracker pin definitions
27 | #define spiCS1 4 // D4 can be used as an SPI chip select or as a general purpose IO pin
28 | #define geofencePin 10 // Input for the ZOE-M8Q's PIO14 (geofence) pin
29 | #define busVoltagePin 13 // Bus voltage divided by 3 (Analog in)
30 | #define iridiumSleep 17 // Iridium 9603N ON/OFF (sleep) pin: pull high to enable the 9603N
31 | #define iridiumNA 18 // Input for the Iridium 9603N Network Available
32 | #define LED 19 // White LED
33 | #define iridiumPwrEN 22 // ADM4210 ON: pull high to enable power for the Iridium 9603N
34 | #define gnssEN 26 // GNSS Enable: pull low to enable power for the GNSS (via Q2)
35 | #define superCapChgEN 27 // LTC3225 super capacitor charger: pull high to enable the super capacitor charger
36 | #define superCapPGOOD 28 // Input for the LTC3225 super capacitor charger PGOOD signal
37 | #define busVoltageMonEN 34 // Bus voltage monitor enable: pull high to enable bus voltage monitoring (via Q4 and Q3)
38 | #define spiCS2 35 // D35 can be used as an SPI chip select or as a general purpose IO pin
39 | #define iridiumRI 41 // Input for the Iridium 9603N Ring Indicator
40 | // Make sure you do not have gnssEN and iridiumPwrEN enabled at the same time!
41 | // If you do, bad things might happen to the AS179 RF switch!
42 |
43 | #include
44 | TwoWire agtWire(9,8); //Create an I2C port using pads 8 (SCL) and 9 (SDA)
45 |
46 | #include //http://librarymanager/All#SparkFun_MS8607
47 |
48 | //Create an instance of the MS8607 object
49 | MS8607 barometricSensor;
50 |
51 | void gnssON(void) // Enable power for the GNSS
52 | {
53 | am_hal_gpio_pincfg_t pinCfg = g_AM_HAL_GPIO_OUTPUT; // Begin by making the gnssEN pin an open-drain output
54 | pinCfg.eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_OPENDRAIN;
55 | pin_config(PinName(gnssEN), pinCfg);
56 | delay(1);
57 |
58 | digitalWrite(gnssEN, LOW); // Enable GNSS power (HIGH = disable; LOW = enable)
59 | }
60 |
61 | void gnssOFF(void) // Disable power for the GNSS
62 | {
63 | am_hal_gpio_pincfg_t pinCfg = g_AM_HAL_GPIO_OUTPUT; // Begin by making the gnssEN pin an open-drain output
64 | pinCfg.eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_OPENDRAIN;
65 | pin_config(PinName(gnssEN), pinCfg);
66 | delay(1);
67 |
68 | digitalWrite(gnssEN, HIGH); // Disable GNSS power (HIGH = disable; LOW = enable)
69 | }
70 |
71 | void setup()
72 | {
73 | // Configure the I/O pins
74 | pinMode(LED, OUTPUT);
75 |
76 | pinMode(iridiumPwrEN, OUTPUT); // Configure the Iridium Power Pin (connected to the ADM4210 ON pin)
77 | digitalWrite(iridiumPwrEN, LOW); // Disable Iridium Power
78 | pinMode(superCapChgEN, OUTPUT); // Configure the super capacitor charger enable pin (connected to LTC3225 !SHDN)
79 | digitalWrite(superCapChgEN, LOW); // Disable the super capacitor charger
80 | gnssOFF(); // Disable power for the GNSS
81 |
82 | // Set up the I2C pins
83 | agtWire.begin();
84 |
85 | // Start the console serial port
86 | Serial.begin(115200);
87 | while (!Serial) // Wait for the user to open the serial monitor
88 | ;
89 | delay(100);
90 | Serial.println();
91 | Serial.println();
92 | Serial.println(F("Artemis Global Tracker"));
93 | Serial.println(F("Example: PHT"));
94 | Serial.println();
95 |
96 | //empty the serial buffer
97 | while(Serial.available() > 0)
98 | Serial.read();
99 |
100 | //wait for the user to press any key before beginning
101 | Serial.println(F("Please check that the Serial Monitor is set to 115200 Baud"));
102 | Serial.println(F("and that the line ending is set to Newline."));
103 | Serial.println(F("Then click Send to start the example."));
104 | Serial.println();
105 | while(Serial.available() == 0)
106 | ;
107 |
108 | if (barometricSensor.begin(agtWire) == false)
109 | {
110 | Serial.println("MS8607 sensor did not respond. Trying again...");
111 | if (barometricSensor.begin(agtWire) == false)
112 | {
113 | Serial.println("MS8607 sensor did not respond. Please check wiring.");
114 | while(1)
115 | ;
116 | }
117 | }
118 | }
119 |
120 | void loop()
121 | {
122 | digitalWrite(LED, LOW);
123 |
124 | float temperature = barometricSensor.getTemperature();
125 | float pressure = barometricSensor.getPressure();
126 | float humidity = barometricSensor.getHumidity();
127 |
128 | Serial.print("Temperature=");
129 | Serial.print(temperature, 1);
130 | Serial.print("(C)");
131 |
132 | Serial.print(" Pressure=");
133 | Serial.print(pressure, 3);
134 | Serial.print("(hPa or mbar)");
135 |
136 |
137 | Serial.print(" Humidity=");
138 | Serial.print(humidity, 1);
139 | Serial.print("(%RH)");
140 |
141 | Serial.println();
142 |
143 | digitalWrite(LED, HIGH);
144 | delay(500);
145 | }
146 |
--------------------------------------------------------------------------------
/Software/examples/Example4_ExternalPHT/Example4_ExternalPHT.ino:
--------------------------------------------------------------------------------
1 | /*
2 | Artemis Global Tracker
3 | Example: External Pressure, Humidity, Temperature
4 |
5 | Written by Paul Clark (PaulZC)
6 | August 7th 2021
7 |
8 | ** Updated for v2.1.0 of the Apollo3 core / Artemis board package **
9 | ** Set the Board to "RedBoard Artemis ATP" **
10 |
11 | ** (The Artemis Module does not have a Wire port defined, which prevents the MS8607 library from compiling) **
12 |
13 | This example reads the pressure, humidity and temperature from an external MS8607 sensor
14 | connected to the Qwiic port.
15 |
16 | You will also need to install the Qwiic_PHT_MS8607_Library:
17 | https://github.com/sparkfun/SparkFun_PHT_MS8607_Arduino_Library
18 | (Available through the Arduino Library Manager: search for MS8607)
19 |
20 | Basic information on how to install an Arduino library is available here:
21 | https://learn.sparkfun.com/tutorials/installing-an-arduino-library
22 |
23 | The MS8607 is connected to Qwiic I2C Port 4: SCL = D39; SDA = D40
24 |
25 | */
26 |
27 | // Artemis Tracker pin definitions
28 | #define spiCS1 4 // D4 can be used as an SPI chip select or as a general purpose IO pin
29 | #define geofencePin 10 // Input for the ZOE-M8Q's PIO14 (geofence) pin
30 | #define busVoltagePin 13 // Bus voltage divided by 3 (Analog in)
31 | #define iridiumSleep 17 // Iridium 9603N ON/OFF (sleep) pin: pull high to enable the 9603N
32 | #define iridiumNA 18 // Input for the Iridium 9603N Network Available
33 | #define LED 19 // White LED
34 | #define iridiumPwrEN 22 // ADM4210 ON: pull high to enable power for the Iridium 9603N
35 | #define gnssEN 26 // GNSS Enable: pull low to enable power for the GNSS (via Q2)
36 | #define superCapChgEN 27 // LTC3225 super capacitor charger: pull high to enable the super capacitor charger
37 | #define superCapPGOOD 28 // Input for the LTC3225 super capacitor charger PGOOD signal
38 | #define busVoltageMonEN 34 // Bus voltage monitor enable: pull high to enable bus voltage monitoring (via Q4 and Q3)
39 | #define spiCS2 35 // D35 can be used as an SPI chip select or as a general purpose IO pin
40 | #define iridiumRI 41 // Input for the Iridium 9603N Ring Indicator
41 | // Make sure you do not have gnssEN and iridiumPwrEN enabled at the same time!
42 | // If you do, bad things might happen to the AS179 RF switch!
43 |
44 | #include
45 | TwoWire qwiic(40,39); //Will use Artemis pads 39 (SCL) and 40 (SDA)
46 |
47 | #include //http://librarymanager/All#MS8607
48 |
49 | //Create an instance of the MS8607 object
50 | MS8607 barometricSensor;
51 |
52 | void gnssON(void) // Enable power for the GNSS
53 | {
54 | am_hal_gpio_pincfg_t pinCfg = g_AM_HAL_GPIO_OUTPUT; // Begin by making the gnssEN pin an open-drain output
55 | pinCfg.eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_OPENDRAIN;
56 | pin_config(PinName(gnssEN), pinCfg);
57 | delay(1);
58 |
59 | digitalWrite(gnssEN, LOW); // Enable GNSS power (HIGH = disable; LOW = enable)
60 | }
61 |
62 | void gnssOFF(void) // Disable power for the GNSS
63 | {
64 | am_hal_gpio_pincfg_t pinCfg = g_AM_HAL_GPIO_OUTPUT; // Begin by making the gnssEN pin an open-drain output
65 | pinCfg.eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_OPENDRAIN;
66 | pin_config(PinName(gnssEN), pinCfg);
67 | delay(1);
68 |
69 | digitalWrite(gnssEN, HIGH); // Disable GNSS power (HIGH = disable; LOW = enable)
70 | }
71 |
72 | void setup()
73 | {
74 | // Configure the I/O pins
75 | pinMode(LED, OUTPUT);
76 |
77 | pinMode(iridiumPwrEN, OUTPUT); // Configure the Iridium Power Pin (connected to the ADM4210 ON pin)
78 | digitalWrite(iridiumPwrEN, LOW); // Disable Iridium Power
79 | pinMode(superCapChgEN, OUTPUT); // Configure the super capacitor charger enable pin (connected to LTC3225 !SHDN)
80 | digitalWrite(superCapChgEN, LOW); // Disable the super capacitor charger
81 | gnssOFF(); // Disable power for the GNSS
82 |
83 | // Set up the I2C pins
84 | qwiic.begin();
85 |
86 | // Start the console serial port
87 | Serial.begin(115200);
88 | while (!Serial) // Wait for the user to open the serial monitor
89 | ;
90 | delay(100);
91 | Serial.println();
92 | Serial.println();
93 | Serial.println(F("Artemis Global Tracker"));
94 | Serial.println(F("Example: External PHT"));
95 | Serial.println();
96 |
97 | //empty the serial buffer
98 | while(Serial.available() > 0)
99 | Serial.read();
100 |
101 | //wait for the user to press any key before beginning
102 | Serial.println(F("Please check that the Serial Monitor is set to 115200 Baud"));
103 | Serial.println(F("and that the line ending is set to Newline."));
104 | Serial.println(F("Then click Send to start the example."));
105 | Serial.println();
106 | while(Serial.available() == 0)
107 | ;
108 |
109 | if (barometricSensor.begin(qwiic) == false)
110 | {
111 | Serial.println("MS8607 sensor did not respond. Trying again...");
112 | if (barometricSensor.begin(qwiic) == false)
113 | {
114 | Serial.println("MS8607 sensor did not respond. Please check wiring.");
115 | while(1)
116 | ;
117 | }
118 | }
119 | }
120 |
121 | void loop()
122 | {
123 | digitalWrite(LED, LOW);
124 |
125 | float temperature = barometricSensor.getTemperature();
126 | float pressure = barometricSensor.getPressure();
127 | float humidity = barometricSensor.getHumidity();
128 |
129 | Serial.print("Temperature=");
130 | Serial.print(temperature, 1);
131 | Serial.print("(C)");
132 |
133 | Serial.print(" Pressure=");
134 | Serial.print(pressure, 3);
135 | Serial.print("(hPa or mbar)");
136 |
137 |
138 | Serial.print(" Humidity=");
139 | Serial.print(humidity, 1);
140 | Serial.print("(%RH)");
141 |
142 | Serial.println();
143 |
144 | digitalWrite(LED, HIGH);
145 | delay(500);
146 | }
147 |
--------------------------------------------------------------------------------
/Software/examples/Example5_GNSS/Example5_GNSS.ino:
--------------------------------------------------------------------------------
1 | /*
2 | Artemis Global Tracker
3 | Example: GNSS
4 |
5 | Written by Paul Clark (PaulZC)
6 | August 7th 2021
7 |
8 | ** Updated for v2.1.0 of the Apollo3 core / Artemis board package **
9 | ** (At the time of writing, v2.1.1 of the core conatins a feature which makes communication with the u-blox GNSS problematic. Be sure to use v2.1.0) **
10 |
11 | ** Set the Board to "RedBoard Artemis ATP" **
12 | ** (The Artemis Module does not have a Wire port defined, which prevents the GNSS library from compiling) **
13 |
14 | This example powers up the ZOE-M8Q and reads the fix, latitude, longitude and altitude.
15 |
16 | You will need to install the SparkFun u-blox library before this example
17 | will run successfully:
18 | https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library
19 |
20 | The ZOE-M8Q shares I2C Port 1 with the MS8607: SCL = D8; SDA = D9
21 |
22 | Power for the ZOE is switched via Q2.
23 | D26 needs to be pulled low to enable the GNSS power.
24 |
25 | The ZOE's PIO14 pin (geofence signal) is conected to D10,
26 | so let's configure D10 as an input even though we aren't using it yet.
27 |
28 | To prevent bad tings happening to the AS179 RF antenna switch,
29 | D27 and D22 should also be pulled low to disable the 5.3V rail.
30 |
31 | */
32 |
33 | // Artemis Tracker pin definitions
34 | #define spiCS1 4 // D4 can be used as an SPI chip select or as a general purpose IO pin
35 | #define geofencePin 10 // Input for the ZOE-M8Q's PIO14 (geofence) pin
36 | #define busVoltagePin 13 // Bus voltage divided by 3 (Analog in)
37 | #define iridiumSleep 17 // Iridium 9603N ON/OFF (sleep) pin: pull high to enable the 9603N
38 | #define iridiumNA 18 // Input for the Iridium 9603N Network Available
39 | #define LED 19 // White LED
40 | #define iridiumPwrEN 22 // ADM4210 ON: pull high to enable power for the Iridium 9603N
41 | #define gnssEN 26 // GNSS Enable: pull low to enable power for the GNSS (via Q2)
42 | #define superCapChgEN 27 // LTC3225 super capacitor charger: pull high to enable the super capacitor charger
43 | #define superCapPGOOD 28 // Input for the LTC3225 super capacitor charger PGOOD signal
44 | #define busVoltageMonEN 34 // Bus voltage monitor enable: pull high to enable bus voltage monitoring (via Q4 and Q3)
45 | #define spiCS2 35 // D35 can be used as an SPI chip select or as a general purpose IO pin
46 | #define iridiumRI 41 // Input for the Iridium 9603N Ring Indicator
47 | // Make sure you do not have gnssEN and iridiumPwrEN enabled at the same time!
48 | // If you do, bad things might happen to the AS179 RF switch!
49 |
50 | #include // Needed for I2C
51 | const byte PIN_AGTWIRE_SCL = 8;
52 | const byte PIN_AGTWIRE_SDA = 9;
53 | TwoWire agtWire(PIN_AGTWIRE_SDA, PIN_AGTWIRE_SCL); //Create an I2C port using pads 8 (SCL) and 9 (SDA)
54 |
55 | #include "SparkFun_u-blox_GNSS_Arduino_Library.h" //http://librarymanager/All#SparkFun_u-blox_GNSS
56 | SFE_UBLOX_GNSS myGNSS;
57 |
58 | void gnssON(void) // Enable power for the GNSS
59 | {
60 | am_hal_gpio_pincfg_t pinCfg = g_AM_HAL_GPIO_OUTPUT; // Begin by making the gnssEN pin an open-drain output
61 | pinCfg.eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_OPENDRAIN;
62 | pin_config(PinName(gnssEN), pinCfg);
63 | delay(1);
64 |
65 | digitalWrite(gnssEN, LOW); // Enable GNSS power (HIGH = disable; LOW = enable)
66 | }
67 |
68 | void gnssOFF(void) // Disable power for the GNSS
69 | {
70 | am_hal_gpio_pincfg_t pinCfg = g_AM_HAL_GPIO_OUTPUT; // Begin by making the gnssEN pin an open-drain output
71 | pinCfg.eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_OPENDRAIN;
72 | pin_config(PinName(gnssEN), pinCfg);
73 | delay(1);
74 |
75 | digitalWrite(gnssEN, HIGH); // Disable GNSS power (HIGH = disable; LOW = enable)
76 | }
77 |
78 | void setup()
79 | {
80 | pinMode(LED, OUTPUT);
81 |
82 | pinMode(iridiumPwrEN, OUTPUT); // Configure the Iridium Power Pin (connected to the ADM4210 ON pin)
83 | digitalWrite(iridiumPwrEN, LOW); // Disable Iridium Power
84 | pinMode(superCapChgEN, OUTPUT); // Configure the super capacitor charger enable pin (connected to LTC3225 !SHDN)
85 | digitalWrite(superCapChgEN, LOW); // Disable the super capacitor charger
86 |
87 | gnssOFF(); // Disable power for the GNSS
88 | pinMode(geofencePin, INPUT); // Configure the geofence pin as an input
89 |
90 | // Set up the I2C pins
91 | agtWire.begin();
92 | agtWire.setClock(100000); // Use 100kHz for best performance
93 | setAGTWirePullups(0); // Remove the pull-ups from the I2C pins (internal to the Artemis) for best performance
94 |
95 | // Start the console serial port
96 | Serial.begin(115200);
97 | while (!Serial) // Wait for the user to open the serial monitor
98 | ;
99 | delay(100);
100 | Serial.println();
101 | Serial.println();
102 | Serial.println(F("Artemis Global Tracker"));
103 | Serial.println(F("Example: GNSS"));
104 | Serial.println();
105 |
106 | //empty the serial buffer
107 | while(Serial.available() > 0)
108 | Serial.read();
109 |
110 | //wait for the user to press any key before beginning
111 | Serial.println(F("Please check that the Serial Monitor is set to 115200 Baud"));
112 | Serial.println(F("and that the line ending is set to Newline."));
113 | Serial.println(F("Then click Send to start the example."));
114 | Serial.println();
115 | while(Serial.available() == 0)
116 | ;
117 |
118 | gnssON(); // Enable power for the GNSS
119 | delay(1000); // Let the ZOE power up
120 |
121 | if (myGNSS.begin(agtWire) == false) //Connect to the u-blox module using pads 8 & 9
122 | {
123 | Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
124 | while (1);
125 | }
126 |
127 | //myGNSS.factoryDefault(); delay(5000); // Uncomment this line to reset the ZOE-M8Q to the factory defaults
128 |
129 | //myGNSS.enableDebugging(); // Uncomment this line to enable helpful debug messages on Serial
130 |
131 | myGNSS.setI2COutput(COM_TYPE_UBX); // Limit I2C output to UBX (disable the NMEA noise)
132 | }
133 |
134 | void loop()
135 | {
136 | byte fixType = myGNSS.getFixType();
137 |
138 | Serial.print(F("Fix: "));
139 | if(fixType == 0) Serial.print(F("No fix"));
140 | else if(fixType == 1) Serial.print(F("Dead reckoning"));
141 | else if(fixType == 2) Serial.print(F("2D"));
142 | else if(fixType == 3) Serial.print(F("3D"));
143 | else if(fixType == 4) Serial.print(F("GNSS+Dead reckoning"));
144 |
145 | if(fixType > 0)
146 | {
147 | float latitude = (float)myGNSS.getLatitude() / 10000000.0; // Get the latitude in degrees
148 | Serial.print(F(" Lat: "));
149 | Serial.print(latitude,7);
150 |
151 | float longitude = (float)myGNSS.getLongitude() / 10000000.0; // Get the longitude in degrees
152 | Serial.print(F(" Long: "));
153 | Serial.print(longitude,7);
154 |
155 | float altitude = (float)myGNSS.getAltitudeMSL() / 1000.0; // Get the altitude above Mean Sea Level in m
156 | Serial.print(F(" Alt: "));
157 | Serial.print(altitude,2);
158 |
159 | digitalWrite(LED, HIGH);
160 | }
161 | else
162 | {
163 | digitalWrite(LED, LOW);
164 | }
165 |
166 | Serial.println();
167 | }
168 |
169 | void setAGTWirePullups(uint32_t i2cBusPullUps)
170 | {
171 | //Change SCL and SDA pull-ups manually using pin_config
172 | am_hal_gpio_pincfg_t sclPinCfg = g_AM_BSP_GPIO_IOM1_SCL;
173 | am_hal_gpio_pincfg_t sdaPinCfg = g_AM_BSP_GPIO_IOM1_SDA;
174 |
175 | if (i2cBusPullUps == 0)
176 | {
177 | sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_NONE; // No pull-ups
178 | sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_NONE;
179 | }
180 | else if (i2cBusPullUps == 1)
181 | {
182 | sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_1_5K; // Use 1K5 pull-ups
183 | sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_1_5K;
184 | }
185 | else if (i2cBusPullUps == 6)
186 | {
187 | sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_6K; // Use 6K pull-ups
188 | sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_6K;
189 | }
190 | else if (i2cBusPullUps == 12)
191 | {
192 | sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_12K; // Use 12K pull-ups
193 | sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_12K;
194 | }
195 | else
196 | {
197 | sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_24K; // Use 24K pull-ups
198 | sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_24K;
199 | }
200 |
201 | pin_config(PinName(PIN_AGTWIRE_SCL), sclPinCfg);
202 | pin_config(PinName(PIN_AGTWIRE_SDA), sdaPinCfg);
203 | }
204 |
--------------------------------------------------------------------------------
/Software/examples/Example6_Geofence/Example6_Geofence.ino:
--------------------------------------------------------------------------------
1 | /*
2 | Artemis Global Tracker
3 | Example: Geofence
4 |
5 | Written by Paul Clark (PaulZC)
6 | August 7th 2021
7 |
8 | ** Updated for v2.1.0 of the Apollo3 core / Artemis board package **
9 | ** (At the time of writing, v2.1.1 of the core conatins a feature which makes communication with the u-blox GNSS problematic. Be sure to use v2.1.0) **
10 |
11 | ** Set the Board to "RedBoard Artemis ATP" **
12 | ** (The Artemis Module does not have a Wire port defined, which prevents the GNSS library from compiling) **
13 |
14 | This example powers up the ZOE-M8Q and reads the fix.
15 | Once a valid 3D fix has been found, the code reads the latitude and longitude.
16 | The code then sets four geofences around that position with a radii of 5m, 10m, 15m and 20m with 95% confidence.
17 | The code then monitors the geofence status.
18 | The LED will be illuminated if you are inside the _combined_ geofence (i.e. within the 20m radius).
19 | If you disconnect the antenna: the status should go unknown, the geofencePin will go high and the LED will go out.
20 |
21 | You will need to install the SparkFun u-blox library before this example
22 | will run successfully:
23 | https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library
24 |
25 | The ZOE-M8Q shares I2C Port 1 with the MS8607: SCL = D8; SDA = D9
26 |
27 | Power for the ZOE is switched via Q2.
28 | D26 needs to be pulled low to enable the GNSS power.
29 |
30 | The ZOE's PIO14 pin (geofence signal) is conected to D10,
31 | so let's configure D10 as an input.
32 |
33 | To prevent bad tings happening to the AS179 RF antenna switch,
34 | D27 and D22 should also be pulled low to disable the 5.3V rail.
35 |
36 | */
37 |
38 | // Artemis Tracker pin definitions
39 | #define spiCS1 4 // D4 can be used as an SPI chip select or as a general purpose IO pin
40 | #define geofencePin 10 // Input for the ZOE-M8Q's PIO14 (geofence) pin
41 | #define busVoltagePin 13 // Bus voltage divided by 3 (Analog in)
42 | #define iridiumSleep 17 // Iridium 9603N ON/OFF (sleep) pin: pull high to enable the 9603N
43 | #define iridiumNA 18 // Input for the Iridium 9603N Network Available
44 | #define LED 19 // White LED
45 | #define iridiumPwrEN 22 // ADM4210 ON: pull high to enable power for the Iridium 9603N
46 | #define gnssEN 26 // GNSS Enable: pull low to enable power for the GNSS (via Q2)
47 | #define superCapChgEN 27 // LTC3225 super capacitor charger: pull high to enable the super capacitor charger
48 | #define superCapPGOOD 28 // Input for the LTC3225 super capacitor charger PGOOD signal
49 | #define busVoltageMonEN 34 // Bus voltage monitor enable: pull high to enable bus voltage monitoring (via Q4 and Q3)
50 | #define spiCS2 35 // D35 can be used as an SPI chip select or as a general purpose IO pin
51 | #define iridiumRI 41 // Input for the Iridium 9603N Ring Indicator
52 | // Make sure you do not have gnssEN and iridiumPwrEN enabled at the same time!
53 | // If you do, bad things might happen to the AS179 RF switch!
54 |
55 | #include // Needed for I2C
56 | const byte PIN_AGTWIRE_SCL = 8;
57 | const byte PIN_AGTWIRE_SDA = 9;
58 | TwoWire agtWire(PIN_AGTWIRE_SDA, PIN_AGTWIRE_SCL); //Create an I2C port using pads 8 (SCL) and 9 (SDA)
59 |
60 | #include "SparkFun_u-blox_GNSS_Arduino_Library.h" //http://librarymanager/All#SparkFun_u-blox_GNSS
61 | SFE_UBLOX_GNSS myGNSS;
62 |
63 | void gnssON(void) // Enable power for the GNSS
64 | {
65 | am_hal_gpio_pincfg_t pinCfg = g_AM_HAL_GPIO_OUTPUT; // Begin by making the gnssEN pin an open-drain output
66 | pinCfg.eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_OPENDRAIN;
67 | pin_config(PinName(gnssEN), pinCfg);
68 | delay(1);
69 |
70 | digitalWrite(gnssEN, LOW); // Enable GNSS power (HIGH = disable; LOW = enable)
71 | }
72 |
73 | void gnssOFF(void) // Disable power for the GNSS
74 | {
75 | am_hal_gpio_pincfg_t pinCfg = g_AM_HAL_GPIO_OUTPUT; // Begin by making the gnssEN pin an open-drain output
76 | pinCfg.eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_OPENDRAIN;
77 | pin_config(PinName(gnssEN), pinCfg);
78 | delay(1);
79 |
80 | digitalWrite(gnssEN, HIGH); // Disable GNSS power (HIGH = disable; LOW = enable)
81 | }
82 |
83 | void setup()
84 | {
85 | pinMode(LED, OUTPUT);
86 |
87 | pinMode(iridiumPwrEN, OUTPUT); // Configure the Iridium Power Pin (connected to the ADM4210 ON pin)
88 | digitalWrite(iridiumPwrEN, LOW); // Disable Iridium Power
89 | pinMode(superCapChgEN, OUTPUT); // Configure the super capacitor charger enable pin (connected to LTC3225 !SHDN)
90 | digitalWrite(superCapChgEN, LOW); // Disable the super capacitor charger
91 |
92 | gnssOFF(); // Disable power for the GNSS
93 | pinMode(geofencePin, INPUT); // Configure the geofence pin as an input
94 |
95 | // Set up the I2C pins
96 | agtWire.begin();
97 | agtWire.setClock(100000); // Use 100kHz for best performance
98 | setAGTWirePullups(0); // Remove the pull-ups from the I2C pins (internal to the Artemis) for best performance
99 |
100 | // Start the console serial port
101 | Serial.begin(115200);
102 | while (!Serial) // Wait for the user to open the serial monitor
103 | ;
104 | delay(100);
105 | Serial.println();
106 | Serial.println();
107 | Serial.println(F("Artemis Global Tracker"));
108 | Serial.println(F("Example: Geofence"));
109 | Serial.println();
110 |
111 | //empty the serial buffer
112 | while(Serial.available() > 0)
113 | Serial.read();
114 |
115 | //wait for the user to press any key before beginning
116 | Serial.println(F("Please check that the Serial Monitor is set to 115200 Baud"));
117 | Serial.println(F("and that the line ending is set to Newline."));
118 | Serial.println(F("Then click Send to start the example."));
119 | Serial.println();
120 | while(Serial.available() == 0)
121 | ;
122 |
123 | gnssON(); // Enable power for the GNSS
124 | delay(1000); // Let the ZOE power up
125 |
126 | if (myGNSS.begin(agtWire) == false) //Connect to the u-blox module using pads 8 & 9
127 | {
128 | Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
129 | while (1)
130 | ;
131 | }
132 |
133 | //myGNSS.enableDebugging(); // Uncomment this line to enable helpful debug messages on Serial
134 |
135 | myGNSS.setI2COutput(COM_TYPE_UBX); // Limit I2C output to UBX (disable the NMEA noise)
136 |
137 | Serial.println(F("Waiting for a 3D fix..."));
138 |
139 | byte fixType = 0;
140 |
141 | while (fixType != 3) // Wait for a 3D fix
142 | {
143 | fixType = myGNSS.getFixType(); // Get the fix type
144 | Serial.print(F("Fix: "));
145 | Serial.print(fixType);
146 | if(fixType == 0) Serial.print(F(" = No fix"));
147 | else if(fixType == 1) Serial.print(F(" = Dead reckoning"));
148 | else if(fixType == 2) Serial.print(F(" = 2D"));
149 | else if(fixType == 3) Serial.print(F(" = 3D"));
150 | else if(fixType == 4) Serial.print(F(" = GNSS + Dead reckoning"));
151 | Serial.println();
152 | delay(1000);
153 | }
154 |
155 | Serial.println(F("3D fix found! Setting the geofence..."));
156 |
157 | long latitude = myGNSS.getLatitude(); // Get the latitude in degrees * 10^-7
158 | Serial.print(F("Lat: "));
159 | Serial.print(latitude);
160 |
161 | long longitude = myGNSS.getLongitude(); // Get the longitude in degrees * 10^-7
162 | Serial.print(F(" Long: "));
163 | Serial.println(longitude);
164 |
165 | uint32_t radius = 500; // Set the radius to 5m (radius is in m * 10^-2 i.e. cm)
166 | byte confidence = 2; // Set the confidence level: 0=none, 1=68%, 2=95%, 3=99.7%, 4=99.99%
167 | byte pinPolarity = 0; // Set the PIO pin polarity: 0 = low means inside, 1 = low means outside (or unknown)
168 | byte pin = 14; // ZOE-M8Q PIO14 is connected to the geofencePin
169 |
170 | // Call clearGeofences() to clear all existing geofences.
171 | Serial.print(F("Clearing any existing geofences. clearGeofences returned: "));
172 | Serial.println(myGNSS.clearGeofences());
173 |
174 | // It is possible to define up to four geofences.
175 | // Call addGeofence up to four times to define them.
176 | // The geofencePin will indicate the combined state of all active geofences.
177 | Serial.println(F("Setting the geofences:"));
178 |
179 | Serial.print(F("addGeofence for geofence 1 returned: "));
180 | Serial.println(myGNSS.addGeofence(latitude, longitude, radius, confidence, pinPolarity, pin));
181 |
182 | radius = 1000; // 10m
183 | Serial.print(F("addGeofence for geofence 2 returned: "));
184 | Serial.println(myGNSS.addGeofence(latitude, longitude, radius, confidence, pinPolarity, pin));
185 |
186 | radius = 1500; // 15m
187 | Serial.print(F("addGeofence for geofence 3 returned: "));
188 | Serial.println(myGNSS.addGeofence(latitude, longitude, radius, confidence, pinPolarity, pin));
189 |
190 | radius = 2000; // 20m
191 | Serial.print(F("addGeofence for geofence 4 returned: "));
192 | Serial.println(myGNSS.addGeofence(latitude, longitude, radius, confidence, pinPolarity, pin));
193 | }
194 |
195 | void loop()
196 | {
197 | geofenceState currentGeofenceState; // Create storage for the geofence state
198 |
199 | boolean result = myGNSS.getGeofenceState(currentGeofenceState);
200 |
201 | Serial.print(F("getGeofenceState returned: ")); // Print the combined state
202 | Serial.print(result); // Get the geofence state
203 |
204 | if (!result) // If getGeofenceState did not return true
205 | {
206 | Serial.println(F(".")); // Tidy up
207 | return; // and go round the loop again
208 | }
209 |
210 | // Print the Geofencing status
211 | // 0 - Geofencing not available or not reliable; 1 - Geofencing active
212 | Serial.print(F(". status is: "));
213 | Serial.print(currentGeofenceState.status);
214 |
215 | // Print the numFences
216 | Serial.print(F(". numFences is: "));
217 | Serial.print(currentGeofenceState.numFences);
218 |
219 | // Print the combined state
220 | // Combined (logical OR) state of all geofences: 0 - Unknown; 1 - Inside; 2 - Outside
221 | Serial.print(F(". combState is: "));
222 | Serial.print(currentGeofenceState.combState);
223 |
224 | // Print the state of each geofence
225 | // 0 - Unknown; 1 - Inside; 2 - Outside
226 | Serial.print(F(". The individual states are: "));
227 | for(int i = 0; i < currentGeofenceState.numFences; i++)
228 | {
229 | if (i > 0) Serial.print(F(","));
230 | Serial.print(currentGeofenceState.states[i]);
231 | }
232 |
233 | byte fenceStatus = digitalRead(geofencePin); // Read the geofence pin
234 | digitalWrite(LED, !fenceStatus); // Set the LED (inverted)
235 | Serial.print(F(". Geofence pin (PIO14) is: ")); // Print the pin state
236 | Serial.print(fenceStatus);
237 | Serial.println(F("."));
238 |
239 | delay(1000);
240 | }
241 |
242 | void setAGTWirePullups(uint32_t i2cBusPullUps)
243 | {
244 | //Change SCL and SDA pull-ups manually using pin_config
245 | am_hal_gpio_pincfg_t sclPinCfg = g_AM_BSP_GPIO_IOM1_SCL;
246 | am_hal_gpio_pincfg_t sdaPinCfg = g_AM_BSP_GPIO_IOM1_SDA;
247 |
248 | if (i2cBusPullUps == 0)
249 | {
250 | sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_NONE; // No pull-ups
251 | sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_NONE;
252 | }
253 | else if (i2cBusPullUps == 1)
254 | {
255 | sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_1_5K; // Use 1K5 pull-ups
256 | sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_1_5K;
257 | }
258 | else if (i2cBusPullUps == 6)
259 | {
260 | sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_6K; // Use 6K pull-ups
261 | sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_6K;
262 | }
263 | else if (i2cBusPullUps == 12)
264 | {
265 | sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_12K; // Use 12K pull-ups
266 | sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_12K;
267 | }
268 | else
269 | {
270 | sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_24K; // Use 24K pull-ups
271 | sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_24K;
272 | }
273 |
274 | pin_config(PinName(PIN_AGTWIRE_SCL), sclPinCfg);
275 | pin_config(PinName(PIN_AGTWIRE_SDA), sdaPinCfg);
276 | }
277 |
--------------------------------------------------------------------------------
/Software/examples/Example7_GetIMEI/Example7_GetIMEI.ino:
--------------------------------------------------------------------------------
1 | /*
2 | Artemis Global Tracker
3 | Example: GetIMEI
4 |
5 | Written by Paul Clark (PaulZC)
6 | September 7th 2021
7 |
8 | ** Updated for v2.1.0 of the Apollo3 core / Artemis board package **
9 | ** (At the time of writing, v2.1.1 of the core conatins a feature which makes communication with the u-blox GNSS problematic. Be sure to use v2.1.0) **
10 |
11 | ** Set the Board to "RedBoard Artemis ATP" **
12 | ** (The Artemis Module does not have a Wire port defined, which prevents the IridiumSBD library from compiling) **
13 |
14 | This example powers up the Iridium 9603N and reads its IMEI.
15 | You do not need message credits or line rental to run this example.
16 |
17 | You will need to install version 3.0.5 of the Iridium SBD I2C library
18 | before this example will run successfully:
19 | https://github.com/sparkfun/SparkFun_IridiumSBD_I2C_Arduino_Library
20 | (Available through the Arduino Library Manager: search for IridiumSBDi2c)
21 |
22 | Power for the 9603N is provided by the LTC3225 super capacitor charger.
23 | D27 needs to be pulled high to enable the charger.
24 | The LTC3225 PGOOD signal is connected to D28.
25 |
26 | Power for the 9603N is switched by the ADM4210 inrush current limiter.
27 | D22 needs to be pulled high to enable power for the 9603N.
28 |
29 | The 9603N itself is enabled via its ON/OFF (SLEEP) pin which is connected
30 | to D17. Pull high - via the IridiumSBD library - to enable the 9603N.
31 |
32 | The 9603N's Network Available signal is conected to D18,
33 | so let's configure D18 as an input.
34 |
35 | The 9603N's Ring Indicator is conected to D41,
36 | so let's configure D41 as an input.
37 |
38 | To prevent bad tings happening to the AS179 RF antenna switch,
39 | D26 needs to be pulled high to disable the GNSS power.
40 |
41 | */
42 |
43 | // Artemis Tracker pin definitions
44 | #define spiCS1 4 // D4 can be used as an SPI chip select or as a general purpose IO pin
45 | #define geofencePin 10 // Input for the ZOE-M8Q's PIO14 (geofence) pin
46 | #define busVoltagePin 13 // Bus voltage divided by 3 (Analog in)
47 | #define iridiumSleep 17 // Iridium 9603N ON/OFF (sleep) pin: pull high to enable the 9603N
48 | #define iridiumNA 18 // Input for the Iridium 9603N Network Available
49 | #define LED 19 // White LED
50 | #define iridiumPwrEN 22 // ADM4210 ON: pull high to enable power for the Iridium 9603N
51 | #define gnssEN 26 // GNSS Enable: pull low to enable power for the GNSS (via Q2)
52 | #define superCapChgEN 27 // LTC3225 super capacitor charger: pull high to enable the super capacitor charger
53 | #define superCapPGOOD 28 // Input for the LTC3225 super capacitor charger PGOOD signal
54 | #define busVoltageMonEN 34 // Bus voltage monitor enable: pull high to enable bus voltage monitoring (via Q4 and Q3)
55 | #define spiCS2 35 // D35 can be used as an SPI chip select or as a general purpose IO pin
56 | #define iridiumRI 41 // Input for the Iridium 9603N Ring Indicator
57 | // Make sure you do not have gnssEN and iridiumPwrEN enabled at the same time!
58 | // If you do, bad things might happen to the AS179 RF switch!
59 |
60 | // We use Serial1 to communicate with the Iridium modem. Serial1 on the ATP uses pin 24 for TX and 25 for RX. AGT uses the same pins.
61 |
62 | #include //http://librarymanager/All#IridiumSBDI2C
63 | #define DIAGNOSTICS false // Change this to true to see IridiumSBD diagnostics
64 | // Declare the IridiumSBD object (including the sleep (ON/OFF) and Ring Indicator pins)
65 | IridiumSBD modem(Serial1, iridiumSleep, iridiumRI);
66 |
67 | void gnssON(void) // Enable power for the GNSS
68 | {
69 | am_hal_gpio_pincfg_t pinCfg = g_AM_HAL_GPIO_OUTPUT; // Begin by making the gnssEN pin an open-drain output
70 | pinCfg.eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_OPENDRAIN;
71 | pin_config(PinName(gnssEN), pinCfg);
72 | delay(1);
73 |
74 | digitalWrite(gnssEN, LOW); // Enable GNSS power (HIGH = disable; LOW = enable)
75 | }
76 |
77 | void gnssOFF(void) // Disable power for the GNSS
78 | {
79 | am_hal_gpio_pincfg_t pinCfg = g_AM_HAL_GPIO_OUTPUT; // Begin by making the gnssEN pin an open-drain output
80 | pinCfg.eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_OPENDRAIN;
81 | pin_config(PinName(gnssEN), pinCfg);
82 | delay(1);
83 |
84 | digitalWrite(gnssEN, HIGH); // Disable GNSS power (HIGH = disable; LOW = enable)
85 | }
86 |
87 | // Overwrite the IridiumSBD beginSerialPort function - a fix for https://github.com/sparkfun/Arduino_Apollo3/issues/423
88 | void IridiumSBD::beginSerialPort() // Start the serial port connected to the satellite modem
89 | {
90 | diagprint(F("custom IridiumSBD::beginSerialPort\r\n"));
91 |
92 | // Configure the standard ATP pins for UART1 TX and RX - endSerialPort may have disabled the RX pin
93 |
94 | am_hal_gpio_pincfg_t pinConfigTx = g_AM_BSP_GPIO_COM_UART_TX;
95 | pinConfigTx.uFuncSel = AM_HAL_PIN_24_UART1TX;
96 | pin_config(D24, pinConfigTx);
97 |
98 | am_hal_gpio_pincfg_t pinConfigRx = g_AM_BSP_GPIO_COM_UART_RX;
99 | pinConfigRx.uFuncSel = AM_HAL_PIN_25_UART1RX;
100 | pinConfigRx.ePullup = AM_HAL_GPIO_PIN_PULLUP_WEAK; // Put a weak pull-up on the Rx pin
101 | pin_config(D25, pinConfigRx);
102 |
103 | Serial1.begin(19200);
104 | }
105 |
106 | // Overwrite the IridiumSBD endSerialPort function - a fix for https://github.com/sparkfun/Arduino_Apollo3/issues/423
107 | void IridiumSBD::endSerialPort()
108 | {
109 | diagprint(F("custom IridiumSBD::endSerialPort\r\n"));
110 |
111 | // Disable the Serial1 RX pin to avoid the code hang
112 | am_hal_gpio_pinconfig(PinName(D25), g_AM_HAL_GPIO_DISABLE);
113 | }
114 |
115 | void setup()
116 | {
117 | int signalQuality = -1;
118 | int err;
119 |
120 | pinMode(LED, OUTPUT); // Make the LED pin an output
121 |
122 | gnssOFF(); // Disable power for the GNSS
123 | pinMode(geofencePin, INPUT); // Configure the geofence pin as an input
124 |
125 | pinMode(iridiumPwrEN, OUTPUT); // Configure the Iridium Power Pin (connected to the ADM4210 ON pin)
126 | digitalWrite(iridiumPwrEN, LOW); // Disable Iridium Power (HIGH = enable; LOW = disable)
127 | pinMode(superCapChgEN, OUTPUT); // Configure the super capacitor charger enable pin (connected to LTC3225 !SHDN)
128 | digitalWrite(superCapChgEN, LOW); // Disable the super capacitor charger (HIGH = enable; LOW = disable)
129 | pinMode(iridiumSleep, OUTPUT); // Iridium 9603N On/Off (Sleep) pin
130 | digitalWrite(iridiumSleep, LOW); // Put the Iridium 9603N to sleep (HIGH = on; LOW = off/sleep)
131 | pinMode(iridiumRI, INPUT); // Configure the Iridium Ring Indicator as an input
132 | pinMode(iridiumNA, INPUT); // Configure the Iridium Network Available as an input
133 | pinMode(superCapPGOOD, INPUT); // Configure the super capacitor charger PGOOD input
134 |
135 | // Make sure the Serial1 RX pin is disabled to prevent the power-on glitch on the modem's RX(OUT) pin
136 | // causing problems with v2.1.0 of the Apollo3 core. Requires v3.0.5 of IridiumSBDi2c.
137 | modem.endSerialPort();
138 |
139 | // Start the console serial port
140 | Serial.begin(115200);
141 | while (!Serial) // Wait for the user to open the serial monitor
142 | ;
143 | delay(100);
144 | Serial.println();
145 | Serial.println();
146 | Serial.println(F("Artemis Global Tracker"));
147 | Serial.println(F("Example: Get IMEI"));
148 | Serial.println();
149 |
150 | //empty the serial buffer
151 | while(Serial.available() > 0)
152 | Serial.read();
153 |
154 | //wait for the user to press any key before beginning
155 | Serial.println(F("Please check that the Serial Monitor is set to 115200 Baud"));
156 | Serial.println(F("and that the line ending is set to Newline."));
157 | Serial.println(F("Then click Send to start the example."));
158 | Serial.println();
159 | while(Serial.available() == 0)
160 | ;
161 |
162 | // Enable the supercapacitor charger
163 | Serial.println(F("Enabling the supercapacitor charger..."));
164 | digitalWrite(superCapChgEN, HIGH); // Enable the super capacitor charger
165 | delay(1000);
166 |
167 | // Wait for the supercapacitor charger PGOOD signal to go high
168 | while (digitalRead(superCapPGOOD) == false)
169 | {
170 | Serial.println(F("Waiting for supercapacitors to charge..."));
171 | delay(1000);
172 | }
173 | Serial.println(F("Supercapacitors charged!"));
174 |
175 | // Enable power for the 9603N
176 | Serial.println(F("Enabling 9603N power..."));
177 | digitalWrite(iridiumPwrEN, HIGH); // Enable Iridium Power
178 | delay(1000);
179 |
180 | // Begin satellite modem operation
181 | // Also begin the serial port connected to the satellite modem via IridiumSBD::beginSerialPort
182 | Serial.println(F("Starting modem..."));
183 | err = modem.begin();
184 | if (err != ISBD_SUCCESS)
185 | {
186 | Serial.print(F("Begin failed: error "));
187 | Serial.println(err);
188 | if (err == ISBD_NO_MODEM_DETECTED)
189 | Serial.println(F("No modem detected: check wiring."));
190 | return;
191 | }
192 |
193 | // Get the IMEI
194 | char IMEI[16];
195 | err = modem.getIMEI(IMEI, sizeof(IMEI));
196 | if (err != ISBD_SUCCESS)
197 | {
198 | Serial.print(F("getIMEI failed: error "));
199 | Serial.println(err);
200 | return;
201 | }
202 | Serial.print(F("IMEI is "));
203 | Serial.print(IMEI);
204 | Serial.println(F("."));
205 |
206 | // Power down the modem
207 | // Also disable the Serial1 RX pin via IridiumSBD::endSerialPort
208 | Serial.println(F("Putting the 9603N to sleep."));
209 | err = modem.sleep();
210 | if (err != ISBD_SUCCESS)
211 | {
212 | Serial.print(F("sleep failed: error "));
213 | Serial.println(err);
214 | }
215 |
216 | // Disable 9603N power
217 | Serial.println(F("Disabling 9603N power..."));
218 | digitalWrite(iridiumPwrEN, LOW); // Disable Iridium Power
219 |
220 | // Disable the supercapacitor charger
221 | Serial.println(F("Disabling the supercapacitor charger..."));
222 | digitalWrite(superCapChgEN, LOW); // Disable the super capacitor charger
223 |
224 | Serial.println(F("Done!"));
225 |
226 | }
227 |
228 | void loop()
229 | {
230 | }
231 |
232 | #if DIAGNOSTICS
233 | void ISBDConsoleCallback(IridiumSBD *device, char c)
234 | {
235 | Serial.write(c);
236 | }
237 |
238 | void ISBDDiagsCallback(IridiumSBD *device, char c)
239 | {
240 | Serial.write(c);
241 | }
242 | #endif
243 |
--------------------------------------------------------------------------------
/Software/examples/Example8_CheckCSQ/Example8_CheckCSQ.ino:
--------------------------------------------------------------------------------
1 | /*
2 | Artemis Global Tracker
3 | Example: CheckCSQ
4 |
5 | Written by Paul Clark (PaulZC)
6 | September 7th 2021
7 |
8 | ** Updated for v2.1.0 of the Apollo3 core / Artemis board package **
9 | ** (At the time of writing, v2.1.1 of the core conatins a feature which makes communication with the u-blox GNSS problematic. Be sure to use v2.1.0) **
10 |
11 | ** Set the Board to "RedBoard Artemis ATP" **
12 | ** (The Artemis Module does not have a Wire port defined, which prevents the IridiumSBD library from compiling) **
13 |
14 | This example powers up the Iridium 9603N and reads the signal quality.
15 | You do not need message credits or line rental to run this example.
16 |
17 | You will need to install version 3.0.5 of the Iridium SBD I2C library
18 | before this example will run successfully:
19 | https://github.com/sparkfun/SparkFun_IridiumSBD_I2C_Arduino_Library
20 | (Available through the Arduino Library Manager: search for IridiumSBDi2c)
21 |
22 | Power for the 9603N is provided by the LTC3225 super capacitor charger.
23 | D27 needs to be pulled high to enable the charger.
24 | The LTC3225 PGOOD signal is connected to D28.
25 |
26 | Power for the 9603N is switched by the ADM4210 inrush current limiter.
27 | D22 needs to be pulled high to enable power for the 9603N.
28 |
29 | The 9603N itself is enabled via its ON/OFF (SLEEP) pin which is connected
30 | to D17. Pull high - via the IridiumSBD library - to enable the 9603N.
31 |
32 | The 9603N's Network Available signal is conected to D18,
33 | so let's configure D18 as an input.
34 |
35 | The 9603N's Ring Indicator is conected to D41,
36 | so let's configure D41 as an input.
37 |
38 | To prevent bad tings happening to the AS179 RF antenna switch,
39 | D26 needs to be pulled high to disable the GNSS power.
40 |
41 | */
42 |
43 | // Artemis Tracker pin definitions
44 | #define spiCS1 4 // D4 can be used as an SPI chip select or as a general purpose IO pin
45 | #define geofencePin 10 // Input for the ZOE-M8Q's PIO14 (geofence) pin
46 | #define busVoltagePin 13 // Bus voltage divided by 3 (Analog in)
47 | #define iridiumSleep 17 // Iridium 9603N ON/OFF (sleep) pin: pull high to enable the 9603N
48 | #define iridiumNA 18 // Input for the Iridium 9603N Network Available
49 | #define LED 19 // White LED
50 | #define iridiumPwrEN 22 // ADM4210 ON: pull high to enable power for the Iridium 9603N
51 | #define gnssEN 26 // GNSS Enable: pull low to enable power for the GNSS (via Q2)
52 | #define superCapChgEN 27 // LTC3225 super capacitor charger: pull high to enable the super capacitor charger
53 | #define superCapPGOOD 28 // Input for the LTC3225 super capacitor charger PGOOD signal
54 | #define busVoltageMonEN 34 // Bus voltage monitor enable: pull high to enable bus voltage monitoring (via Q4 and Q3)
55 | #define spiCS2 35 // D35 can be used as an SPI chip select or as a general purpose IO pin
56 | #define iridiumRI 41 // Input for the Iridium 9603N Ring Indicator
57 | // Make sure you do not have gnssEN and iridiumPwrEN enabled at the same time!
58 | // If you do, bad things might happen to the AS179 RF switch!
59 |
60 | // We use Serial1 to communicate with the Iridium modem. Serial1 on the ATP uses pin 24 for TX and 25 for RX. AGT uses the same pins.
61 |
62 | #include //http://librarymanager/All#IridiumSBDI2C
63 | #define DIAGNOSTICS false // Change this to true to see IridiumSBD diagnostics
64 | // Declare the IridiumSBD object (including the sleep (ON/OFF) and Ring Indicator pins)
65 | IridiumSBD modem(Serial1, iridiumSleep, iridiumRI);
66 |
67 | void gnssON(void) // Enable power for the GNSS
68 | {
69 | am_hal_gpio_pincfg_t pinCfg = g_AM_HAL_GPIO_OUTPUT; // Begin by making the gnssEN pin an open-drain output
70 | pinCfg.eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_OPENDRAIN;
71 | pin_config(PinName(gnssEN), pinCfg);
72 | delay(1);
73 |
74 | digitalWrite(gnssEN, LOW); // Enable GNSS power (HIGH = disable; LOW = enable)
75 | }
76 |
77 | void gnssOFF(void) // Disable power for the GNSS
78 | {
79 | am_hal_gpio_pincfg_t pinCfg = g_AM_HAL_GPIO_OUTPUT; // Begin by making the gnssEN pin an open-drain output
80 | pinCfg.eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_OPENDRAIN;
81 | pin_config(PinName(gnssEN), pinCfg);
82 | delay(1);
83 |
84 | digitalWrite(gnssEN, HIGH); // Disable GNSS power (HIGH = disable; LOW = enable)
85 | }
86 |
87 | // Overwrite the IridiumSBD beginSerialPort function - a fix for https://github.com/sparkfun/Arduino_Apollo3/issues/423
88 | void IridiumSBD::beginSerialPort() // Start the serial port connected to the satellite modem
89 | {
90 | diagprint(F("custom IridiumSBD::beginSerialPort\r\n"));
91 |
92 | // Configure the standard ATP pins for UART1 TX and RX - endSerialPort may have disabled the RX pin
93 |
94 | am_hal_gpio_pincfg_t pinConfigTx = g_AM_BSP_GPIO_COM_UART_TX;
95 | pinConfigTx.uFuncSel = AM_HAL_PIN_24_UART1TX;
96 | pin_config(D24, pinConfigTx);
97 |
98 | am_hal_gpio_pincfg_t pinConfigRx = g_AM_BSP_GPIO_COM_UART_RX;
99 | pinConfigRx.uFuncSel = AM_HAL_PIN_25_UART1RX;
100 | pinConfigRx.ePullup = AM_HAL_GPIO_PIN_PULLUP_WEAK; // Put a weak pull-up on the Rx pin
101 | pin_config(D25, pinConfigRx);
102 |
103 | Serial1.begin(19200);
104 | }
105 |
106 | // Overwrite the IridiumSBD endSerialPort function - a fix for https://github.com/sparkfun/Arduino_Apollo3/issues/423
107 | void IridiumSBD::endSerialPort()
108 | {
109 | diagprint(F("custom IridiumSBD::endSerialPort\r\n"));
110 |
111 | // Disable the Serial1 RX pin to avoid the code hang
112 | am_hal_gpio_pinconfig(PinName(D25), g_AM_HAL_GPIO_DISABLE);
113 | }
114 |
115 | void setup()
116 | {
117 | int signalQuality = -1;
118 | int err;
119 |
120 | pinMode(LED, OUTPUT); // Make the LED pin an output
121 |
122 | gnssOFF(); // Disable power for the GNSS
123 | pinMode(geofencePin, INPUT); // Configure the geofence pin as an input
124 |
125 | pinMode(iridiumPwrEN, OUTPUT); // Configure the Iridium Power Pin (connected to the ADM4210 ON pin)
126 | digitalWrite(iridiumPwrEN, LOW); // Disable Iridium Power (HIGH = enable; LOW = disable)
127 | pinMode(superCapChgEN, OUTPUT); // Configure the super capacitor charger enable pin (connected to LTC3225 !SHDN)
128 | digitalWrite(superCapChgEN, LOW); // Disable the super capacitor charger (HIGH = enable; LOW = disable)
129 | pinMode(iridiumSleep, OUTPUT); // Iridium 9603N On/Off (Sleep) pin
130 | digitalWrite(iridiumSleep, LOW); // Put the Iridium 9603N to sleep (HIGH = on; LOW = off/sleep)
131 | pinMode(iridiumRI, INPUT); // Configure the Iridium Ring Indicator as an input
132 | pinMode(iridiumNA, INPUT); // Configure the Iridium Network Available as an input
133 | pinMode(superCapPGOOD, INPUT); // Configure the super capacitor charger PGOOD input
134 |
135 | // Make sure the Serial1 RX pin is disabled to prevent the power-on glitch on the modem's RX(OUT) pin
136 | // causing problems with v2.1.0 of the Apollo3 core. Requires v3.0.5 of IridiumSBDi2c.
137 | modem.endSerialPort();
138 |
139 | // Start the console serial port
140 | Serial.begin(115200);
141 | while (!Serial) // Wait for the user to open the serial monitor
142 | ;
143 | delay(100);
144 | Serial.println();
145 | Serial.println();
146 | Serial.println(F("Artemis Global Tracker"));
147 | Serial.println(F("Example: Check CSQ"));
148 | Serial.println();
149 |
150 | //empty the serial buffer
151 | while(Serial.available() > 0)
152 | Serial.read();
153 |
154 | //wait for the user to press any key before beginning
155 | Serial.println(F("Please check that the Serial Monitor is set to 115200 Baud"));
156 | Serial.println(F("and that the line ending is set to Newline."));
157 | Serial.println(F("Then click Send to start the example."));
158 | Serial.println();
159 | while(Serial.available() == 0)
160 | ;
161 |
162 | // Enable the supercapacitor charger
163 | Serial.println(F("Enabling the supercapacitor charger..."));
164 | digitalWrite(superCapChgEN, HIGH); // Enable the super capacitor charger
165 | delay(1000);
166 |
167 | // Wait for the supercapacitor charger PGOOD signal to go high
168 | while (digitalRead(superCapPGOOD) == false)
169 | {
170 | Serial.println(F("Waiting for supercapacitors to charge..."));
171 | delay(1000);
172 | }
173 | Serial.println(F("Supercapacitors charged!"));
174 |
175 | // Enable power for the 9603N
176 | Serial.println(F("Enabling 9603N power..."));
177 | digitalWrite(iridiumPwrEN, HIGH); // Enable Iridium Power
178 | delay(1000);
179 |
180 | // Begin satellite modem operation
181 | // Also begin the serial port connected to the satellite modem via IridiumSBD::beginSerialPort
182 | Serial.println(F("Starting modem..."));
183 | err = modem.begin();
184 | if (err != ISBD_SUCCESS)
185 | {
186 | Serial.print(F("Begin failed: error "));
187 | Serial.println(err);
188 | if (err == ISBD_NO_MODEM_DETECTED)
189 | Serial.println(F("No modem detected: check wiring."));
190 | return;
191 | }
192 |
193 | // Print the firmware revision
194 | char version[12];
195 | err = modem.getFirmwareVersion(version, sizeof(version));
196 | if (err != ISBD_SUCCESS)
197 | {
198 | Serial.print(F("FirmwareVersion failed: error "));
199 | Serial.println(err);
200 | return;
201 | }
202 | Serial.print(F("Firmware Version is "));
203 | Serial.print(version);
204 | Serial.println(F("."));
205 |
206 | // Get the IMEI
207 | char IMEI[16];
208 | err = modem.getIMEI(IMEI, sizeof(IMEI));
209 | if (err != ISBD_SUCCESS)
210 | {
211 | Serial.print(F("getIMEI failed: error "));
212 | Serial.println(err);
213 | return;
214 | }
215 | Serial.print(F("IMEI is "));
216 | Serial.print(IMEI);
217 | Serial.println(F("."));
218 |
219 | // Check the signal quality.
220 | // This returns a number between 0 and 5.
221 | // 2 or better is preferred.
222 | err = modem.getSignalQuality(signalQuality);
223 | if (err != ISBD_SUCCESS)
224 | {
225 | Serial.print(F("SignalQuality failed: error "));
226 | Serial.println(err);
227 | return;
228 | }
229 |
230 | Serial.print(F("On a scale of 0 to 5, signal quality is currently "));
231 | Serial.print(signalQuality);
232 | Serial.println(F("."));
233 |
234 | // Power down the modem
235 | // Also disable the Serial1 RX pin via IridiumSBD::endSerialPort
236 | Serial.println(F("Putting the 9603N to sleep."));
237 | err = modem.sleep();
238 | if (err != ISBD_SUCCESS)
239 | {
240 | Serial.print(F("sleep failed: error "));
241 | Serial.println(err);
242 | }
243 |
244 | // Disable 9603N power
245 | Serial.println(F("Disabling 9603N power..."));
246 | digitalWrite(iridiumPwrEN, LOW); // Disable Iridium Power
247 |
248 | // Disable the supercapacitor charger
249 | Serial.println(F("Disabling the supercapacitor charger..."));
250 | digitalWrite(superCapChgEN, LOW); // Disable the super capacitor charger
251 |
252 | Serial.println(F("Done!"));
253 |
254 | }
255 |
256 | void loop()
257 | {
258 | }
259 |
260 | #if DIAGNOSTICS
261 | void ISBDConsoleCallback(IridiumSBD *device, char c)
262 | {
263 | Serial.write(c);
264 | }
265 |
266 | void ISBDDiagsCallback(IridiumSBD *device, char c)
267 | {
268 | Serial.write(c);
269 | }
270 | #endif
271 |
--------------------------------------------------------------------------------
/Software/examples/Example9_GetTime/Example9_GetTime.ino:
--------------------------------------------------------------------------------
1 | /*
2 | Artemis Global Tracker
3 | Example: Get Time
4 |
5 | Written by Paul Clark (PaulZC)
6 | September 7th 2021
7 |
8 | ** Updated for v2.1.0 of the Apollo3 core / Artemis board package **
9 | ** (At the time of writing, v2.1.1 of the core conatins a feature which makes communication with the u-blox GNSS problematic. Be sure to use v2.1.0) **
10 |
11 | ** Set the Board to "RedBoard Artemis ATP" **
12 | ** (The Artemis Module does not have a Wire port defined, which prevents the IridiumSBD library from compiling) **
13 |
14 | This example powers up the Iridium 9603N and retrieve the Iridium system time
15 | from the modem using the getSystemTime method. This uses
16 | the Iridium command AT-MSSTM to acquire the time. The method will
17 | fail if the Iridium network has not yet been acquired.
18 | You do not need message credits or line rental to run this example.
19 |
20 | You will need to install version 3.0.5 of the Iridium SBD I2C library
21 | before this example will run successfully:
22 | https://github.com/sparkfun/SparkFun_IridiumSBD_I2C_Arduino_Library
23 | (Available through the Arduino Library Manager: search for IridiumSBDi2c)
24 |
25 | Power for the 9603N is provided by the LTC3225 super capacitor charger.
26 | D27 needs to be pulled high to enable the charger.
27 | The LTC3225 PGOOD signal is connected to D28.
28 |
29 | Power for the 9603N is switched by the ADM4210 inrush current limiter.
30 | D22 needs to be pulled high to enable power for the 9603N.
31 |
32 | The 9603N itself is enabled via its ON/OFF (SLEEP) pin which is connected
33 | to D17. Pull high - via the IridiumSBD library - to enable the 9603N.
34 |
35 | The 9603N's Network Available signal is conected to D18,
36 | so let's configure D18 as an input.
37 |
38 | The 9603N's Ring Indicator is conected to D41,
39 | so let's configure D41 as an input.
40 |
41 | To prevent bad tings happening to the AS179 RF antenna switch,
42 | D26 needs to be pulled high to disable the GNSS power.
43 |
44 | To prevent bad tings happening to the AS179 RF antenna switch,
45 | D26 needs to be pulled high to disable the GNSS power.
46 |
47 | */
48 |
49 | // Artemis Tracker pin definitions
50 | #define spiCS1 4 // D4 can be used as an SPI chip select or as a general purpose IO pin
51 | #define geofencePin 10 // Input for the ZOE-M8Q's PIO14 (geofence) pin
52 | #define busVoltagePin 13 // Bus voltage divided by 3 (Analog in)
53 | #define iridiumSleep 17 // Iridium 9603N ON/OFF (sleep) pin: pull high to enable the 9603N
54 | #define iridiumNA 18 // Input for the Iridium 9603N Network Available
55 | #define LED 19 // White LED
56 | #define iridiumPwrEN 22 // ADM4210 ON: pull high to enable power for the Iridium 9603N
57 | #define gnssEN 26 // GNSS Enable: pull low to enable power for the GNSS (via Q2)
58 | #define superCapChgEN 27 // LTC3225 super capacitor charger: pull high to enable the super capacitor charger
59 | #define superCapPGOOD 28 // Input for the LTC3225 super capacitor charger PGOOD signal
60 | #define busVoltageMonEN 34 // Bus voltage monitor enable: pull high to enable bus voltage monitoring (via Q4 and Q3)
61 | #define spiCS2 35 // D35 can be used as an SPI chip select or as a general purpose IO pin
62 | #define iridiumRI 41 // Input for the Iridium 9603N Ring Indicator
63 | // Make sure you do not have gnssEN and iridiumPwrEN enabled at the same time!
64 | // If you do, bad things might happen to the AS179 RF switch!
65 |
66 | // We use Serial1 to communicate with the Iridium modem. Serial1 on the ATP uses pin 24 for TX and 25 for RX. AGT uses the same pins.
67 |
68 | #include //http://librarymanager/All#IridiumSBDI2C
69 | #include
70 | #define DIAGNOSTICS false // Change this to true see IridiumSBD diagnostics
71 | // Declare the IridiumSBD object
72 | IridiumSBD modem(Serial1, iridiumSleep, iridiumRI);
73 |
74 | void gnssON(void) // Enable power for the GNSS
75 | {
76 | am_hal_gpio_pincfg_t pinCfg = g_AM_HAL_GPIO_OUTPUT; // Begin by making the gnssEN pin an open-drain output
77 | pinCfg.eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_OPENDRAIN;
78 | pin_config(PinName(gnssEN), pinCfg);
79 | delay(1);
80 |
81 | digitalWrite(gnssEN, LOW); // Enable GNSS power (HIGH = disable; LOW = enable)
82 | }
83 |
84 | void gnssOFF(void) // Disable power for the GNSS
85 | {
86 | am_hal_gpio_pincfg_t pinCfg = g_AM_HAL_GPIO_OUTPUT; // Begin by making the gnssEN pin an open-drain output
87 | pinCfg.eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_OPENDRAIN;
88 | pin_config(PinName(gnssEN), pinCfg);
89 | delay(1);
90 |
91 | digitalWrite(gnssEN, HIGH); // Disable GNSS power (HIGH = disable; LOW = enable)
92 | }
93 |
94 | // Overwrite the IridiumSBD beginSerialPort function - a fix for https://github.com/sparkfun/Arduino_Apollo3/issues/423
95 | void IridiumSBD::beginSerialPort() // Start the serial port connected to the satellite modem
96 | {
97 | diagprint(F("custom IridiumSBD::beginSerialPort\r\n"));
98 |
99 | // Configure the standard ATP pins for UART1 TX and RX - endSerialPort may have disabled the RX pin
100 |
101 | am_hal_gpio_pincfg_t pinConfigTx = g_AM_BSP_GPIO_COM_UART_TX;
102 | pinConfigTx.uFuncSel = AM_HAL_PIN_24_UART1TX;
103 | pin_config(D24, pinConfigTx);
104 |
105 | am_hal_gpio_pincfg_t pinConfigRx = g_AM_BSP_GPIO_COM_UART_RX;
106 | pinConfigRx.uFuncSel = AM_HAL_PIN_25_UART1RX;
107 | pinConfigRx.ePullup = AM_HAL_GPIO_PIN_PULLUP_WEAK; // Put a weak pull-up on the Rx pin
108 | pin_config(D25, pinConfigRx);
109 |
110 | Serial1.begin(19200);
111 | }
112 |
113 | // Overwrite the IridiumSBD endSerialPort function - a fix for https://github.com/sparkfun/Arduino_Apollo3/issues/423
114 | void IridiumSBD::endSerialPort()
115 | {
116 | diagprint(F("custom IridiumSBD::endSerialPort\r\n"));
117 |
118 | // Disable the Serial1 RX pin to avoid the code hang
119 | am_hal_gpio_pinconfig(PinName(D25), g_AM_HAL_GPIO_DISABLE);
120 | }
121 |
122 | void setup()
123 | {
124 | int signalQuality = -1;
125 | int err;
126 |
127 | pinMode(LED, OUTPUT); // Make the LED pin an output
128 |
129 | gnssOFF(); // Disable power for the GNSS
130 | pinMode(geofencePin, INPUT); // Configure the geofence pin as an input
131 |
132 | pinMode(iridiumPwrEN, OUTPUT); // Configure the Iridium Power Pin (connected to the ADM4210 ON pin)
133 | digitalWrite(iridiumPwrEN, LOW); // Disable Iridium Power (HIGH = enable; LOW = disable)
134 | pinMode(superCapChgEN, OUTPUT); // Configure the super capacitor charger enable pin (connected to LTC3225 !SHDN)
135 | digitalWrite(superCapChgEN, LOW); // Disable the super capacitor charger (HIGH = enable; LOW = disable)
136 | pinMode(iridiumSleep, OUTPUT); // Iridium 9603N On/Off (Sleep) pin
137 | digitalWrite(iridiumSleep, LOW); // Put the Iridium 9603N to sleep (HIGH = on; LOW = off/sleep)
138 | pinMode(iridiumRI, INPUT); // Configure the Iridium Ring Indicator as an input
139 | pinMode(iridiumNA, INPUT); // Configure the Iridium Network Available as an input
140 | pinMode(superCapPGOOD, INPUT); // Configure the super capacitor charger PGOOD input
141 |
142 | // Make sure the Serial1 RX pin is disabled to prevent the power-on glitch on the modem's RX(OUT) pin
143 | // causing problems with v2.1.0 of the Apollo3 core. Requires v3.0.5 of IridiumSBDi2c.
144 | modem.endSerialPort();
145 |
146 | // Start the console serial port
147 | Serial.begin(115200);
148 | while (!Serial) // Wait for the user to open the serial monitor
149 | ;
150 | delay(100);
151 | Serial.println();
152 | Serial.println();
153 | Serial.println(F("Artemis Global Tracker"));
154 | Serial.println(F("Example: Get Time"));
155 | Serial.println();
156 |
157 | //empty the serial buffer
158 | while(Serial.available() > 0)
159 | Serial.read();
160 |
161 | //wait for the user to press any key before beginning
162 | Serial.println(F("Please check that the Serial Monitor is set to 115200 Baud"));
163 | Serial.println(F("and that the line ending is set to Newline."));
164 | Serial.println(F("Then click Send to start the example."));
165 | Serial.println();
166 | while(Serial.available() == 0)
167 | ;
168 |
169 | // Enable the supercapacitor charger
170 | Serial.println(F("Enabling the supercapacitor charger..."));
171 | digitalWrite(superCapChgEN, HIGH); // Enable the super capacitor charger
172 | delay(1000);
173 |
174 | // Wait for the supercapacitor charger PGOOD signal to go high
175 | while (digitalRead(superCapPGOOD) == false)
176 | {
177 | Serial.println(F("Waiting for supercapacitors to charge..."));
178 | delay(1000);
179 | }
180 | Serial.println(F("Supercapacitors charged!"));
181 |
182 | // Enable power for the 9603N
183 | Serial.println(F("Enabling 9603N power..."));
184 | digitalWrite(iridiumPwrEN, HIGH); // Enable Iridium Power
185 | delay(1000);
186 |
187 | // If we're powering the device by USB, tell the library to
188 | // relax timing constraints waiting for the supercap to recharge.
189 | modem.setPowerProfile(IridiumSBD::USB_POWER_PROFILE);
190 |
191 | // Begin satellite modem operation
192 | // Also begin the serial port connected to the satellite modem via IridiumSBD::beginSerialPort
193 | Serial.println(F("Starting modem..."));
194 | err = modem.begin();
195 | if (err != ISBD_SUCCESS)
196 | {
197 | Serial.print(F("Begin failed: error "));
198 | Serial.println(err);
199 | if (err == ISBD_NO_MODEM_DETECTED)
200 | Serial.println(F("No modem detected: check wiring."));
201 | return;
202 | }
203 |
204 | // Get the IMEI
205 | char IMEI[16];
206 | err = modem.getIMEI(IMEI, sizeof(IMEI));
207 | if (err != ISBD_SUCCESS)
208 | {
209 | Serial.print(F("getIMEI failed: error "));
210 | Serial.println(err);
211 | return;
212 | }
213 | Serial.print(F("IMEI is "));
214 | Serial.print(IMEI);
215 | Serial.println(F("."));
216 |
217 | }
218 |
219 | void loop()
220 | {
221 | // Check the signal quality.
222 | // This returns a number between 0 and 5.
223 | // 2 or better is preferred.
224 | int signalQuality = -1;
225 | int err = modem.getSignalQuality(signalQuality);
226 | if (err != ISBD_SUCCESS)
227 | {
228 | Serial.print(F("SignalQuality failed: error "));
229 | Serial.println(err);
230 | return;
231 | }
232 |
233 | Serial.print(F("On a scale of 0 to 5, signal quality is currently "));
234 | Serial.print(signalQuality);
235 | Serial.println(F("."));
236 |
237 | struct tm t;
238 | err = modem.getSystemTime(t);
239 | if (err == ISBD_SUCCESS)
240 | {
241 | char buf[32];
242 | sprintf(buf, "%d-%02d-%02d %02d:%02d:%02d",
243 | t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
244 | Serial.print(F("Iridium date/time is "));
245 | Serial.println(buf);
246 | }
247 |
248 | else if (err == ISBD_NO_NETWORK) // Did it fail because the transceiver has not yet seen the network?
249 | {
250 | Serial.println(F("No network detected. Waiting 5 seconds."));
251 | }
252 |
253 | else
254 | {
255 | Serial.print(F("Unexpected error "));
256 | Serial.println(err);
257 | return;
258 | }
259 |
260 | // Delay 5 seconds
261 | delay(5 * 1000UL);
262 | }
263 |
264 | #if DIAGNOSTICS
265 | void ISBDConsoleCallback(IridiumSBD *device, char c)
266 | {
267 | Serial.write(c);
268 | }
269 |
270 | void ISBDDiagsCallback(IridiumSBD *device, char c)
271 | {
272 | Serial.write(c);
273 | }
274 | #endif
275 |
--------------------------------------------------------------------------------
/Software/examples/README.md:
--------------------------------------------------------------------------------
1 | # Artemis Global Tracker Examples
2 |
3 | These examples demonstrate how to use the Artemis Global Tracker. There are examples showing: how to communicate with the MS8607 PHT sensor;
4 | how to get a fix from the ZOE-M8Q GNSS; how to set up a geofence and how to wake up the Artemis when the geofence status changes;
5 | how to send Iridium Short Burst Data (SBD) messages and monitor the ring channel for new messages. Example16 contains the code
6 | for the full GlobalTracker.
7 |
8 | If you don't want to use the Arduino IDE, you can upload the examples using the [Artemis Firmware Upload GUI](https://github.com/sparkfun/Artemis-Firmware-Upload-GUI) instead.
9 | You will find the binary files in the [binaries folder](../../binaries).
10 |
11 | **Example1 - Blink** powers up the tracker and blinks the white LED (connected to D19).
12 |
13 | **Example2 - Bus Voltage** demonstrates how to read: the battery (bus) voltage; the internal VCC voltage; the Artemis internal temperature; the VSS (ground) voltage.
14 |
15 | **Example3 - PHT** demonstrates how to read the pressure, humidity and temperature from the on-board MS8607 sensor.
16 |
17 | **Example4 - External PHT** demonstrates how to read the pressure, humidity and temperature from an [external MS8607 sensor](https://www.sparkfun.com/products/16298) connected to the Qwiic port.
18 |
19 | **Example5 - GNSS** demonstrates how to read the tracker's position from the ZOE-M8Q GNSS.
20 |
21 | **Example6 - Geofence** demonstrates how to set four geofences around the tracker's current position. The white LED will go out if the tracker is moved outside the largest geofenced area.
22 |
23 | **Example7 - Get IMEI** demonstrates how to read the IMEI identifier from the Iridium 9603N modem. You do not need message credits to run this example.
24 |
25 | **Example8 - Check CSQ** demonstrates how to read the signal quality from the Iridium 9603N modem. You do not need message credits to run this example.
26 |
27 | **Example9 - Get Time** demonstrates how to read the time from the Iridium network. You do not need message credits to run this example.
28 |
29 | **Example10 - Basic Send** demonstrates how to send a simple "Hello, world!" message via Iridium. This example will use one message credit each time you run it.
30 |
31 | **Example11 - Ring** demonstrates how to monitor the Iridium ring channel and download new messages sent to the tracker. This example will use one or more credits each time
32 | a message is downloaded (depending on the length of the message).
33 |
34 | **Example12 - Test Low Power** demonstrates how to put the Artemis into deep sleep and wake it up again every INTERVAL seconds.
35 |
36 | **Example13 - Geofence Alert** demonstrates how to set a geofence around the tracker's current position. The Artemis will then go into deep sleep and will be woken up again by the ZOE-M8Q
37 | if the geofence status changes. The ZOE is put into power save mode to help reduce the current draw (to approximately 9mA).
38 |
39 | **Example14 - Simple Tracker** is a simple tracker which: wakes up every INTERVAL minutes; gets a GNSS fix; reads the PHT sensor; and sends all the data in a SBD message.
40 | The message is transmitted as text and has the format:
41 | - DateTime,Latitude,Longitude,Altitude,Speed,Course,PDOP,Satellites,Pressure,Temperature,Battery,Count
42 |
43 | This example will use two message credits each time a message is sent due to the length of the message.
44 |
45 | **Example15 - Better Tracker** is a better tracker where the INTERVAL, RBDESTINATION and RBSOURCE are stored in 'EEPROM' (Flash) and can be configured via Iridium SBD messages.
46 |
47 | The message transmit interval can be configured by sending a plain text message to the tracker via the RockBLOCK Gateway using the format _[INTERVAL=nnn]_
48 | where _nnn_ is the new message interval in _minutes_. The interval will be updated the next time the beacon wakes up for a transmit cycle.
49 |
50 | If you want to enable message forwarding via the RockBLOCK Gateway, you can do this by including the text _[RBDESTINATION=nnnnn]_ in the message
51 | where _nnnnn_ is the RockBLOCK serial number of the tracker or RockBLOCK you want the messages to be forwarded to. You can disable message forwarding
52 | again by sending a message containing _[RBDESTINATION=0]_. You can change the source serial number which is included in the messages by including the text
53 | _[RBSOURCE=nnnnn]_ in the RockBLOCK message where _nnnnn_ is the serial number of the RockBLOCK 9603N on the tracker. You can concatenate the configuration messages.
54 | Send the following to set all three settings in one go: _[INTERVAL=5][RBDESTINATION=12345][RBSOURCE=54321]_
55 |
56 | If message forwarding is enabled, the message format will be (using the above example):
57 | - RB0012345,DateTime,Latitude,Longitude,Altitude,Speed,Course,PDOP,Satellites,Pressure,Temperature,Battery,Count,RB0054321
58 |
59 | If message forwarding is enabled, you will be charged twice for each message: once to send it, and once to receive it.
60 |
61 | **Example16 - Global Tracker** is the full Global Tracker which has many settings that can be configured and stored in EEPROM. The GlobalTracker can be configured to transmit:
62 | on a GeoFence alert; or when Pressure, Temperature or Humidity limits are exceeded; or if the battery voltage is low. All of the settings can be configured via USB-C
63 | or remotely via a binary format Iridium SBD message.
64 |
65 | Messages can be sent in text format (human-readable) or binary format (to save messages credits). You can configure which message fields are included in the message so you only send the data you need.
66 | The [Artemis Global Tracker Configuration Tool (AGTCT)](../../Tools) will generate the configuration messages for you.
67 |
68 | You can trigger user-defined functions e.g. to operate an [external relay](https://www.sparkfun.com/products/15093).
69 |
70 | You can also include readings from additional external sensors.
71 |
72 | You can have the Iridium 9603N monitor the ring channel continuously for new Mobile Terminated messages so it can respond to them immediately,
73 | but this will increase the current draw considerably. This is not recommended for battery-powered applications.
74 |
75 | Please refer to the [GlobalTracker FAQs](../../Documentation/GlobalTracker_FAQs/README.md) for more information.
76 |
77 | **Example17 - Production Test** is code used to test the Artemis Global Tracker during production. You will need an AGT Test Header to allow this code to run.
78 |
79 | **Example18 - Production Test 2** is code used to test the Artemis Global Tracker during production. You will need an AGT Test Header to allow this code to run.
80 |
81 | **Example19 - Serial Terminal** allows the AGT to be operated via a simple Serial Terminal interface. Open the Serial Monitor or a Terminal Emulator at 115200 baud to see the menu. You can:
82 | - Read the temperature and pressure from the MS8607
83 | - Read position, velocity and time data from the ZOE-M8Q GNSS
84 | - Check for new Iridium messages
85 | - Send and receive text and binary Iridium messages
86 | - Flush the Iridium Mobile Terminated message queue
87 |
88 | **Example20 - GNSS Module Info** reads the module information from the ZOE-M8Q GNSS, allowing you to see what software version it is running
89 |
90 | **Example21 - Iridium Serial and Power Test** tests the work-around for v2.1 of the Apollo3 core (where the Iridium modem pulling the Serial1 RX pin low can cause the Artemis to hang)
91 |
92 |
93 |
94 | To run the examples, you will need to install **v2.1.0** of the SparkFun Apollo3 core and then set the board to the "**RedBoard Artemis ATP**":
95 | - At the time of writing, v2.1.1 of the core contains a feature which makes communication with the u-blox GNSS problematic. Be sure to use **v2.1.0**
96 | - https://learn.sparkfun.com/tutorials/artemis-development-with-the-arduino-ide
97 |
98 | You will need to install [this version of the Iridium SBD library](https://github.com/sparkfun/SparkFun_IridiumSBD_I2C_Arduino_Library)
99 | - (Available through the Arduino Library Manager: search for IridiumSBDi2c)
100 |
101 | You will also need to install the [Qwiic_PHT_MS8607_Library](https://github.com/sparkfun/SparkFun_PHT_MS8607_Arduino_Library)
102 | - (Available through the Arduino Library Manager: search for SparkFun MS8607)
103 |
104 | You also need the [SparkFun u-blox GNSS library](https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library)
105 | - (Available through the Arduino Library Manager: search for SparkFun u-blox GNSS)
106 |
107 | Basic information on how to install an Arduino library is available [here](https://learn.sparkfun.com/tutorials/installing-an-arduino-library)
108 |
--------------------------------------------------------------------------------
/Tools/Artemis_Global_Tracker_Configuration_Tool/Windows_64-bit/AGTCT.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/Tools/Artemis_Global_Tracker_Configuration_Tool/Windows_64-bit/AGTCT.exe
--------------------------------------------------------------------------------
/Tools/Artemis_Global_Tracker_Configuration_Tool/Windows_64-bit/default.pkl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/Tools/Artemis_Global_Tracker_Configuration_Tool/Windows_64-bit/default.pkl
--------------------------------------------------------------------------------
/Tools/Artemis_Global_Tracker_Configuration_Tool/Windows_64-bit/empty.pkl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/Tools/Artemis_Global_Tracker_Configuration_Tool/Windows_64-bit/empty.pkl
--------------------------------------------------------------------------------
/Tools/Artemis_Global_Tracker_Configuration_Tool/Windows_64-bit/mapper.pkl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/Tools/Artemis_Global_Tracker_Configuration_Tool/Windows_64-bit/mapper.pkl
--------------------------------------------------------------------------------
/Tools/Artemis_Global_Tracker_Configuration_Tool/default.pkl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/Tools/Artemis_Global_Tracker_Configuration_Tool/default.pkl
--------------------------------------------------------------------------------
/Tools/Artemis_Global_Tracker_Configuration_Tool/empty.pkl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/Tools/Artemis_Global_Tracker_Configuration_Tool/empty.pkl
--------------------------------------------------------------------------------
/Tools/Artemis_Global_Tracker_Configuration_Tool/mapper.pkl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/Tools/Artemis_Global_Tracker_Configuration_Tool/mapper.pkl
--------------------------------------------------------------------------------
/Tools/Artemis_Global_Tracker_Mapping_Tools/Artemis_Global_Tracker_CSV_DateTime.py:
--------------------------------------------------------------------------------
1 | # Artemis Global Tracker: Convert CSV DateTime
2 |
3 | # Written by: Paul Clark (PaulZC)
4 | # 29th February 2020
5 |
6 | # Licence: MIT
7 |
8 | # This code converts the first column of a Global Tracker csv file
9 | # from YYYYMMDDHHMMSS format into a more friendly DD/MM/YY HH:MM:SS format
10 |
11 | import csv
12 | from datetime import datetime
13 | import os
14 | import codecs
15 |
16 | print('Artemis Global Tracker: CSV DateTime Converter')
17 | print
18 |
19 | resp = 'N'
20 |
21 | # Find the csv file
22 | for root, dirs, files in os.walk("."):
23 | if len(files) > 0:
24 | # Comment out the next two lines to process all files in this directory and its subdirectories
25 | # Uncomment one or the other to search only this directory or only subdirectories
26 | #if root != ".": # Only check sub directories
27 | if root == ".": # Only check this directory
28 | for filename in files:
29 | if filename[-4:] == '.csv':
30 | longfilename = os.path.join(root, filename)
31 | question = 'Open ' + filename + '? (Y/n) : '
32 | resp = input(question)
33 | if resp == '' or resp == 'Y' or resp == 'y': break
34 | longfilename = ''
35 | if resp == '' or resp == 'Y' or resp == 'y': break
36 | if resp == '' or resp == 'Y' or resp == 'y': break
37 | if resp == '' or resp == 'Y' or resp == 'y': break
38 |
39 | if longfilename == '': raise Exception('No file to open!')
40 |
41 | outfile = longfilename[:-4] + '_DateTime' + longfilename[-4:]
42 |
43 | with open(outfile,"w", newline='') as dest:
44 | with open(longfilename, "r") as source:
45 | reader = csv.reader(source)
46 | writer = csv.writer(dest)
47 | for line in reader:
48 | try:
49 | if len(line) > 6: # Check it has sufficient fields
50 | if (line[0][:2] == 'RB') : # Does the message payload have an RB prefix?
51 | dt = datetime.strptime(line[1],'%Y%m%d%H%M%S')
52 | line.append(line[-1])
53 | for l in range((len(line)-2), 1, -1):
54 | line[l+1] = line[l]
55 | line[1] = dt.strftime('%d/%m/%Y')
56 | line[2] = dt.strftime('%H:%M:%S')
57 | else:
58 | dt = datetime.strptime(line[0],'%Y%m%d%H%M%S')
59 | line.append(line[-1])
60 | for l in range((len(line)-2), 0, -1):
61 | line[l+1] = line[l]
62 | line[0] = dt.strftime('%d/%m/%Y')
63 | line[1] = dt.strftime('%H:%M:%S')
64 | writer.writerow(line)
65 | except:
66 | pass
67 | source.close()
68 | dest.close()
69 |
--------------------------------------------------------------------------------
/Tools/Artemis_Global_Tracker_Mapping_Tools/Artemis_Global_Tracker_DateTime_CSV_to_KML.py:
--------------------------------------------------------------------------------
1 | # Artemis Global Tracker: Convert CSV DateTime to KML
2 |
3 | # Written by: Paul Clark (PaulZC)
4 | # 29th February 2020
5 |
6 | # Licence: MIT
7 |
8 | # This code converts a stitched .csv file into .kml files for GoogleEarth
9 |
10 | # The .csv file should have been processed by Artemis_Global_Tracker_CSV_DateTime.py
11 | # _before_ being processed by this code
12 |
13 | # With thanks to Kyle Lancaster for simplekml:
14 | # http://simplekml.readthedocs.io/en/latest/index.html
15 | # https://pypi.python.org/pypi/simplekml
16 |
17 | # Converts the processed .csv into .kml files showing the combined route in point,
18 | # arrow and linestring (3D flightpath and course-over-ground) format.
19 |
20 | # This code expects the .csv file to contain:
21 | # (Optional) Column 0 = DEST RockBLOCK serial number
22 | # Column 1 = GNSS Tx Date (DD/MM/YY)
23 | # Column 2 = GNSS Tx Time (HH:MM:SS)
24 | # Column 3 = GNSS Latitude (degrees) (float)
25 | # Column 4 = GNSS Longitude (degrees) (float)
26 | # Column 5 = GNSS Altitude (m) (int)
27 | # Column 6 = GNSS Speed (m/s) (float)
28 | # Column 7 = GNSS Heading (Degrees) (int)
29 | # Column 8 = message MOMSN (appended by Artemis_Global_Tracker_Stitcher.py)
30 |
31 | # You can use the Artemis_Global_Tracker_Configuration_Tool to configure the Tracker
32 | # to send the appropriate MOFIELDS:
33 | #
34 | # DATETIME
35 | # LAT
36 | # LON
37 | # ALT
38 | # SPEED
39 | # HEAD
40 |
41 | import csv
42 | import simplekml
43 | import matplotlib.dates as mdates
44 | import os
45 |
46 | print('Artemis Global Tracker: DateTime CSV to KML Converter')
47 | print
48 |
49 | # point style
50 | style = simplekml.Style()
51 | style.labelstyle.color = simplekml.Color.red # Make the text red
52 | #style.labelstyle.scale = 2 # Make the text twice as big
53 | style.iconstyle.icon.href = 'http://maps.google.com/mapfiles/kml/shapes/placemark_circle.png'
54 |
55 | # arrow (heading) styles
56 | heading_styles = []
57 | for heading in range(361): # Create iconstyles for each heading 0:360
58 | heading_styles.append(simplekml.Style())
59 | heading_styles[-1].iconstyle.icon.href = 'http://maps.google.com/mapfiles/kml/shapes/arrow.png'
60 | heading_styles[-1].iconstyle.heading = (heading + 180.) % 360. # Fix arrow orientation
61 |
62 | longfilename = ''
63 | resp = 'N'
64 |
65 | # Find the csv file
66 | for root, dirs, files in os.walk("."):
67 | if len(files) > 0:
68 | # Comment out the next two lines to process all files in this directory and its subdirectories
69 | # Uncomment one or the other to search only this directory or only subdirectories
70 | #if root != ".": # Only check sub directories
71 | if root == ".": # Only check this directory
72 | for filename in files:
73 | if filename[-13:] == '_DateTime.csv':
74 | longfilename = os.path.join(root, filename)
75 | question = 'Open ' + filename + '? (Y/n) : '
76 | resp = input(question)
77 | if resp == '' or resp == 'Y' or resp == 'y': break
78 | longfilename = ''
79 | if resp == '' or resp == 'Y' or resp == 'y': break
80 | if resp == '' or resp == 'Y' or resp == 'y': break
81 | if resp == '' or resp == 'Y' or resp == 'y': break
82 |
83 | if longfilename == '': raise Exception('No file to open!')
84 |
85 | point_filename = longfilename[:-4] + '_points.kml' # Create the points filename
86 | arrow_filename = longfilename[:-4] + '_arrows.kml' # Create the arrows filename
87 | linestring_filename = longfilename[:-4] + '_flightpath.kml' # Create the linestring filename
88 | course_filename = longfilename[:-4] + '_COG.kml' # Create the linestring filename
89 | point_kml = simplekml.Kml() # Create an empty kml for the points
90 | arrow_kml = simplekml.Kml() # Create an empty kml for the arrows
91 | linestring_kml = simplekml.Kml() # Create an empty kml for the flightpath linestring
92 | course_kml = simplekml.Kml() # Create an empty kml for the COG linestring
93 | coords = [] # Create coordinates
94 |
95 | with open(longfilename, "r") as f:
96 | reader = csv.reader(f)
97 | for line in reader:
98 | if (line[0][:2] == 'RB') : # Does the message payload have an RB prefix?
99 | try:
100 | latitude = float(line[3]) # Extract the latitude
101 | longitude = float(line[4]) # Extract the longitude
102 | altitude = float(line[5]) # Extract the altitude
103 | heading = float(line[7]) # Extract the heading
104 | momsn = line[8] # Extract the MOMSN
105 | except:
106 | latitude = 0.
107 | longitude = 0.
108 | else:
109 | try:
110 | latitude = float(line[2]) # Extract the latitude
111 | longitude = float(line[3]) # Extract the longitude
112 | altitude = float(line[4]) # Extract the altitude
113 | heading = float(line[6]) # Extract the heading
114 | momsn = line[7] # Extract the MOMSN
115 | except:
116 | latitude = 0.
117 | longitude = 0.
118 |
119 | if (latitude == 0.) and (longitude == 0.): # Check lat and lon are valid
120 | pass
121 | else:
122 | # Check heading is valid
123 | if (heading < 0.) or (heading > 360.): heading = 0.
124 |
125 | # Update point kml
126 | pnt = point_kml.newpoint(name=momsn)
127 | pnt.coords=[(longitude,latitude,altitude)]
128 | pnt.style = style
129 | # Update arrow kml
130 | pnt = arrow_kml.newpoint(name=momsn)
131 | pnt.coords=[(longitude,latitude,altitude)]
132 | pnt.style = heading_styles[int(round(heading))]
133 | # Add these coordinates to the list for the linestring
134 | coords.append((longitude,latitude,altitude))
135 |
136 | # We have finished processing the csv file so now save the kml files
137 | point_kml.save(point_filename) # Save the points kml file
138 | arrow_kml.save(arrow_filename) # Save the arrows kml file
139 |
140 | # Create and save the linestrings (flightpath and course-over-ground) using coords
141 | ls = linestring_kml.newlinestring()
142 | ls.altitudemode = simplekml.AltitudeMode.absolute
143 | ls.coords = coords
144 | ls.extrude = 1
145 | ls.tessellate = 1
146 | ls.style.linestyle.width = 5
147 | ls.style.linestyle.color = simplekml.Color.yellow
148 | ls.style.polystyle.color = simplekml.Color.yellow
149 | linestring_kml.save(linestring_filename)
150 |
151 | cls = course_kml.newlinestring()
152 | cls.coords = coords
153 | cls.style.linestyle.width = 5
154 | cls.style.linestyle.color = simplekml.Color.yellow
155 | cls.style.polystyle.color = simplekml.Color.yellow
156 | course_kml.save(course_filename)
157 |
158 | f.close()
159 |
160 |
161 |
162 |
163 |
164 |
165 |
--------------------------------------------------------------------------------
/Tools/Artemis_Global_Tracker_Mapping_Tools/Artemis_Global_Tracker_GMail_Downloader.py:
--------------------------------------------------------------------------------
1 | # Artemis Global Tracker: GMail Downloader using the GMail Python API
2 |
3 | # Written by: Paul Clark (PaulZC)
4 | # 7th March 2020
5 |
6 | # Licence: MIT
7 |
8 | # This code logs into your GMail account using the API and checks for new Tracker SBD
9 | # messages every 15 seconds. If a new message is found, the code saves the attachment
10 | # to file, and then moves the message to the SBD folder (to free up your inbox).
11 |
12 | # You will need to create an SBD folder in GMail if it doesn't already exist.
13 |
14 | # The code assumes your messages are being delivered by the Rock7 RockBLOCK gateway
15 | # and that the message subject contains the words "Message" "from RockBLOCK".
16 |
17 | # Follow these instructions to create your credentials for the API:
18 | # https://developers.google.com/gmail/api/quickstart/python
19 |
20 | # If modifying these scopes, delete the file token.pickle.
21 | #SCOPES = ['https://www.googleapis.com/auth/gmail.readonly'] # Read only
22 | SCOPES = ['https://www.googleapis.com/auth/gmail.modify'] # Everything except delete
23 | #SCOPES = ['https://mail.google.com/'] # Full permissions
24 |
25 | import base64
26 | import pickle
27 | import os.path
28 | from googleapiclient.discovery import build
29 | from google_auth_oauthlib.flow import InstalledAppFlow
30 | from google.auth.transport.requests import Request
31 | from time import sleep
32 |
33 | def get_credentials():
34 | """Gets valid user credentials from storage.
35 |
36 | If nothing has been stored, or if the stored credentials are invalid,
37 | the oauthlib flow is completed to obtain the new credentials.
38 |
39 | Returns:
40 | Credentials, the obtained credential.
41 | """
42 |
43 | creds = None
44 | # The file token.pickle stores the user's access and refresh tokens, and is
45 | # created automatically when the authorization flow completes for the first
46 | # time. You will need to delete it if you change the SCOPES.
47 | if os.path.exists('token.pickle'):
48 | with open('token.pickle', 'rb') as token:
49 | creds = pickle.load(token)
50 | # If there are no (valid) credentials available, let the user log in.
51 | if not creds or not creds.valid:
52 | if creds and creds.expired and creds.refresh_token:
53 | creds.refresh(Request())
54 | else:
55 | flow = InstalledAppFlow.from_client_secrets_file(
56 | 'credentials.json', SCOPES)
57 | creds = flow.run_local_server(port=0)
58 | # Save the credentials for the next run
59 | with open('token.pickle', 'wb') as token:
60 | pickle.dump(creds, token)
61 | return creds
62 |
63 | def ListMessagesMatchingQuery(service, user_id, query=''):
64 | """List all Messages of the user's mailbox matching the query.
65 |
66 | Args:
67 | service: Authorized Gmail API service instance.
68 | user_id: User's email address. The special value "me"
69 | can be used to indicate the authenticated user.
70 | query: String used to filter messages returned.
71 | Eg.- 'from:user@some_domain.com' for Messages from a particular sender.
72 |
73 | Returns:
74 | List of Messages that match the criteria of the query. Note that the
75 | returned list contains Message IDs, you must use get with the
76 | appropriate ID to get the details of a Message.
77 | """
78 | response = service.users().messages().list(userId=user_id,q=query).execute()
79 | messages = []
80 | if 'messages' in response:
81 | messages.extend(response['messages'])
82 |
83 | while 'nextPageToken' in response:
84 | page_token = response['nextPageToken']
85 | response = service.users().messages().list(userId=user_id, q=query,pageToken=page_token).execute()
86 | messages.extend(response['messages'])
87 |
88 | return messages
89 |
90 | def SaveAttachments(service, user_id, msg_id):
91 | """Get and store attachment from Message with given id.
92 |
93 | Args:
94 | service: Authorized Gmail API service instance.
95 | user_id: User's email address. The special value "me"
96 | can be used to indicate the authenticated user.
97 | msg_id: ID of Message containing attachment.
98 | """
99 | message = service.users().messages().get(userId=user_id, id=msg_id).execute()
100 |
101 | for part in message['payload']['parts']:
102 | if part['filename']:
103 | if 'data' in part['body']:
104 | data=part['body']['data']
105 | else:
106 | att_id=part['body']['attachmentId']
107 | att=service.users().messages().attachments().get(userId=user_id, messageId=msg_id,id=att_id).execute()
108 | data=att['data']
109 | file_data = base64.urlsafe_b64decode(data.encode('UTF-8'))
110 | #path = date_str+part['filename']
111 | path = part['filename']
112 |
113 | with open(path, 'wb') as f:
114 | f.write(file_data)
115 | f.close()
116 |
117 | def GetMessageBody(contents):
118 | """Save the message body.
119 |
120 | Assumes plaintext message body.
121 |
122 | Gratefully plagiarised from:
123 | https://github.com/rtklibexplorer/GMail_RTKLIB/blob/master/email_utils.py
124 | """
125 | for part in contents['payload']['parts']:
126 | if part['mimeType'] == 'text/plain':
127 | body = part['body']['data']
128 | return base64.urlsafe_b64decode(body.encode('UTF-8')).decode('UTF-8')
129 | elif 'parts' in part:
130 | # go two levels if necessary
131 | for sub_part in part['parts']:
132 | if sub_part['mimeType'] == 'text/plain':
133 | body = sub_part['body']['data']
134 | return base64.urlsafe_b64decode(body.encode('UTF-8')).decode('UTF-8')
135 |
136 | def SaveMessageBody(service, user_id, msg_id):
137 | """Save the body from Message with given id.
138 |
139 | Args:
140 | service: Authorized Gmail API service instance.
141 | user_id: User's email address. The special value "me"
142 | can be used to indicate the authenticated user.
143 | msg_id: ID of Message.
144 | """
145 | message = service.users().messages().get(userId=user_id, id=msg_id).execute()
146 | file_data = GetMessageBody(message)
147 |
148 | subject = GetSubject(service, user_id, msg_id);
149 | for c in r' []/\;,><&*:%=+@!#^()|?^': # substitute any invalid characters
150 | subject = subject.replace(c,'_')
151 |
152 | path = subject+".txt"
153 |
154 | with open(path, 'w') as f:
155 | f.write(file_data)
156 | f.close()
157 |
158 | def GetSubject(service, user_id, msg_id):
159 | """Returns the subject of the message with given id.
160 |
161 | Args:
162 | service: Authorized Gmail API service instance.
163 | user_id: User's email address. The special value "me"
164 | can be used to indicate the authenticated user.
165 | msg_id: ID of Message.
166 | """
167 | subject = ''
168 | message = service.users().messages().get(userId=user_id, id=msg_id).execute()
169 | payload = message["payload"]
170 | headers = payload["headers"]
171 | for header in headers:
172 | if header["name"] == "Subject":
173 | subject = header["value"]
174 | break
175 | return subject
176 |
177 | def MarkAsRead(service, user_id, msg_id):
178 | """Marks the message with given id as read.
179 |
180 | Args:
181 | service: Authorized Gmail API service instance.
182 | user_id: User's email address. The special value "me"
183 | can be used to indicate the authenticated user.
184 | msg_id: ID of Message.
185 | """
186 | service.users().messages().modify(userId=user_id, id=msg_id, body={ 'removeLabelIds': ['UNREAD']}).execute()
187 |
188 | def MoveToLabel(service, user_id, msg_id, dest):
189 | """Changes the labels of the message with given id to 'move' it.
190 |
191 | Args:
192 | service: Authorized Gmail API service instance.
193 | user_id: User's email address. The special value "me"
194 | can be used to indicate the authenticated user.
195 | msg_id: ID of Message.
196 | dest: destination label
197 | """
198 | # Find Label_ID of destination label
199 | results = service.users().labels().list(userId=user_id).execute()
200 | labels = results.get('labels', [])
201 | for label in labels:
202 | if label['name'] == dest: dest_id = label['id']
203 |
204 | service.users().messages().modify(userId=user_id, id=msg_id, body={ 'addLabelIds': [dest_id]}).execute()
205 | service.users().messages().modify(userId=user_id, id=msg_id, body={ 'removeLabelIds': ['INBOX']}).execute()
206 |
207 | def main():
208 | """Creates a Gmail API service object.
209 | Searches for unread messages, with attachments, with "Message" "from RockBLOCK" in the subject.
210 | Saves the attachment to disk.
211 | Marks the message as read.
212 | Moves it to the SBD folder.
213 | You will need to create the SBD folder in GMail if it doesn't already exist.
214 | """
215 | creds = get_credentials()
216 | service = build('gmail', 'v1', credentials=creds)
217 |
218 | # Include your RockBLOCK IMEI in the subject search if required
219 | messages = ListMessagesMatchingQuery(service, 'me', 'subject:(Message \"from RockBLOCK\") is:unread has:attachment')
220 | if messages:
221 | for message in messages:
222 | print('Processing: '+GetSubject(service, 'me', message["id"]))
223 | #SaveMessageBody(service, 'me', message["id"])
224 | SaveAttachments(service, 'me', message["id"])
225 | MarkAsRead(service, 'me', message["id"])
226 | MoveToLabel(service, 'me', message["id"], 'SBD')
227 | #else:
228 | #print('No messages found!')
229 |
230 | if __name__ == '__main__':
231 | print('Artemis Global Tracker: GMail API Downloader')
232 | print('Press Ctrl-C to quit')
233 | try:
234 | while True:
235 | #print('Checking for messages...')
236 | main()
237 | for i in range(15):
238 | sleep(1) # Sleep
239 | except KeyboardInterrupt:
240 | print('Ctrl-C received!')
241 |
--------------------------------------------------------------------------------
/Tools/Artemis_Global_Tracker_Mapping_Tools/Artemis_Global_Tracker_Stitcher.py:
--------------------------------------------------------------------------------
1 | # Artemis Global Tracker: Stitcher
2 |
3 | # Written by: Paul Clark (PaulZC)
4 | # 29th February 2020
5 |
6 | # Licence: MIT
7 |
8 | # Stitches .bin SBD files from the Global Tracker into .csv files
9 |
10 | # This code searches through the current directory and/or sub-directories,
11 | # finds all .bin SBD files (downloaded by Artemis_Global_Tracker_GMail_Downloader.py)
12 | # and converts them into .csv files.
13 |
14 | # Files from different trackers (with different IMEIs) are processed separately.
15 | # The MOMSN is added to the end of each line.
16 |
17 | # Rock7 RockBLOCK SBD filenames have the format IMEI-MOMSN.bin where:
18 | # IMEI is the International Mobile Equipment Identity number (15 digits)
19 | # MOMSN is the Mobile Originated Message Sequence Number (1+ digits)
20 | # Other Iridium service providers use different filename conventions.
21 |
22 | # All files get processed. You will need to 'hide' files you don't
23 | # want to process by moving them to (e.g.) a different directory.
24 |
25 | import numpy as np
26 | import matplotlib.dates as mdates
27 | import os
28 | import re
29 |
30 | # https://stackoverflow.com/a/2669120
31 | def sorted_nicely(l):
32 | """ Sort the given iterable in the way that humans expect."""
33 | convert = lambda text: int(text) if text.isdigit() else text
34 | alphanum_key = lambda key: [ convert(c) for c in re.split('([0-9]+)', key) ]
35 | return sorted(l, key = alphanum_key)
36 |
37 | # list of imeis
38 | imeis = []
39 |
40 | # csv filenames
41 | csv_filenames = []
42 |
43 | print('Artemis Global Tracker: Stitcher')
44 | print
45 |
46 | # Ask the user if they want to Overwrite or Append existing sbd files
47 | try:
48 | overwrite_files = input('Do you want to Overwrite or Append_To existing csv files? (O/A) (Default: O) : ')
49 | except:
50 | overwrite_files = 'O'
51 | if (overwrite_files != 'O') and (overwrite_files != 'o') and (overwrite_files != 'A') and (overwrite_files != 'a'):
52 | overwrite_files = 'O'
53 | if (overwrite_files == 'o'): overwrite_files = 'O'
54 |
55 | print
56 |
57 | # Identify all .bin SBD files
58 | for root, dirs, files in os.walk(".", followlinks=False):
59 |
60 | # Comment out the next two lines to process all files in this directory and its subdirectories
61 | # Uncomment one or the other to search only this directory or only subdirectories
62 | #if root != ".": # Ignore files in this directory - only process subdirectories
63 | if root == ".": # Ignore subdirectories - only process this directory
64 |
65 | # Uncomment and modify the next two lines to only process a single subdirectory
66 | #search_me = "Test_Messages" # Search this subdirectory
67 | #if root == os.path.join(".",search_me): # Only process files in this subdirectory
68 |
69 | if len(files) > 0:
70 | # Find filenames with the correct format (imei-momsn.bin)
71 | valid_files = [afile for afile in files if ((afile[-4:] == '.bin') and (afile[15:16] == '-'))]
72 | else:
73 | valid_files = []
74 |
75 | if len(valid_files) > 0:
76 | for filename in sorted_nicely(valid_files):
77 | longfilename = os.path.join(root, filename)
78 | momsn = filename[16:-4] # Get the momsn
79 | imei = filename[0:15] # Get the imei
80 |
81 | print('Found SBD file from beacon IMEI',imei,'with MOMSN',momsn)
82 |
83 | # Check if this new file is from a beacon imei we haven't seen before
84 | if imei in imeis:
85 | pass # We have seen this one before
86 | else:
87 | imeis.append(imei) # New imei so add it to the list
88 | csv_filenames.append('%s.csv'%imei) # Create the csv filename
89 | if (overwrite_files == 'O'):
90 | fp = open(csv_filenames[-1],'w') # Create the csv file (clear it if it already exists)
91 | fp.close()
92 |
93 | index = imeis.index(imei) # Get the imei index
94 |
95 | fp = open(csv_filenames[index],'a') # Open the csv file for append
96 | fr = open(longfilename,'r') # Open the SBD file for read
97 | the_sbd = fr.read() # Read the SBD data
98 | if (ord(the_sbd[-2]) == 13) and (ord(the_sbd[-1]) == 10):
99 | the_sbd = the_sbd[:-2] # Strip CRLF is present
100 | if (ord(the_sbd[-1]) == 13):
101 | the_sbd = the_sbd[:-1] # Strip CR is present
102 | if (ord(the_sbd[-1]) == 10):
103 | the_sbd = the_sbd[:-1] # Strip LF is present
104 | fp.write(the_sbd) # Copy the SBD data into the csv file
105 | fp.write(',') # Add a comma
106 | fp.write(momsn) # Add the MOMSN
107 | fp.write('\n') # Add LF
108 | fr.close() # Close the SBD file
109 | fp.close() # Close the csv file
110 |
111 |
112 |
113 |
114 |
115 |
116 |
--------------------------------------------------------------------------------
/Tools/Artemis_Global_Tracker_Mapping_Tools/map_image_blank.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/Tools/Artemis_Global_Tracker_Mapping_Tools/map_image_blank.png
--------------------------------------------------------------------------------
/Tools/README.md:
--------------------------------------------------------------------------------
1 | # Artemis Global Tracker: Tools
2 |
3 | Tools to help: configure the full GlobalTracker example via USB or remotely via Iridium messaging; and track and map its position
4 |
5 | ## /Artemis_Global_Tracker_Configuration_Tool
6 |
7 | A Python3 PyQt5 tool to configure the full GlobalTracker example via USB or remotely via Iridium messaging.
8 |
9 | 
10 |
11 | Please refer to the [GlobalTracker FAQs](../Documentation/GlobalTracker_FAQs/README.md) for full instructions.
12 |
13 | ### Quickstart:
14 |
15 | First select the message fields (MOFIELDS) that you want the tracker to send. If you are going to use the Mapper (see below)
16 | to track the tracker, you need to select **DATETIME**, **LAT**, **LON**, **ALT**, **SPEED** and **HEAD**. Tick the _Include_ checkbox for **MOFIELDS** too
17 | otherwise the settings will not be updated. The Mapper expects text messages, while the Message Translator can translate binary messages.
18 | Depending on which program you want to use, either tick the FLAGS1 _Send message in binary format_ box or ensure it is not ticked.
19 | Tick the **FLAGS1** _Include_ checkbox too to make sure FLAGS1 is updated. Click _Calculate Config_ to generate the configuration message.
20 |
21 | You can upload the configuration to a tracker locally by:
22 | - Connecting the tracker via a USB-C cable
23 | - Click the _Refresh_ button and select the COM port
24 | - Click _Open Port_ and you should see a welcome message from the tracker
25 | - Click _Upload Config_ to send the configuration message to the tracker
26 | - Check the _Serial Terminal_ to see if the configuration worked
27 | - Click _Close Port_ and then disconnect the tracker
28 |
29 | You can update a tracker remotely by:
30 | - Right-clicking in the _Configuration Message_ window and select _Select All_
31 | - Right-click again and select _Copy_
32 | - Log in to [Rock7 Operations](https://rockblock.rock7.com/Operations)
33 | - Click on the _Send a Message_ tab
34 | - Select _Mode Hex_ and paste the configuration message into the _Hex String_ window
35 | - Tick the RockBLOCK serial number for the tracker(s) you want to update and click _Send Message_
36 | - The tracker settings will be updated and stored the next time the tracker sends a message
37 |
38 | ## /Artemis_Global_Tracker_Mapping_Tools
39 |
40 | A set of Python tools which will allow you to: download messages from the tracker via a GMail account; stitch the messages together into a single .csv file;
41 | convert the .csv file into .kml files for Google Earth; and display the real-time paths and locations of up to eight trackers using the Google Maps Static API.
42 |
43 | 
44 |
45 | The tools are:
46 | - **Artemis_Global_Tracker_GMail_Downloader.py:** a Python3 tool which uses the GMail API to download messages from the tracker from your GMail account.
47 | - **Artemis_Global_Tracker_Message_Translator.py:** a Python 3 tool to translate binary SBD messages. It can read messages from local files or an IMAP server and optionally create a GPX file from all read messages.
48 | - **Artemis_Global_Tracker_Mapper.py:** a Python3 PyQt5 tool which will read the tracker messages downloaded by the Downloader and display the location and routes of up to eight trackers on Google Maps Static images.
49 | - **Artemis_Global_Tracker_Stitcher.py:** this tool will stitch the individual tracker messages downloaded by the Downloader together into combined .csv files. Each tracker gets its own .csv file.
50 | - **Artemis_Global_Tracker_CSV_DateTime.py:** this tool will convert the first column of the stitched .csv files from YYYYMMDDHHMMSS DateTime format into a more friendly DD/MM/YY,HH:MM:SS format.
51 | - **Artemis_Global_Tracker_DateTime_CSV_to_KML.py:** this tool will convert the .csv files produced by the CSV_DateTime tool into .kml files that can be viewed in Google Earth. The path of the tracker can be shown as: a 2D (course over ground) or 3D (course and altitude) linestring; points (labelled with message sequence numbers); and arrows (indicating the heading of the tracker).
52 | - **Flight_Simulator.py:** this tool generates simulated messages from up to eight virtual trackers. These messages can be used to test the other tools, including the Mapper.
53 |
54 | ### Artemis_Global_Tracker_GMail_Downloader.py:
55 |
56 | Artemis_Global_Tracker_GMail_Downloader.py is a Python3 tool which uses the GMail API to download messages from the tracker from your GMail account.
57 |
58 | Create yourself a GMail account. You can then add that email address to the _Delivery Group_ for your tracker in [Rock7 Operations](https://rockblock.rock7.com/Operations). Choose _EMAIL_ROCKBLOCK_ as the message format.
59 |
60 | 
61 |
62 | Log in to your GMail account in a web browser and create a 'label' (folder) called _SBD_. You can do this by: selecting an email in your inbox; then click on the _Move to_ icon
63 | (the folder icon with the right arrow); select _Create new_; enter _SBD_ as the new label name; leave the Nest box empty; click _Create_. Your tracker messages will be automatically
64 | moved to this label by the Downloader to avoid clogging up your inbox.
65 |
66 | The Downloader requires access to your GMail credentials. Follow [these instructions](https://developers.google.com/gmail/api/quickstart/python)
67 | to create your credentials and enable access for Python. After you have run the quickstart.py you will need to delete your token.pickle file as the
68 | Downloader needs _modify_ permissions and quickstart.py only requests _readonly_ permissions. A new token.pickle will be created when you run the
69 | Downloader.
70 |
71 | You may see a warning message in your browser when you log in to authenticate the new token.pickle. This is normal. Follow the _Advanced_ link; then _Go to Quickstart (unsafe)_;
72 | then click _Allow_; then click _Allow_ again. If the credentials were created successfully, you should see the message _The authentication flow has completed. You may close this window._
73 |
74 | 
75 | 
76 | 
77 | 
78 | 
79 |
80 | When you run the Downloader, it will automatically check your GMail inbox every 15 seconds for new tracker messages. When it finds one, it will download the SBD .bin attachment to to your computer,
81 | mark the message as seen (read) and 'move' it to a folder called SBD by changing the message labels. This avoids clogging up your inbox. All of the messages are in SBD if you need to download the
82 | attachments again.
83 |
84 | ### Artemis_Global_Tracker_Message_Translator.py:
85 |
86 | A command-line script to translate binary SBD messages. Give the files to translate as argument, e.g. `*.bin`. To write coordinates into a GPX track, use the `-o` option combined with an output filename.
87 | Example:
88 | ```
89 | python3 Artemis_Global_Tracker_Message_Translator.py *.bin -o track.gpx
90 | ```
91 |
92 | Alternatively, messages can be read from email attachments from an IMAP server with the `-i` option. In this case, give the name of an ini file with the server details as argument. The ini file should
93 | look as follows:
94 | ```
95 | [email]
96 | host = imap.mymailserver.com
97 | user = myusername
98 | password = mypassword
99 | from = 300123456789012@rockblock.rock7.com
100 | ```
101 | Adjust the entries according to your configuration. The `from` entry filters messages according to sender and is handy to select messages from a specific device. Write just `@rockblock.rock7.com`
102 | to process all messages from RockBLOCK. By default, the script only retrieves new messages. Use the `-a` option to retrieve all messages. Example for invoking the script:
103 | ```
104 | python3 Artemis_Global_Tracker_Message_Translator.py -i imap_settings.ini -a -o track.gpx
105 | ```
106 |
107 | ### Artemis_Global_Tracker_Mapper.py:
108 |
109 | 
110 |
111 | Artemis_Global_Tracker_Mapper.py uses the Google Maps Static API to display the location and paths of up to eight trackers. The code will check
112 | for the arrival of new .bin SBD messages, downloaded by the Downloader, every 15 seconds. When it finds one, it will display the location and path
113 | of the tracker on a Google Maps Static API image.
114 |
115 | If you are going to use the _Mapper_, run that first and tell it to ignore any existing .bin messages (if you want to).
116 | Then start the _Downloader_. The downloader will download any new messages received by your GMail account from Rock7.
117 | The Mapper will then pick them up and display your tracker's location.
118 |
119 | You can find more details about the Maps Static API [here](https://developers.google.com/maps/documentation/maps-static/intro). Sadly, the API is not free.
120 | You can find details of the pricing and plans [here](https://developers.google.com/maps/documentation/maps-static/usage-and-billing).
121 |
122 | Follow [these instructions](https://developers.google.com/maps/documentation/maps-static/get-api-key)
123 | to get your own key and copy and paste it into a file called _Google_Static_Maps_API_Key.txt_ so the mapper can read it.
124 |
125 | You will need to download _map_image_blank.png_ too. This is displayed until a .bin file is processed or whenever the GUI isn't able to download map images from the API.
126 |
127 | The displayed map is automatically centered on the position of a new tracker. The center position can be changed by left-clicking in the image. The zoom level defaults to '15'
128 | but can be changed using the zoom buttons.
129 |
130 | Each tracker gets its own colored button which matches the color of its map icon. Clicking on a tracker button will center the map on its location.
131 |
132 | Each tracker's path is displayed as a coloured line on the map. The Maps Static API can only accept requests up to 8K bytes in length. When tracking multiple trackers it is
133 | easy to exceed this and so the start of each tracker's route is automatically truncated if required.
134 |
135 | You can change the Mapper's _Update Interval_ using the drop down menu. Selecting a longer interval will reduce the number of Maps Static API requests.
136 |
137 | The GUI uses 640x480 pixel map images. Higher resolution images are available if you have a premium plan with Google.
138 |
139 | ### Artemis_Global_Tracker_Stitcher.py:
140 |
141 | Artemis_Global_Tracker_Stitcher.py will stitch the .bin SBD attachments downloaded by Artemis_Global_Tracker_GMail_Downloader.py together into a single .csv (Comma Separated Value)
142 | file which can be opened by (e.g.) Microsoft Excel or LibreOffice Calc. Each tracker gets its own .csv file.
143 |
144 | ### Artemis_Global_Tracker_CSV_DateTime.py:
145 |
146 | Artemis_Global_Tracker_CSV_DateTime.py will convert the first column of the stitched .csv file from YYYYMMDDHHMMSS format into DD/MM/YY,HH:MM:SS format, making the message
147 | timing easier to interpret using Excel or Calc.
148 |
149 | ### Artemis_Global_Tracker_DateTime_CSV_to_KML.py:
150 |
151 | Artemis_Global_Tracker_DateTime_CSV_to_KML.py will convert the .csv file produced by Artemis_Global_Tracker_CSV_DateTime.py into .kml files which can be opened in Google Earth.
152 | The complete path of the tracker can be shown as: a 2D (course over ground) or 3D (course and altitude) linestring; points (labelled with message sequence numbers);
153 | and arrows (indicating the heading of the tracker).
154 |
155 | You will need to install simplekml to allow the code to run:
156 | - pip install simplekml
157 |
158 | ### Flight_Simulator.py:
159 |
160 | Also included is a _Flight Simulator_ tool which will generate fake .bin SBD messages for eight virtual trackers travelling from
161 | St. James' Park (Newcastle, UK) to The Stadium of Light (Sunderland, UK) and reaching an altitude of 30km along the way.
162 | You can use this tool to test both the Mapper and the Stitcher / CSV / KML converters.
163 |
164 | 
165 |
166 | You can edit the code to create your own UK flight paths. The code uses Hannah Fry's Latitude and Longitude to OSGB coordinate converter.
167 |
--------------------------------------------------------------------------------
/binaries/Example14_SimpleTracker/Example14_SimpleTracker.ino.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/binaries/Example14_SimpleTracker/Example14_SimpleTracker.ino.bin
--------------------------------------------------------------------------------
/binaries/Example15_BetterTracker/Example15_BetterTracker.ino.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/binaries/Example15_BetterTracker/Example15_BetterTracker.ino.bin
--------------------------------------------------------------------------------
/binaries/Example16_GlobalTracker/Example16_GlobalTracker.ino.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/binaries/Example16_GlobalTracker/Example16_GlobalTracker.ino.bin
--------------------------------------------------------------------------------
/binaries/Example17_ProductionTest/Example17_ProductionTest.ino.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/binaries/Example17_ProductionTest/Example17_ProductionTest.ino.bin
--------------------------------------------------------------------------------
/binaries/Example18_ProductionTestPart2/Example18_ProductionTestPart2.ino.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/binaries/Example18_ProductionTestPart2/Example18_ProductionTestPart2.ino.bin
--------------------------------------------------------------------------------
/binaries/Example19_SerialTerminal/Example19_SerialTerminal.ino.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/binaries/Example19_SerialTerminal/Example19_SerialTerminal.ino.bin
--------------------------------------------------------------------------------
/binaries/Example1_Blink/Example1_Blink.ino.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/binaries/Example1_Blink/Example1_Blink.ino.bin
--------------------------------------------------------------------------------
/binaries/Example21_IridiumSerialAndPowerTest/Example21_IridiumSerialAndPowerTest.ino.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/binaries/Example21_IridiumSerialAndPowerTest/Example21_IridiumSerialAndPowerTest.ino.bin
--------------------------------------------------------------------------------
/binaries/Example5_GNSS/Example5_GNSS.ino.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/binaries/Example5_GNSS/Example5_GNSS.ino.bin
--------------------------------------------------------------------------------
/binaries/Example7_GetIMEI/Example7_GetIMEI.ino.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/binaries/Example7_GetIMEI/Example7_GetIMEI.ino.bin
--------------------------------------------------------------------------------
/binaries/Example9_GetTime/Example9_GetTime.ino.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/binaries/Example9_GetTime/Example9_GetTime.ino.bin
--------------------------------------------------------------------------------
/binaries/README.md:
--------------------------------------------------------------------------------
1 | # Artemis Global Tracker: Binaries
2 |
3 | This folder contains the binary files for some of the AGT examples.
4 |
5 | You can upload these to the AGT using the [Artemis Firmware Upload GUI](https://github.com/sparkfun/Artemis-Firmware-Upload-GUI) instead of the Arduino IDE.
6 | Which is handy if you want to quickly update the firmware in the field, or are not familiar with the IDE.
7 |
8 | To use:
9 |
10 | * Download and extract the [AGT repo ZIP](https://github.com/sparkfun/Artemis_Global_Tracker/archive/main.zip)
11 | * Download and extract the [AFU repo ZIP](https://github.com/sparkfun/Artemis-Firmware-Upload-GUI/archive/master.zip)
12 | * Run the AFU artemis_firmware_uploader_gui executable for your platform
13 | * **/Windows** contains the Windows .exe
14 | * **/OSX** contains an executable for macOS X
15 | * **/Linux** contains an executable built on Ubuntu
16 | * **/Raspberry_Pi__Debian** contains an executable for Raspberry Pi 4 (Debian Buster)
17 | * Select the AGT firmware file you'd like to upload (should end in *.bin*)
18 | * **Example1 - Blink** powers up the tracker and blinks the white LED (connected to D19).
19 | * **Example14 - Simple Tracker** is a simple tracker which: wakes up every INTERVAL minutes; gets a GNSS fix; reads the PHT sensor; and sends all the data in a SBD message.
20 | * **Example15 - Better Tracker** is a better tracker where the INTERVAL, RBDESTINATION and RBSOURCE are stored in 'EEPROM' (Flash) and can be configured via Iridium SBD messages.
21 | * **Example16 - Global Tracker** is the full Global Tracker. All of the settings can be configured via USB-C or remotely via an Iridium SBD message using the [Artemis Global Tracker Configuration Tool (AGTCT)](../Tools).
22 | * **Example19 - Serial Terminal** allows the AGT to be operated via a simple Serial Terminal interface. Open the Serial Monitor or a Terminal Emulator at 115200 baud to see the menu.
23 | * Attach the AGT target board using USB
24 | * Select the COM port (hit Refresh to refresh the list of USB devices)
25 | * Press Upload
26 |
27 | The GUI does take a few seconds to load and run. _**Don't Panic**_ if the GUI does not start right away.
28 |
--------------------------------------------------------------------------------
/img/16469-Artemis_Global_Tracker-02.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/img/16469-Artemis_Global_Tracker-02.jpg
--------------------------------------------------------------------------------
/img/16469-Artemis_Global_Tracker-04.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/img/16469-Artemis_Global_Tracker-04.jpg
--------------------------------------------------------------------------------
/img/9603N.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/img/9603N.JPG
--------------------------------------------------------------------------------
/img/AGTCT1.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/img/AGTCT1.PNG
--------------------------------------------------------------------------------
/img/AGTCT10.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/img/AGTCT10.PNG
--------------------------------------------------------------------------------
/img/AGTCT11.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/img/AGTCT11.PNG
--------------------------------------------------------------------------------
/img/AGTCT12.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/img/AGTCT12.PNG
--------------------------------------------------------------------------------
/img/AGTCT13.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/img/AGTCT13.PNG
--------------------------------------------------------------------------------
/img/AGTCT14.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/img/AGTCT14.PNG
--------------------------------------------------------------------------------
/img/AGTCT2.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/img/AGTCT2.PNG
--------------------------------------------------------------------------------
/img/AGTCT3.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/img/AGTCT3.PNG
--------------------------------------------------------------------------------
/img/AGTCT4.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/img/AGTCT4.PNG
--------------------------------------------------------------------------------
/img/AGTCT5.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/img/AGTCT5.PNG
--------------------------------------------------------------------------------
/img/AGTCT6.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/img/AGTCT6.PNG
--------------------------------------------------------------------------------
/img/AGTCT7.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/img/AGTCT7.PNG
--------------------------------------------------------------------------------
/img/AGTCT8.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/img/AGTCT8.PNG
--------------------------------------------------------------------------------
/img/AGTCT9.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/img/AGTCT9.PNG
--------------------------------------------------------------------------------
/img/Artemis.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/img/Artemis.JPG
--------------------------------------------------------------------------------
/img/Bottom.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/img/Bottom.JPG
--------------------------------------------------------------------------------
/img/Bus_V.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/img/Bus_V.JPG
--------------------------------------------------------------------------------
/img/Config.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/img/Config.JPG
--------------------------------------------------------------------------------
/img/Delivery_Group.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/img/Delivery_Group.PNG
--------------------------------------------------------------------------------
/img/Dimensions.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/img/Dimensions.png
--------------------------------------------------------------------------------
/img/GPS_EN.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/img/GPS_EN.JPG
--------------------------------------------------------------------------------
/img/Google_Earth.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/img/Google_Earth.JPG
--------------------------------------------------------------------------------
/img/LTC3225.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/img/LTC3225.JPG
--------------------------------------------------------------------------------
/img/LiPo.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/img/LiPo.JPG
--------------------------------------------------------------------------------
/img/Mapper.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/img/Mapper.JPG
--------------------------------------------------------------------------------
/img/PHT.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/img/PHT.JPG
--------------------------------------------------------------------------------
/img/Pins.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/img/Pins.JPG
--------------------------------------------------------------------------------
/img/Power_Select.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/img/Power_Select.JPG
--------------------------------------------------------------------------------
/img/Quickstart1.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/img/Quickstart1.PNG
--------------------------------------------------------------------------------
/img/Quickstart2.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/img/Quickstart2.PNG
--------------------------------------------------------------------------------
/img/Quickstart3.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/img/Quickstart3.PNG
--------------------------------------------------------------------------------
/img/Quickstart4.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/img/Quickstart4.PNG
--------------------------------------------------------------------------------
/img/Quickstart5.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/img/Quickstart5.PNG
--------------------------------------------------------------------------------
/img/Qwiic.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/img/Qwiic.JPG
--------------------------------------------------------------------------------
/img/RF.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/img/RF.JPG
--------------------------------------------------------------------------------
/img/Reg.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/img/Reg.JPG
--------------------------------------------------------------------------------
/img/Reg_EN.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/img/Reg_EN.JPG
--------------------------------------------------------------------------------
/img/Top.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/img/Top.JPG
--------------------------------------------------------------------------------
/img/Tracker_with_Internet.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/img/Tracker_with_Internet.JPG
--------------------------------------------------------------------------------
/img/USB.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/img/USB.JPG
--------------------------------------------------------------------------------
/img/VBCKP.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/img/VBCKP.JPG
--------------------------------------------------------------------------------
/img/ZOE-M8Q_Mask.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/img/ZOE-M8Q_Mask.JPG
--------------------------------------------------------------------------------
/img/ZOE-M8Q_Paste.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/img/ZOE-M8Q_Paste.JPG
--------------------------------------------------------------------------------
/img/ZOE-M8Q_Placed.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/img/ZOE-M8Q_Placed.JPG
--------------------------------------------------------------------------------
/img/ZOE.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparkfunX/Artemis_Global_Tracker/c4258bcefcb37aaa17a8662f89b0a0d5369ebf7d/img/ZOE.JPG
--------------------------------------------------------------------------------