diff --git a/cubesatsim/cubesatsim.h b/cubesatsim/cubesatsim.h index 37764857..bacf397a 100644 --- a/cubesatsim/cubesatsim.h +++ b/cubesatsim/cubesatsim.h @@ -47,12 +47,23 @@ #define SCL2 5 // I2C 2 Clock #define BPSK_CONTROL_A 6 // was 16 // control for Phase A to switch #define BPSK_CONTROL_B 7 // was 15 // control for Phase A to switch + +#ifdef PICO_0V1 +#define BPF_PIN 8 // BPF is installed for v0.1 Pico +#define PI_3V3_PIN 9 // 3.3V supply used to detect Pi Zero for v0.1 Pico +#define TX2 12 // Serial2 to ESP32-CAM transmit data +#define RX2 13 // Serial2 to ESP32-CAM receive data +#else #define TX2 8 // Serial2 to ESP32-CAM transmit data #define RX2 9 // Serial2 to ESP32-CAM receive data +#define BPF_PIN 12 // BPF is installed +#define PI_3V3_PIN 13 // 3.3V supply used to detect Pi Zero +#endif + + #define MAIN_PB_PIN 10 // Main board PB pushbutton pin #define TXC_PIN 11 // Transceiver Board is present -#define LPF_PIN 12 // BPF is installed -#define PI_3V3_PIN 13 // 3.3V supply used to detect Pi Zero + #define BPSK_PWM_A_PIN 14 // was 6 // PWM Output Phase A to switch #define BPSK_PWM_B_PIN 15 // was 7 // PWM Output Phase B to switch #define SWTX_PIN 16 // was 14 SR_FRS_05W Transmit Pico software serial port @@ -111,7 +122,12 @@ #define PROMPT_QUERY 5 #define PROMPT_HELP 6 #define PROMPT_RESTART 7 +#define PROMPT_DEBUG 8 +#define PROMPT_VOLTAGE 9 +#define PAYLOAD_QUERY 1 +#define PAYLOAD_RESET 2 +#define PAYLOAD_CLEAR 3 volatile int prompt = false; char serial_string[128]; @@ -182,6 +198,9 @@ void load_files(); void show_dir(); void serial_input(); void get_serial_string(); +void get_serial_char(); +void get_serial_clear_buffer(); +void set_lat_lon(); #ifndef STASSID #define STASSID "Pico" @@ -319,6 +338,11 @@ int buffer_size; long micro_timer; int ready = FALSE; bool cw_stop = false; +int payload_command = false; +bool debug_mode = false; +bool voltage_read = false; +bool ina219_started = false; +bool camera_detected = false; #define PRESSED 0 #define HELD 0 diff --git a/cubesatsim/cubesatsim.ino b/cubesatsim/cubesatsim.ino index 572cd3d1..e7a4cd48 100644 --- a/cubesatsim/cubesatsim.ino +++ b/cubesatsim/cubesatsim.ino @@ -1,5 +1,5 @@ /* - * Transmits CubeSat Telemetry at 434.9MHz in AFSK, FSK, or CW format + * Transmits CubeSat Telemetry at 432.25MHz in AFSK, FSK, BPSK, or CW format * * Copyright Alan B. Johnston * @@ -18,6 +18,8 @@ // This code is an Arduino sketch for the Raspberry Pi Pico // based on the Raspberry Pi Code +#define PICO_0V1 // define for Pico v0.1 hardware + #include "cubesatsim.h" #include "DumbTXSWS.h" #include @@ -61,6 +63,9 @@ WiFiClient client; byte green_led_counter = 0; char call[] = "AMSAT"; // put your callsign here +extern bool get_camera_image(); +extern bool start_camera(); + void setup() { set_sys_clock_khz(133000, true); @@ -72,8 +77,12 @@ void setup() { pinMode(LED_BUILTIN, OUTPUT); blinkTimes(1); - sleep(5.0); - + sleep(5.0); + +// otherwise, run CubeSatSim Pico code + + Serial.println("CubeSatSim Pico v0.14 starting...\n"); + config_gpio(); EEPROM.begin(512); @@ -84,9 +93,6 @@ void setup() { // detect Pi Zero using 3.3V // if Pi is present, run Payload OK software -// otherwise, run CubeSatSim Pico code - - Serial.println("\n\nCubeSatSim Pico v0.13 starting...\n\n"); load_files(); /* @@ -101,7 +107,11 @@ void setup() { } } */ -// configure STEM Payload sensors +// configure STEM Payload sensors + + pinMode(PI_3V3_PIN, OUTPUT); + digitalWrite(PI_3V3_PIN, HIGH); + start_payload(); // above code not working, so forcing it read_reset_count(); @@ -130,7 +140,15 @@ void setup() { } */ // start_button_isr(); + setup_sstv(); + if (start_camera()) { + camera_detected = true; + Serial.println("Camera detected!"); + } else { + camera_detected = false; + Serial.println("No camera detected!"); + } start_isr(); start_pwm(); @@ -148,6 +166,9 @@ void setup() { ready = TRUE; // flag for core1 to start looping + prompt = PROMPT_HELP; // display input help menu + prompt_for_input(); + Serial.print("s"); Serial.print(" "); Serial.println(millis()); @@ -182,37 +203,48 @@ void loop() { { char image_file[128]; if (first_time_sstv) { +// if (false) { // turn this off for now strcpy(image_file, sstv1_filename); first_time_sstv = false; } else { - - // get jpeg from camera in future - - - - - strcpy(image_file, sstv2_filename); - } - Serial.print("\nSending SSTV image "); - print_string(image_file); + if (camera_detected) { + Serial.println("Getting image file"); + get_camera_image(); +// Serial.println("Got image file"); + char camera_file[] = "/cam.jpg"; + strcpy(image_file, camera_file); + } else + strcpy(image_file, sstv2_filename); // 2nd stored image + } + if (debug_mode) { + Serial.print("\nSending SSTV image "); + print_string(image_file); + } // send_sstv("/cam.raw"); // send_sstv(image_file); char output_file[] = "/cam.bin"; - jpeg_decode(image_file, output_file); - - Serial.println("Start transmit!!!"); + jpeg_decode(image_file, output_file, debug_mode); + + if (debug_mode) + Serial.println("Start transmit!!!"); digitalWrite(PTT_PIN, LOW); // start transmit + if (!wifi) + digitalWrite(LED_BUILTIN, HIGH); digitalWrite(MAIN_LED_BLUE, HIGH); - scottie1_transmit_file(output_file); - - Serial.println("Stop transmit!"); + scottie1_transmit_file(output_file, debug_mode); + + if (debug_mode) + Serial.println("Stop transmit!"); digitalWrite(PTT_PIN, HIGH); // stop transmit + if (!wifi) + digitalWrite(LED_BUILTIN, HIGH); digitalWrite(MAIN_LED_BLUE, LOW); - Serial.println("\nImage sent!"); + if (debug_mode) + Serial.println("\nImage sent!"); } else Serial.println("Unknown mode!"); @@ -248,22 +280,25 @@ void loop() { sleep(0.5); config_telem(); config_radio(); + sampleTime = (unsigned int) millis(); } if (prompt) { - Serial.println("Need to prompt for input!"); +// Serial.println("Need to prompt for input!"); prompt_for_input(); prompt = false; } // Calculate loop time - Serial.print("\nLoop time: "); - Serial.println(millis() - startSleep); + if (debug_mode) { + Serial.print("\nLoop time: "); + Serial.println(millis() - startSleep); + } } bool TimerHandler1(struct repeating_timer *t) { -// serial_input(); + serial_input(); // check for button press if (digitalRead(MAIN_PB_PIN) == PRESSED) // pushbutton is pressed @@ -324,10 +359,11 @@ void send_aprs_packet() { strcpy(str, tlm_str); strcat(str, payload_str); set_status(str); - - Serial.println("Sending APRS packet!"); + + if (debug_mode) + Serial.println("Sending APRS packet!"); transmit_on(); - send_packet(_FIXPOS_STATUS); + send_packet(_FIXPOS_STATUS, debug_mode); transmit_off(); } @@ -335,27 +371,30 @@ void send_cw() { char de[] = " DE "; char telem[1000]; char space[] = " "; - - Serial.println("Sending CW packet!"); + + if (debug_mode) + Serial.println("Sending CW packet!"); strcpy(telem, de); strcat(telem, callsign); strcat(telem, space); strcat(telem, tlm_str); // don't send payload since it isn't encoded and has "." print_string(telem); - Serial.println(strlen(telem)); +// Serial.println(strlen(telem)); transmit_string(telem); } void transmit_on() { if ((mode == SSTV) || (mode == AFSK)) { // this isn't quite right for APRS - should only do when sending APRS packet - Serial.println("Transmit on!"); + if (debug_mode) + Serial.println("Transmit on!"); digitalWrite(MAIN_LED_BLUE, HIGH); digitalWrite(PTT_PIN, LOW); } - else if (mode == BPSK) { - Serial.println("Transmit on!"); + else if (mode == BPSK) { + if (debug_mode) + Serial.println("Transmit on!"); pwm_set_gpio_level(BPSK_PWM_A_PIN, (config.top + 1) * 0.5); pwm_set_gpio_level(BPSK_PWM_B_PIN, (config.top + 1) * 0.5); } @@ -363,13 +402,14 @@ void transmit_on() { // Serial.println("Transmit on!"); cw_stop = false; } - else + else Serial.println("No transmit!"); } void transmit_off() { digitalWrite(PTT_PIN, HIGH); - Serial.println("Transmit off!"); + if (debug_mode) + Serial.println("Transmit off!"); digitalWrite(MAIN_LED_BLUE, LOW); // ITimer0.stopTimer(); // stop BPSK ISR timer if (mode == BPSK) { @@ -386,7 +426,7 @@ void config_telem() { frameCnt = 1; - Serial.println("v1 Present with UHF BPF\n"); + // Serial.println("v1 Present with UHF BPF\n"); txLed = 2; txLedOn = HIGH; txLedOff = LOW; @@ -412,15 +452,15 @@ void config_telem() { sample_rate = 200; // samples = S_RATE / bitRate; samples = sample_rate / bitRate; - Serial.println(samples); +// Serial.println(samples); bufLen = (frameCnt * (syncBits + 10 * (headerLen + rsFrames * (rsFrameLen + parityLen))) * samples); - Serial.println(bufLen); +// Serial.println(bufLen); samplePeriod = (int) (((float)((syncBits + 10 * (headerLen + rsFrames * (rsFrameLen + parityLen)))) / (float) bitRate) * 1000 - 500); sleepTime = 0.1; - Serial.println(samplePeriod); +// Serial.println(samplePeriod); frameTime = ((float)((float)bufLen / (samples * frameCnt * bitRate))) * 1000; // frame time in ms - Serial.println(frameTime); +// Serial.println(frameTime); // printf("\n FSK Mode, %d bits per frame, %d bits per second, %d ms per frame, %d ms sample period\n", // bufLen / (samples * frameCnt), bitRate, frameTime, samplePeriod); memset(buffer, 0xa5, sizeof(buffer)); @@ -441,19 +481,19 @@ void config_telem() { sample_rate = 1200; // samples = S_RATE / bitRate; samples = sample_rate / bitRate; - Serial.println(samples); +// Serial.println(samples); // bufLen = (frameCnt * (syncBits + 10 * (headerLen + rsFrames * (rsFrameLen + parityLen))) * samples); // * 2; // 2 * bufLen = 5751; // instead of 5841 - Serial.println(bufLen); +// Serial.println(bufLen); // samplePeriod = ((float)((syncBits + 10 * (headerLen + rsFrames * (rsFrameLen + parityLen))))/(float)bitRate) * 1000 - 500; samplePeriod = ((float)((syncBits + 10 * (headerLen + rsFrames * (rsFrameLen + parityLen))))/(float)bitRate) * 1000; // - 500; // samplePeriod = 3000; // sleepTime = 3.0; //samplePeriod = 2200; // reduce dut to python and sensor querying delays sleepTime = 2.2f; - Serial.println(samplePeriod); + // Serial.println(samplePeriod); frameTime = ((float)((float)bufLen / (samples * frameCnt * bitRate))) * 1000; // frame time in ms - Serial.println(frameTime); +// Serial.println(frameTime); // printf("\n BPSK Mode, bufLen: %d, %d bits per frame, %d bits per second, %d ms per frame %d ms sample period\n", // bufLen, bufLen / (samples * frameCnt), bitRate, frameTime, samplePeriod); @@ -471,15 +511,11 @@ void config_telem() { Serial.println("Configuring for AFSK\n"); set_pin(AUDIO_OUT_PIN); - -// char callsign[] = "W3ZM"; - set_callsign(callsign); - char lat_default[] = "0610.55S"; - char lon_default[] = "10649.62E"; - char sym_ovl_default = 'H'; - char sym_tab_default = 'a'; - char icon[] = "Ha"; - set_lat_lon_icon(lat_default, lon_default, icon); + + char destination[] = "APCSS"; + set_callsign(callsign, destination); + + set_lat_lon(); samplePeriod = 5000; frameTime = 5000; @@ -492,7 +528,8 @@ void config_telem() { bufLen = 1000; } // clearing min and max values - Serial.println("Clearing min and max telemetry values"); + if (debug_mode) + Serial.println("Clearing min and max telemetry values"); for (int i = 0; i < 9; i++) { voltage_min[i] = 1000.0; @@ -588,7 +625,8 @@ void generate_simulated_telem() { if ((time_stamp - eclipse_time) > period) { eclipse = (eclipse == 1) ? 0 : 1; eclipse_time = time_stamp; - Serial.println("\n\nSwitching eclipse mode! \n\n"); + if (debug_mode) + Serial.println("\n\nSwitching eclipse mode! \n\n"); } double Xi = eclipse * amps_max[0] * (float) sin(2.0 * 3.14 * time_stamp / (46.0 * rotation_speed)) + rnd_float(-2, 2); @@ -776,7 +814,8 @@ void get_tlm_fox() { { // Serial.println("Starting"); if (loop_count % 32 == 0) { // was 8 /// was loop now loop_count - Serial.println("Sending MIN frame"); + if (debug_mode) + Serial.println("Sending MIN frame"); frm_type = 0x03; for (int count1 = 0; count1 < 17; count1++) { if (count1 < 3) @@ -790,7 +829,8 @@ void get_tlm_fox() { } } if ((loop_count + 16) % 32 == 0) { // was 8 - Serial.println("Sending MAX frame"); + if (debug_mode) + Serial.println("Sending MAX frame"); frm_type = 0x02; for (int count1 = 0; count1 < 17; count1++) { if (count1 < 3) @@ -1196,9 +1236,11 @@ void get_tlm_fox() { } // Serial.println("CC"); } - Serial.println(" "); - Serial.print("get_fox_tlm returning with counter: "); - Serial.println(ctr); + if (debug_mode) { + Serial.println(" "); + Serial.print("get_fox_tlm returning with counter: "); + Serial.println(ctr); + } if (firstTime) { Serial.println(" "); firstTime = FALSE; @@ -1231,9 +1273,11 @@ void write_wave(int i, short int *buffer) // ctr = ctr - BUFFER_SIZE; if (ctr > bufLen) { ctr = ctr - bufLen; - Serial.print("\r"); - Serial.print(" "); - Serial.println(millis()); + if (debug_mode) { +// Serial.print("\r"); +// Serial.print(" "); + Serial.println(millis()); + } } } @@ -2015,6 +2059,13 @@ void test_radio() void read_ina219() { + if (voltage_read && !i2c_bus1 && !i2c_bus3) + Serial.println("Nothing to read"); +/* +#ifdef PICO_0V1 + digitalWrite(PI_3V3_PIN, HIGH); +#endif +*/ float shuntvoltage = 0; float busvoltage = 0; float current_mA = 0; @@ -2025,13 +2076,14 @@ void read_ina219() busvoltage = ina219_1_0x40.getBusVoltage_V(); current_mA = ina219_1_0x40.getCurrent_mA(); loadvoltage = busvoltage + (shuntvoltage / 1000); - - Serial.print("1 0x40 Voltage: "); - Serial.print(loadvoltage); - Serial.print("V Current: "); - Serial.print(current_mA); - Serial.println(" mA"); + if ((debug_mode) || (voltage_read)) { + Serial.print("1 0x40 Voltage: "); + Serial.print(loadvoltage); + Serial.print("V Current: "); + Serial.print(current_mA); + Serial.println(" mA"); + } voltage[0] = loadvoltage; current[0] = current_mA; @@ -2039,13 +2091,14 @@ void read_ina219() busvoltage = ina219_1_0x41.getBusVoltage_V(); current_mA = ina219_1_0x41.getCurrent_mA(); loadvoltage = busvoltage + (shuntvoltage / 1000); - - Serial.print("1 0x41 Voltage: "); - Serial.print(loadvoltage); - Serial.print("V Current: "); - Serial.print(current_mA); - Serial.println(" mA"); + if ((debug_mode) || (voltage_read)) { + Serial.print("1 0x41 Voltage: "); + Serial.print(loadvoltage); + Serial.print("V Current: "); + Serial.print(current_mA); + Serial.println(" mA"); + } voltage[1] = loadvoltage; current[1] = current_mA; @@ -2053,13 +2106,14 @@ void read_ina219() busvoltage = ina219_1_0x44.getBusVoltage_V(); current_mA = ina219_1_0x44.getCurrent_mA(); loadvoltage = busvoltage + (shuntvoltage / 1000); - + + if ((debug_mode) || (voltage_read)) { Serial.print("1 0x44 Voltage: "); Serial.print(loadvoltage); Serial.print("V Current: "); Serial.print(current_mA); Serial.println(" mA"); - + } voltage[2] = loadvoltage; current[2] = current_mA; @@ -2067,13 +2121,14 @@ void read_ina219() busvoltage = ina219_1_0x45.getBusVoltage_V(); current_mA = ina219_1_0x45.getCurrent_mA(); loadvoltage = busvoltage + (shuntvoltage / 1000); - + + if ((debug_mode) || (voltage_read)) { Serial.print("1 0x45 Voltage: "); Serial.print(loadvoltage); Serial.print("V Current: "); Serial.print(current_mA); Serial.println(" mA"); - + } voltage[3] = loadvoltage; current[3] = current_mA; } @@ -2083,13 +2138,14 @@ void read_ina219() busvoltage = ina219_2_0x40.getBusVoltage_V(); current_mA = ina219_2_0x40.getCurrent_mA(); loadvoltage = busvoltage + (shuntvoltage / 1000); - + + if ((debug_mode) || (voltage_read)) { Serial.print("2 0x40 Voltage: "); Serial.print(loadvoltage); Serial.print("V Current: "); Serial.print(current_mA); Serial.println(" mA"); - + } voltage[4] = loadvoltage; current[4] = current_mA; @@ -2097,13 +2153,14 @@ void read_ina219() busvoltage = ina219_2_0x41.getBusVoltage_V(); current_mA = ina219_2_0x41.getCurrent_mA(); loadvoltage = busvoltage + (shuntvoltage / 1000); - + + if ((debug_mode) || (voltage_read)) { Serial.print("2 0x41 Voltage: "); Serial.print(loadvoltage); Serial.print("V Current: "); Serial.print(current_mA); Serial.println(" mA"); - + } voltage[5] = loadvoltage; current[5] = current_mA; @@ -2111,13 +2168,14 @@ void read_ina219() busvoltage = ina219_2_0x44.getBusVoltage_V(); current_mA = ina219_2_0x44.getCurrent_mA(); loadvoltage = busvoltage + (shuntvoltage / 1000); - + + if ((debug_mode) || (voltage_read)) { Serial.print("2 0x44 Voltage: "); Serial.print(loadvoltage); Serial.print("V Current: "); Serial.print(current_mA); Serial.println(" mA"); - + } voltage[6] = loadvoltage; current[6] = current_mA; @@ -2125,16 +2183,18 @@ void read_ina219() busvoltage = ina219_2_0x45.getBusVoltage_V(); current_mA = ina219_2_0x45.getCurrent_mA(); loadvoltage = busvoltage + (shuntvoltage / 1000); - + + if ((debug_mode) || (voltage_read)) { Serial.print("2 0x45 Voltage: "); Serial.print(loadvoltage); Serial.print("V Current: "); Serial.print(current_mA); Serial.println(" mA"); - + } voltage[7] = loadvoltage; current[7] = current_mA; - } + } + voltage_read = false; } void read_sensors() @@ -2219,7 +2279,7 @@ void start_payload() { float zOffset; EEPROM.get(0, flag); - if (flag == 0xA07) + if ((flag == 0xA07) && (payload_command != PAYLOAD_RESET)) { Serial.println("Reading gyro offsets from EEPROM\n"); @@ -2236,6 +2296,8 @@ void start_payload() { } else { + payload_command = false; + Serial.println("Calculating gyro offsets and storing in EEPROM\n"); mpu6050.calcGyroOffsets(true); @@ -2334,8 +2396,11 @@ void read_payload() sprintf(str, "XS %.1f 0.0\n", Temp); strcat(payload_str, str); - print_string(payload_str); - + if ((debug_mode) || (payload_command == PAYLOAD_QUERY)) { + payload_command = false; + print_string(payload_str); + } + /* if (result == 'R') { Serial.println("OK"); @@ -2759,19 +2824,29 @@ void led_set(int ledPin, bool state) } void start_ina219() { +//#define PI_3V3_PIN 9 // for v0.1 hardware + Serial.println("Starting INA219"); +// Serial.println(PI_3V3_PIN); + ina219_started = true; + +#ifndef PICO_0V1 // check if Pi is present by 3.3V voltage pinMode(PI_3V3_PIN, INPUT); - Serial.print("Pi 3.3V: "); - Serial.println(digitalRead(PI_3V3_PIN)); +// Serial.print("Pi 3.3V: "); +// Serial.println(digitalRead(PI_3V3_PIN)); if (digitalRead(PI_3V3_PIN) == LOW) { - Serial.println("Powering INA219s through 3.3V pin"); + Serial.println("Pi Zero not present, powering INA219s through 3.3V pin"); pinMode(PI_3V3_PIN, OUTPUT); digitalWrite(PI_3V3_PIN, HIGH); } else { - Serial.println("Not powering INA219s since 3.3V is present"); -// pinMode(MAIN_INA219, OUTPUT); -// digitalWrite(MAIN_INA219, HIGH); + Serial.println("Not powering INA219s since Pi Zero is present"); } +#else + Serial.println("Powering INA219s through 3.3V pin"); + pinMode(PI_3V3_PIN, OUTPUT); + digitalWrite(PI_3V3_PIN, HIGH); +#endif + sleep(0.1); i2c_bus1 = ina219_1_0x40.begin(); // check i2c bus 1 ina219_1_0x41.begin(); @@ -2824,15 +2899,16 @@ void start_pwm() { bpsk_pin_slice_A = pwm_gpio_to_slice_num(BPSK_PWM_A_PIN); bpsk_pin_slice_B = pwm_gpio_to_slice_num(BPSK_PWM_B_PIN); - - Serial.print(pwm_gpio_to_slice_num(BPSK_PWM_A_PIN)); - Serial.print(" "); - Serial.print(pwm_gpio_to_channel(BPSK_PWM_A_PIN)); - Serial.print(" "); - Serial.print(pwm_gpio_to_slice_num(BPSK_PWM_B_PIN)); - Serial.print(" "); - Serial.print(pwm_gpio_to_channel(BPSK_PWM_B_PIN)); - Serial.println(" "); + if (debug_mode) { + Serial.print(pwm_gpio_to_slice_num(BPSK_PWM_A_PIN)); + Serial.print(" "); + Serial.print(pwm_gpio_to_channel(BPSK_PWM_A_PIN)); + Serial.print(" "); + Serial.print(pwm_gpio_to_slice_num(BPSK_PWM_B_PIN)); + Serial.print(" "); + Serial.print(pwm_gpio_to_channel(BPSK_PWM_B_PIN)); + Serial.println(" "); + } /* // Setup PWM interrupt to fire when PWM cycle is complete pwm_clear_irq(bpsk_pin_slice); @@ -3228,13 +3304,13 @@ void config_gpio() { // set input pins and read pinMode(MAIN_PB_PIN, INPUT_PULLUP); // Read Main Board push button pinMode(TXC_PIN, INPUT_PULLUP); // Read TXC to see if present - pinMode(LPF_PIN, INPUT_PULLUP); // Read LPF to see if present + pinMode(BPF_PIN, INPUT_PULLUP); // Read LPF to see if present // pinMode(SQUELCH, INPUT); // Squelch from TXC - if (digitalRead(LPF_PIN) == FALSE) - Serial.println("LPF present"); + if (digitalRead(BPF_PIN) == FALSE) + Serial.println("BPF present"); else - Serial.println("LPF not present"); + Serial.println("BPF not present"); if (digitalRead(TXC_PIN) == FALSE) Serial.println("TXC present"); @@ -3245,8 +3321,8 @@ void config_gpio() { // Serial.println(digitalRead(SQUELCH)); - Serial.print("Pi 3.3V: "); - Serial.println(digitalRead(PI_3V3_PIN)); +// Serial.print("Pi 3.3V: "); +// Serial.println(digitalRead(PI_3V3_PIN)); // set anlog inputs and read Serial.print("Diode voltage (temperature): "); @@ -3299,11 +3375,13 @@ bool TimerHandler0(struct repeating_timer *t) { // Serial.print("\nR"); // Serial.print(" "); // Serial.println(millis()); - Serial.print("R Microseconds: "); - Serial.println((micros() - micro_timer)/bufLen); - micro_timer = micros(); - } + if (debug_mode) { + Serial.print("R Microseconds: "); + Serial.println((micros() - micro_timer)/bufLen); + } + micro_timer = micros(); } +} /* if (digitalRead(MAIN_PB_PIN) == PRESSED) // pushbutton is pressed process_pushbutton(); @@ -3329,7 +3407,8 @@ void start_isr() { if (ITimer0.attachInterruptInterval(827, TimerHandler0)) // was 828 // if (ITimer0.attachInterruptInterval(1667, TimerHandler0)) { - Serial.print(F("Starting ITimer0 OK, micros() = ")); Serial.println(micros()); + if (debug_mode) + Serial.print(F("Starting ITimer0 OK, micros() = ")); Serial.println(micros()); timer0_on = true; } else @@ -3348,7 +3427,8 @@ void start_button_isr() { if (ITimer1.attachInterruptInterval(10000, TimerHandler1)) { - Serial.print(F("Starting ITimer1 OK, micros() = ")); + if (debug_mode) + Serial.print(F("Starting ITimer1 OK, micros() = ")); Serial.println(micros()); } else @@ -3500,6 +3580,10 @@ void configure_wifi() { } void transmit_cw(int freq, float duration) { // freq in Hz, duration in milliseconds + if (!wifi) + digitalWrite(LED_BUILTIN, HIGH); // Transmit LED on + digitalWrite(MAIN_LED_BLUE, HIGH); + unsigned long start = micros(); unsigned long duration_us = duration * 1000; float period_us = (0.5E6) / (float)(freq); @@ -3511,6 +3595,9 @@ void transmit_cw(int freq, float duration) { // freq in Hz, duration in millise sleep(min(time_left, period_us) / 1.0E6); } digitalWrite(AUDIO_OUT_PIN, LOW); + if (!wifi) + digitalWrite(LED_BUILTIN, LOW); // Transmit LED off + digitalWrite(MAIN_LED_BLUE, LOW); } void transmit_callsign(char *callsign) { @@ -3525,7 +3612,8 @@ void transmit_callsign(char *callsign) { void transmit_string(char *string) { int j = 0; - Serial.println("Transmit on"); + if (debug_mode) + Serial.println("Transmit on"); digitalWrite(PD_PIN, HIGH); // Enable SR_FRS digitalWrite(MAIN_LED_BLUE, HIGH); digitalWrite(PTT_PIN, LOW); @@ -3541,7 +3629,8 @@ void transmit_string(char *string) { j++; } } - Serial.println("Transmit off"); + if (debug_mode) + Serial.println("Transmit off"); digitalWrite(MAIN_LED_BLUE, LOW); digitalWrite(PTT_PIN, HIGH); digitalWrite(PD_PIN, LOW); // disable SR_FRS @@ -3661,7 +3750,7 @@ void serial_input() { switch(result) { case 'h': case 'H': - Serial.println("Help"); + // Serial.println("Help"); prompt = PROMPT_HELP; /* Serial.println("\nChange settings by typing the letter:"); @@ -3711,7 +3800,7 @@ void serial_input() { case 'i': case 'I': - Serial.println("Restart CubeSatsim software"); +// Serial.println("Restart CubeSatsim software"); prompt = PROMPT_RESTART; break; @@ -3738,12 +3827,23 @@ void serial_input() { Serial.println("Change the Latitude and Longitude"); prompt = PROMPT_LAT; break; - + + case 'v': + case 'V': + Serial.println("Read INA219 voltage and current"); + prompt = PROMPT_VOLTAGE; + break; + case '?': Serial.println("Query payload sensors"); prompt = PROMPT_QUERY; break; - + + case 'd': + Serial.println("Change debug mode"); + prompt = PROMPT_DEBUG; + break; + default: Serial.println("Not a command\n"); @@ -3758,6 +3858,7 @@ void serial_input() { } void prompt_for_input() { + float float_result; while (Serial.available() > 0) // clear any characters in serial input buffer Serial.read(); @@ -3777,7 +3878,9 @@ void prompt_for_input() { Serial.println("t Simulated Telemetry"); Serial.println("r Resets Count, or payload & EEPROM"); Serial.println("l Lat and Long"); - Serial.println("? Query sensors\n"); + Serial.println("? Query sensors"); + Serial.println("v Read INA219 voltage and current"); + Serial.println("d Change debug mode\n"); break; case PROMPT_CALLSIGN: @@ -3793,8 +3896,10 @@ void prompt_for_input() { if (strlen(serial_string) > 0) { strcpy(callsign, serial_string); - if (mode == AFSK) - set_callsign(callsign); + if (mode == AFSK) { + char destination[] = "APCSS"; + set_callsign(callsign, destination); + } Serial.println("Callsign updated!"); } else Serial.println("Callsign not updated!"); @@ -3802,25 +3907,112 @@ void prompt_for_input() { break; case PROMPT_SIM: - + if (sim_mode == TRUE) + Serial.println("Simulted Telemetry mode is currently on"); + else + Serial.println("Simulted Telemetry mode is currently off"); + Serial.println("Do you want Simulated Telemetry on (y/n)"); + get_serial_char(); + if ((serial_string[0] == 'y') || (serial_string[0] == 'Y')) { + Serial.println("Setting Simulated telemetry to on"); + config_simulated_telem(); + } else if ((serial_string[0] == 'n') || (serial_string[0] == 'N')) { + Serial.println("Setting Simulated telemetry to off"); + sim_mode = false; + if (!ina219_started) + start_ina219(); + } else + Serial.println("No change to Simulated Telemetry mode"); break; case PROMPT_LAT: + + Serial.println("Changing the latitude and longitude - only used for APRS telemetry"); + Serial.println("Hitting return keeps the current value."); + + Serial.print("Current value of latitude is "); + Serial.println(latitude); + Serial.println("Enter latitude (decimal degrees, positive is north): "); + get_serial_string(); + float_result = atof(serial_string); + if (float_result != 0.0) { + Serial.print("Latitude updated to "); + Serial.println(float_result); + latitude = float_result; + } else + Serial.println("Latitude not updated"); + + get_serial_clear_buffer(); + Serial.print("Current value of longitude is "); + Serial.println(longitude); + Serial.println("Enter longitude (decimal degrees, positive is east): "); + get_serial_string(); + float_result = atof(serial_string); + if (float_result != 0.0) { + Serial.print("Longitude updated to "); + Serial.println(float_result); + longitude = float_result; + } else + Serial.println("Longitude not updated"); + if (mode == AFSK) + set_lat_lon(); break; case PROMPT_QUERY: - + Serial.println("Querying payload sensors"); + payload_command = PAYLOAD_QUERY; break; - + + case PROMPT_VOLTAGE: + Serial.println("Querying INA219 voltage and current sensors"); + if (!ina219_started) + start_ina219(); + voltage_read = true; + read_ina219(); + break; + case PROMPT_RESET: + Serial.println("Do you want to Reset the Reset Count (r) or Reset the Payload (p)?"); + Serial.println("Enter r or p"); + get_serial_char(); + if ((serial_string[0] == 'r') || (serial_string[0] == 'R')) { + Serial.println("Reset count is now 0"); + Serial.println("Storing initial reset count in EEPROM"); + +// reset_flag = 0xA07; +// EEPROM.put(16, reset_flag); + reset_count = 0; + EEPROM.put(20, reset_count + 1); + if (EEPROM.commit()) { + Serial.println("EEPROM successfully committed"); + } else { + Serial.println("ERROR! EEPROM commit failed"); + } + + } else if ((serial_string[0] == 'p') || (serial_string[0] == 'P')) { + Serial.println("Resetting the Payload"); + payload_command = PAYLOAD_RESET; + start_payload(); + } else + Serial.println("No action"); break; case PROMPT_RESTART: Serial.println("Restart not yet implemented"); - break; } - + break; + + case PROMPT_DEBUG: + Serial.print("Changing Debug Mode to "); + debug_mode = !debug_mode; + if (debug_mode) + Serial.println("on"); + else + Serial.println("off"); + break; + } + prompt = false; } void get_serial_string() { @@ -3834,9 +4026,58 @@ void get_serial_string() { serial_string[i++] = input; Serial.write(input); } - } + } sleep(0.1); } serial_string[i] = 0; Serial.println(" "); } + +void get_serial_char() { + unsigned int elapsed_time = (unsigned int) millis(); + while (((millis() - elapsed_time) < 20000) && (Serial.available() < 1)) { } + if (Serial.available() > 0) { + serial_string[0] = Serial.read(); // get character + Serial.write(serial_string[0]); + serial_string[1] = 0; + Serial.println(" "); + } else + { + serial_string[0] = 0; // timeout - no character + } +} + +void get_serial_clear_buffer() { +// Serial.println("Emptying serial input buffer"); + while (Serial.available() > 0) + Serial.read(); + +} + +void set_lat_lon() { +// Serial.println("Setting lat and lon for APRS"); + char lat_string[64]; + char lon_string[64]; + + char sym_ovl_default = '\\'; //'H'; + char sym_tab_default = 'S'; // 'a'; + char icon[] = "\\S"; //Ha"; + +// latitude = toAprsFormat(latitude); +// longitude = toAprsFormat(longitude); + // sprintf(header_str2b, "=%7.2f%c%c%c%08.2f%cShi hi ",4003.79,'N',0x5c,0x5c,07534.33,'W'); // add APRS lat and long + if (latitude > 0) + sprintf(lat_string, "%07.2f%c", toAprsFormat(latitude), 'N'); // lat + else + sprintf(lat_string, "%07.2f%c", toAprsFormat(latitude) * (-1.0), 'S'); // lat + if (longitude > 0) + sprintf(lon_string, "%08.2f%c", toAprsFormat(longitude), 'E'); // long + else + sprintf(lon_string, "%08.2f%c", toAprsFormat(longitude) * (-1.0), 'W'); // long + +// print_string(lat_string); +// print_string(lon_string); + + set_lat_lon_icon(lat_string, lon_string, icon); + +} diff --git a/cubesatsim/pico-get-jpeg-serial.cpp b/cubesatsim/pico-get-jpeg-serial.cpp new file mode 100644 index 00000000..833b4719 --- /dev/null +++ b/cubesatsim/pico-get-jpeg-serial.cpp @@ -0,0 +1,264 @@ +// Pico code to get camera image from ESP32-CAM running the esp32-cam-send-jpeg-serial software +// +// run start_camera() once to initialize. Also runs get_camera_image and returns true if got an image +// +// run get_camera_image() to get image. If returns true, an image was recevied. If false, +// the CAMERA_TIMEOUT milli second timeout was reached - might indicate no camera +// + +#include +#include + +bool finished = false; + +char buffer2[100001]; +int index1 = 0; +char start_flag[] = "3d99de816e5ad7742b61a37c39141783"; +char end_flag[] = "f681a5c52351befe0e3524eb1a40f14b7803317a"; +int flag_count = 0; +int start_flag_detected = false; +int start_flag_complete = false; +int end_flag_detected = false; +int jpeg_start = 0; +FastCRC8 CRC8; +#define CAMERA_TIMEOUT 12000 // Camera timeout in milli seconds + +//#define GET_IMAGE_DEBUG + +//#define DEBUG + +//#define PICOW true +int led_pin = LED_BUILTIN; + +bool get_camera_image(); +bool start_camera(); + +bool start_camera() { + + // setup for ESP32-CAM + +//if (PICOW) +// led_pin = STEM_LED2_PIN; + + Serial.begin(115200); + +// delay(5000); + +/* + pinMode(led_pin, OUTPUT); + + digitalWrite(led_pin, LOW); + delay(500); + digitalWrite(led_pin, HIGH); + delay(500); + digitalWrite(led_pin, LOW); + delay(500); + digitalWrite(led_pin, HIGH); + delay(500); + if (PICOW) + digitalWrite(led_pin, LOW); + + delay(2000); +*/ + Serial2.setRX(9); + delay(100); + Serial2.setTX(8); + delay(100); + Serial2.begin(115200); +#ifdef GET_IMAGE_DEBUG + Serial.println("Started Serial2 to camera"); +#endif + LittleFS.begin(); + + return(get_camera_image()); +} + +void show_dir2() { + int count = 0; + Dir dir = LittleFS.openDir("/"); +// or Dir dir = LittleFS.openDir("/data"); + Serial.println(">"); + while (dir.next()) { + count++; + Serial.print(count); + Serial.print(" "); + Serial.print(dir.fileName()); + // if(dir.fileSize()) { + File f = dir.openFile("r"); + Serial.print(" "); + Serial.println(f.size()); + // } else + // Serial.println(" "); + } + Serial.println(">"); +} + + +void write_jpg() { +/* + Serial.println("---------------"); + Serial.println(buffer2[jpeg_start], HEX); + Serial.println(buffer2[jpeg_start + 1], HEX); + Serial.println(buffer2[jpeg_start + 2], HEX); + Serial.println(buffer2[jpeg_start + 3], HEX); +*/ + if ((buffer2[jpeg_start] == 0xff) && (buffer2[jpeg_start + 1] == 0xd8) + && (buffer2[index1 - 2] == 0xff) && (buffer2[index1 - 1] == 0xd9)) { + + Serial.println("Received a JPEG! Writing to file."); + File i = LittleFS.open("/cam.jpg", "w+"); + if (i) { + i.write(&buffer2[jpeg_start], (size_t) (index1 - jpeg_start)); + finished = true; + } else + Serial.println("Error opening cam.jpg"); + +// Serial.println("---------------"); + i.close(); +// } + } else + Serial.println("Not a JPEG"); +#ifdef GET_IMAGE_DEBUG + show_dir2(); +#endif +/* + delay(2000); + + char read_values[2]; + File i = LittleFS.open("/cam.jpg", "r"); + while (i.available()) { + i.readBytes(read_values, 1); + char hexValue[5]; + sprintf(hexValue, "%02X", read_values[0]); + Serial.print(hexValue); + } + i.close(); + Serial.println("\n\n finished read"); + + */ +} + +/* +void loop() { + + char input_file[] = "/cam.jpg"; + char output_file[] = "/cam.bin"; + + get_image_file(); + + Serial.println("Got image from ESP-32-CAM!"); + + delay(1000); + +} +*/ + +bool get_camera_image() { + + index1 = 0; + flag_count = 0; + start_flag_detected = false; + start_flag_complete = false; + end_flag_detected = false; + jpeg_start = 0; + +#ifdef GET_IMAGE_DEBUG + Serial.println("Starting get_image_file"); + #endif + finished = false; + + unsigned long time_start = millis(); + while ((!finished) && ((millis() - time_start) < CAMERA_TIMEOUT)) { + + if (Serial2.available()) { // If anything comes in Serial2 + byte octet = Serial2.read(); + + if (start_flag_complete) { +// Serial.println("Start flag complete detected"); + buffer2[index1++] = octet; + if (octet == end_flag[flag_count]) { // looking for end flag +// if (end_flag_detected) { + flag_count++; +#ifdef GET_IMAGE_DEBUG + Serial.println("Found part of end flag!"); +#endif + if (flag_count >= strlen(end_flag)) { // complete image +/// buffer2[index1++] = octet; + Serial.println("\nFound end flag"); +// Serial.println(octet, HEX); + while(!Serial2.available()) { } // Wait for another byte +// octet = Serial2.read(); +// buffer2[index1++] = octet; +// Serial.println(octet, HEX); +// while(!Serial2.available()) { } // Wait for another byte + int received_crc = Serial2.read(); +// buffer2[index1++] = octet; + + Serial.print("\nFile length: "); + Serial.println(index1 - (int)strlen(end_flag)); +// index1 -= 1; // 40; +// Serial.println(buffer2[index1 - 1], HEX); +// int received_crc = buffer2[index1]; +// index1 -= 1; + + uint8_t * data = (uint8_t *) &buffer2[0]; +#ifdef GET_IMAGE_DEBUG + Serial.println("\nCRC cacluation data:"); + Serial.println(buffer2[0], HEX); + Serial.println(buffer2[index1 - 1], HEX); + Serial.println(index1); + Serial.println(received_crc, HEX); + #endif + int calculated_crc = CRC8.smbus(data, index1); + // Serial.println(calculated_crc, HEX); + if (received_crc == calculated_crc) + Serial.println("CRC check succeeded!"); + else + Serial.println("CRC check failed!"); + + index1 -= 40; + write_jpg(); + index1 = 0; + start_flag_complete = false; + start_flag_detected = false; // get ready for next image + end_flag_detected = false; + flag_count = 0; +// delay(6000); + } + } else { + flag_count = 0; + } + /// buffer2[index1++] = octet; + +#ifdef GET_IMAGE_DEBUG + char hexValue[5]; + if (octet != 0x66) { + sprintf(hexValue, "%02X", octet); + Serial.print(hexValue); + } else { +// Serial.println("\n********************************************* Got a 66!"); + Serial.print("66"); + } +// Serial.write(octet); +#endif + if (index1 > 100000) + index1 = 0; +// } + } else if (octet == start_flag[flag_count]) { // looking for start flag + start_flag_detected = true; + flag_count++; +// Serial.println("Found part of start flag! "); + if (flag_count >= strlen(start_flag)) { + flag_count = 0; + start_flag_complete = true; + Serial.println("Found start flag!\n"); + } + } else { // not the flag, keep looking + start_flag_detected = false; + flag_count = 0; + // Serial.println("Resetting. Not start flag."); + } + } + } + return(finished); +} diff --git a/cubesatsim/pico-get-jpeg-serial/pico-get-jpeg-serial.ino b/cubesatsim/pico-get-jpeg-serial/examples/pico-get-jpeg-serial.ino similarity index 100% rename from cubesatsim/pico-get-jpeg-serial/pico-get-jpeg-serial.ino rename to cubesatsim/pico-get-jpeg-serial/examples/pico-get-jpeg-serial.ino diff --git a/cubesatsim/pico-get-jpeg-serial/pico-get-jpeg-serial.cpp b/cubesatsim/pico-get-jpeg-serial/pico-get-jpeg-serial.cpp new file mode 100644 index 00000000..12d83125 --- /dev/null +++ b/cubesatsim/pico-get-jpeg-serial/pico-get-jpeg-serial.cpp @@ -0,0 +1,212 @@ +#include "pico-get-jpeg-serial.h" + +/* +void setup() { + + // put your setup code here, to run once: + +if (PICOW) + led_pin = STEM_LED2_PIN; + + Serial.begin(115200); + + delay(5000); + + pinMode(led_pin, OUTPUT); + + digitalWrite(led_pin, LOW); + delay(500); + digitalWrite(led_pin, HIGH); + delay(500); + digitalWrite(led_pin, LOW); + delay(500); + digitalWrite(led_pin, HIGH); + delay(500); + if (PICOW) + digitalWrite(led_pin, LOW); + + delay(2000); + + Serial2.setRX(9); + delay(100); + Serial2.setTX(8); + delay(100); + Serial2.begin(115200); + + Serial.println("Starting"); + + LittleFS.begin(); +} + +void show_dir() { + int count = 0; + Dir dir = LittleFS.openDir("/"); +// or Dir dir = LittleFS.openDir("/data"); + Serial.println(">"); + while (dir.next()) { + count++; + Serial.print(count); + Serial.print(" "); + Serial.print(dir.fileName()); + // if(dir.fileSize()) { + File f = dir.openFile("r"); + Serial.print(" "); + Serial.println(f.size()); + // } else + // Serial.println(" "); + } + Serial.println(">"); +} +*/ + +void write_jpg() { +/* + Serial.println("---------------"); + Serial.println(buffer[jpeg_start], HEX); + Serial.println(buffer[jpeg_start + 1], HEX); + Serial.println(buffer[jpeg_start + 2], HEX); + Serial.println(buffer[jpeg_start + 3], HEX); +*/ + if ((buffer[jpeg_start] == 0xff) && (buffer[jpeg_start + 1] == 0xd8) + && (buffer[index1 - 2] == 0xff) && (buffer[index1 - 1] == 0xd9)) { + + Serial.println("Received a JPEG! Writing to file."); + File i = LittleFS.open("/cam.jpg", "w+"); + if (i) { + i.write(&buffer[jpeg_start], (size_t) (index1 - jpeg_start)); + finished = true; + } else + Serial.println("Error opening cam.jpg"); + +// Serial.println("---------------"); + i.close(); +// } + } else + Serial.println("Not a JPEG"); + + show_dir(); +/* + delay(2000); + + char read_values[2]; + File i = LittleFS.open("/cam.jpg", "r"); + while (i.available()) { + i.readBytes(read_values, 1); + char hexValue[5]; + sprintf(hexValue, "%02X", read_values[0]); + Serial.print(hexValue); + } + i.close(); + Serial.println("\n\n finished read"); + + */ +} + +/* +void loop() { + + char input_file[] = "/cam.jpg"; + char output_file[] = "/cam.bin"; + + get_image_file(); + + Serial.println("Got image from ESP-32-CAM!"); + + delay(1000); + +} +*/ + +void get_image_file() { + finished = false; + while (!finished) { + // put your main code here, to run repeatedly: + if (Serial2.available()) { // If anything comes in Serial2 + byte octet = Serial2.read(); + + if (start_flag_complete) { +// Serial.println("Start flag complete detected"); + buffer[index1++] = octet; + if (octet == end_flag[flag_count]) { // looking for end flag +// if (end_flag_detected) { + flag_count++; +// Serial.println("Found part of end flag!"); + if (flag_count >= strlen(end_flag)) { // complete image +/// buffer[index1++] = octet; + Serial.println("\nFound end flag"); +// Serial.println(octet, HEX); + while(!Serial2.available()) { } // Wait for another byte +// octet = Serial2.read(); +// buffer[index1++] = octet; +// Serial.println(octet, HEX); +// while(!Serial2.available()) { } // Wait for another byte + int received_crc = Serial2.read(); +// buffer[index1++] = octet; + + Serial.print("\nFile length: "); + Serial.println(index1 - (int)strlen(end_flag)); +// index1 -= 1; // 40; +// Serial.println(buffer[index1 - 1], HEX); +// int received_crc = buffer[index1]; +// index1 -= 1; + + uint8_t * data = (uint8_t *) &buffer[0]; +#ifdef DEBUG + Serial.println("\nCRC cacluation data:"); + Serial.println(buffer[0], HEX); + Serial.println(buffer[index1 - 1], HEX); + Serial.println(index1); + Serial.println(received_crc, HEX); + #endif + int calculated_crc = CRC8.smbus(data, index1); + // Serial.println(calculated_crc, HEX); + if (received_crc == calculated_crc) + Serial.println("CRC check succeeded!"); + else + Serial.println("CRC check failed!"); + + index1 -= 40; + write_jpg(); + index1 = 0; + start_flag_complete = false; + start_flag_detected = false; // get ready for next image + end_flag_detected = false; + flag_count = 0; +// delay(6000); + } + } else { + flag_count = 0; + } + /// buffer[index1++] = octet; + +#ifdef DEBUG + char hexValue[5]; + if (octet != 0x66) { + sprintf(hexValue, "%02X", octet); + Serial.print(hexValue); + } else { +// Serial.println("\n********************************************* Got a 66!"); + Serial.print("66"); + } +// Serial.write(octet); +#endif + if (index1 > 100000) + index1 = 0; +// } + } else if (octet == start_flag[flag_count]) { // looking for start flag + start_flag_detected = true; + flag_count++; +// Serial.println("Found part of start flag! "); + if (flag_count >= strlen(start_flag)) { + flag_count = 0; + start_flag_complete = true; + Serial.println("Found start flag!\n"); + } + } else { // not the flag, keep looking + start_flag_detected = false; + flag_count = 0; + // Serial.println("Resetting. Not start flag."); + } + } + } +} diff --git a/cubesatsim/pico-get-jpeg-serial/pico-get-jpeg-serial.h b/cubesatsim/pico-get-jpeg-serial/pico-get-jpeg-serial.h new file mode 100644 index 00000000..c8363370 --- /dev/null +++ b/cubesatsim/pico-get-jpeg-serial/pico-get-jpeg-serial.h @@ -0,0 +1,22 @@ +#include +#include + +bool finished = false; + +//char buffer[100001]; +int index1 = 0; +char start_flag[] = "3d99de816e5ad7742b61a37c39141783"; +char end_flag[] = "f681a5c52351befe0e3524eb1a40f14b7803317a"; +int flag_count = 0; +int start_flag_detected = false; +int start_flag_complete = false; +int end_flag_detected = false; +int jpeg_start = 0; +FastCRC8 CRC8; + +//#define DEBUG + +//#define PICOW true +int led_pin = LED_BUILTIN; + +void get_image_file();