Removed STM32 based modulation and moved task to PH of Si4464 (so stable HSE is not needed for STM32 anymore which was needed for radio modulation)

Fixed receiver value in decoder.py
Limited data display on decoder map to 14 days
Implemented additional exception handlers for bad internet connections
Modified SSDV/APRS protocol: removed redundant transmitted data
Modified SSDV/APRS protocol: Increased amount of data being sent in one packet
Adjusted clocks: (in order to save energy)
- Use HSI for STM32 only
- Use HSE for Si4464 only (HSE switched off, only switched on when Si4464 needs it)
- Reduced STM32 clock to 3MHz
Improved Morse implementation
Fixed thread (module) startup delay bug
Changed behavior of Watchdog LED: Flashing instead of blinking (in order to save energy)
Fixed preamble bug from AX25 implementation
master
Sven Steudte 2017-10-14 05:58:51 +02:00
rodzic af870d89e0
commit f6d69c9afe
18 zmienionych plików z 564 dodań i 549 usunięć

Wyświetl plik

@ -12,7 +12,7 @@ import position
# Parse arguments from terminal # Parse arguments from terminal
parser = argparse.ArgumentParser(description='APRS/SSDV decoder') 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('-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('-d', '--device', help='Serial device (\'-\' for stdin)', default='-')
parser.add_argument('-b', '--baudrate', help='Baudrate for serial device', default=9600, type=int) parser.add_argument('-b', '--baudrate', help='Baudrate for serial device', default=9600, type=int)
@ -30,7 +30,7 @@ sqlite.cursor().execute("""
lat FLOAT, lat FLOAT,
lon FLOAT, lon FLOAT,
alt INTEGER, alt INTEGER,
new INTEGER, isnew INTEGER,
comment TEXT, comment TEXT,
sequ INTEGER, sequ INTEGER,
tel1 INTEGER, tel1 INTEGER,
@ -61,11 +61,6 @@ sqlite.cursor().execute("""
""" Packet handler for received APRS packets""" """ Packet handler for received APRS packets"""
def received_data(data): def received_data(data):
# Debug
print('====================================================================================================')
print(data)
print('----------------------------------------------------------------------------------------------------')
# Parse line and detect data # Parse line and detect data
# Position (.*)\>APECAN(.*?):\/([0-9]{6}h)(.{13})(.*?)\|(.*)\| # Position (.*)\>APECAN(.*?):\/([0-9]{6}h)(.{13})(.*?)\|(.*)\|
# Image (.*)\>APECAN(.*?):\/([0-9]{6}h)(.{13})I(.*) # 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) dat = re.search("(.*)\>APECAN(.*?):\/([0-9]{6}h)(.{13})(I|J|L)(.*)", data)
if all: 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] rxer = all.group(2).split(',')[-1]
if not len(rxer): rxer = args.call
tim = all.group(3) tim = all.group(3)
posi = all.group(4) posi = all.group(4)

Wyświetl plik

@ -32,6 +32,8 @@ class MyDB extends SQLite3 {
WHERE position.call = :call WHERE position.call = :call
AND position.lat != 0 AND position.lat != 0
AND position.lon != 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 GROUP BY position.call,position.time
ORDER BY position.time ASC ORDER BY position.time ASC
"); ");
@ -45,4 +47,3 @@ class MyDB extends SQLite3 {
} }
} }
?> ?>

Wyświetl plik

@ -41,18 +41,17 @@ data - Binary data
def insert_image(sqlite, receiver, call, tim, posi, data, typ, server, grouping): def insert_image(sqlite, receiver, call, tim, posi, data, typ, server, grouping):
global jsons global jsons
if len(data) != 110: if not (typ is 'I' and len(data) == 125) and not (typ is 'J' and len(data) == 124):
return # APRS message sampled too short return # APRS message has invalid type or length (or both)
# Decode various meta data # Decode various meta data
timd,x,y,z,teld,new = decode_position(tim, posi, None) timd,x,y,z,teld,new = decode_position(tim, posi, None)
imageID = data[0] imageID = data[0]
packetID = (data[1] << 8) | data[2] packetID = (data[1] << 8) | data[2]
data = binascii.hexlify(data[3:]).decode("ascii") data = binascii.hexlify(data[3:]).decode("ascii")
print(len(data))
# Debug # 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 # Insert
sqlite.cursor().execute(""" sqlite.cursor().execute("""
@ -75,7 +74,7 @@ def insert_image(sqlite, receiver, call, tim, posi, data, typ, server, grouping)
else: else:
bcall = bcall[0][0:6] # Callsign has 6 chars, so take the call without SSID 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(""" sqlite.cursor().execute("""
UPDATE image UPDATE image
@ -101,7 +100,6 @@ def insert_image(sqlite, receiver, call, tim, posi, data, typ, server, grouping)
sqlite.commit() sqlite.commit()
# Get both data entries # Get both data entries
cur = sqlite.cursor() cur = sqlite.cursor()
cur.execute(""" cur.execute("""
@ -136,7 +134,7 @@ def insert_image(sqlite, receiver, call, tim, posi, data, typ, server, grouping)
# SSDV decode # SSDV decode
cur = sqlite.cursor() 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) name = 'html/images/%s-%d-%d.jpg' % (call.replace('-',''), int(timd.timestamp()), imageID)
f = open(name, 'wb') f = open(name, 'wb')
process = Popen(['./ssdv', '-d'], stdin=PIPE, stdout=f, stderr=PIPE) 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() f.close()
# Create message for SSDV server (and save to array) # Create message for SSDV server (and save to array)
ssdv = '55' + data + ('%08x' % crc) + (64*'0') ssdv = '55' + data + ('%08x' % crc)
jsons.append("""{ jsons.append("""{
\"type\": \"packet\", \"type\": \"packet\",
\"packet\": \"""" + ssdv + """\", \"packet\": \"""" + ssdv + """\",
@ -168,11 +166,13 @@ def insert_image(sqlite, receiver, call, tim, posi, data, typ, server, grouping)
print('Send to SSDV data server') print('Send to SSDV data server')
try: try:
result = urllib.request.urlopen(req, "".join(json.split(' ')).encode("ascii")) # Send packets to server 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 err = False
except urllib.error.URLError as error: except urllib.error.URLError as error:
if error.code == 400: if not hasattr(error, 'code'): # (Bug in urllib) most likely network not available
print('Response from Server: %s', error.read()) 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 err = False
else: else:
print('SSDV-Server connection error... try again') print('SSDV-Server connection error... try again')

Wyświetl plik

@ -18,7 +18,7 @@ def insert_log(sqlite, call, data):
tim_stringified = datetime.utcfromtimestamp(tim).strftime("%Y-%m-%d %H:%M:%S") tim_stringified = datetime.utcfromtimestamp(tim).strftime("%Y-%m-%d %H:%M:%S")
try: 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)) print("Decoded log from %s time %s => lat=%06.3f lon=%07.3f alt=%05d" % (call, tim_stringified, lat, lon, alt))
except sqlite3.IntegrityError: 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)) 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) timd -= timedelta(1)
# Decode GPS Fix Type # Decode GPS Fix Type
new = ((ord(posi[12])-33) >> 5) & 0x1 isnew = ((ord(posi[12])-33) >> 5) & 0x1
# Decode telemetry # Decode telemetry
teld = [0]*6 teld = [0]*6
@ -66,22 +66,22 @@ def decode_position(tim, posi, tel):
t0 = ord(tel[i*2+1]) - 33 t0 = ord(tel[i*2+1]) - 33
teld.append(t0 + t1*91) 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 def insert_position(sqlite, call, tim, posi, comm, tel): #sqlite, call, data
# Decode # Decode
timd,x,y,z,teld,new = decode_position(tim, posi, tel) timd,x,y,z,teld,isnew = decode_position(tim, posi, tel)
# Insert # Insert
sqlite.cursor().execute(""" 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',?,?,?,?,?,?,?,?,?,?,?)""", 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() sqlite.commit()
# Debug # Debug
tim_stringified = timd.strftime("%Y-%m-%d %H:%M:%S") 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]" 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]))

BIN
decoder/ssdv 100755

Plik binarny nie jest wyświetlany.

Wyświetl plik

@ -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 = TRUE; // Transmit Telemetry encoding information activated
config[0].aprs_conf.tel_enc_cycle = 3600; // Transmit Telemetry encoding information every 3600sec 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 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 // Module POSITION, UKHAS 2m 2FSK
config[1].power = 127; // Transmission Power 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].trigger.type = TRIG_CONTINUOUSLY; // Transmit continuously
config[1].fsk_conf.bits = 8; // 8 bit config[1].fsk_conf.bits = 8; // 8 bit
config[1].fsk_conf.stopbits = 2; // 2 stopbits 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.baud = 50; // Baudrate
config[1].fsk_conf.shift = 425; // Frequency shift in Hz config[1].fsk_conf.shift = 425; // Frequency shift in Hz
chsnprintf(config[1].ukhas_conf.callsign, 16, "DL7AD"); // UKHAS Callsign 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.res = RES_QVGA; // Resolution QVGA
config[3].ssdv_conf.redundantTx = true; // Redundant transmission (transmit packets twice) config[3].ssdv_conf.redundantTx = true; // Redundant transmission (transmit packets twice)
config[3].ssdv_conf.quality = 4; // Image quality config[3].ssdv_conf.quality = 4; // Image quality
start_image_thread(&config[3]); //start_image_thread(&config[3]);
// Module IMAGE, APRS 2m 2GFSK // Module IMAGE, APRS 2m 2GFSK
config[4].power = 127; // Transmission Power 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].trigger.type = TRIG_CONTINUOUSLY; // Transmit continuously
config[5].fsk_conf.bits = 8; // 8bit config[5].fsk_conf.bits = 8; // 8bit
config[5].fsk_conf.stopbits = 2; // 2 Stopbits config[5].fsk_conf.stopbits = 2; // 2 Stopbits
config[5].fsk_conf.predelay = 1000; // Preamble (1000ms) config[5].fsk_conf.predelay = 3000; // Preamble (1000ms)
config[5].fsk_conf.baud = 600; // Baudrate (600baud) config[5].fsk_conf.baud = 300; // Baudrate (600baud)
config[5].fsk_conf.shift = 1000; // Frequency shift (1000Hz) config[5].fsk_conf.shift = 425; // Frequency shift (1000Hz)
chsnprintf(config[5].ssdv_conf.callsign, 7, "DL7AD"); // SSDV Callsign 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_buffer = ssdv_buffer; // Camera buffer
config[5].ssdv_conf.ram_size = sizeof(ssdv_buffer); // Buffer size 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 config[6].aprs_conf.symbol = SYM_BALLOON; // APRS Symbol
chsnprintf(config[6].aprs_conf.path, 16, "WIDE1-1"); // APRS Path chsnprintf(config[6].aprs_conf.path, 16, "WIDE1-1"); // APRS Path
config[6].aprs_conf.preamble = 300; // APRS Preamble (300ms) config[6].aprs_conf.preamble = 300; // APRS Preamble (300ms)
start_logging_thread(&config[6]); //start_logging_thread(&config[6]);
} }

Wyświetl plik

@ -27,18 +27,20 @@ bool initialized = false;
* @param mv Oscillator voltage in mv * @param mv Oscillator voltage in mv
*/ */
void Si4464_Init(void) { void Si4464_Init(void) {
// Reset radio) // Configure Radio pins
Si4464_shutdown();
chThdSleepMilliseconds(10);
// Configure SPI pins
palSetLineMode(LINE_SPI_SCK, PAL_MODE_ALTERNATE(6) | PAL_STM32_OSPEED_HIGHEST); // SCK 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_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_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_CS, PAL_MODE_OUTPUT_PUSHPULL | PAL_STM32_OSPEED_HIGHEST); // RADIO CS
palSetLineMode(LINE_RADIO_SDN, PAL_MODE_OUTPUT_PUSHPULL); // RADIO SDN palSetLineMode(LINE_RADIO_SDN, PAL_MODE_OUTPUT_PUSHPULL); // RADIO SDN
palSetLineMode(LINE_OSC_EN, PAL_MODE_OUTPUT_PUSHPULL); // Oscillator
palSetLine(LINE_RADIO_CS); palSetLine(LINE_RADIO_CS);
// Reset radio
Si4464_shutdown();
palSetLine(LINE_OSC_EN); // Activate Oscillator
chThdSleepMilliseconds(10);
// Power up transmitter // Power up transmitter
palClearLine(LINE_RADIO_SDN); // Radio SDN low (power up transmitter) palClearLine(LINE_RADIO_SDN); // Radio SDN low (power up transmitter)
chThdSleepMilliseconds(10); // Wait for transmitter to power up chThdSleepMilliseconds(10); // Wait for transmitter to power up
@ -52,6 +54,55 @@ void Si4464_Init(void) {
Si4464_write(init_command, 7); Si4464_write(init_command, 7);
chThdSleepMilliseconds(25); 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 // Temperature readout
TRACE_INFO("SI > Transmitter temperature %d degC", Si4464_getTemperature()); TRACE_INFO("SI > Transmitter temperature %d degC", Si4464_getTemperature());
initialized = true; initialized = true;
@ -173,44 +224,12 @@ void setShift(uint16_t shift) {
} }
void setModemAFSK(void) { 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 // 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); Si4464_write(setup_data_rate, 7);
// Use 2GFSK from async GPIO1 // Use 2GFSK from FIFO (PH)
uint8_t use_2gfsk[] = {0x11, 0x20, 0x01, 0x00, 0x2B}; uint8_t use_2gfsk[] = {0x11, 0x20, 0x01, 0x00, 0x03};
Si4464_write(use_2gfsk, 5); Si4464_write(use_2gfsk, 5);
// Set AFSK filter // Set AFSK filter
@ -222,109 +241,35 @@ void setModemAFSK(void) {
} }
} }
void setModemOOK(void) { void setModemOOK(ook_conf_t* conf) {
// Set transmitter GPIOs // Setup the NCO data rate for 2FSK
palSetLineMode(LINE_RADIO_GPIO, PAL_MODE_OUTPUT_PUSHPULL); // GPIO1 uint16_t speed = conf->speed * 5 / 6;
uint8_t gpio_pin_cfg_command[] = { uint8_t setup_data_rate[] = {0x11, 0x20, 0x03, 0x03, 0x00, 0x00, (uint8_t)speed};
0x13, // Command type = GPIO settings Si4464_write(setup_data_rate, 7);
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);
// Use OOK from async GPIO1 // Use 2FSK from FIFO (PH)
uint8_t use_ook[] = {0x11, 0x20, 0x01, 0x00, 0xA9}; uint8_t use_ook[] = {0x11, 0x20, 0x01, 0x00, 0x01};
Si4464_write(use_ook, 5); Si4464_write(use_ook, 5);
} }
void setModem2FSK(void) { void setModem2FSK(fsk_conf_t* conf) {
// Set transmitter GPIOs // Setup the NCO data rate for 2FSK
palSetLineMode(LINE_RADIO_GPIO, PAL_MODE_OUTPUT_PUSHPULL); // GPIO1 uint8_t setup_data_rate[] = {0x11, 0x20, 0x03, 0x03, (uint8_t)(conf->baud >> 16), (uint8_t)(conf->baud >> 8), (uint8_t)conf->baud};
uint8_t gpio_pin_cfg_command[] = { Si4464_write(setup_data_rate, 7);
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);
// Initialize high tone // Use 2FSK from FIFO (PH)
RADIO_WRITE_GPIO(HIGH); uint8_t use_2fsk[] = {0x11, 0x20, 0x01, 0x00, 0x02};
// use 2FSK from async GPIO1
uint8_t use_2fsk[] = {0x11, 0x20, 0x01, 0x00, 0xAA};
Si4464_write(use_2fsk, 5); Si4464_write(use_2fsk, 5);
} }
void setModem2GFSK(gfsk_conf_t* conf) { 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 // 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}; 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); Si4464_write(setup_data_rate, 7);
// Use 2GFSK from FIFO (PH) // 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); 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) { void setPowerLevel(int8_t level) {
@ -350,7 +295,8 @@ void stopTx(void) {
void Si4464_shutdown(void) { void Si4464_shutdown(void) {
palSetLine(LINE_RADIO_SDN); // Power down chip palSetLine(LINE_RADIO_SDN); // Power down chip
palSetLine(LINE_IO_LED1); // Set indication LED 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; initialized = false;
} }
@ -416,3 +362,4 @@ int8_t Si4464_getTemperature(void) {
bool isRadioInitialized(void) { bool isRadioInitialized(void) {
return initialized; return initialized;
} }

Wyświetl plik

@ -27,8 +27,8 @@ void Si4464_write(uint8_t* txData, uint32_t len);
void setFrequency(uint32_t freq, uint16_t shift); void setFrequency(uint32_t freq, uint16_t shift);
void setShift(uint16_t shift); void setShift(uint16_t shift);
void setModemAFSK(void); void setModemAFSK(void);
void setModemOOK(void); void setModemOOK(ook_conf_t* conf);
void setModem2FSK(void); void setModem2FSK(fsk_conf_t* conf);
void setModem2GFSK(gfsk_conf_t* conf); void setModem2GFSK(gfsk_conf_t* conf);
void setDeviation(uint32_t deviation); void setDeviation(uint32_t deviation);
void setPowerLevel(int8_t level); void setPowerLevel(int8_t level);

Wyświetl plik

@ -55,11 +55,13 @@ int main(void) {
start_user_modules(); // Startup optional modules (eg. POSITION, LOG, ...) start_user_modules(); // Startup optional modules (eg. POSITION, LOG, ...)
while(true) { while(true) {
#if ACTIVATE_USB
if(SDU1.config->usbp->state == USB_ACTIVE) { if(SDU1.config->usbp->state == USB_ACTIVE) {
thread_t *shelltp = chThdCreateFromHeap(NULL, THD_WORKING_AREA_SIZE(512), "shell", NORMALPRIO+1, shellThread, (void*)&shell_cfg); thread_t *shelltp = chThdCreateFromHeap(NULL, THD_WORKING_AREA_SIZE(512), "shell", NORMALPRIO+1, shellThread, (void*)&shell_cfg);
chThdWait(shelltp); chThdWait(shelltp);
} }
chThdSleepMilliseconds(1000); #endif
chThdSleepMilliseconds(10000);
} }
} }

Wyświetl plik

@ -39,21 +39,21 @@
* HAL driver system settings. * HAL driver system settings.
*/ */
#define STM32_NO_INIT FALSE #define STM32_NO_INIT FALSE
#define STM32_HSI_ENABLED FALSE #define STM32_HSI_ENABLED TRUE
#define STM32_LSI_ENABLED TRUE #define STM32_LSI_ENABLED TRUE
#define STM32_HSE_ENABLED TRUE #define STM32_HSE_ENABLED FALSE
#define STM32_LSE_ENABLED FALSE #define STM32_LSE_ENABLED FALSE
#define STM32_CLOCK48_REQUIRED TRUE #define STM32_CLOCK48_REQUIRED TRUE
#define STM32_SW STM32_SW_PLL #define STM32_SW STM32_SW_PLL
#define STM32_PLLSRC STM32_PLLSRC_HSE #define STM32_PLLSRC STM32_PLLSRC_HSI
#define STM32_PLLM_VALUE 26 #define STM32_PLLM_VALUE 16
#define STM32_PLLN_VALUE 192 #define STM32_PLLN_VALUE 192
#define STM32_PLLP_VALUE 4 #define STM32_PLLP_VALUE 4
#define STM32_PLLQ_VALUE 4 #define STM32_PLLQ_VALUE 4
#if ACTIVATE_USB /* Activate 48MHz when USB is activated, otherwise 6MHz */ #if ACTIVATE_USB /* Activate 48MHz when USB is activated, otherwise 6MHz */
#define STM32_HPRE STM32_HPRE_DIV1 #define STM32_HPRE STM32_HPRE_DIV1
#else #else
#define STM32_HPRE STM32_HPRE_DIV8 #define STM32_HPRE STM32_HPRE_DIV16
#endif #endif
#define STM32_PPRE1 STM32_PPRE1_DIV1 #define STM32_PPRE1 STM32_PPRE1_DIV1
#define STM32_PPRE2 STM32_PPRE2_DIV1 #define STM32_PPRE2 STM32_PPRE2_DIV1

Wyświetl plik

@ -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) 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]; uint8_t tmp[8];
packet->ones_in_a_row = 0; packet->ones_in_a_row = 0;
packet->crc = 0xffff; packet->crc = 0xffff;

Wyświetl plik

@ -1,265 +1,259 @@
#include "ch.h" #include <stdint.h>
#include "hal.h" #include <string.h>
#include "morse.h"
#include "debug.h"
static uint8_t *buffer;
static uint32_t c; static uint32_t c;
#define ADDB(bit) { \ #define ADDB(buffer, bit) { \
buffer[c/8] |= ((bit & 0x1) << (c % 8)); \ buffer[c/8] |= ((bit & 0x1) << (c % 8)); \
c++; \ c++; \
} }
void dah(void) void dah(uint8_t *buffer)
{ {
ADDB(1); ADDB(buffer, 1);
ADDB(1); ADDB(buffer, 1);
ADDB(1); ADDB(buffer, 1);
ADDB(0); ADDB(buffer, 0);
} }
void dit(void) void dit(uint8_t *buffer)
{ {
ADDB(1); ADDB(buffer, 1);
ADDB(0); ADDB(buffer, 0);
} }
void blank(uint32_t ticks) { void blank(uint8_t *buffer, uint32_t ticks) {
for(uint32_t i=0; i<ticks; i++) for(uint32_t i=0; i<ticks; i++)
ADDB(0); ADDB(buffer, 0);
} }
void morse_encode_char(char letter) void morse_encode_char(uint8_t *buffer, char letter)
{ {
switch(letter) { switch(letter) {
case 'A': case 'A':
dit(); dit(buffer);
dah(); dah(buffer);
break; break;
case 'B': case 'B':
dah(); dah(buffer);
dit(); dit(buffer);
dit(); dit(buffer);
dit(); dit(buffer);
break; break;
case 'C': case 'C':
dah(); dah(buffer);
dit(); dit(buffer);
dah(); dah(buffer);
dit(); dit(buffer);
break; break;
case 'D': case 'D':
dah(); dah(buffer);
dit(); dit(buffer);
dit(); dit(buffer);
break; break;
case 'E': case 'E':
dit(); dit(buffer);
break; break;
case 'F': case 'F':
dit(); dit(buffer);
dit(); dit(buffer);
dah(); dah(buffer);
dit(); dit(buffer);
break; break;
case 'G': case 'G':
dah(); dah(buffer);
dah(); dah(buffer);
dit(); dit(buffer);
break; break;
case 'H': case 'H':
dit(); dit(buffer);
dit(); dit(buffer);
dit(); dit(buffer);
dit(); dit(buffer);
break; break;
case 'I': case 'I':
dit(); dit(buffer);
dit(); dit(buffer);
break; break;
case 'J': case 'J':
dit(); dit(buffer);
dah(); dah(buffer);
dah(); dah(buffer);
dah(); dah(buffer);
break; break;
case 'K': case 'K':
dah(); dah(buffer);
dit(); dit(buffer);
dah(); dah(buffer);
break; break;
case 'L': case 'L':
dit(); dit(buffer);
dah(); dah(buffer);
dit(); dit(buffer);
dit(); dit(buffer);
break; break;
case 'M': case 'M':
dah(); dah(buffer);
dah(); dah(buffer);
break; break;
case 'N': case 'N':
dah(); dah(buffer);
dit(); dit(buffer);
break; break;
case 'O': case 'O':
dah(); dah(buffer);
dah(); dah(buffer);
dah(); dah(buffer);
break; break;
case 'P': case 'P':
dit(); dit(buffer);
dah(); dah(buffer);
dah(); dah(buffer);
dit(); dit(buffer);
break; break;
case 'Q': case 'Q':
dah(); dah(buffer);
dah(); dah(buffer);
dit(); dit(buffer);
dah(); dah(buffer);
break; break;
case 'R': case 'R':
dit(); dit(buffer);
dah(); dah(buffer);
dit(); dit(buffer);
break; break;
case 'S': case 'S':
dit(); dit(buffer);
dit(); dit(buffer);
dit(); dit(buffer);
break; break;
case 'T': case 'T':
dah(); dah(buffer);
break; break;
case 'U': case 'U':
dit(); dit(buffer);
dit(); dit(buffer);
dah(); dah(buffer);
break; break;
case 'V': case 'V':
dit(); dit(buffer);
dit(); dit(buffer);
dit(); dit(buffer);
dah(); dah(buffer);
break; break;
case 'W': case 'W':
dit(); dit(buffer);
dah(); dah(buffer);
dah(); dah(buffer);
break; break;
case 'X': case 'X':
dah(); dah(buffer);
dit(); dit(buffer);
dit(); dit(buffer);
dah(); dah(buffer);
break; break;
case 'Y': case 'Y':
dah(); dah(buffer);
dit(); dit(buffer);
dah(); dah(buffer);
dah(); dah(buffer);
break; break;
case 'Z': case 'Z':
dah(); dah(buffer);
dah(); dah(buffer);
dit(); dit(buffer);
dit(); dit(buffer);
break; break;
case '1': case '1':
dit(); dit(buffer);
dah(); dah(buffer);
dah(); dah(buffer);
dah(); dah(buffer);
dah(); dah(buffer);
break; break;
case '2': case '2':
dit(); dit(buffer);
dit(); dit(buffer);
dah(); dah(buffer);
dah(); dah(buffer);
dah(); dah(buffer);
break; break;
case '3': case '3':
dit(); dit(buffer);
dit(); dit(buffer);
dit(); dit(buffer);
dah(); dah(buffer);
dah(); dah(buffer);
break; break;
case '4': case '4':
dit(); dit(buffer);
dit(); dit(buffer);
dit(); dit(buffer);
dit(); dit(buffer);
dah(); dah(buffer);
break; break;
case '5': case '5':
dit(); dit(buffer);
dit(); dit(buffer);
dit(); dit(buffer);
dit(); dit(buffer);
dit(); dit(buffer);
break; break;
case '6': case '6':
dah(); dah(buffer);
dit(); dit(buffer);
dit(); dit(buffer);
dit(); dit(buffer);
dit(); dit(buffer);
break; break;
case '7': case '7':
dah(); dah(buffer);
dah(); dah(buffer);
dit(); dit(buffer);
dit(); dit(buffer);
dit(); dit(buffer);
break; break;
case '8': case '8':
dah(); dah(buffer);
dah(); dah(buffer);
dah(); dah(buffer);
dit(); dit(buffer);
dit(); dit(buffer);
break; break;
case '9': case '9':
dah(); dah(buffer);
dah(); dah(buffer);
dah(); dah(buffer);
dah(); dah(buffer);
dit(); dit(buffer);
break; break;
case '0': case '0':
dah(); dah(buffer);
dah(); dah(buffer);
dah(); dah(buffer);
dah(); dah(buffer);
dah(); dah(buffer);
break; break;
case ' ': case ' ':
blank(3); blank(buffer, 3);
break; break;
case '.': case '.':
dit(); dit(buffer);
dah(); dah(buffer);
dit(); dit(buffer);
dah(); dah(buffer);
dit(); dit(buffer);
dah(); dah(buffer);
break; break;
} }
blank(4); blank(buffer, 4);
} }
uint32_t morse_encode(uint8_t* data, const char* letter) uint32_t morse_encode(uint8_t* buffer, uint32_t length, const char* in)
{ {
// Blanking bits TODO: Replace this memset(buffer, 0, length); // Tidy up
for(uint32_t i=0; i<256; i++) c = 0; // Bitlength
data[i] = 0;
// Encode morse // Encode morse
buffer = data; // Buffer for(uint32_t i=0; in[i] != 0 && c < length*8-16; i++)
c = 0; // Bitlength morse_encode_char(buffer, in[i]);
for(uint32_t i=0; letter[i]!=0; i++)
morse_encode_char(letter[i]);
return c; return c;
} }

Wyświetl plik

@ -4,7 +4,7 @@
#include "ch.h" #include "ch.h"
#include "hal.h" #include "hal.h"
uint32_t morse_encode(uint8_t* data, const char* letter); uint32_t morse_encode(uint8_t* buffer, uint32_t length, const char* in);
#endif #endif

Wyświetl plik

@ -11,7 +11,7 @@
#include <string.h> #include <string.h>
// APRS related // 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 BAUD_RATE 1200 /* APRS AFSK baudrate */
#define SAMPLES_PER_BAUD (PLAYBACK_RATE / BAUD_RATE) /* Samples per baud (192kHz / 1200baud = 160samp/baud) */ #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 */ #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; 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 // Initialize variables for timer
phase_delta = PHASE_DELTA_1200; phase_delta = PHASE_DELTA_1200;
phase = 0; phase = 0;
packet_pos = 0; packet_pos = 0;
current_sample_in_baud = 0; current_sample_in_baud = 0;
current_byte = 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 // Initial FIFO fill
radioTune(radio_freq, 0, radio_msg.power, 0); for(uint16_t i=0; i<c; i++)
localBuffer[i] = getAFSKbyte();
Si4464_writeFIFO(localBuffer, c);
// Initialize timer // Start transmission
RCC->APB1ENR |= RCC_APB1ENR_TIM7EN; radioTune(radio_freq, 0, radio_msg.power, all);
nvicEnableVector(TIM7_IRQn, 1);
TIM7->ARR = 500;
TIM7->CR1 &= ~STM32_TIM_CR1_ARPE;
TIM7->DIER |= STM32_TIM_DIER_UIE;
// Start timer while(c < all) { // Do while bytes not written into FIFO completely
TIM7->CR1 |= STM32_TIM_CR1_CEN; // 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 for(uint16_t i=0; i<more; i++)
while(TIM7->CR1 & STM32_TIM_CR1_CEN) localBuffer[i] = getAFSKbyte();
chThdSleepMilliseconds(10);
Si4464_writeFIFO(localBuffer, more); // Write into FIFO
c += more;
chThdSleepMilliseconds(15);
}
// Shutdown radio (and wait for Si4464 to finish transmission)
shutdownRadio(); shutdownRadio();
chThdExit(MSG_OK);
}
THD_FUNCTION(si_fifo_feeder_thd3, arg)
{
(void)arg;
chRegSetThreadName("radio_tx_feeder");
// Initialize variables for timer
txs = 6;
txc = 0;
txi = 0;
txj = 0;
uint8_t localBuffer[129];
uint16_t c = 129;
uint16_t all = ((radio_msg.fsk_conf->predelay * 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; i<c; i++)
localBuffer[i] = getFSKbyte();
Si4464_writeFIFO(localBuffer, c);
// Start transmission
radioTune(radio_freq, radio_msg.fsk_conf->shift, 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; i<more; i++)
localBuffer[i] = getFSKbyte();
Si4464_writeFIFO(localBuffer, more); // Write into FIFO
c += more;
chThdSleepMilliseconds(500);
}
// Shutdown radio (and wait for Si4464 to finish transmission)
shutdownRadio();
chThdExit(MSG_OK);
}
static void sendAFSK(void) {
// Start/re-start FIFO feeder
feeder_thd = chThdCreateStatic(si_fifo_feeder_wa, sizeof(si_fifo_feeder_wa), HIGHPRIO+1, si_fifo_feeder_thd2, NULL);
// Wait for the transmitter to start (because it is used as mutex)
while(Si4464_getState() != SI4464_STATE_TX)
chThdSleepMilliseconds(1);
} }
static void init2GFSK(void) { static void init2GFSK(void) {
@ -84,13 +243,11 @@ static void init2GFSK(void) {
active_mod = MOD_2GFSK; active_mod = MOD_2GFSK;
} }
static thread_t *feeder_thd = NULL;
static THD_WORKING_AREA(si_fifo_feeder_wa, 1024);
THD_FUNCTION(si_fifo_feeder_thd, arg) THD_FUNCTION(si_fifo_feeder_thd, arg)
{ {
(void)arg; (void)arg;
uint16_t c = 64; uint16_t c = 129;
uint16_t all = (radio_msg.bin_len+7)/8; uint16_t all = (radio_msg.bin_len+7)/8;
chRegSetThreadName("radio_tx_feeder"); chRegSetThreadName("radio_tx_feeder");
@ -127,98 +284,10 @@ static void send2GFSK(void) {
chThdSleepMilliseconds(1); chThdSleepMilliseconds(1);
} }
/**
* Fast interrupt handler for AFSK modulation. It has has the highest priority
* in order to provide an accurate low jitter modulation.
*/
CH_FAST_IRQ_HANDLER(STM32_TIM7_HANDLER)
{
if(active_mod == MOD_AFSK) // AFSK
{
if(packet_pos == radio_msg.bin_len) { // Packet transmission finished
TIM7->CR1 &= ~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) { static void initOOK(void) {
// Initialize radio // Initialize radio
Si4464_Init(); Si4464_Init();
setModemOOK(); setModemOOK(radio_msg.ook_conf);
active_mod = MOD_OOK; active_mod = MOD_OOK;
} }
@ -226,58 +295,34 @@ static void initOOK(void) {
* Transmits binary OOK message. One bit = 20ms (1: TONE, 0: NO TONE) * Transmits binary OOK message. One bit = 20ms (1: TONE, 0: NO TONE)
*/ */
static void sendOOK(void) { static void sendOOK(void) {
// Tune // Start/re-start FIFO feeder
radioTune(radio_freq, 0, radio_msg.power, 0); feeder_thd = chThdCreateStatic(si_fifo_feeder_wa, sizeof(si_fifo_feeder_wa), HIGHPRIO+1, si_fifo_feeder_thd, NULL);
// Transmit data // Wait for the transmitter to start (because it is used as mutex)
uint32_t bit = 0; while(Si4464_getState() != SI4464_STATE_TX)
systime_t time = chVTGetSystemTimeX(); chThdSleepMilliseconds(1);
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();
} }
static void init2FSK(void) { static void init2FSK(void) {
// Initialize radio and tune // Initialize radio and tune
Si4464_Init(); Si4464_Init();
setModem2FSK(); setModem2FSK(radio_msg.fsk_conf);
active_mod = MOD_2FSK;
} }
static void send2FSK(void) { static void send2FSK(void) {
txs = 6; // Start/re-start FIFO feeder
txc = 0; feeder_thd = chThdCreateStatic(si_fifo_feeder_wa, sizeof(si_fifo_feeder_wa), HIGHPRIO+1, si_fifo_feeder_thd3, NULL);
txi = 0;
txj = 0;
// Tune // Wait for the transmitter to start (because it is used as mutex)
radioTune(radio_freq, radio_msg.fsk_conf->shift, radio_msg.power, 0); while(Si4464_getState() != SI4464_STATE_TX)
chThdSleepMilliseconds(1);
// 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();
} }
void shutdownRadio(void) void shutdownRadio(void)
{ {
// Wait for PH to finish transmission for 2GFSK // Wait for PH to finish transmission
while(active_mod == MOD_2GFSK && Si4464_getState() == SI4464_STATE_TX) while(Si4464_getState() == SI4464_STATE_TX)
chThdSleepMilliseconds(10); chThdSleepMilliseconds(10);
Si4464_shutdown(); Si4464_shutdown();

Wyświetl plik

@ -279,12 +279,36 @@ uint8_t gimage_id; // Global image ID (for all image threads)
mutex_t camera_mtx; mutex_t camera_mtx;
bool camera_mtx_init = false; 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) 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; ssdv_t ssdv;
uint8_t pkt[SSDV_PKT_SIZE]; uint8_t pkt[SSDV_PKT_SIZE];
uint8_t pkt_base91i[150]; uint8_t pkt_base91i[160];
uint8_t pkt_base91j[150]; uint8_t pkt_base91j[160];
const uint8_t *b; const uint8_t *b;
uint32_t bi = 0; uint32_t bi = 0;
uint8_t c = SSDV_OK; 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) // Init SSDV (FEC at 2FSK, non FEC at APRS)
bi = 0; 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); ssdv_enc_set_buffer(&ssdv, pkt);
// Init transmission packet // Init transmission packet
radioMSG_t msg; radioMSG_t msg;
uint8_t buffer[conf->packet_spacing ? 8192 : 512]; uint8_t buffer[conf->packet_spacing ? 2048 : 8192];
msg.buffer = buffer; msg.buffer = buffer;
msg.bin_len = 0; msg.bin_len = 0;
msg.freq = &conf->frequency; 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) if(r <= 0)
{ {
TRACE_ERROR("SSDV > Premature end of file"); 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); flush_ssdv_buffer(conf->protocol, &ax25_handle, &msg);
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);
}
break; break;
} }
ssdv_enc_feed(&ssdv, b, r); 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) if(c == SSDV_EOI)
{ {
TRACE_INFO("SSDV > ssdv_enc_get_packet said 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); flush_ssdv_buffer(conf->protocol, &ax25_handle, &msg);
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);
}
break; break;
} else if(c != SSDV_OK) { } else if(c != SSDV_OK) {
TRACE_ERROR("SSDV > ssdv_enc_get_packet failed: %i", c); 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); flush_ssdv_buffer(conf->protocol, &ax25_handle, &msg);
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);
}
return; 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"); TRACE_INFO("IMG > Encode APRS/SSDV packet");
// Sync byte, CRC and FEC of SSDV not transmitted (because its not neccessary inside an APRS packet) // Sync byte, CRC and FEC of SSDV not transmitted (because its not neccessary inside an APRS packet)
pkt[3] = pkt[6]; base91_encode(&pkt[6 ], pkt_base91i, 109+16);
pkt[4] = pkt[7]; pkt[112+16] = pkt[6];
pkt[5] = pkt[8]; pkt[113+16] = pkt[7];
base91_encode(&pkt[3 ], pkt_base91i, 110); pkt[114+16] = pkt[8];
pkt[110] = pkt[6]; base91_encode(&pkt[112+16], pkt_base91j, 108+16);
pkt[111] = pkt[7];
pkt[112] = pkt[8];
base91_encode(&pkt[3+107], pkt_base91j, 110);
aprs_encode_data_packet(&ax25_handle, 'I', &conf->aprs_conf, pkt_base91i, strlen((char*)pkt_base91i), captureLocation); 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); aprs_encode_data_packet(&ax25_handle, 'J', &conf->aprs_conf, pkt_base91j, strlen((char*)pkt_base91j), captureLocation);
if(redudantTx) 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, '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); aprs_encode_data_packet(&ax25_handle, 'J', &conf->aprs_conf, pkt_base91j, strlen((char*)pkt_base91j), captureLocation);
} }
// Transmit // Transmit if buffer is almost full or if single packet transmission is activated (packet_spacing != 0)
if(ax25_handle.size >= 58000 || conf->packet_spacing) // 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 // Transmit packets
msg.bin_len = aprs_encode_finalize(&ax25_handle); flush_ssdv_buffer(conf->protocol, &ax25_handle, &msg);
transmitOnRadio(&msg, false);
// Initialize new packet buffer // Initialize new packet buffer
aprs_encode_init(&ax25_handle, buffer, sizeof(buffer), msg.mod); 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 // Transmit
if(msg.bin_len >= 61440 || conf->packet_spacing) { // Transmit if buffer is full or if single packet transmission activation (packet_spacing != 0) if(msg.bin_len >= 32768 || conf->packet_spacing) // Transmit if buffer is full or if single packet transmission activation (packet_spacing != 0)
// Transmit packets flush_ssdv_buffer(conf->protocol, NULL, &msg);
transmitOnRadio(&msg, false);
// Initialize new packet buffer
msg.bin_len = 0;
}
break; break;
default: default:
@ -450,6 +460,9 @@ bool takePicture(ssdv_conf_t *conf, bool enableJpegValidation)
TRACE_INFO("IMG > OV5640 found"); TRACE_INFO("IMG > OV5640 found");
camera_found = true; camera_found = true;
// Lock Radio (The radio uses the same DMA for SPI as the camera)
lockRadio(); // Lock radio
// Init camera // Init camera
if(!camInitialized) { if(!camInitialized) {
OV5640_init(); OV5640_init();
@ -457,9 +470,10 @@ bool takePicture(ssdv_conf_t *conf, bool enableJpegValidation)
} }
// Sample data from pseudo DCMI through DMA into RAM // 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); conf->size_sampled = OV5640_Snapshot2RAM(conf->ram_buffer, conf->ram_size, conf->res, enableJpegValidation);
unlockRadio(); // Unlock radio
// Unlock radio
unlockRadio();
// Switch off camera // Switch off camera
if(!keep_cam_switched_on) { if(!keep_cam_switched_on) {
@ -481,9 +495,13 @@ bool takePicture(ssdv_conf_t *conf, bool enableJpegValidation)
return camera_found; return camera_found;
} }
THD_FUNCTION(imgThread, arg) { THD_FUNCTION(imgThread, arg)
{
module_conf_t* conf = (module_conf_t*)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(); systime_t time = chVTGetSystemTimeX();
while(true) while(true)
{ {
@ -516,10 +534,8 @@ THD_FUNCTION(imgThread, arg) {
void start_image_thread(module_conf_t *conf) 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"); 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) { if(!th) {
// Print startup error, do not start watchdog for this thread // Print startup error, do not start watchdog for this thread
TRACE_ERROR("IMG > Could not startup thread (not enough memory available)"); TRACE_ERROR("IMG > Could not startup thread (not enough memory available)");

Wyświetl plik

@ -135,6 +135,9 @@ THD_FUNCTION(logThread, arg)
{ {
module_conf_t* conf = (module_conf_t*)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(); systime_t time = chVTGetSystemTimeX();
while(true) while(true)
{ {
@ -211,8 +214,6 @@ THD_FUNCTION(logThread, arg)
void start_logging_thread(module_conf_t *conf) 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"); chsnprintf(conf->name, sizeof(conf->name), "LOG");
thread_t *th = chThdCreateFromHeap(NULL, THD_WORKING_AREA_SIZE(2*1024), "LOG", NORMALPRIO, logThread, conf); thread_t *th = chThdCreateFromHeap(NULL, THD_WORKING_AREA_SIZE(2*1024), "LOG", NORMALPRIO, logThread, conf);
if(!th) { if(!th) {

Wyświetl plik

@ -105,15 +105,25 @@ void replace_placeholders(char* fskmsg, uint16_t size, trackPoint_t *tp) {
str_replace(fskmsg, size, "<LOC>", buf); str_replace(fskmsg, size, "<LOC>", buf);
} }
THD_FUNCTION(posThread, arg) { THD_FUNCTION(posThread, arg)
{
module_conf_t* conf = (module_conf_t*)arg; module_conf_t* conf = (module_conf_t*)arg;
trackPoint_t *trackPoint = getLastTrackPoint(); // Wait
systime_t time = chVTGetSystemTimeX(); 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(); systime_t last_conf_transmission = chVTGetSystemTimeX();
uint32_t current_conf_count = 0; uint32_t current_conf_count = 0;
trackPoint_t *trackPoint;
systime_t time = chVTGetSystemTimeX();
while(true) while(true)
{ {
TRACE_INFO("POS > Do module POSITION cycle"); TRACE_INFO("POS > Do module POSITION cycle");
@ -128,7 +138,7 @@ THD_FUNCTION(posThread, arg) {
TRACE_INFO("POS > Transmit position"); TRACE_INFO("POS > Transmit position");
radioMSG_t msg; radioMSG_t msg;
uint8_t buffer[256]; uint8_t buffer[512];
msg.buffer = buffer; msg.buffer = buffer;
msg.freq = &conf->frequency; msg.freq = &conf->frequency;
msg.power = conf->power; msg.power = conf->power;
@ -188,7 +198,7 @@ THD_FUNCTION(posThread, arg) {
memcpy(fskmsg, conf->ukhas_conf.format, sizeof(conf->ukhas_conf.format)); memcpy(fskmsg, conf->ukhas_conf.format, sizeof(conf->ukhas_conf.format));
replace_placeholders(fskmsg, sizeof(fskmsg), trackPoint); replace_placeholders(fskmsg, sizeof(fskmsg), trackPoint);
str_replace(fskmsg, sizeof(fskmsg), "<CALL>", conf->ukhas_conf.callsign); str_replace(fskmsg, sizeof(fskmsg), "<CALL>", 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 // Transmit message
transmitOnRadio(&msg, true); transmitOnRadio(&msg, true);
@ -205,7 +215,7 @@ THD_FUNCTION(posThread, arg) {
str_replace(morse, sizeof(morse), "<CALL>", conf->morse_conf.callsign); str_replace(morse, sizeof(morse), "<CALL>", conf->morse_conf.callsign);
// Transmit message // 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); transmitOnRadio(&msg, true);
break; break;
@ -220,16 +230,8 @@ THD_FUNCTION(posThread, arg) {
void start_position_thread(module_conf_t *conf) 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"); 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) { if(!th) {
// Print startup error, do not start watchdog for this thread // Print startup error, do not start watchdog for this thread
TRACE_ERROR("POS > Could not startup thread (not enough memory available)"); 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); conf->wdg_timeout = chVTGetSystemTimeX() + S2ST(1);
} }
} }

Wyświetl plik

@ -19,6 +19,7 @@ void register_thread_at_wdg(module_conf_t *thread_config)
THD_FUNCTION(wdgThread, arg) { THD_FUNCTION(wdgThread, arg) {
(void)arg; (void)arg;
uint8_t counter = 0;
while(true) while(true)
{ {
bool healthy = true; bool healthy = true;
@ -34,8 +35,13 @@ THD_FUNCTION(wdgThread, arg) {
wdgReset(&WDGD1); // Reset hardware watchdog at no error wdgReset(&WDGD1); // Reset hardware watchdog at no error
// Switch LEDs // Switch LEDs
palToggleLine(LINE_IO_LED2); // Show I'M ALIVE if(counter++ % (4*healthy) == 0)
chThdSleepMilliseconds(healthy ? 500 : 100); // Blink faster (less delay) in case of an error {
palClearLine(LINE_IO_LED2);
chThdSleepMilliseconds(50);
palSetLine(LINE_IO_LED2);
}
chThdSleepMilliseconds(1000);
} }
} }