diff --git a/decoder/decoder.py b/decoder/decoder.py index 2d5ea8d..5a47650 100755 --- a/decoder/decoder.py +++ b/decoder/decoder.py @@ -12,7 +12,7 @@ import position # Parse arguments from terminal parser = argparse.ArgumentParser(description='APRS/SSDV decoder') -parser.add_argument('-c', '--call', help='Callsign of the station', required=True) +parser.add_argument('-c', '--call', help='Callsign of the station', default='N0CALL') parser.add_argument('-n', '--grouping', help='Amount packets that will be sent to the SSDV server in one request', default=1, type=int) parser.add_argument('-d', '--device', help='Serial device (\'-\' for stdin)', default='-') parser.add_argument('-b', '--baudrate', help='Baudrate for serial device', default=9600, type=int) @@ -30,7 +30,7 @@ sqlite.cursor().execute(""" lat FLOAT, lon FLOAT, alt INTEGER, - new INTEGER, + isnew INTEGER, comment TEXT, sequ INTEGER, tel1 INTEGER, @@ -61,11 +61,6 @@ sqlite.cursor().execute(""" """ Packet handler for received APRS packets""" def received_data(data): - # Debug - print('====================================================================================================') - print(data) - print('----------------------------------------------------------------------------------------------------') - # Parse line and detect data # Position (.*)\>APECAN(.*?):\/([0-9]{6}h)(.{13})(.*?)\|(.*)\| # Image (.*)\>APECAN(.*?):\/([0-9]{6}h)(.{13})I(.*) @@ -76,8 +71,14 @@ def received_data(data): dat = re.search("(.*)\>APECAN(.*?):\/([0-9]{6}h)(.{13})(I|J|L)(.*)", data) if all: - call = all.group(1) + # Debug + print('='*100) + print(data) + print('-'*100) + + call = all.group(1).split(' ')[-1] rxer = all.group(2).split(',')[-1] + if not len(rxer): rxer = args.call tim = all.group(3) posi = all.group(4) diff --git a/decoder/html/database.class.php b/decoder/html/database.class.php index 4994ec9..d153c0c 100644 --- a/decoder/html/database.class.php +++ b/decoder/html/database.class.php @@ -32,6 +32,8 @@ class MyDB extends SQLite3 { WHERE position.call = :call AND position.lat != 0 AND position.lon != 0 + AND position.isnew = 1 + AND position.time + 86400*14 > CAST(strftime('%s', 'now') as DECIMAL) GROUP BY position.call,position.time ORDER BY position.time ASC "); @@ -45,4 +47,3 @@ class MyDB extends SQLite3 { } } ?> - diff --git a/decoder/image.py b/decoder/image.py index 850ee4e..9ea9042 100644 --- a/decoder/image.py +++ b/decoder/image.py @@ -41,18 +41,17 @@ data - Binary data def insert_image(sqlite, receiver, call, tim, posi, data, typ, server, grouping): global jsons - if len(data) != 110: - return # APRS message sampled too short + if not (typ is 'I' and len(data) == 125) and not (typ is 'J' and len(data) == 124): + return # APRS message has invalid type or length (or both) # Decode various meta data timd,x,y,z,teld,new = decode_position(tim, posi, None) imageID = data[0] packetID = (data[1] << 8) | data[2] data = binascii.hexlify(data[3:]).decode("ascii") - print(len(data)) # Debug - print('Received packet from %s image %d packet %d' % (call, imageID, packetID)) + print('Received %s-Packet Image %d Packet %d' % (typ, imageID, packetID)) # Insert sqlite.cursor().execute(""" @@ -75,7 +74,7 @@ def insert_image(sqlite, receiver, call, tim, posi, data, typ, server, grouping) else: bcall = bcall[0][0:6] # Callsign has 6 chars, so take the call without SSID - data = '66%08x' % encode_callsign(bcall) + data + data = ('67%08x%02x%04x' % (encode_callsign(bcall), imageID, packetID)) + data sqlite.cursor().execute(""" UPDATE image @@ -101,7 +100,6 @@ def insert_image(sqlite, receiver, call, tim, posi, data, typ, server, grouping) sqlite.commit() - # Get both data entries cur = sqlite.cursor() cur.execute(""" @@ -136,7 +134,7 @@ def insert_image(sqlite, receiver, call, tim, posi, data, typ, server, grouping) # SSDV decode cur = sqlite.cursor() - cur.execute("SELECT GROUP_CONCAT('55' || data1 || data2 || crc || '0000000000000000000000000000000000000000000000000000000000000000', '') FROM image WHERE call = ? AND imageID = ? AND time = ? GROUP BY imageID ORDER BY packetID", (call, imageID, int(timd.timestamp()))) + cur.execute("SELECT GROUP_CONCAT('55' || data1 || data2 || crc, '') FROM image WHERE call = ? AND imageID = ? AND time = ? GROUP BY imageID ORDER BY packetID", (call, imageID, int(timd.timestamp()))) name = 'html/images/%s-%d-%d.jpg' % (call.replace('-',''), int(timd.timestamp()), imageID) f = open(name, 'wb') process = Popen(['./ssdv', '-d'], stdin=PIPE, stdout=f, stderr=PIPE) @@ -145,7 +143,7 @@ def insert_image(sqlite, receiver, call, tim, posi, data, typ, server, grouping) f.close() # Create message for SSDV server (and save to array) - ssdv = '55' + data + ('%08x' % crc) + (64*'0') + ssdv = '55' + data + ('%08x' % crc) jsons.append("""{ \"type\": \"packet\", \"packet\": \"""" + ssdv + """\", @@ -168,11 +166,13 @@ def insert_image(sqlite, receiver, call, tim, posi, data, typ, server, grouping) print('Send to SSDV data server') try: result = urllib.request.urlopen(req, "".join(json.split(' ')).encode("ascii")) # Send packets to server - print('Response from Server: OK') + print('Response from SSDV-Server: OK') err = False except urllib.error.URLError as error: - if error.code == 400: - print('Response from Server: %s', error.read()) + if not hasattr(error, 'code'): # (Bug in urllib) most likely network not available + print('Error: Could not connect to SSDV-Server') + elif error.code == 400: + print('Response from SSDV-Server: %s' % error.read().decode('ascii').replace('\n','')) err = False else: print('SSDV-Server connection error... try again') diff --git a/decoder/position.py b/decoder/position.py index be099fb..a993ce1 100644 --- a/decoder/position.py +++ b/decoder/position.py @@ -18,7 +18,7 @@ def insert_log(sqlite, call, data): tim_stringified = datetime.utcfromtimestamp(tim).strftime("%Y-%m-%d %H:%M:%S") try: - sqlite.cursor().execute("INSERT OR FAIL INTO position (call,time,org,lat,lon,alt) VALUES (?,?,'log',?,?,?)", (call, tim, lat, lon, alt)) + sqlite.cursor().execute("INSERT OR FAIL INTO position (call,time,org,lat,lon,alt,isnew) VALUES (?,?,'log',?,?,?,1)", (call, tim, lat, lon, alt)) print("Decoded log from %s time %s => lat=%06.3f lon=%07.3f alt=%05d" % (call, tim_stringified, lat, lon, alt)) except sqlite3.IntegrityError: print("Decoded log from %s time %s => lat=%06.3f lon=%07.3f alt=%05d already in db" % (call, tim_stringified, lat, lon, alt)) @@ -56,7 +56,7 @@ def decode_position(tim, posi, tel): timd -= timedelta(1) # Decode GPS Fix Type - new = ((ord(posi[12])-33) >> 5) & 0x1 + isnew = ((ord(posi[12])-33) >> 5) & 0x1 # Decode telemetry teld = [0]*6 @@ -66,22 +66,22 @@ def decode_position(tim, posi, tel): t0 = ord(tel[i*2+1]) - 33 teld.append(t0 + t1*91) - return timd,x,y,z,teld,new + return timd,x,y,z,teld,isnew def insert_position(sqlite, call, tim, posi, comm, tel): #sqlite, call, data # Decode - timd,x,y,z,teld,new = decode_position(tim, posi, tel) + timd,x,y,z,teld,isnew = decode_position(tim, posi, tel) # Insert sqlite.cursor().execute(""" - INSERT OR REPLACE INTO position (call,time,org,lat,lon,alt,new,comment,sequ,tel1,tel2,tel3,tel4,tel5) + INSERT OR REPLACE INTO position (call,time,org,lat,lon,alt,isnew,comment,sequ,tel1,tel2,tel3,tel4,tel5) VALUES (?,?,'pos',?,?,?,?,?,?,?,?,?,?,?)""", - (call, int(timd.timestamp()), y, x, int(z), new, comm, teld[0], teld[1], teld[2], teld[3], teld[4], teld[5]) + (call, int(timd.timestamp()), y, x, int(z), isnew, comm, teld[0], teld[1], teld[2], teld[3], teld[4], teld[5]) ) sqlite.commit() # Debug tim_stringified = timd.strftime("%Y-%m-%d %H:%M:%S") print("Decoded position from %s time %s => lat=%f lon=%f alt=%d new=%d comment=%s, sequ=%d tel=[%d,%d,%d,%d,%d]" - % (call, tim_stringified, y, x, int(z), new, comm, teld[0], teld[1], teld[2], teld[3], teld[4], teld[5])) + % (call, tim_stringified, y, x, int(z), isnew, comm, teld[0], teld[1], teld[2], teld[3], teld[4], teld[5])) diff --git a/decoder/ssdv b/decoder/ssdv new file mode 100755 index 0000000..716d76e Binary files /dev/null and b/decoder/ssdv differ diff --git a/tracker/software/config.c b/tracker/software/config.c index 5454b9a..1fba492 100644 --- a/tracker/software/config.c +++ b/tracker/software/config.c @@ -397,7 +397,7 @@ void start_user_modules(void) config[0].aprs_conf.tel_enc = TRUE; // Transmit Telemetry encoding information activated config[0].aprs_conf.tel_enc_cycle = 3600; // Transmit Telemetry encoding information every 3600sec chsnprintf(config[0].aprs_conf.tel_comment, 30, "http://ssdv.habhub.org/DL7AD");// Telemetry comment - start_position_thread(&config[0]); + //start_position_thread(&config[0]); // Module POSITION, UKHAS 2m 2FSK config[1].power = 127; // Transmission Power @@ -407,7 +407,7 @@ void start_user_modules(void) config[1].trigger.type = TRIG_CONTINUOUSLY; // Transmit continuously config[1].fsk_conf.bits = 8; // 8 bit config[1].fsk_conf.stopbits = 2; // 2 stopbits - config[1].fsk_conf.predelay = 1000; // Preamble (1000ms) + config[1].fsk_conf.predelay = 3000; // Preamble (1000ms) config[1].fsk_conf.baud = 50; // Baudrate config[1].fsk_conf.shift = 425; // Frequency shift in Hz chsnprintf(config[1].ukhas_conf.callsign, 16, "DL7AD"); // UKHAS Callsign @@ -446,7 +446,7 @@ void start_user_modules(void) config[3].ssdv_conf.res = RES_QVGA; // Resolution QVGA config[3].ssdv_conf.redundantTx = true; // Redundant transmission (transmit packets twice) config[3].ssdv_conf.quality = 4; // Image quality - start_image_thread(&config[3]); + //start_image_thread(&config[3]); // Module IMAGE, APRS 2m 2GFSK config[4].power = 127; // Transmission Power @@ -473,9 +473,9 @@ void start_user_modules(void) config[5].trigger.type = TRIG_CONTINUOUSLY; // Transmit continuously config[5].fsk_conf.bits = 8; // 8bit config[5].fsk_conf.stopbits = 2; // 2 Stopbits - config[5].fsk_conf.predelay = 1000; // Preamble (1000ms) - config[5].fsk_conf.baud = 600; // Baudrate (600baud) - config[5].fsk_conf.shift = 1000; // Frequency shift (1000Hz) + config[5].fsk_conf.predelay = 3000; // Preamble (1000ms) + config[5].fsk_conf.baud = 300; // Baudrate (600baud) + config[5].fsk_conf.shift = 425; // Frequency shift (1000Hz) chsnprintf(config[5].ssdv_conf.callsign, 7, "DL7AD"); // SSDV Callsign config[5].ssdv_conf.ram_buffer = ssdv_buffer; // Camera buffer config[5].ssdv_conf.ram_size = sizeof(ssdv_buffer); // Buffer size @@ -499,7 +499,6 @@ void start_user_modules(void) config[6].aprs_conf.symbol = SYM_BALLOON; // APRS Symbol chsnprintf(config[6].aprs_conf.path, 16, "WIDE1-1"); // APRS Path config[6].aprs_conf.preamble = 300; // APRS Preamble (300ms) - start_logging_thread(&config[6]); + //start_logging_thread(&config[6]); } - diff --git a/tracker/software/drivers/si4464.c b/tracker/software/drivers/si4464.c index cfa7e18..bd4676f 100644 --- a/tracker/software/drivers/si4464.c +++ b/tracker/software/drivers/si4464.c @@ -27,18 +27,20 @@ bool initialized = false; * @param mv Oscillator voltage in mv */ void Si4464_Init(void) { - // Reset radio) - Si4464_shutdown(); - chThdSleepMilliseconds(10); - - // Configure SPI pins + // Configure Radio pins palSetLineMode(LINE_SPI_SCK, PAL_MODE_ALTERNATE(6) | PAL_STM32_OSPEED_HIGHEST); // SCK palSetLineMode(LINE_SPI_MISO, PAL_MODE_ALTERNATE(6) | PAL_STM32_OSPEED_HIGHEST); // MISO palSetLineMode(LINE_SPI_MOSI, PAL_MODE_ALTERNATE(6) | PAL_STM32_OSPEED_HIGHEST); // MOSI palSetLineMode(LINE_RADIO_CS, PAL_MODE_OUTPUT_PUSHPULL | PAL_STM32_OSPEED_HIGHEST); // RADIO CS palSetLineMode(LINE_RADIO_SDN, PAL_MODE_OUTPUT_PUSHPULL); // RADIO SDN + palSetLineMode(LINE_OSC_EN, PAL_MODE_OUTPUT_PUSHPULL); // Oscillator palSetLine(LINE_RADIO_CS); + // Reset radio + Si4464_shutdown(); + palSetLine(LINE_OSC_EN); // Activate Oscillator + chThdSleepMilliseconds(10); + // Power up transmitter palClearLine(LINE_RADIO_SDN); // Radio SDN low (power up transmitter) chThdSleepMilliseconds(10); // Wait for transmitter to power up @@ -52,6 +54,55 @@ void Si4464_Init(void) { Si4464_write(init_command, 7); chThdSleepMilliseconds(25); + // Set transmitter GPIOs + uint8_t gpio_pin_cfg_command[] = { + 0x13, // Command type = GPIO settings + 0x00, // GPIO0 0 - PULL_CTL[1bit] - GPIO_MODE[6bit] + 0x23, // GPIO1 0 - PULL_CTL[1bit] - GPIO_MODE[6bit] + 0x00, // GPIO2 0 - PULL_CTL[1bit] - GPIO_MODE[6bit] + 0x00, // GPIO3 0 - PULL_CTL[1bit] - GPIO_MODE[6bit] + 0x00, // NIRQ + 0x00, // SDO + 0x00 // GEN_CONFIG + }; + Si4464_write(gpio_pin_cfg_command, 8); + chThdSleepMilliseconds(25); + + // Set FIFO empty interrupt threshold (32 byte) + uint8_t set_fifo_irq[] = {0x11, 0x12, 0x01, 0x0B, 0x20}; + Si4464_write(set_fifo_irq, 5); + + // Set FIFO to 129 byte + uint8_t set_129byte[] = {0x11, 0x00, 0x01, 0x03, 0x10}; + Si4464_write(set_129byte, 5); + + // Reset FIFO + uint8_t reset_fifo[] = {0x15, 0x01}; + Si4464_write(reset_fifo, 2); + uint8_t unreset_fifo[] = {0x15, 0x00}; + Si4464_write(unreset_fifo, 2); + + // Disable preamble + uint8_t disable_preamble[] = {0x11, 0x10, 0x01, 0x00, 0x00}; + Si4464_write(disable_preamble, 5); + + // Do not transmit sync word + uint8_t no_sync_word[] = {0x11, 0x11, 0x01, 0x00, (0x01 << 7)}; + Si4464_write(no_sync_word, 5); + + // Setup the NCO modulo and oversampling mode + uint32_t s = RADIO_CLK / 10; + uint8_t f3 = (s >> 24) & 0xFF; + uint8_t f2 = (s >> 16) & 0xFF; + uint8_t f1 = (s >> 8) & 0xFF; + uint8_t f0 = (s >> 0) & 0xFF; + uint8_t setup_oversampling[] = {0x11, 0x20, 0x04, 0x06, f3, f2, f1, f0}; + Si4464_write(setup_oversampling, 8); + + // transmit LSB first + uint8_t use_lsb_first[] = {0x11, 0x12, 0x01, 0x06, 0x01}; + Si4464_write(use_lsb_first, 5); + // Temperature readout TRACE_INFO("SI > Transmitter temperature %d degC", Si4464_getTemperature()); initialized = true; @@ -173,44 +224,12 @@ void setShift(uint16_t shift) { } void setModemAFSK(void) { - // Set transmitter GPIOs - palSetLineMode(LINE_RADIO_GPIO, PAL_MODE_OUTPUT_PUSHPULL); // GPIO1 - uint8_t gpio_pin_cfg_command[] = { - 0x13, // Command type = GPIO settings - 0x00, // GPIO0 0 - PULL_CTL[1bit] - GPIO_MODE[6bit] - 0x44, // GPIO1 0 - PULL_CTL[1bit] - GPIO_MODE[6bit] - 0x00, // GPIO2 0 - PULL_CTL[1bit] - GPIO_MODE[6bit] - 0x00, // GPIO3 0 - PULL_CTL[1bit] - GPIO_MODE[6bit] - 0x00, // NIRQ - 0x00, // SDO - 0x00 // GEN_CONFIG - }; - Si4464_write(gpio_pin_cfg_command, 8); - chThdSleepMilliseconds(25); - - // Disable preamble - uint8_t disable_preamble[] = {0x11, 0x10, 0x01, 0x00, 0x00}; - Si4464_write(disable_preamble, 5); - - // Do not transmit sync word - uint8_t no_sync_word[] = {0x11, 0x11, 0x01, 0x00, (0x01 << 7)}; - Si4464_write(no_sync_word, 5); - - // Setup the NCO modulo and oversampling mode - uint32_t s = RADIO_CLK / 10; - uint8_t f3 = (s >> 24) & 0xFF; - uint8_t f2 = (s >> 16) & 0xFF; - uint8_t f1 = (s >> 8) & 0xFF; - uint8_t f0 = (s >> 0) & 0xFF; - uint8_t setup_oversampling[] = {0x11, 0x20, 0x04, 0x06, f3, f2, f1, f0}; - Si4464_write(setup_oversampling, 8); - // Setup the NCO data rate for APRS - uint8_t setup_data_rate[] = {0x11, 0x20, 0x03, 0x03, 0x00, 0x11, 0x30}; + uint8_t setup_data_rate[] = {0x11, 0x20, 0x03, 0x03, 0x00, 0x33, 0x90}; Si4464_write(setup_data_rate, 7); - // Use 2GFSK from async GPIO1 - uint8_t use_2gfsk[] = {0x11, 0x20, 0x01, 0x00, 0x2B}; + // Use 2GFSK from FIFO (PH) + uint8_t use_2gfsk[] = {0x11, 0x20, 0x01, 0x00, 0x03}; Si4464_write(use_2gfsk, 5); // Set AFSK filter @@ -222,109 +241,35 @@ void setModemAFSK(void) { } } -void setModemOOK(void) { - // Set transmitter GPIOs - palSetLineMode(LINE_RADIO_GPIO, PAL_MODE_OUTPUT_PUSHPULL); // GPIO1 - uint8_t gpio_pin_cfg_command[] = { - 0x13, // Command type = GPIO settings - 0x00, // GPIO0 0 - PULL_CTL[1bit] - GPIO_MODE[6bit] - 0x44, // GPIO1 0 - PULL_CTL[1bit] - GPIO_MODE[6bit] - 0x00, // GPIO2 0 - PULL_CTL[1bit] - GPIO_MODE[6bit] - 0x00, // GPIO3 0 - PULL_CTL[1bit] - GPIO_MODE[6bit] - 0x00, // NIRQ - 0x00, // SDO - 0x00 // GEN_CONFIG - }; - Si4464_write(gpio_pin_cfg_command, 8); - chThdSleepMilliseconds(25); +void setModemOOK(ook_conf_t* conf) { + // Setup the NCO data rate for 2FSK + uint16_t speed = conf->speed * 5 / 6; + uint8_t setup_data_rate[] = {0x11, 0x20, 0x03, 0x03, 0x00, 0x00, (uint8_t)speed}; + Si4464_write(setup_data_rate, 7); - // Use OOK from async GPIO1 - uint8_t use_ook[] = {0x11, 0x20, 0x01, 0x00, 0xA9}; + // Use 2FSK from FIFO (PH) + uint8_t use_ook[] = {0x11, 0x20, 0x01, 0x00, 0x01}; Si4464_write(use_ook, 5); } -void setModem2FSK(void) { - // Set transmitter GPIOs - palSetLineMode(LINE_RADIO_GPIO, PAL_MODE_OUTPUT_PUSHPULL); // GPIO1 - uint8_t gpio_pin_cfg_command[] = { - 0x13, // Command type = GPIO settings - 0x00, // GPIO0 0 - PULL_CTL[1bit] - GPIO_MODE[6bit] - 0x44, // GPIO1 0 - PULL_CTL[1bit] - GPIO_MODE[6bit] - 0x00, // GPIO2 0 - PULL_CTL[1bit] - GPIO_MODE[6bit] - 0x00, // GPIO3 0 - PULL_CTL[1bit] - GPIO_MODE[6bit] - 0x00, // NIRQ - 0x00, // SDO - 0x00 // GEN_CONFIG - }; - Si4464_write(gpio_pin_cfg_command, 8); - chThdSleepMilliseconds(25); +void setModem2FSK(fsk_conf_t* conf) { + // Setup the NCO data rate for 2FSK + uint8_t setup_data_rate[] = {0x11, 0x20, 0x03, 0x03, (uint8_t)(conf->baud >> 16), (uint8_t)(conf->baud >> 8), (uint8_t)conf->baud}; + Si4464_write(setup_data_rate, 7); - // Initialize high tone - RADIO_WRITE_GPIO(HIGH); - - // use 2FSK from async GPIO1 - uint8_t use_2fsk[] = {0x11, 0x20, 0x01, 0x00, 0xAA}; + // Use 2FSK from FIFO (PH) + uint8_t use_2fsk[] = {0x11, 0x20, 0x01, 0x00, 0x02}; Si4464_write(use_2fsk, 5); } void setModem2GFSK(gfsk_conf_t* conf) { - // Set transmitter GPIOs - palSetLineMode(LINE_RADIO_GPIO, PAL_MODE_INPUT); // GPIO1 - uint8_t gpio_pin_cfg_command[] = { - 0x13, // Command type = GPIO settings - 0x00, // GPIO0 0 - PULL_CTL[1bit] - GPIO_MODE[6bit] - 0x23, // GPIO1 0 - PULL_CTL[1bit] - GPIO_MODE[6bit] - 0x00, // GPIO2 0 - PULL_CTL[1bit] - GPIO_MODE[6bit] - 0x00, // GPIO3 0 - PULL_CTL[1bit] - GPIO_MODE[6bit] - 0x00, // NIRQ - 0x00, // SDO - 0x00 // GEN_CONFIG - }; - Si4464_write(gpio_pin_cfg_command, 8); - chThdSleepMilliseconds(25); - - // Set FIFO empty interrupt threshold (32 byte) - uint8_t set_fifo_irq[] = {0x11, 0x12, 0x01, 0x0B, 0x20}; - Si4464_write(set_fifo_irq, 5); - - // Set FIFO to 129 byte - uint8_t set_129byte[] = {0x11, 0x00, 0x01, 0x03, 0x10}; - Si4464_write(set_129byte, 5); - - // Reset FIFO - uint8_t reset_fifo[] = {0x15, 0x01}; - Si4464_write(reset_fifo, 2); - uint8_t unreset_fifo[] = {0x15, 0x00}; - Si4464_write(unreset_fifo, 2); - - // Disable preamble - uint8_t disable_preamble[] = {0x11, 0x10, 0x01, 0x00, 0x00}; - Si4464_write(disable_preamble, 5); - - // Do not transmit sync word - uint8_t no_sync_word[] = {0x11, 0x11, 0x01, 0x00, (0x01 << 7)}; - Si4464_write(no_sync_word, 5); - - // Setup the NCO modulo and oversampling mode - uint32_t s = RADIO_CLK / 10; - uint8_t f3 = (s >> 24) & 0xFF; - uint8_t f2 = (s >> 16) & 0xFF; - uint8_t f1 = (s >> 8) & 0xFF; - uint8_t f0 = (s >> 0) & 0xFF; - uint8_t setup_oversampling[] = {0x11, 0x20, 0x04, 0x06, f3, f2, f1, f0}; - Si4464_write(setup_oversampling, 8); - // Setup the NCO data rate for 2GFSK uint8_t setup_data_rate[] = {0x11, 0x20, 0x03, 0x03, (uint8_t)(conf->speed >> 16), (uint8_t)(conf->speed >> 8), (uint8_t)conf->speed}; Si4464_write(setup_data_rate, 7); // Use 2GFSK from FIFO (PH) - uint8_t use_2gfsk[] = {0x11, 0x20, 0x01, 0x00, 0x23}; + uint8_t use_2gfsk[] = {0x11, 0x20, 0x01, 0x00, 0x03}; Si4464_write(use_2gfsk, 5); - - // transmit LSB first - uint8_t use_lsb_first[] = {0x11, 0x12, 0x01, 0x06, 0x01}; - Si4464_write(use_lsb_first, 5); } void setPowerLevel(int8_t level) { @@ -350,7 +295,8 @@ void stopTx(void) { void Si4464_shutdown(void) { palSetLine(LINE_RADIO_SDN); // Power down chip palSetLine(LINE_IO_LED1); // Set indication LED - RADIO_WRITE_GPIO(false); // Set GPIO1 low + palClearLine(LINE_OSC_EN); // Shutdown oscillator + RADIO_WRITE_GPIO(false); // Set GPIO1 low initialized = false; } @@ -416,3 +362,4 @@ int8_t Si4464_getTemperature(void) { bool isRadioInitialized(void) { return initialized; } + diff --git a/tracker/software/drivers/si4464.h b/tracker/software/drivers/si4464.h index 7506351..2644bb1 100644 --- a/tracker/software/drivers/si4464.h +++ b/tracker/software/drivers/si4464.h @@ -27,8 +27,8 @@ void Si4464_write(uint8_t* txData, uint32_t len); void setFrequency(uint32_t freq, uint16_t shift); void setShift(uint16_t shift); void setModemAFSK(void); -void setModemOOK(void); -void setModem2FSK(void); +void setModemOOK(ook_conf_t* conf); +void setModem2FSK(fsk_conf_t* conf); void setModem2GFSK(gfsk_conf_t* conf); void setDeviation(uint32_t deviation); void setPowerLevel(int8_t level); diff --git a/tracker/software/main.c b/tracker/software/main.c index 70f8e95..1949ef4 100644 --- a/tracker/software/main.c +++ b/tracker/software/main.c @@ -55,11 +55,13 @@ int main(void) { start_user_modules(); // Startup optional modules (eg. POSITION, LOG, ...) while(true) { + #if ACTIVATE_USB if(SDU1.config->usbp->state == USB_ACTIVE) { thread_t *shelltp = chThdCreateFromHeap(NULL, THD_WORKING_AREA_SIZE(512), "shell", NORMALPRIO+1, shellThread, (void*)&shell_cfg); chThdWait(shelltp); } - chThdSleepMilliseconds(1000); + #endif + chThdSleepMilliseconds(10000); } } diff --git a/tracker/software/mcuconf.h b/tracker/software/mcuconf.h index 028604c..23f6d7e 100644 --- a/tracker/software/mcuconf.h +++ b/tracker/software/mcuconf.h @@ -39,21 +39,21 @@ * HAL driver system settings. */ #define STM32_NO_INIT FALSE -#define STM32_HSI_ENABLED FALSE +#define STM32_HSI_ENABLED TRUE #define STM32_LSI_ENABLED TRUE -#define STM32_HSE_ENABLED TRUE +#define STM32_HSE_ENABLED FALSE #define STM32_LSE_ENABLED FALSE #define STM32_CLOCK48_REQUIRED TRUE #define STM32_SW STM32_SW_PLL -#define STM32_PLLSRC STM32_PLLSRC_HSE -#define STM32_PLLM_VALUE 26 +#define STM32_PLLSRC STM32_PLLSRC_HSI +#define STM32_PLLM_VALUE 16 #define STM32_PLLN_VALUE 192 #define STM32_PLLP_VALUE 4 #define STM32_PLLQ_VALUE 4 #if ACTIVATE_USB /* Activate 48MHz when USB is activated, otherwise 6MHz */ #define STM32_HPRE STM32_HPRE_DIV1 #else -#define STM32_HPRE STM32_HPRE_DIV8 +#define STM32_HPRE STM32_HPRE_DIV16 #endif #define STM32_PPRE1 STM32_PPRE1_DIV1 #define STM32_PPRE2 STM32_PPRE2_DIV1 diff --git a/tracker/software/protocols/aprs/ax25.c b/tracker/software/protocols/aprs/ax25.c index 96347ff..a8d1c26 100644 --- a/tracker/software/protocols/aprs/ax25.c +++ b/tracker/software/protocols/aprs/ax25.c @@ -120,7 +120,7 @@ void ax25_init(ax25_t *packet) void ax25_send_header(ax25_t *packet, const char *callsign, uint8_t ssid, const char *path, uint16_t preamble) { - uint8_t i, j; + uint16_t i, j; uint8_t tmp[8]; packet->ones_in_a_row = 0; packet->crc = 0xffff; diff --git a/tracker/software/protocols/morse/morse.c b/tracker/software/protocols/morse/morse.c index 674b632..fb4889b 100644 --- a/tracker/software/protocols/morse/morse.c +++ b/tracker/software/protocols/morse/morse.c @@ -1,265 +1,259 @@ -#include "ch.h" -#include "hal.h" -#include "morse.h" -#include "debug.h" +#include +#include -static uint8_t *buffer; static uint32_t c; -#define ADDB(bit) { \ +#define ADDB(buffer, bit) { \ buffer[c/8] |= ((bit & 0x1) << (c % 8)); \ c++; \ } -void dah(void) +void dah(uint8_t *buffer) { - ADDB(1); - ADDB(1); - ADDB(1); - ADDB(0); + ADDB(buffer, 1); + ADDB(buffer, 1); + ADDB(buffer, 1); + ADDB(buffer, 0); } -void dit(void) +void dit(uint8_t *buffer) { - ADDB(1); - ADDB(0); + ADDB(buffer, 1); + ADDB(buffer, 0); } -void blank(uint32_t ticks) { +void blank(uint8_t *buffer, uint32_t ticks) { for(uint32_t i=0; i // APRS related -#define PLAYBACK_RATE ((STM32_PCLK1) / 500) /* Samples per second (48Mhz / 250 = 192kHz) */ +#define PLAYBACK_RATE 13200 #define BAUD_RATE 1200 /* APRS AFSK baudrate */ #define SAMPLES_PER_BAUD (PLAYBACK_RATE / BAUD_RATE) /* Samples per baud (192kHz / 1200baud = 160samp/baud) */ #define PHASE_DELTA_1200 (((2 * 1200) << 16) / PLAYBACK_RATE) /* Delta-phase per sample for 1200Hz tone */ @@ -49,32 +49,191 @@ static void initAFSK(void) { active_mod = MOD_AFSK; } -static void sendAFSK(void) { +uint8_t getAFSKbyte(void) +{ + if(packet_pos == radio_msg.bin_len) // Packet transmission finished + return false; + + uint8_t b = 0; + for(uint8_t i=0; i<8; i++) + { + if(current_sample_in_baud == 0) { + if((packet_pos & 7) == 0) { // Load up next byte + current_byte = radio_msg.buffer[packet_pos >> 3]; + } else { // Load up next bit + current_byte = current_byte / 2; + } + } + + // Toggle tone (1200 <> 2200) + phase_delta = (current_byte & 1) ? PHASE_DELTA_1200 : PHASE_DELTA_2200; + + phase += phase_delta; // Add delta-phase (delta-phase tone dependent) + b |= ((phase >> 16) & 1) << i; // Set modulation bit + + current_sample_in_baud++; + + if(current_sample_in_baud == SAMPLES_PER_BAUD) { // Old bit consumed, load next bit + current_sample_in_baud = 0; + packet_pos++; + } + } + + return b; +} + +uint8_t ba = HIGH; +uint8_t getFSKbyte(void) +{ + uint8_t b = 0; + for(uint8_t i=0; i<8; i++) + { + switch(txs) + { + case 6: // TX-delay + txj++; + if(txj > (uint32_t)(radio_msg.fsk_conf->predelay * radio_msg.fsk_conf->baud / 1000)) { + txj = 0; + txs = 7; + } + break; + + case 7: // Transmit a single char + if(txj < radio_msg.bin_len/8) { + txc = radio_msg.buffer[txj]; // Select char + txj++; + ba = LOW; // Start Bit (Synchronizing) + txi = 0; + txs = 8; + } else { // Finished to transmit string + ba = HIGH; + return b; + } + break; + + case 8: + if(txi < radio_msg.fsk_conf->bits) { + txi++; + ba = txc & 1; + txc = txc >> 1; + } else { + ba = HIGH; // Stop Bit + txi = 0; + txs = 9; + } + break; + + case 9: + if(radio_msg.fsk_conf->stopbits == 2) + ba = HIGH; // Stop Bit + txs = 7; + } + b |= ba << i; + } + + return b; +} + +static thread_t *feeder_thd = NULL; +static THD_WORKING_AREA(si_fifo_feeder_wa, 1024); +THD_FUNCTION(si_fifo_feeder_thd2, arg) +{ + (void)arg; + + chRegSetThreadName("radio_tx_feeder"); + // Initialize variables for timer phase_delta = PHASE_DELTA_1200; phase = 0; packet_pos = 0; current_sample_in_baud = 0; current_byte = 0; + uint8_t localBuffer[129]; + uint16_t c = 129; + uint16_t all = (radio_msg.bin_len*SAMPLES_PER_BAUD+7)/8; - // Tune - radioTune(radio_freq, 0, radio_msg.power, 0); + // Initial FIFO fill + for(uint16_t i=0; iAPB1ENR |= RCC_APB1ENR_TIM7EN; - nvicEnableVector(TIM7_IRQn, 1); - TIM7->ARR = 500; - TIM7->CR1 &= ~STM32_TIM_CR1_ARPE; - TIM7->DIER |= STM32_TIM_DIER_UIE; + // Start transmission + radioTune(radio_freq, 0, radio_msg.power, all); - // Start timer - TIM7->CR1 |= STM32_TIM_CR1_CEN; + while(c < all) { // Do while bytes not written into FIFO completely + // Determine free memory in Si4464-FIFO + uint8_t more = Si4464_freeFIFO(); + if(more > all-c) { + if((more = all-c) == 0) // Calculate remainder to send + break; // End if nothing left + } - // Block execution while timer is running - while(TIM7->CR1 & STM32_TIM_CR1_CEN) - chThdSleepMilliseconds(10); + for(uint16_t i=0; ipredelay * radio_msg.fsk_conf->baud / 1000) + radio_msg.bin_len + radio_msg.bin_len*(radio_msg.fsk_conf->stopbits+1)/8 + 7) / 8; // FIXME: I transmit more bytes than neccessary + + // Initial FIFO fill + for(uint16_t i=0; ishift, radio_msg.power, all); + + while(c < all) { // Do while bytes not written into FIFO completely + // Determine free memory in Si4464-FIFO + uint8_t more = Si4464_freeFIFO(); + if(more > all-c) { + if((more = all-c) == 0) // Calculate remainder to send + break; // End if nothing left + } + + for(uint16_t i=0; iCR1 &= ~STM32_TIM_CR1_CEN; // Disable timer - TIM7->SR &= ~STM32_TIM_SR_UIF; // Reset interrupt flag - return; - } - - if(current_sample_in_baud == 0) { - if((packet_pos & 7) == 0) { // Load up next byte - current_byte = radio_msg.buffer[packet_pos >> 3]; - } else { // Load up next bit - current_byte = current_byte / 2; - } - } - - // Toggle tone (1200 <> 2200) - phase_delta = (current_byte & 1) ? PHASE_DELTA_1200 : PHASE_DELTA_2200; - - phase += phase_delta; // Add delta-phase (delta-phase tone dependent) - RADIO_WRITE_GPIO((phase >> 16) & 1); // Set modulaton pin (connected to Si4464) - - current_sample_in_baud++; - - if(current_sample_in_baud == SAMPLES_PER_BAUD) { // Old bit consumed, load next bit - current_sample_in_baud = 0; - packet_pos++; - } - - } else { // 2FSK - - switch(txs) - { - case 6: // TX-delay - txj++; - if(txj > (uint32_t)(radio_msg.fsk_conf->predelay * radio_msg.fsk_conf->baud / 1000)) { - txj = 0; - txs = 7; - } - break; - - case 7: // Transmit a single char - if(txj < radio_msg.bin_len/8) { - txc = radio_msg.buffer[txj]; // Select char - txj++; - RADIO_WRITE_GPIO(LOW); // Start Bit (Synchronizing) - txi = 0; - txs = 8; - } else { // Finished to transmit string - RADIO_WRITE_GPIO(HIGH); - TIM7->CR1 &= ~STM32_TIM_CR1_CEN; // Disable timer - TIM7->SR &= ~STM32_TIM_SR_UIF; // Reset interrupt flag - return; - } - break; - - case 8: - if(txi < radio_msg.fsk_conf->bits) { - txi++; - RADIO_WRITE_GPIO(txc & 1); - txc = txc >> 1; - } else { - RADIO_WRITE_GPIO(HIGH); // Stop Bit - txi = 0; - txs = 9; - } - break; - - case 9: - if(radio_msg.fsk_conf->stopbits == 2) - RADIO_WRITE_GPIO(HIGH); // Stop Bit - txs = 7; - } - - } - - palToggleLine(LINE_IO_LED1); - - TIM7->SR &= ~STM32_TIM_SR_UIF; // Reset interrupt flag -} - static void initOOK(void) { // Initialize radio Si4464_Init(); - setModemOOK(); + setModemOOK(radio_msg.ook_conf); active_mod = MOD_OOK; } @@ -226,58 +295,34 @@ static void initOOK(void) { * Transmits binary OOK message. One bit = 20ms (1: TONE, 0: NO TONE) */ static void sendOOK(void) { - // Tune - radioTune(radio_freq, 0, radio_msg.power, 0); + // Start/re-start FIFO feeder + feeder_thd = chThdCreateStatic(si_fifo_feeder_wa, sizeof(si_fifo_feeder_wa), HIGHPRIO+1, si_fifo_feeder_thd, NULL); - // Transmit data - uint32_t bit = 0; - systime_t time = chVTGetSystemTimeX(); - while(bit < radio_msg.bin_len) { - RADIO_WRITE_GPIO((radio_msg.buffer[bit/8] >> (bit%8)) & 0x1); - bit++; - - time = chThdSleepUntilWindowed(time, time + MS2ST(1200 / radio_msg.ook_conf->speed)); - } - shutdownRadio(); + // Wait for the transmitter to start (because it is used as mutex) + while(Si4464_getState() != SI4464_STATE_TX) + chThdSleepMilliseconds(1); } static void init2FSK(void) { // Initialize radio and tune Si4464_Init(); - setModem2FSK(); + setModem2FSK(radio_msg.fsk_conf); + active_mod = MOD_2FSK; } static void send2FSK(void) { - txs = 6; - txc = 0; - txi = 0; - txj = 0; + // Start/re-start FIFO feeder + feeder_thd = chThdCreateStatic(si_fifo_feeder_wa, sizeof(si_fifo_feeder_wa), HIGHPRIO+1, si_fifo_feeder_thd3, NULL); - // Tune - radioTune(radio_freq, radio_msg.fsk_conf->shift, radio_msg.power, 0); - - // Initialize timer - RCC->APB1ENR |= RCC_APB1ENR_TIM7EN; - nvicEnableVector(TIM7_IRQn, 1); - TIM7->ARR = STM32_PCLK1 / 16 / radio_msg.fsk_conf->baud; - TIM7->PSC = 15; - TIM7->CR1 &= ~STM32_TIM_CR1_ARPE; - TIM7->DIER |= STM32_TIM_DIER_UIE; - - // Start timer - TIM7->CR1 |= STM32_TIM_CR1_CEN; - - // Block execution while timer is running - while(TIM7->CR1 & STM32_TIM_CR1_CEN) - chThdSleepMilliseconds(10); - - shutdownRadio(); + // Wait for the transmitter to start (because it is used as mutex) + while(Si4464_getState() != SI4464_STATE_TX) + chThdSleepMilliseconds(1); } void shutdownRadio(void) { - // Wait for PH to finish transmission for 2GFSK - while(active_mod == MOD_2GFSK && Si4464_getState() == SI4464_STATE_TX) + // Wait for PH to finish transmission + while(Si4464_getState() == SI4464_STATE_TX) chThdSleepMilliseconds(10); Si4464_shutdown(); diff --git a/tracker/software/threads/image.c b/tracker/software/threads/image.c index 0685538..f114f0d 100644 --- a/tracker/software/threads/image.c +++ b/tracker/software/threads/image.c @@ -279,12 +279,36 @@ uint8_t gimage_id; // Global image ID (for all image threads) mutex_t camera_mtx; bool camera_mtx_init = false; +/** + * At EOI or if picture is cut prematurely, when buffer has to be flushed + * so all packets are transmitted. + */ +static void flush_ssdv_buffer(prot_t protocol, ax25_t *ax25_handle, radioMSG_t *msg) +{ + switch(protocol) { + case PROT_APRS_2GFSK: + case PROT_APRS_AFSK: + if(protocol == PROT_APRS_2GFSK || protocol == PROT_APRS_AFSK) + msg->bin_len = aprs_encode_finalize(ax25_handle); + + transmitOnRadio(msg, false); + break; + + case PROT_SSDV_2FSK: + transmitOnRadio(msg, false); + msg->bin_len = 0; + break; + + default: break; + } +} + void encode_ssdv(const uint8_t *image, uint32_t image_len, module_conf_t* conf, uint8_t image_id, trackPoint_t* captureLocation, bool redudantTx) { ssdv_t ssdv; uint8_t pkt[SSDV_PKT_SIZE]; - uint8_t pkt_base91i[150]; - uint8_t pkt_base91j[150]; + uint8_t pkt_base91i[160]; + uint8_t pkt_base91j[160]; const uint8_t *b; uint32_t bi = 0; uint8_t c = SSDV_OK; @@ -292,12 +316,12 @@ void encode_ssdv(const uint8_t *image, uint32_t image_len, module_conf_t* conf, // Init SSDV (FEC at 2FSK, non FEC at APRS) bi = 0; - ssdv_enc_init(&ssdv, SSDV_TYPE_NORMAL, conf->ssdv_conf.callsign, image_id, conf->ssdv_conf.quality); + ssdv_enc_init(&ssdv, conf->protocol == PROT_SSDV_2FSK ? SSDV_TYPE_NORMAL : SSDV_TYPE_NOFEC, conf->ssdv_conf.callsign, image_id, conf->ssdv_conf.quality); ssdv_enc_set_buffer(&ssdv, pkt); // Init transmission packet radioMSG_t msg; - uint8_t buffer[conf->packet_spacing ? 8192 : 512]; + uint8_t buffer[conf->packet_spacing ? 2048 : 8192]; msg.buffer = buffer; msg.bin_len = 0; msg.freq = &conf->frequency; @@ -325,12 +349,7 @@ void encode_ssdv(const uint8_t *image, uint32_t image_len, module_conf_t* conf, if(r <= 0) { TRACE_ERROR("SSDV > Premature end of file"); - if(conf->protocol == PROT_APRS_2GFSK || conf->protocol == PROT_APRS_AFSK) msg.bin_len = aprs_encode_finalize(&ax25_handle); - if(ax25_handle.size > 0) transmitOnRadio(&msg, false); // Empty buffer - if(conf->protocol == PROT_APRS_2GFSK || conf->protocol == PROT_APRS_AFSK) - { - aprs_encode_init(&ax25_handle, buffer, sizeof(buffer), msg.mod); - } + flush_ssdv_buffer(conf->protocol, &ax25_handle, &msg); break; } ssdv_enc_feed(&ssdv, b, r); @@ -339,21 +358,11 @@ void encode_ssdv(const uint8_t *image, uint32_t image_len, module_conf_t* conf, if(c == SSDV_EOI) { TRACE_INFO("SSDV > ssdv_enc_get_packet said EOI"); - if(conf->protocol == PROT_APRS_2GFSK || conf->protocol == PROT_APRS_AFSK) msg.bin_len = aprs_encode_finalize(&ax25_handle); - if(ax25_handle.size > 0) transmitOnRadio(&msg, false); // Empty buffer - if(conf->protocol == PROT_APRS_2GFSK || conf->protocol == PROT_APRS_AFSK) - { - aprs_encode_init(&ax25_handle, buffer, sizeof(buffer), msg.mod); - } + flush_ssdv_buffer(conf->protocol, &ax25_handle, &msg); break; } else if(c != SSDV_OK) { TRACE_ERROR("SSDV > ssdv_enc_get_packet failed: %i", c); - if(conf->protocol == PROT_APRS_2GFSK || conf->protocol == PROT_APRS_AFSK) msg.bin_len = aprs_encode_finalize(&ax25_handle); - if(ax25_handle.size > 0) transmitOnRadio(&msg, false); // Empty buffer - if(conf->protocol == PROT_APRS_2GFSK || conf->protocol == PROT_APRS_AFSK) - { - aprs_encode_init(&ax25_handle, buffer, sizeof(buffer), msg.mod); - } + flush_ssdv_buffer(conf->protocol, &ax25_handle, &msg); return; } @@ -364,29 +373,34 @@ void encode_ssdv(const uint8_t *image, uint32_t image_len, module_conf_t* conf, TRACE_INFO("IMG > Encode APRS/SSDV packet"); // Sync byte, CRC and FEC of SSDV not transmitted (because its not neccessary inside an APRS packet) - pkt[3] = pkt[6]; - pkt[4] = pkt[7]; - pkt[5] = pkt[8]; - base91_encode(&pkt[3 ], pkt_base91i, 110); - pkt[110] = pkt[6]; - pkt[111] = pkt[7]; - pkt[112] = pkt[8]; - base91_encode(&pkt[3+107], pkt_base91j, 110); + base91_encode(&pkt[6 ], pkt_base91i, 109+16); + pkt[112+16] = pkt[6]; + pkt[113+16] = pkt[7]; + pkt[114+16] = pkt[8]; + base91_encode(&pkt[112+16], pkt_base91j, 108+16); aprs_encode_data_packet(&ax25_handle, 'I', &conf->aprs_conf, pkt_base91i, strlen((char*)pkt_base91i), captureLocation); aprs_encode_data_packet(&ax25_handle, 'J', &conf->aprs_conf, pkt_base91j, strlen((char*)pkt_base91j), captureLocation); if(redudantTx) { + if(conf->protocol == PROT_APRS_AFSK) // AFSK can handle max. 2 packets in the buffer + { + // Transmit packets + flush_ssdv_buffer(conf->protocol, &ax25_handle, &msg); + + // Initialize new packet buffer + aprs_encode_init(&ax25_handle, buffer, sizeof(buffer), msg.mod); + } aprs_encode_data_packet(&ax25_handle, 'I', &conf->aprs_conf, pkt_base91i, strlen((char*)pkt_base91i), captureLocation); aprs_encode_data_packet(&ax25_handle, 'J', &conf->aprs_conf, pkt_base91j, strlen((char*)pkt_base91j), captureLocation); } - // Transmit - if(ax25_handle.size >= 58000 || conf->packet_spacing) // Transmit if buffer is almost full or if single packet transmission is activated (packet_spacing != 0) + // Transmit if buffer is almost full or if single packet transmission is activated (packet_spacing != 0) + // or if AFSK is selected (because the encoding takes a lot of buffer) + if(ax25_handle.size >= 58000 || conf->packet_spacing || conf->protocol == PROT_APRS_AFSK) { // Transmit packets - msg.bin_len = aprs_encode_finalize(&ax25_handle); - transmitOnRadio(&msg, false); + flush_ssdv_buffer(conf->protocol, &ax25_handle, &msg); // Initialize new packet buffer aprs_encode_init(&ax25_handle, buffer, sizeof(buffer), msg.mod); @@ -408,13 +422,9 @@ void encode_ssdv(const uint8_t *image, uint32_t image_len, module_conf_t* conf, } // Transmit - if(msg.bin_len >= 61440 || conf->packet_spacing) { // Transmit if buffer is full or if single packet transmission activation (packet_spacing != 0) - // Transmit packets - transmitOnRadio(&msg, false); + if(msg.bin_len >= 32768 || conf->packet_spacing) // Transmit if buffer is full or if single packet transmission activation (packet_spacing != 0) + flush_ssdv_buffer(conf->protocol, NULL, &msg); - // Initialize new packet buffer - msg.bin_len = 0; - } break; default: @@ -450,6 +460,9 @@ bool takePicture(ssdv_conf_t *conf, bool enableJpegValidation) TRACE_INFO("IMG > OV5640 found"); camera_found = true; + // Lock Radio (The radio uses the same DMA for SPI as the camera) + lockRadio(); // Lock radio + // Init camera if(!camInitialized) { OV5640_init(); @@ -457,9 +470,10 @@ bool takePicture(ssdv_conf_t *conf, bool enableJpegValidation) } // Sample data from pseudo DCMI through DMA into RAM - lockRadio(); // Lock radio conf->size_sampled = OV5640_Snapshot2RAM(conf->ram_buffer, conf->ram_size, conf->res, enableJpegValidation); - unlockRadio(); // Unlock radio + + // Unlock radio + unlockRadio(); // Switch off camera if(!keep_cam_switched_on) { @@ -481,9 +495,13 @@ bool takePicture(ssdv_conf_t *conf, bool enableJpegValidation) return camera_found; } -THD_FUNCTION(imgThread, arg) { +THD_FUNCTION(imgThread, arg) +{ module_conf_t* conf = (module_conf_t*)arg; + if(conf->init_delay) chThdSleepMilliseconds(conf->init_delay); + TRACE_INFO("IMG > Startup image thread"); + systime_t time = chVTGetSystemTimeX(); while(true) { @@ -516,10 +534,8 @@ THD_FUNCTION(imgThread, arg) { void start_image_thread(module_conf_t *conf) { - if(conf->init_delay) chThdSleepMilliseconds(conf->init_delay); - TRACE_INFO("IMG > Startup image thread"); chsnprintf(conf->name, sizeof(conf->name), "IMG"); - thread_t *th = chThdCreateFromHeap(NULL, THD_WORKING_AREA_SIZE(conf->packet_spacing ? 20*1024 : 5*1024), "IMG", NORMALPRIO, imgThread, conf); + thread_t *th = chThdCreateFromHeap(NULL, THD_WORKING_AREA_SIZE(conf->packet_spacing ? 6*1024 : 12*1024), "IMG", NORMALPRIO, imgThread, conf); if(!th) { // Print startup error, do not start watchdog for this thread TRACE_ERROR("IMG > Could not startup thread (not enough memory available)"); diff --git a/tracker/software/threads/log.c b/tracker/software/threads/log.c index 3a48f14..0b2c81f 100644 --- a/tracker/software/threads/log.c +++ b/tracker/software/threads/log.c @@ -135,6 +135,9 @@ THD_FUNCTION(logThread, arg) { module_conf_t* conf = (module_conf_t*)arg; + if(conf->init_delay) chThdSleepMilliseconds(conf->init_delay); + TRACE_INFO("LOG > Startup logging thread"); + systime_t time = chVTGetSystemTimeX(); while(true) { @@ -211,8 +214,6 @@ THD_FUNCTION(logThread, arg) void start_logging_thread(module_conf_t *conf) { - if(conf->init_delay) chThdSleepMilliseconds(conf->init_delay); - TRACE_INFO("LOG > Startup logging thread"); chsnprintf(conf->name, sizeof(conf->name), "LOG"); thread_t *th = chThdCreateFromHeap(NULL, THD_WORKING_AREA_SIZE(2*1024), "LOG", NORMALPRIO, logThread, conf); if(!th) { diff --git a/tracker/software/threads/position.c b/tracker/software/threads/position.c index 6b24888..8c90638 100644 --- a/tracker/software/threads/position.c +++ b/tracker/software/threads/position.c @@ -105,15 +105,25 @@ void replace_placeholders(char* fskmsg, uint16_t size, trackPoint_t *tp) { str_replace(fskmsg, size, "", buf); } -THD_FUNCTION(posThread, arg) { +THD_FUNCTION(posThread, arg) +{ module_conf_t* conf = (module_conf_t*)arg; - trackPoint_t *trackPoint = getLastTrackPoint(); - systime_t time = chVTGetSystemTimeX(); + // Wait + if(conf->init_delay) chThdSleepMilliseconds(conf->init_delay); + // Start tracking manager (if not running yet) + init_tracking_manager(true); + + // Start position thread + TRACE_INFO("POS > Startup position thread"); + + // Set telemetry configuration transmission variables systime_t last_conf_transmission = chVTGetSystemTimeX(); uint32_t current_conf_count = 0; + trackPoint_t *trackPoint; + systime_t time = chVTGetSystemTimeX(); while(true) { TRACE_INFO("POS > Do module POSITION cycle"); @@ -128,7 +138,7 @@ THD_FUNCTION(posThread, arg) { TRACE_INFO("POS > Transmit position"); radioMSG_t msg; - uint8_t buffer[256]; + uint8_t buffer[512]; msg.buffer = buffer; msg.freq = &conf->frequency; msg.power = conf->power; @@ -188,7 +198,7 @@ THD_FUNCTION(posThread, arg) { memcpy(fskmsg, conf->ukhas_conf.format, sizeof(conf->ukhas_conf.format)); replace_placeholders(fskmsg, sizeof(fskmsg), trackPoint); str_replace(fskmsg, sizeof(fskmsg), "", conf->ukhas_conf.callsign); - msg.bin_len = 8*chsnprintf((char*)msg.buffer, sizeof(fskmsg), "$$$$$%s*%04X\n", fskmsg, crc16(fskmsg)); + msg.bin_len = 8*chsnprintf((char*)buffer, sizeof(buffer), "$$$$$%s*%04X\n", fskmsg, crc16(fskmsg)); // Transmit message transmitOnRadio(&msg, true); @@ -205,7 +215,7 @@ THD_FUNCTION(posThread, arg) { str_replace(morse, sizeof(morse), "", conf->morse_conf.callsign); // Transmit message - msg.bin_len = morse_encode(msg.buffer, morse); // Convert message to binary stream + msg.bin_len = morse_encode(buffer, sizeof(buffer), morse); // Convert message to binary stream transmitOnRadio(&msg, true); break; @@ -220,16 +230,8 @@ THD_FUNCTION(posThread, arg) { void start_position_thread(module_conf_t *conf) { - // Wait - if(conf->init_delay) chThdSleepMilliseconds(conf->init_delay); - - // Start tracking manager (if not running yet) - init_tracking_manager(true); - - // Start position thread - TRACE_INFO("POS > Startup position thread"); chsnprintf(conf->name, sizeof(conf->name), "POS"); - thread_t *th = chThdCreateFromHeap(NULL, THD_WORKING_AREA_SIZE(20*1024), "POS", NORMALPRIO, posThread, conf); + thread_t *th = chThdCreateFromHeap(NULL, THD_WORKING_AREA_SIZE(5*1024), "POS", NORMALPRIO, posThread, conf); if(!th) { // Print startup error, do not start watchdog for this thread TRACE_ERROR("POS > Could not startup thread (not enough memory available)"); @@ -238,3 +240,4 @@ void start_position_thread(module_conf_t *conf) conf->wdg_timeout = chVTGetSystemTimeX() + S2ST(1); } } + diff --git a/tracker/software/threads/watchdog.c b/tracker/software/threads/watchdog.c index 2b6fbe2..490110d 100644 --- a/tracker/software/threads/watchdog.c +++ b/tracker/software/threads/watchdog.c @@ -19,6 +19,7 @@ void register_thread_at_wdg(module_conf_t *thread_config) THD_FUNCTION(wdgThread, arg) { (void)arg; + uint8_t counter = 0; while(true) { bool healthy = true; @@ -34,8 +35,13 @@ THD_FUNCTION(wdgThread, arg) { wdgReset(&WDGD1); // Reset hardware watchdog at no error // Switch LEDs - palToggleLine(LINE_IO_LED2); // Show I'M ALIVE - chThdSleepMilliseconds(healthy ? 500 : 100); // Blink faster (less delay) in case of an error + if(counter++ % (4*healthy) == 0) + { + palClearLine(LINE_IO_LED2); + chThdSleepMilliseconds(50); + palSetLine(LINE_IO_LED2); + } + chThdSleepMilliseconds(1000); } }