From 1528d8bb96b2e0d1610bab35be345dce1b3f9083 Mon Sep 17 00:00:00 2001 From: asiemsen Date: Tue, 29 Jul 2025 19:05:04 -0500 Subject: [PATCH 1/6] change boot sequence to allow for writing to internal file system --- src/flight-software/boot.py | 38 +++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/flight-software/boot.py b/src/flight-software/boot.py index e69de29..b5f46f8 100644 --- a/src/flight-software/boot.py +++ b/src/flight-software/boot.py @@ -0,0 +1,38 @@ +import os +import time + +import storage + +mount_points = [ + "/sd", +] + +wait_time = 0.02 + +storage.disable_usb_drive() +print("Disabling USB drive") +time.sleep(wait_time) + +storage.remount("/", False) +print("Remounting root filesystem") +time.sleep(wait_time) + +attempts = 0 +while attempts < 5: + attempts += 1 + try: + for path in mount_points: + try: + os.mkdir(path) + print(f"Mount point {path} created.") + except OSError: + print(f"Mount point {path} already exists.") + except Exception as e: + print(f"Error creating mount point {path}: {e}") + time.sleep(wait_time) + continue + + break + +storage.enable_usb_drive() +print("Enabling USB drive") \ No newline at end of file From ec5382fa95a95a05c0a4c9764a8724e10a2e2b64 Mon Sep 17 00:00:00 2001 From: asiemsen Date: Sat, 2 Aug 2025 17:17:42 -0500 Subject: [PATCH 2/6] adding sd init to main.py --- src/flight-software/main.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/flight-software/main.py b/src/flight-software/main.py index b0bbdbf..0ba23f0 100644 --- a/src/flight-software/main.py +++ b/src/flight-software/main.py @@ -36,6 +36,7 @@ from lib.pysquared.rtc.manager.microcontroller import MicrocontrollerManager from lib.pysquared.sleep_helper import SleepHelper from lib.pysquared.watchdog import Watchdog +from lib.pysquared.sdcard import SDCardManager from version import __version__ boot_time: float = time.time() @@ -45,6 +46,7 @@ (boot_count := Counter(index=Register.boot_count)).increment() error_count: Counter = Counter(index=Register.error_count) + logger: Logger = Logger( error_counter=error_count, colorized=False, @@ -77,6 +79,11 @@ board.SPI0_MISO, ) + sdCard: SDCardManager = SDCardManager( + spi0, + + ) + radio = RFM9xManager( logger, config.radio, From f6f62da054529d21f4f737f33ce1a269b1bc41c1 Mon Sep 17 00:00:00 2001 From: asiemsen Date: Tue, 5 Aug 2025 18:38:40 -0500 Subject: [PATCH 3/6] cleaned files --- src/flight-software/boot.py | 2 +- src/flight-software/main.py | 8 +- src/flight-software/repl.py | 8 ++ usbmodem101/boot.py | 38 +++++++++ usbmodem101/config.json | 84 ++++++++++++++++++++ usbmodem101/main.py | 152 ++++++++++++++++++++++++++++++++++++ usbmodem101/repl.py | 108 +++++++++++++++++++++++++ usbmodem101/safemode.py | 8 ++ usbmodem101/version.py | 1 + 9 files changed, 405 insertions(+), 4 deletions(-) create mode 100644 usbmodem101/boot.py create mode 100644 usbmodem101/config.json create mode 100644 usbmodem101/main.py create mode 100644 usbmodem101/repl.py create mode 100644 usbmodem101/safemode.py create mode 100644 usbmodem101/version.py diff --git a/src/flight-software/boot.py b/src/flight-software/boot.py index b5f46f8..c9f4c42 100644 --- a/src/flight-software/boot.py +++ b/src/flight-software/boot.py @@ -13,7 +13,7 @@ print("Disabling USB drive") time.sleep(wait_time) -storage.remount("/", False) +storage.mount("/", False) print("Remounting root filesystem") time.sleep(wait_time) diff --git a/src/flight-software/main.py b/src/flight-software/main.py index 0ba23f0..40f6973 100644 --- a/src/flight-software/main.py +++ b/src/flight-software/main.py @@ -36,7 +36,7 @@ from lib.pysquared.rtc.manager.microcontroller import MicrocontrollerManager from lib.pysquared.sleep_helper import SleepHelper from lib.pysquared.watchdog import Watchdog -from lib.pysquared.sdcard import SDCardManager +from lib.pysquared.sd_card import SDCardManager from version import __version__ boot_time: float = time.time() @@ -80,8 +80,8 @@ ) sdCard: SDCardManager = SDCardManager( - spi0, - + spi0, + board.SPI0_CS1 ) radio = RFM9xManager( @@ -92,6 +92,8 @@ initialize_pin(logger, board.RF1_RST, digitalio.Direction.OUTPUT, True), ) + logger.sd_card = sdCard + packet_manager = PacketManager( logger, radio, diff --git a/src/flight-software/repl.py b/src/flight-software/repl.py index 4c1275a..e542f19 100644 --- a/src/flight-software/repl.py +++ b/src/flight-software/repl.py @@ -29,6 +29,7 @@ from lib.pysquared.rtc.manager.microcontroller import MicrocontrollerManager from lib.pysquared.sleep_helper import SleepHelper from lib.pysquared.watchdog import Watchdog +from lib.pysquared.sd_card import SDCardManager from version import __version__ boot_time: float = time.time() @@ -63,6 +64,13 @@ board.SPI0_MISO, ) + sdCard: SDCardManager = SDCardManager( + spi0, + board.SPI0_CS1 + ) + + logger.sd_card = sdCard + radio = RFM9xManager( logger, config.radio, diff --git a/usbmodem101/boot.py b/usbmodem101/boot.py new file mode 100644 index 0000000..b5f46f8 --- /dev/null +++ b/usbmodem101/boot.py @@ -0,0 +1,38 @@ +import os +import time + +import storage + +mount_points = [ + "/sd", +] + +wait_time = 0.02 + +storage.disable_usb_drive() +print("Disabling USB drive") +time.sleep(wait_time) + +storage.remount("/", False) +print("Remounting root filesystem") +time.sleep(wait_time) + +attempts = 0 +while attempts < 5: + attempts += 1 + try: + for path in mount_points: + try: + os.mkdir(path) + print(f"Mount point {path} created.") + except OSError: + print(f"Mount point {path} already exists.") + except Exception as e: + print(f"Error creating mount point {path}: {e}") + time.sleep(wait_time) + continue + + break + +storage.enable_usb_drive() +print("Enabling USB drive") \ No newline at end of file diff --git a/usbmodem101/config.json b/usbmodem101/config.json new file mode 100644 index 0000000..5893978 --- /dev/null +++ b/usbmodem101/config.json @@ -0,0 +1,84 @@ +{ + "critical_battery_voltage": 6.6, + "cubesat_name": "PROVES-MY_SATELLITE_NAME", + "current_draw": 240.5, + "debug": true, + "degraded_battery_voltage": 5.4, + "detumble_enable_x": true, + "detumble_enable_y": true, + "detumble_enable_z": true, + "heating": false, + "jokes": [ + "Hey it is pretty cold up here, did someone forget to pay the electric bill?", + "sudo rf - rf*", + "Why did the astronaut break up with his girlfriend? He needed space.", + "Why did the sun go to school? To get a little brighter.", + "why is the mall called the mall? because instead of going to one store you go to them all", + "Alien detected. Blurring photo...", + "Wait it is all open source? Always has been... www.github.com/proveskit", + "What did 0 say to 1? You're a bit too much.", + "Pleiades - Orpheus has been recently acquired by the Onion News Network", + "This jokesat was brought to you by the Bronco Space Ministry of Labor and Job Placement", + "Catch you on the next pass!", + "Pleiades - Orpheus was not The Impostor", + "Sorry for messing with your long-exposure astrophoto!", + "Better buy a telescope. Wanna see me. Buy a telescope. Gonna be in space.", + "According to all known laws of aviation, there is no way bees should be able to fly...", + "You lost the game ", + "Bobby Tables is a good friend of mine", + "Why did the computer cross the road? To get a byte to eat!", + "Why are the astronauts not hungry when they got to space? They had a big launch.", + "Why did the computer get glasses? To improve its web sight!", + "What are computers favorite snacks? Chips!", + "Wait! I think I see a White 2019 Subaru Crosstrek 2.0i Premium", + "IS THAT A SUPRA?!", + "Finally escpaed the LA Traffic", + "My CubeSat is really good at jokes, but its delivery is always delayed.", + "exec order 66", + "I had a joke about UDP, but I am not sure if you'd get it.", + "I am not saying FSK modulation is the best way to send jokes, but at least it is never monotone!", + "I am sorry David, I am afrain I can not do that.", + "My memory is volatile like RAM, so it only makes sense that I forget things.", + "Imagine it gets stuck and just keeps repeating this joke every 2 mins", + "Check Engine: Error Code 404: Joke Not Found", + "CQ CQ KN6NAQ ... KN6NAT are you out there?", + "Woah is that the Launcher Orbiter?????", + "Everything in life is a spring if you think hard enough!", + "Your Mom", + "Your Mum", + "Your Face", + "not True lol", + "I have brought peace, freedom, justice, and security to my new empire! Your New Empire?" + ], + "last_battery_temp": 20.0, + "longest_allowable_sleep_time": 600, + "normal_battery_temp": 1, + "normal_battery_voltage": 6.9, + "normal_charge_current": 0.5, + "normal_micro_temp": 20, + "normal_temp": 20, + "radio": { + "fsk": { + "broadcast_address": 255, + "modulation_type": 0, + "node_address": 1 + }, + "license": "KK4PDM", + "lora": { + "ack_delay": 0.2, + "coding_rate": 8, + "cyclic_redundancy_check": true, + "max_output": true, + "spreading_factor": 8, + "transmit_power": 23 + }, + "modulation": "LoRa", + "start_time": 80000, + "transmit_frequency": 437.4 + }, + "reboot_time": 3600, + "repeat_code": "RP", + "sleep_duration": 30, + "super_secret_code": "ABCD", + "turbo_clock": false +} diff --git a/usbmodem101/main.py b/usbmodem101/main.py new file mode 100644 index 0000000..b0bbdbf --- /dev/null +++ b/usbmodem101/main.py @@ -0,0 +1,152 @@ +# This is where the magic happens! +# This file is executed on every boot (including wake-boot from deepsleep) +# Created By: Michael Pham + +""" +Built for the PySquared FC Board +Version: 2.0.0 +Published: Nov 19, 2024 +""" + +import gc +import os +import time + +import digitalio +import microcontroller +from busio import SPI + +try: + from board_definitions import proveskit_rp2040_v4 as board +except ImportError: + import board + +from lib.proveskit_rp2040_v4.register import Register +from lib.pysquared.beacon import Beacon +from lib.pysquared.cdh import CommandDataHandler +from lib.pysquared.config.config import Config +from lib.pysquared.hardware.busio import _spi_init, initialize_i2c_bus +from lib.pysquared.hardware.digitalio import initialize_pin +from lib.pysquared.hardware.imu.manager.lsm6dsox import LSM6DSOXManager +from lib.pysquared.hardware.magnetometer.manager.lis2mdl import LIS2MDLManager +from lib.pysquared.hardware.radio.manager.rfm9x import RFM9xManager +from lib.pysquared.hardware.radio.packetizer.packet_manager import PacketManager +from lib.pysquared.logger import Logger, LogLevel +from lib.pysquared.nvm.counter import Counter +from lib.pysquared.rtc.manager.microcontroller import MicrocontrollerManager +from lib.pysquared.sleep_helper import SleepHelper +from lib.pysquared.watchdog import Watchdog +from version import __version__ + +boot_time: float = time.time() + +rtc = MicrocontrollerManager() + +(boot_count := Counter(index=Register.boot_count)).increment() +error_count: Counter = Counter(index=Register.error_count) + +logger: Logger = Logger( + error_counter=error_count, + colorized=False, + log_level=LogLevel.INFO, +) + +logger.info( + "Booting", + hardware_version=os.uname().version, + software_version=__version__, +) + +try: + loiter_time: int = 5 + for i in range(loiter_time): + logger.info(f"Code Starting in {loiter_time-i} seconds") + time.sleep(1) + + watchdog = Watchdog(logger, board.WDT_WDI) + watchdog.pet() + + logger.debug("Initializing Config") + config: Config = Config("config.json") + + # TODO(nateinaction): fix spi init + spi0: SPI = _spi_init( + logger, + board.SPI0_SCK, + board.SPI0_MOSI, + board.SPI0_MISO, + ) + + radio = RFM9xManager( + logger, + config.radio, + spi0, + initialize_pin(logger, board.SPI0_CS0, digitalio.Direction.OUTPUT, True), + initialize_pin(logger, board.RF1_RST, digitalio.Direction.OUTPUT, True), + ) + + packet_manager = PacketManager( + logger, + radio, + config.radio.license, + Counter(Register.message_count), + 0.2, + ) + + i2c1 = initialize_i2c_bus( + logger, + board.I2C1_SCL, + board.I2C1_SDA, + 100000, + ) + + magnetometer = LIS2MDLManager(logger, i2c1) + + imu = LSM6DSOXManager(logger, i2c1, 0x6B) + + sleep_helper = SleepHelper(logger, config, watchdog) + + cdh = CommandDataHandler(logger, config, packet_manager) + + beacon = Beacon( + logger, + config.cubesat_name, + packet_manager, + boot_time, + imu, + magnetometer, + radio, + error_count, + boot_count, + ) + + def nominal_power_loop(): + logger.debug( + "FC Board Stats", + bytes_remaining=gc.mem_free(), + ) + + packet_manager.send(config.radio.license.encode("utf-8")) + + beacon.send() + + cdh.listen_for_commands(10) + + sleep_helper.safe_sleep(config.sleep_duration) + + try: + logger.info("Entering main loop") + while True: + # TODO(nateinaction): Modify behavior based on power state + nominal_power_loop() + + except Exception as e: + logger.critical("Critical in Main Loop", e) + time.sleep(10) + microcontroller.on_next_reset(microcontroller.RunMode.NORMAL) + microcontroller.reset() + finally: + logger.info("Going Neutral!") + +except Exception as e: + logger.critical("An exception occured within main.py", e) diff --git a/usbmodem101/repl.py b/usbmodem101/repl.py new file mode 100644 index 0000000..4c1275a --- /dev/null +++ b/usbmodem101/repl.py @@ -0,0 +1,108 @@ +""" +Built for the PySquared FC Board V4x +Published: May, 2025 +""" + +import os +import time + +import digitalio +from busio import SPI + +try: + from board_definitions import proveskit_rp2040_v4 as board +except ImportError: + import board + +from lib.proveskit_rp2040_v4.register import Register +from lib.pysquared.beacon import Beacon +from lib.pysquared.cdh import CommandDataHandler +from lib.pysquared.config.config import Config +from lib.pysquared.hardware.busio import _spi_init, initialize_i2c_bus +from lib.pysquared.hardware.digitalio import initialize_pin +from lib.pysquared.hardware.imu.manager.lsm6dsox import LSM6DSOXManager +from lib.pysquared.hardware.magnetometer.manager.lis2mdl import LIS2MDLManager +from lib.pysquared.hardware.radio.manager.rfm9x import RFM9xManager +from lib.pysquared.hardware.radio.packetizer.packet_manager import PacketManager +from lib.pysquared.logger import Logger +from lib.pysquared.nvm.counter import Counter +from lib.pysquared.rtc.manager.microcontroller import MicrocontrollerManager +from lib.pysquared.sleep_helper import SleepHelper +from lib.pysquared.watchdog import Watchdog +from version import __version__ + +boot_time: float = time.time() + +rtc = MicrocontrollerManager() + +(boot_count := Counter(index=Register.boot_count)).increment() +error_count: Counter = Counter(index=Register.error_count) + +logger: Logger = Logger( + error_counter=error_count, + colorized=False, +) + +logger.info( + "Booting", + hardware_version=os.uname().version, + software_version=__version__, +) + +try: + watchdog = Watchdog(logger, board.WDT_WDI) + + logger.debug("Initializing Config") + config: Config = Config("config.json") + + # TODO(nateinaction): fix spi init + spi0: SPI = _spi_init( + logger, + board.SPI0_SCK, + board.SPI0_MOSI, + board.SPI0_MISO, + ) + + radio = RFM9xManager( + logger, + config.radio, + spi0, + initialize_pin(logger, board.SPI0_CS0, digitalio.Direction.OUTPUT, True), + initialize_pin(logger, board.RF1_RST, digitalio.Direction.OUTPUT, True), + ) + + packet_manager = PacketManager( + logger, + radio, + config.radio.license, + Counter(Register.message_count), + 0.2, + ) + + i2c1 = initialize_i2c_bus( + logger, + board.I2C1_SCL, + board.I2C1_SDA, + 100000, + ) + + magnetometer = LIS2MDLManager(logger, i2c1) + + imu = LSM6DSOXManager(logger, i2c1, 0x6B) + + sleep_helper = SleepHelper(logger, config, watchdog) + + cdh = CommandDataHandler(logger, config, packet_manager) + + beacon = Beacon( + logger, + config.cubesat_name, + packet_manager, + boot_time, + imu, + magnetometer, + radio, + ) + +except Exception as e: + logger.critical("An exception occurred within repl.py", e) diff --git a/usbmodem101/safemode.py b/usbmodem101/safemode.py new file mode 100644 index 0000000..0d4496a --- /dev/null +++ b/usbmodem101/safemode.py @@ -0,0 +1,8 @@ +import time + +import microcontroller + +print("I am in safemode. Help!") + +time.sleep(10) +microcontroller.reset() diff --git a/usbmodem101/version.py b/usbmodem101/version.py new file mode 100644 index 0000000..cf194e0 --- /dev/null +++ b/usbmodem101/version.py @@ -0,0 +1 @@ +__version__ = '' From deac851d8dfaf4f3996cef502baf699d9088d9ff Mon Sep 17 00:00:00 2001 From: asiemsen Date: Tue, 5 Aug 2025 18:43:17 -0500 Subject: [PATCH 4/6] getting rid of usbmodem101 directory --- usbmodem101/boot.py | 38 ---------- usbmodem101/config.json | 84 ---------------------- usbmodem101/main.py | 152 ---------------------------------------- usbmodem101/repl.py | 108 ---------------------------- usbmodem101/safemode.py | 8 --- usbmodem101/version.py | 1 - 6 files changed, 391 deletions(-) delete mode 100644 usbmodem101/boot.py delete mode 100644 usbmodem101/config.json delete mode 100644 usbmodem101/main.py delete mode 100644 usbmodem101/repl.py delete mode 100644 usbmodem101/safemode.py delete mode 100644 usbmodem101/version.py diff --git a/usbmodem101/boot.py b/usbmodem101/boot.py deleted file mode 100644 index b5f46f8..0000000 --- a/usbmodem101/boot.py +++ /dev/null @@ -1,38 +0,0 @@ -import os -import time - -import storage - -mount_points = [ - "/sd", -] - -wait_time = 0.02 - -storage.disable_usb_drive() -print("Disabling USB drive") -time.sleep(wait_time) - -storage.remount("/", False) -print("Remounting root filesystem") -time.sleep(wait_time) - -attempts = 0 -while attempts < 5: - attempts += 1 - try: - for path in mount_points: - try: - os.mkdir(path) - print(f"Mount point {path} created.") - except OSError: - print(f"Mount point {path} already exists.") - except Exception as e: - print(f"Error creating mount point {path}: {e}") - time.sleep(wait_time) - continue - - break - -storage.enable_usb_drive() -print("Enabling USB drive") \ No newline at end of file diff --git a/usbmodem101/config.json b/usbmodem101/config.json deleted file mode 100644 index 5893978..0000000 --- a/usbmodem101/config.json +++ /dev/null @@ -1,84 +0,0 @@ -{ - "critical_battery_voltage": 6.6, - "cubesat_name": "PROVES-MY_SATELLITE_NAME", - "current_draw": 240.5, - "debug": true, - "degraded_battery_voltage": 5.4, - "detumble_enable_x": true, - "detumble_enable_y": true, - "detumble_enable_z": true, - "heating": false, - "jokes": [ - "Hey it is pretty cold up here, did someone forget to pay the electric bill?", - "sudo rf - rf*", - "Why did the astronaut break up with his girlfriend? He needed space.", - "Why did the sun go to school? To get a little brighter.", - "why is the mall called the mall? because instead of going to one store you go to them all", - "Alien detected. Blurring photo...", - "Wait it is all open source? Always has been... www.github.com/proveskit", - "What did 0 say to 1? You're a bit too much.", - "Pleiades - Orpheus has been recently acquired by the Onion News Network", - "This jokesat was brought to you by the Bronco Space Ministry of Labor and Job Placement", - "Catch you on the next pass!", - "Pleiades - Orpheus was not The Impostor", - "Sorry for messing with your long-exposure astrophoto!", - "Better buy a telescope. Wanna see me. Buy a telescope. Gonna be in space.", - "According to all known laws of aviation, there is no way bees should be able to fly...", - "You lost the game ", - "Bobby Tables is a good friend of mine", - "Why did the computer cross the road? To get a byte to eat!", - "Why are the astronauts not hungry when they got to space? They had a big launch.", - "Why did the computer get glasses? To improve its web sight!", - "What are computers favorite snacks? Chips!", - "Wait! I think I see a White 2019 Subaru Crosstrek 2.0i Premium", - "IS THAT A SUPRA?!", - "Finally escpaed the LA Traffic", - "My CubeSat is really good at jokes, but its delivery is always delayed.", - "exec order 66", - "I had a joke about UDP, but I am not sure if you'd get it.", - "I am not saying FSK modulation is the best way to send jokes, but at least it is never monotone!", - "I am sorry David, I am afrain I can not do that.", - "My memory is volatile like RAM, so it only makes sense that I forget things.", - "Imagine it gets stuck and just keeps repeating this joke every 2 mins", - "Check Engine: Error Code 404: Joke Not Found", - "CQ CQ KN6NAQ ... KN6NAT are you out there?", - "Woah is that the Launcher Orbiter?????", - "Everything in life is a spring if you think hard enough!", - "Your Mom", - "Your Mum", - "Your Face", - "not True lol", - "I have brought peace, freedom, justice, and security to my new empire! Your New Empire?" - ], - "last_battery_temp": 20.0, - "longest_allowable_sleep_time": 600, - "normal_battery_temp": 1, - "normal_battery_voltage": 6.9, - "normal_charge_current": 0.5, - "normal_micro_temp": 20, - "normal_temp": 20, - "radio": { - "fsk": { - "broadcast_address": 255, - "modulation_type": 0, - "node_address": 1 - }, - "license": "KK4PDM", - "lora": { - "ack_delay": 0.2, - "coding_rate": 8, - "cyclic_redundancy_check": true, - "max_output": true, - "spreading_factor": 8, - "transmit_power": 23 - }, - "modulation": "LoRa", - "start_time": 80000, - "transmit_frequency": 437.4 - }, - "reboot_time": 3600, - "repeat_code": "RP", - "sleep_duration": 30, - "super_secret_code": "ABCD", - "turbo_clock": false -} diff --git a/usbmodem101/main.py b/usbmodem101/main.py deleted file mode 100644 index b0bbdbf..0000000 --- a/usbmodem101/main.py +++ /dev/null @@ -1,152 +0,0 @@ -# This is where the magic happens! -# This file is executed on every boot (including wake-boot from deepsleep) -# Created By: Michael Pham - -""" -Built for the PySquared FC Board -Version: 2.0.0 -Published: Nov 19, 2024 -""" - -import gc -import os -import time - -import digitalio -import microcontroller -from busio import SPI - -try: - from board_definitions import proveskit_rp2040_v4 as board -except ImportError: - import board - -from lib.proveskit_rp2040_v4.register import Register -from lib.pysquared.beacon import Beacon -from lib.pysquared.cdh import CommandDataHandler -from lib.pysquared.config.config import Config -from lib.pysquared.hardware.busio import _spi_init, initialize_i2c_bus -from lib.pysquared.hardware.digitalio import initialize_pin -from lib.pysquared.hardware.imu.manager.lsm6dsox import LSM6DSOXManager -from lib.pysquared.hardware.magnetometer.manager.lis2mdl import LIS2MDLManager -from lib.pysquared.hardware.radio.manager.rfm9x import RFM9xManager -from lib.pysquared.hardware.radio.packetizer.packet_manager import PacketManager -from lib.pysquared.logger import Logger, LogLevel -from lib.pysquared.nvm.counter import Counter -from lib.pysquared.rtc.manager.microcontroller import MicrocontrollerManager -from lib.pysquared.sleep_helper import SleepHelper -from lib.pysquared.watchdog import Watchdog -from version import __version__ - -boot_time: float = time.time() - -rtc = MicrocontrollerManager() - -(boot_count := Counter(index=Register.boot_count)).increment() -error_count: Counter = Counter(index=Register.error_count) - -logger: Logger = Logger( - error_counter=error_count, - colorized=False, - log_level=LogLevel.INFO, -) - -logger.info( - "Booting", - hardware_version=os.uname().version, - software_version=__version__, -) - -try: - loiter_time: int = 5 - for i in range(loiter_time): - logger.info(f"Code Starting in {loiter_time-i} seconds") - time.sleep(1) - - watchdog = Watchdog(logger, board.WDT_WDI) - watchdog.pet() - - logger.debug("Initializing Config") - config: Config = Config("config.json") - - # TODO(nateinaction): fix spi init - spi0: SPI = _spi_init( - logger, - board.SPI0_SCK, - board.SPI0_MOSI, - board.SPI0_MISO, - ) - - radio = RFM9xManager( - logger, - config.radio, - spi0, - initialize_pin(logger, board.SPI0_CS0, digitalio.Direction.OUTPUT, True), - initialize_pin(logger, board.RF1_RST, digitalio.Direction.OUTPUT, True), - ) - - packet_manager = PacketManager( - logger, - radio, - config.radio.license, - Counter(Register.message_count), - 0.2, - ) - - i2c1 = initialize_i2c_bus( - logger, - board.I2C1_SCL, - board.I2C1_SDA, - 100000, - ) - - magnetometer = LIS2MDLManager(logger, i2c1) - - imu = LSM6DSOXManager(logger, i2c1, 0x6B) - - sleep_helper = SleepHelper(logger, config, watchdog) - - cdh = CommandDataHandler(logger, config, packet_manager) - - beacon = Beacon( - logger, - config.cubesat_name, - packet_manager, - boot_time, - imu, - magnetometer, - radio, - error_count, - boot_count, - ) - - def nominal_power_loop(): - logger.debug( - "FC Board Stats", - bytes_remaining=gc.mem_free(), - ) - - packet_manager.send(config.radio.license.encode("utf-8")) - - beacon.send() - - cdh.listen_for_commands(10) - - sleep_helper.safe_sleep(config.sleep_duration) - - try: - logger.info("Entering main loop") - while True: - # TODO(nateinaction): Modify behavior based on power state - nominal_power_loop() - - except Exception as e: - logger.critical("Critical in Main Loop", e) - time.sleep(10) - microcontroller.on_next_reset(microcontroller.RunMode.NORMAL) - microcontroller.reset() - finally: - logger.info("Going Neutral!") - -except Exception as e: - logger.critical("An exception occured within main.py", e) diff --git a/usbmodem101/repl.py b/usbmodem101/repl.py deleted file mode 100644 index 4c1275a..0000000 --- a/usbmodem101/repl.py +++ /dev/null @@ -1,108 +0,0 @@ -""" -Built for the PySquared FC Board V4x -Published: May, 2025 -""" - -import os -import time - -import digitalio -from busio import SPI - -try: - from board_definitions import proveskit_rp2040_v4 as board -except ImportError: - import board - -from lib.proveskit_rp2040_v4.register import Register -from lib.pysquared.beacon import Beacon -from lib.pysquared.cdh import CommandDataHandler -from lib.pysquared.config.config import Config -from lib.pysquared.hardware.busio import _spi_init, initialize_i2c_bus -from lib.pysquared.hardware.digitalio import initialize_pin -from lib.pysquared.hardware.imu.manager.lsm6dsox import LSM6DSOXManager -from lib.pysquared.hardware.magnetometer.manager.lis2mdl import LIS2MDLManager -from lib.pysquared.hardware.radio.manager.rfm9x import RFM9xManager -from lib.pysquared.hardware.radio.packetizer.packet_manager import PacketManager -from lib.pysquared.logger import Logger -from lib.pysquared.nvm.counter import Counter -from lib.pysquared.rtc.manager.microcontroller import MicrocontrollerManager -from lib.pysquared.sleep_helper import SleepHelper -from lib.pysquared.watchdog import Watchdog -from version import __version__ - -boot_time: float = time.time() - -rtc = MicrocontrollerManager() - -(boot_count := Counter(index=Register.boot_count)).increment() -error_count: Counter = Counter(index=Register.error_count) - -logger: Logger = Logger( - error_counter=error_count, - colorized=False, -) - -logger.info( - "Booting", - hardware_version=os.uname().version, - software_version=__version__, -) - -try: - watchdog = Watchdog(logger, board.WDT_WDI) - - logger.debug("Initializing Config") - config: Config = Config("config.json") - - # TODO(nateinaction): fix spi init - spi0: SPI = _spi_init( - logger, - board.SPI0_SCK, - board.SPI0_MOSI, - board.SPI0_MISO, - ) - - radio = RFM9xManager( - logger, - config.radio, - spi0, - initialize_pin(logger, board.SPI0_CS0, digitalio.Direction.OUTPUT, True), - initialize_pin(logger, board.RF1_RST, digitalio.Direction.OUTPUT, True), - ) - - packet_manager = PacketManager( - logger, - radio, - config.radio.license, - Counter(Register.message_count), - 0.2, - ) - - i2c1 = initialize_i2c_bus( - logger, - board.I2C1_SCL, - board.I2C1_SDA, - 100000, - ) - - magnetometer = LIS2MDLManager(logger, i2c1) - - imu = LSM6DSOXManager(logger, i2c1, 0x6B) - - sleep_helper = SleepHelper(logger, config, watchdog) - - cdh = CommandDataHandler(logger, config, packet_manager) - - beacon = Beacon( - logger, - config.cubesat_name, - packet_manager, - boot_time, - imu, - magnetometer, - radio, - ) - -except Exception as e: - logger.critical("An exception occurred within repl.py", e) diff --git a/usbmodem101/safemode.py b/usbmodem101/safemode.py deleted file mode 100644 index 0d4496a..0000000 --- a/usbmodem101/safemode.py +++ /dev/null @@ -1,8 +0,0 @@ -import time - -import microcontroller - -print("I am in safemode. Help!") - -time.sleep(10) -microcontroller.reset() diff --git a/usbmodem101/version.py b/usbmodem101/version.py deleted file mode 100644 index cf194e0..0000000 --- a/usbmodem101/version.py +++ /dev/null @@ -1 +0,0 @@ -__version__ = '' From 83708bdb4c361a724f20e5f3edde5e81415861fd Mon Sep 17 00:00:00 2001 From: asiemsen Date: Tue, 5 Aug 2025 18:50:24 -0500 Subject: [PATCH 5/6] move sd card injection after sd init --- src/flight-software/main.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/flight-software/main.py b/src/flight-software/main.py index 40f6973..33fe441 100644 --- a/src/flight-software/main.py +++ b/src/flight-software/main.py @@ -84,6 +84,8 @@ board.SPI0_CS1 ) + logger.sd_card = sdCard + radio = RFM9xManager( logger, config.radio, @@ -92,7 +94,6 @@ initialize_pin(logger, board.RF1_RST, digitalio.Direction.OUTPUT, True), ) - logger.sd_card = sdCard packet_manager = PacketManager( logger, From 7c3e576d648693c475122d06d348a6bf865c6764 Mon Sep 17 00:00:00 2001 From: asiemsen Date: Tue, 2 Sep 2025 18:25:18 -0500 Subject: [PATCH 6/6] new boot sequence to use mkdir function --- src/flight-software/boot.py | 40 +-------- usbmodem101/boot.py | 4 + usbmodem101/config.json | 84 +++++++++++++++++++ usbmodem101/main.py | 158 ++++++++++++++++++++++++++++++++++++ usbmodem101/repl.py | 113 ++++++++++++++++++++++++++ usbmodem101/safemode.py | 8 ++ usbmodem101/version.py | 1 + usbmodem1101/boot.py | 4 + usbmodem1101/config.json | 84 +++++++++++++++++++ usbmodem1101/main.py | 158 ++++++++++++++++++++++++++++++++++++ usbmodem1101/repl.py | 113 ++++++++++++++++++++++++++ usbmodem1101/safemode.py | 8 ++ usbmodem1101/version.py | 1 + 13 files changed, 739 insertions(+), 37 deletions(-) create mode 100644 usbmodem101/boot.py create mode 100644 usbmodem101/config.json create mode 100644 usbmodem101/main.py create mode 100644 usbmodem101/repl.py create mode 100644 usbmodem101/safemode.py create mode 100644 usbmodem101/version.py create mode 100644 usbmodem1101/boot.py create mode 100644 usbmodem1101/config.json create mode 100644 usbmodem1101/main.py create mode 100644 usbmodem1101/repl.py create mode 100644 usbmodem1101/safemode.py create mode 100644 usbmodem1101/version.py diff --git a/src/flight-software/boot.py b/src/flight-software/boot.py index c9f4c42..e94111c 100644 --- a/src/flight-software/boot.py +++ b/src/flight-software/boot.py @@ -1,38 +1,4 @@ -import os -import time +from lib.pysquared.boot.filesystem import mkdir -import storage - -mount_points = [ - "/sd", -] - -wait_time = 0.02 - -storage.disable_usb_drive() -print("Disabling USB drive") -time.sleep(wait_time) - -storage.mount("/", False) -print("Remounting root filesystem") -time.sleep(wait_time) - -attempts = 0 -while attempts < 5: - attempts += 1 - try: - for path in mount_points: - try: - os.mkdir(path) - print(f"Mount point {path} created.") - except OSError: - print(f"Mount point {path} already exists.") - except Exception as e: - print(f"Error creating mount point {path}: {e}") - time.sleep(wait_time) - continue - - break - -storage.enable_usb_drive() -print("Enabling USB drive") \ No newline at end of file +# Create the SD card directory so we can mount it later +mkdir("/sd") diff --git a/usbmodem101/boot.py b/usbmodem101/boot.py new file mode 100644 index 0000000..e94111c --- /dev/null +++ b/usbmodem101/boot.py @@ -0,0 +1,4 @@ +from lib.pysquared.boot.filesystem import mkdir + +# Create the SD card directory so we can mount it later +mkdir("/sd") diff --git a/usbmodem101/config.json b/usbmodem101/config.json new file mode 100644 index 0000000..5893978 --- /dev/null +++ b/usbmodem101/config.json @@ -0,0 +1,84 @@ +{ + "critical_battery_voltage": 6.6, + "cubesat_name": "PROVES-MY_SATELLITE_NAME", + "current_draw": 240.5, + "debug": true, + "degraded_battery_voltage": 5.4, + "detumble_enable_x": true, + "detumble_enable_y": true, + "detumble_enable_z": true, + "heating": false, + "jokes": [ + "Hey it is pretty cold up here, did someone forget to pay the electric bill?", + "sudo rf - rf*", + "Why did the astronaut break up with his girlfriend? He needed space.", + "Why did the sun go to school? To get a little brighter.", + "why is the mall called the mall? because instead of going to one store you go to them all", + "Alien detected. Blurring photo...", + "Wait it is all open source? Always has been... www.github.com/proveskit", + "What did 0 say to 1? You're a bit too much.", + "Pleiades - Orpheus has been recently acquired by the Onion News Network", + "This jokesat was brought to you by the Bronco Space Ministry of Labor and Job Placement", + "Catch you on the next pass!", + "Pleiades - Orpheus was not The Impostor", + "Sorry for messing with your long-exposure astrophoto!", + "Better buy a telescope. Wanna see me. Buy a telescope. Gonna be in space.", + "According to all known laws of aviation, there is no way bees should be able to fly...", + "You lost the game ", + "Bobby Tables is a good friend of mine", + "Why did the computer cross the road? To get a byte to eat!", + "Why are the astronauts not hungry when they got to space? They had a big launch.", + "Why did the computer get glasses? To improve its web sight!", + "What are computers favorite snacks? Chips!", + "Wait! I think I see a White 2019 Subaru Crosstrek 2.0i Premium", + "IS THAT A SUPRA?!", + "Finally escpaed the LA Traffic", + "My CubeSat is really good at jokes, but its delivery is always delayed.", + "exec order 66", + "I had a joke about UDP, but I am not sure if you'd get it.", + "I am not saying FSK modulation is the best way to send jokes, but at least it is never monotone!", + "I am sorry David, I am afrain I can not do that.", + "My memory is volatile like RAM, so it only makes sense that I forget things.", + "Imagine it gets stuck and just keeps repeating this joke every 2 mins", + "Check Engine: Error Code 404: Joke Not Found", + "CQ CQ KN6NAQ ... KN6NAT are you out there?", + "Woah is that the Launcher Orbiter?????", + "Everything in life is a spring if you think hard enough!", + "Your Mom", + "Your Mum", + "Your Face", + "not True lol", + "I have brought peace, freedom, justice, and security to my new empire! Your New Empire?" + ], + "last_battery_temp": 20.0, + "longest_allowable_sleep_time": 600, + "normal_battery_temp": 1, + "normal_battery_voltage": 6.9, + "normal_charge_current": 0.5, + "normal_micro_temp": 20, + "normal_temp": 20, + "radio": { + "fsk": { + "broadcast_address": 255, + "modulation_type": 0, + "node_address": 1 + }, + "license": "KK4PDM", + "lora": { + "ack_delay": 0.2, + "coding_rate": 8, + "cyclic_redundancy_check": true, + "max_output": true, + "spreading_factor": 8, + "transmit_power": 23 + }, + "modulation": "LoRa", + "start_time": 80000, + "transmit_frequency": 437.4 + }, + "reboot_time": 3600, + "repeat_code": "RP", + "sleep_duration": 30, + "super_secret_code": "ABCD", + "turbo_clock": false +} diff --git a/usbmodem101/main.py b/usbmodem101/main.py new file mode 100644 index 0000000..3694db2 --- /dev/null +++ b/usbmodem101/main.py @@ -0,0 +1,158 @@ +# This is where the magic happens! +# This file is executed on every boot (including wake-boot from deepsleep) +# Created By: Michael Pham + +""" +Built for the PySquared FC Board +Version: 2.0.0 +Published: Nov 19, 2024 +""" + +import gc +import os +import time + +import digitalio +import microcontroller +from busio import SPI + +try: + from board_definitions import proveskit_rp2040_v4 as board +except ImportError: + import board + +from lib.proveskit_rp2040_v4.register import Register +from lib.pysquared.beacon import Beacon +from lib.pysquared.cdh import CommandDataHandler +from lib.pysquared.config.config import Config +from lib.pysquared.hardware.busio import _spi_init, initialize_i2c_bus +from lib.pysquared.hardware.digitalio import initialize_pin +from lib.pysquared.hardware.imu.manager.lsm6dsox import LSM6DSOXManager +from lib.pysquared.hardware.magnetometer.manager.lis2mdl import LIS2MDLManager +from lib.pysquared.hardware.radio.manager.rfm9x import RFM9xManager +from lib.pysquared.hardware.radio.packetizer.packet_manager import PacketManager +from lib.pysquared.hardware.sd_card.manager.sd_card import SDCardManager +from lib.pysquared.logger import Logger, LogLevel +from lib.pysquared.nvm.counter import Counter +from lib.pysquared.rtc.manager.microcontroller import MicrocontrollerManager +from lib.pysquared.sleep_helper import SleepHelper +from lib.pysquared.watchdog import Watchdog +from version import __version__ + +boot_time: float = time.time() + +rtc = MicrocontrollerManager() + +(boot_count := Counter(index=Register.boot_count)).increment() +error_count: Counter = Counter(index=Register.error_count) + + +logger: Logger = Logger( + error_counter=error_count, + colorized=False, + log_level=LogLevel.INFO, +) + +logger.info( + "Booting", + hardware_version=os.uname().version, + software_version=__version__, +) + +try: + loiter_time: int = 5 + for i in range(loiter_time): + logger.info(f"Code Starting in {loiter_time-i} seconds") + time.sleep(1) + + watchdog = Watchdog(logger, board.WDT_WDI) + watchdog.pet() + + logger.debug("Initializing Config") + config: Config = Config("config.json") + + # TODO(nateinaction): fix spi init + spi0: SPI = _spi_init( + logger, + board.SPI0_SCK, + board.SPI0_MOSI, + board.SPI0_MISO, + ) + + sdCard: SDCardManager = SDCardManager(spi0, board.SPI0_CS1) + + logger.set_log_dir("/sd") + + radio = RFM9xManager( + logger, + config.radio, + spi0, + initialize_pin(logger, board.SPI0_CS0, digitalio.Direction.OUTPUT, True), + initialize_pin(logger, board.RF1_RST, digitalio.Direction.OUTPUT, True), + ) + + packet_manager = PacketManager( + logger, + radio, + config.radio.license, + Counter(Register.message_count), + 0.2, + ) + + i2c1 = initialize_i2c_bus( + logger, + board.I2C1_SCL, + board.I2C1_SDA, + 100000, + ) + + magnetometer = LIS2MDLManager(logger, i2c1) + + imu = LSM6DSOXManager(logger, i2c1, 0x6B) + + sleep_helper = SleepHelper(logger, config, watchdog) + + cdh = CommandDataHandler(logger, config, packet_manager) + + beacon = Beacon( + logger, + config.cubesat_name, + packet_manager, + boot_time, + imu, + magnetometer, + radio, + error_count, + boot_count, + ) + + def nominal_power_loop(): + logger.debug( + "FC Board Stats", + bytes_remaining=gc.mem_free(), + ) + + packet_manager.send(config.radio.license.encode("utf-8")) + + beacon.send() + + cdh.listen_for_commands(10) + + sleep_helper.safe_sleep(config.sleep_duration) + + try: + logger.info("Entering main loop") + while True: + # TODO(nateinaction): Modify behavior based on power state + nominal_power_loop() + + except Exception as e: + logger.critical("Critical in Main Loop", e) + time.sleep(10) + microcontroller.on_next_reset(microcontroller.RunMode.NORMAL) + microcontroller.reset() + finally: + logger.info("Going Neutral!") + +except Exception as e: + logger.critical("An exception occured within main.py", e) diff --git a/usbmodem101/repl.py b/usbmodem101/repl.py new file mode 100644 index 0000000..9b9f34b --- /dev/null +++ b/usbmodem101/repl.py @@ -0,0 +1,113 @@ +""" +Built for the PySquared FC Board V4x +Published: May, 2025 +""" + +import os +import time + +import digitalio +from busio import SPI + +try: + from board_definitions import proveskit_rp2040_v4 as board +except ImportError: + import board + +from lib.proveskit_rp2040_v4.register import Register +from lib.pysquared.beacon import Beacon +from lib.pysquared.cdh import CommandDataHandler +from lib.pysquared.config.config import Config +from lib.pysquared.hardware.busio import _spi_init, initialize_i2c_bus +from lib.pysquared.hardware.digitalio import initialize_pin +from lib.pysquared.hardware.imu.manager.lsm6dsox import LSM6DSOXManager +from lib.pysquared.hardware.magnetometer.manager.lis2mdl import LIS2MDLManager +from lib.pysquared.hardware.radio.manager.rfm9x import RFM9xManager +from lib.pysquared.hardware.radio.packetizer.packet_manager import PacketManager +from lib.pysquared.hardware.sd_card.manager.sd_card import SDCardManager +from lib.pysquared.logger import Logger +from lib.pysquared.nvm.counter import Counter +from lib.pysquared.rtc.manager.microcontroller import MicrocontrollerManager +from lib.pysquared.sleep_helper import SleepHelper +from lib.pysquared.watchdog import Watchdog +from version import __version__ + +boot_time: float = time.time() + +rtc = MicrocontrollerManager() + +(boot_count := Counter(index=Register.boot_count)).increment() +error_count: Counter = Counter(index=Register.error_count) + +logger: Logger = Logger( + error_counter=error_count, + colorized=False, +) + +logger.info( + "Booting", + hardware_version=os.uname().version, + software_version=__version__, +) + +try: + watchdog = Watchdog(logger, board.WDT_WDI) + + logger.debug("Initializing Config") + config: Config = Config("config.json") + + # TODO(nateinaction): fix spi init + spi0: SPI = _spi_init( + logger, + board.SPI0_SCK, + board.SPI0_MOSI, + board.SPI0_MISO, + ) + + sdCard: SDCardManager = SDCardManager(spi0, board.SPI0_CS1) + + logger.set_log_dir("/sd") + + radio = RFM9xManager( + logger, + config.radio, + spi0, + initialize_pin(logger, board.SPI0_CS0, digitalio.Direction.OUTPUT, True), + initialize_pin(logger, board.RF1_RST, digitalio.Direction.OUTPUT, True), + ) + + packet_manager = PacketManager( + logger, + radio, + config.radio.license, + Counter(Register.message_count), + 0.2, + ) + + i2c1 = initialize_i2c_bus( + logger, + board.I2C1_SCL, + board.I2C1_SDA, + 100000, + ) + + magnetometer = LIS2MDLManager(logger, i2c1) + + imu = LSM6DSOXManager(logger, i2c1, 0x6B) + + sleep_helper = SleepHelper(logger, config, watchdog) + + cdh = CommandDataHandler(logger, config, packet_manager) + + beacon = Beacon( + logger, + config.cubesat_name, + packet_manager, + boot_time, + imu, + magnetometer, + radio, + ) + +except Exception as e: + logger.critical("An exception occurred within repl.py", e) diff --git a/usbmodem101/safemode.py b/usbmodem101/safemode.py new file mode 100644 index 0000000..0d4496a --- /dev/null +++ b/usbmodem101/safemode.py @@ -0,0 +1,8 @@ +import time + +import microcontroller + +print("I am in safemode. Help!") + +time.sleep(10) +microcontroller.reset() diff --git a/usbmodem101/version.py b/usbmodem101/version.py new file mode 100644 index 0000000..cf194e0 --- /dev/null +++ b/usbmodem101/version.py @@ -0,0 +1 @@ +__version__ = '' diff --git a/usbmodem1101/boot.py b/usbmodem1101/boot.py new file mode 100644 index 0000000..e94111c --- /dev/null +++ b/usbmodem1101/boot.py @@ -0,0 +1,4 @@ +from lib.pysquared.boot.filesystem import mkdir + +# Create the SD card directory so we can mount it later +mkdir("/sd") diff --git a/usbmodem1101/config.json b/usbmodem1101/config.json new file mode 100644 index 0000000..5893978 --- /dev/null +++ b/usbmodem1101/config.json @@ -0,0 +1,84 @@ +{ + "critical_battery_voltage": 6.6, + "cubesat_name": "PROVES-MY_SATELLITE_NAME", + "current_draw": 240.5, + "debug": true, + "degraded_battery_voltage": 5.4, + "detumble_enable_x": true, + "detumble_enable_y": true, + "detumble_enable_z": true, + "heating": false, + "jokes": [ + "Hey it is pretty cold up here, did someone forget to pay the electric bill?", + "sudo rf - rf*", + "Why did the astronaut break up with his girlfriend? He needed space.", + "Why did the sun go to school? To get a little brighter.", + "why is the mall called the mall? because instead of going to one store you go to them all", + "Alien detected. Blurring photo...", + "Wait it is all open source? Always has been... www.github.com/proveskit", + "What did 0 say to 1? You're a bit too much.", + "Pleiades - Orpheus has been recently acquired by the Onion News Network", + "This jokesat was brought to you by the Bronco Space Ministry of Labor and Job Placement", + "Catch you on the next pass!", + "Pleiades - Orpheus was not The Impostor", + "Sorry for messing with your long-exposure astrophoto!", + "Better buy a telescope. Wanna see me. Buy a telescope. Gonna be in space.", + "According to all known laws of aviation, there is no way bees should be able to fly...", + "You lost the game ", + "Bobby Tables is a good friend of mine", + "Why did the computer cross the road? To get a byte to eat!", + "Why are the astronauts not hungry when they got to space? They had a big launch.", + "Why did the computer get glasses? To improve its web sight!", + "What are computers favorite snacks? Chips!", + "Wait! I think I see a White 2019 Subaru Crosstrek 2.0i Premium", + "IS THAT A SUPRA?!", + "Finally escpaed the LA Traffic", + "My CubeSat is really good at jokes, but its delivery is always delayed.", + "exec order 66", + "I had a joke about UDP, but I am not sure if you'd get it.", + "I am not saying FSK modulation is the best way to send jokes, but at least it is never monotone!", + "I am sorry David, I am afrain I can not do that.", + "My memory is volatile like RAM, so it only makes sense that I forget things.", + "Imagine it gets stuck and just keeps repeating this joke every 2 mins", + "Check Engine: Error Code 404: Joke Not Found", + "CQ CQ KN6NAQ ... KN6NAT are you out there?", + "Woah is that the Launcher Orbiter?????", + "Everything in life is a spring if you think hard enough!", + "Your Mom", + "Your Mum", + "Your Face", + "not True lol", + "I have brought peace, freedom, justice, and security to my new empire! Your New Empire?" + ], + "last_battery_temp": 20.0, + "longest_allowable_sleep_time": 600, + "normal_battery_temp": 1, + "normal_battery_voltage": 6.9, + "normal_charge_current": 0.5, + "normal_micro_temp": 20, + "normal_temp": 20, + "radio": { + "fsk": { + "broadcast_address": 255, + "modulation_type": 0, + "node_address": 1 + }, + "license": "KK4PDM", + "lora": { + "ack_delay": 0.2, + "coding_rate": 8, + "cyclic_redundancy_check": true, + "max_output": true, + "spreading_factor": 8, + "transmit_power": 23 + }, + "modulation": "LoRa", + "start_time": 80000, + "transmit_frequency": 437.4 + }, + "reboot_time": 3600, + "repeat_code": "RP", + "sleep_duration": 30, + "super_secret_code": "ABCD", + "turbo_clock": false +} diff --git a/usbmodem1101/main.py b/usbmodem1101/main.py new file mode 100644 index 0000000..3694db2 --- /dev/null +++ b/usbmodem1101/main.py @@ -0,0 +1,158 @@ +# This is where the magic happens! +# This file is executed on every boot (including wake-boot from deepsleep) +# Created By: Michael Pham + +""" +Built for the PySquared FC Board +Version: 2.0.0 +Published: Nov 19, 2024 +""" + +import gc +import os +import time + +import digitalio +import microcontroller +from busio import SPI + +try: + from board_definitions import proveskit_rp2040_v4 as board +except ImportError: + import board + +from lib.proveskit_rp2040_v4.register import Register +from lib.pysquared.beacon import Beacon +from lib.pysquared.cdh import CommandDataHandler +from lib.pysquared.config.config import Config +from lib.pysquared.hardware.busio import _spi_init, initialize_i2c_bus +from lib.pysquared.hardware.digitalio import initialize_pin +from lib.pysquared.hardware.imu.manager.lsm6dsox import LSM6DSOXManager +from lib.pysquared.hardware.magnetometer.manager.lis2mdl import LIS2MDLManager +from lib.pysquared.hardware.radio.manager.rfm9x import RFM9xManager +from lib.pysquared.hardware.radio.packetizer.packet_manager import PacketManager +from lib.pysquared.hardware.sd_card.manager.sd_card import SDCardManager +from lib.pysquared.logger import Logger, LogLevel +from lib.pysquared.nvm.counter import Counter +from lib.pysquared.rtc.manager.microcontroller import MicrocontrollerManager +from lib.pysquared.sleep_helper import SleepHelper +from lib.pysquared.watchdog import Watchdog +from version import __version__ + +boot_time: float = time.time() + +rtc = MicrocontrollerManager() + +(boot_count := Counter(index=Register.boot_count)).increment() +error_count: Counter = Counter(index=Register.error_count) + + +logger: Logger = Logger( + error_counter=error_count, + colorized=False, + log_level=LogLevel.INFO, +) + +logger.info( + "Booting", + hardware_version=os.uname().version, + software_version=__version__, +) + +try: + loiter_time: int = 5 + for i in range(loiter_time): + logger.info(f"Code Starting in {loiter_time-i} seconds") + time.sleep(1) + + watchdog = Watchdog(logger, board.WDT_WDI) + watchdog.pet() + + logger.debug("Initializing Config") + config: Config = Config("config.json") + + # TODO(nateinaction): fix spi init + spi0: SPI = _spi_init( + logger, + board.SPI0_SCK, + board.SPI0_MOSI, + board.SPI0_MISO, + ) + + sdCard: SDCardManager = SDCardManager(spi0, board.SPI0_CS1) + + logger.set_log_dir("/sd") + + radio = RFM9xManager( + logger, + config.radio, + spi0, + initialize_pin(logger, board.SPI0_CS0, digitalio.Direction.OUTPUT, True), + initialize_pin(logger, board.RF1_RST, digitalio.Direction.OUTPUT, True), + ) + + packet_manager = PacketManager( + logger, + radio, + config.radio.license, + Counter(Register.message_count), + 0.2, + ) + + i2c1 = initialize_i2c_bus( + logger, + board.I2C1_SCL, + board.I2C1_SDA, + 100000, + ) + + magnetometer = LIS2MDLManager(logger, i2c1) + + imu = LSM6DSOXManager(logger, i2c1, 0x6B) + + sleep_helper = SleepHelper(logger, config, watchdog) + + cdh = CommandDataHandler(logger, config, packet_manager) + + beacon = Beacon( + logger, + config.cubesat_name, + packet_manager, + boot_time, + imu, + magnetometer, + radio, + error_count, + boot_count, + ) + + def nominal_power_loop(): + logger.debug( + "FC Board Stats", + bytes_remaining=gc.mem_free(), + ) + + packet_manager.send(config.radio.license.encode("utf-8")) + + beacon.send() + + cdh.listen_for_commands(10) + + sleep_helper.safe_sleep(config.sleep_duration) + + try: + logger.info("Entering main loop") + while True: + # TODO(nateinaction): Modify behavior based on power state + nominal_power_loop() + + except Exception as e: + logger.critical("Critical in Main Loop", e) + time.sleep(10) + microcontroller.on_next_reset(microcontroller.RunMode.NORMAL) + microcontroller.reset() + finally: + logger.info("Going Neutral!") + +except Exception as e: + logger.critical("An exception occured within main.py", e) diff --git a/usbmodem1101/repl.py b/usbmodem1101/repl.py new file mode 100644 index 0000000..9b9f34b --- /dev/null +++ b/usbmodem1101/repl.py @@ -0,0 +1,113 @@ +""" +Built for the PySquared FC Board V4x +Published: May, 2025 +""" + +import os +import time + +import digitalio +from busio import SPI + +try: + from board_definitions import proveskit_rp2040_v4 as board +except ImportError: + import board + +from lib.proveskit_rp2040_v4.register import Register +from lib.pysquared.beacon import Beacon +from lib.pysquared.cdh import CommandDataHandler +from lib.pysquared.config.config import Config +from lib.pysquared.hardware.busio import _spi_init, initialize_i2c_bus +from lib.pysquared.hardware.digitalio import initialize_pin +from lib.pysquared.hardware.imu.manager.lsm6dsox import LSM6DSOXManager +from lib.pysquared.hardware.magnetometer.manager.lis2mdl import LIS2MDLManager +from lib.pysquared.hardware.radio.manager.rfm9x import RFM9xManager +from lib.pysquared.hardware.radio.packetizer.packet_manager import PacketManager +from lib.pysquared.hardware.sd_card.manager.sd_card import SDCardManager +from lib.pysquared.logger import Logger +from lib.pysquared.nvm.counter import Counter +from lib.pysquared.rtc.manager.microcontroller import MicrocontrollerManager +from lib.pysquared.sleep_helper import SleepHelper +from lib.pysquared.watchdog import Watchdog +from version import __version__ + +boot_time: float = time.time() + +rtc = MicrocontrollerManager() + +(boot_count := Counter(index=Register.boot_count)).increment() +error_count: Counter = Counter(index=Register.error_count) + +logger: Logger = Logger( + error_counter=error_count, + colorized=False, +) + +logger.info( + "Booting", + hardware_version=os.uname().version, + software_version=__version__, +) + +try: + watchdog = Watchdog(logger, board.WDT_WDI) + + logger.debug("Initializing Config") + config: Config = Config("config.json") + + # TODO(nateinaction): fix spi init + spi0: SPI = _spi_init( + logger, + board.SPI0_SCK, + board.SPI0_MOSI, + board.SPI0_MISO, + ) + + sdCard: SDCardManager = SDCardManager(spi0, board.SPI0_CS1) + + logger.set_log_dir("/sd") + + radio = RFM9xManager( + logger, + config.radio, + spi0, + initialize_pin(logger, board.SPI0_CS0, digitalio.Direction.OUTPUT, True), + initialize_pin(logger, board.RF1_RST, digitalio.Direction.OUTPUT, True), + ) + + packet_manager = PacketManager( + logger, + radio, + config.radio.license, + Counter(Register.message_count), + 0.2, + ) + + i2c1 = initialize_i2c_bus( + logger, + board.I2C1_SCL, + board.I2C1_SDA, + 100000, + ) + + magnetometer = LIS2MDLManager(logger, i2c1) + + imu = LSM6DSOXManager(logger, i2c1, 0x6B) + + sleep_helper = SleepHelper(logger, config, watchdog) + + cdh = CommandDataHandler(logger, config, packet_manager) + + beacon = Beacon( + logger, + config.cubesat_name, + packet_manager, + boot_time, + imu, + magnetometer, + radio, + ) + +except Exception as e: + logger.critical("An exception occurred within repl.py", e) diff --git a/usbmodem1101/safemode.py b/usbmodem1101/safemode.py new file mode 100644 index 0000000..0d4496a --- /dev/null +++ b/usbmodem1101/safemode.py @@ -0,0 +1,8 @@ +import time + +import microcontroller + +print("I am in safemode. Help!") + +time.sleep(10) +microcontroller.reset() diff --git a/usbmodem1101/version.py b/usbmodem1101/version.py new file mode 100644 index 0000000..cf194e0 --- /dev/null +++ b/usbmodem1101/version.py @@ -0,0 +1 @@ +__version__ = ''