├── 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 | ![Artemis](../../img/Artemis.JPG) 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 | ![Power_Select](../../img/Power_Select.JPG) 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 | ![USB](../../img/USB.JPG) 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 | ![LiPo](../../img/LiPo.JPG) 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 | ![Reg](../../img/Reg.JPG) 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 | ![Reg_EN](../../img/Reg_EN.JPG) 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 | ![ZOE](../../img/ZOE.JPG) 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 | ![VBCKP](../../img/VBCKP.JPG) 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 | ![GPS_EN](../../img/GPS_EN.JPG) 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 | ![9603N](../../img/9603N.JPG) 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 | ![LTC3225](../../img/LTC3225.JPG) 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 | ![RF](../../img/RF.JPG) 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 | ![PHT](../../img/PHT.JPG) 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 | ![Pins](../../img/Pins.JPG) 133 | 134 | I2C port 4 is broken out on a standard SparkFun Qwiic connector. 135 | 136 | ![Qwiic](../../img/Qwiic.JPG) 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 | ![Bus_V](../../img/Bus_V.JPG) 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 | [![SparkX Artemis Global Tracker (SPX-16469)](img/16469-Artemis_Global_Tracker-02.jpg)](https://www.sparkfun.com/products/16469) 7 | 8 | [*SparkX Artemis Global Tracker (SPX-16469)*](https://www.sparkfun.com/products/16469) 9 | 10 | [![SparkX Artemis Global Tracker (SPX-16469)](img/16469-Artemis_Global_Tracker-04.jpg)](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 | ![Config](../img/Config.JPG) 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 | ![Tracker with Internet](../img/Tracker_with_Internet.JPG) 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 | ![Delivery Group](../img/Delivery_Group.PNG) 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 | ![Quickstart1](../img/Quickstart1.PNG) 75 | ![Quickstart2](../img/Quickstart2.PNG) 76 | ![Quickstart3](../img/Quickstart3.PNG) 77 | ![Quickstart4](../img/Quickstart4.PNG) 78 | ![Quickstart5](../img/Quickstart5.PNG) 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 | ![Mapper](../img/Mapper.JPG) 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 | ![Google_Earth](../img/Google_Earth.JPG) 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 --------------------------------------------------------------------------------