Skip to content

Commit

Permalink
Merge pull request #19 from TheCacophonyProject/add-long-rec
Browse files Browse the repository at this point in the history
add audio seed and 5 minute recording
  • Loading branch information
gferraro authored Nov 3, 2024
2 parents edf9428 + f589a01 commit 5d8883a
Show file tree
Hide file tree
Showing 6 changed files with 152 additions and 87 deletions.
51 changes: 37 additions & 14 deletions src/attiny_rtc_i2c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ pub mod tc2_agent_state {
pub const TAKE_AUDIO: u8 = 1 << 4;
pub const OFFLOAD: u8 = 1 << 5;
pub const THERMAL_MODE: u8 = 1 << 6;
pub const LONG_AUDIO_RECORDING: u8 = 1 << 7;
}

#[repr(u8)]
Expand Down Expand Up @@ -72,6 +73,16 @@ impl From<u8> for CameraState {
}
}

#[repr(u8)]
#[derive(Format)]

pub enum RecordingType {
TestRecording = 0,
LongRecording = 1,
ScheduledRecording = 2,
ThermalRequestedScheduledRecording = 3,
}

#[repr(u8)]
enum CameraConnectionState {
NoConnection = 0x00,
Expand Down Expand Up @@ -475,14 +486,28 @@ impl SharedI2C {
self.try_attiny_read_command(REG_TC2_AGENT_STATE, delay, None)
}

pub fn tc2_agent_requested_test_audio_rec(&mut self, delay: &mut Delay) -> Result<bool, Error> {
pub fn tc2_agent_requested_audio_recording(
&mut self,
delay: &mut Delay,
) -> Result<Option<RecordingType>, Error> {
match self.try_attiny_read_command(REG_TC2_AGENT_STATE, delay, None) {
Ok(state) => {
let rec_state: bool = (state & tc2_agent_state::READY
== state & tc2_agent_state::READY)
&& (state & tc2_agent_state::TEST_AUDIO_RECORDING
== tc2_agent_state::TEST_AUDIO_RECORDING);
Ok(rec_state)
let rec_state: bool =
state & tc2_agent_state::READY == state & tc2_agent_state::READY;
if rec_state {
if state & tc2_agent_state::TEST_AUDIO_RECORDING
== tc2_agent_state::TEST_AUDIO_RECORDING
{
return Ok(Some(RecordingType::TestRecording));
} else if state & tc2_agent_state::LONG_AUDIO_RECORDING
== tc2_agent_state::LONG_AUDIO_RECORDING
{
return Ok(Some(RecordingType::LongRecording));
} else if state & tc2_agent_state::TAKE_AUDIO == tc2_agent_state::TAKE_AUDIO {
return Ok(Some(RecordingType::ThermalRequestedScheduledRecording));
}
}
Ok(None)
}
Err(e) => Err(e),
}
Expand Down Expand Up @@ -514,11 +539,15 @@ impl SharedI2C {
&mut self,
delay: &mut Delay,
clear_flag: u8,
set_flag: u8,
set_flag: Option<u8>,
) -> Result<(), Error> {
match self.try_attiny_read_command(REG_TC2_AGENT_STATE, delay, None) {
Ok(state) => {
let val = (state & !clear_flag) | set_flag;
let mut val = state & !clear_flag;
if let Some(flag) = set_flag {
val = val | flag;
}

match self.try_attiny_write_command(REG_TC2_AGENT_STATE, val, delay) {
Ok(_) => Ok(()),
Err(x) => Err(x),
Expand All @@ -544,12 +573,6 @@ impl SharedI2C {
self.tc2_agent_write_flag(delay, tc2_agent_state::THERMAL_MODE, false)
}

pub fn tc2_agent_requested_audio_rec(&mut self, delay: &mut Delay) -> Result<bool, Error> {
match self.try_attiny_read_command(REG_TC2_AGENT_STATE, delay, None) {
Ok(state) => Ok((state & tc2_agent_state::TAKE_AUDIO) == tc2_agent_state::TAKE_AUDIO),
Err(e) => Err(e),
}
}
pub fn tc2_agent_take_audio_rec(&mut self, delay: &mut Delay) -> Result<(), Error> {
self.tc2_agent_write_flag(delay, tc2_agent_state::TAKE_AUDIO, true)
}
Expand Down
154 changes: 93 additions & 61 deletions src/core0_audio.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::attiny_rtc_i2c::{tc2_agent_state, I2CConfig, SharedI2C};
use crate::attiny_rtc_i2c::{tc2_agent_state, I2CConfig, RecordingType, SharedI2C};
use crate::bsp;
use crate::bsp::pac;
use crate::bsp::pac::Peripherals;
Expand Down Expand Up @@ -169,12 +169,36 @@ pub fn audio_task(
);
}

let mut take_test_rec = false;
if let Ok(test_rec) = shared_i2c.tc2_agent_requested_test_audio_rec(&mut delay) {
take_test_rec = test_rec;
}
let mut do_recording = alarm_triggered;
let mut duration = 60;
let mut recording_type = None;
let mut user_recording_requested = false;
let mut thermal_requested_audio = false;
if alarm_triggered {
recording_type = Some(RecordingType::ScheduledRecording);
} else {
if let Ok(audio_rec) = shared_i2c.tc2_agent_requested_audio_recording(&mut delay) {
recording_type = audio_rec;

if let Some(rec_type) = recording_type.as_mut() {
match rec_type {
RecordingType::LongRecording => {
duration = 60 * 5;
user_recording_requested = true;
}
RecordingType::TestRecording => {
duration = 10;
user_recording_requested = true;
}
RecordingType::ThermalRequestedScheduledRecording => {
duration = 60;
thermal_requested_audio = true;
}
_ => {}
}
}
}
}

let mut reschedule = false;
let mut alarm_date_time: Option<NaiveDateTime> = None;

Expand Down Expand Up @@ -204,9 +228,10 @@ pub fn audio_task(
);
}

if !take_test_rec {
if !user_recording_requested {
if device_config_was_updated {
let reboot;

if device_config.config().is_audio_device() && !thermal_requested_audio {
if let AudioMode::AudioOnly = device_config.config().audio_mode {
reboot = false;
Expand Down Expand Up @@ -349,21 +374,12 @@ pub fn audio_task(
}
}

if let Ok(take_rec) = shared_i2c.tc2_agent_requested_audio_rec(&mut delay) {
thermal_requested_audio = take_rec;
if thermal_requested_audio {
do_recording = true;
}
} else {
thermal_requested_audio = false;
}

info!(
"Alarm triggered {} scheduled {} thermal requested {}",
alarm_triggered, scheduled, thermal_requested_audio
alarm_triggered, scheduled, recording_type
);

if !do_recording && scheduled {
if recording_type.is_none() && scheduled {
// check we haven't missed the alarm somehow
if let Some(alarm) = alarm_date_time {
let synced = synced_date_time.get_adjusted_dt(timer);
Expand All @@ -385,12 +401,12 @@ pub fn audio_task(
),
&mut flash_storage,
);
do_recording = true;
recording_type = Some(RecordingType::ScheduledRecording);
}
}
}
}
if do_recording || take_test_rec {
if recording_type.is_some() {
watchdog.feed();
//should of already offloaded but extra safety check
if !flash_storage.is_too_full_for_audio() {
Expand All @@ -408,10 +424,7 @@ pub fn audio_task(
pio1,
sm1,
);
let mut duration = 60;
if !do_recording && take_test_rec {
duration = 10;
}

event_logger.log_event(
LoggerEvent::new(
LoggerEventKind::StartedAudioRecording,
Expand Down Expand Up @@ -454,48 +467,62 @@ pub fn audio_task(
),
&mut flash_storage,
);
if take_test_rec {
info!("taken test recoridng clearing status");
watchdog.feed();
let _ = shared_i2c.tc2_agent_clear_and_set_flag(
&mut delay,
tc2_agent_state::TEST_AUDIO_RECORDING,
tc2_agent_state::THERMAL_MODE,
);

let mut peripherals: Peripherals = unsafe { Peripherals::steal() };

offload_flash_storage_and_events(
&mut flash_storage,
&mut pi_spi,
&mut peripherals.RESETS,
&mut peripherals.DMA,
clock_freq,
&mut shared_i2c,
&mut delay,
timer,
&mut event_logger,
&synced_date_time,
Some(watchdog),
true,
);
match recording_type.as_mut().unwrap() {
RecordingType::LongRecording | RecordingType::TestRecording => {
info!("taken test recoridng clearing status");
watchdog.feed();
let _ = shared_i2c.tc2_agent_clear_and_set_flag(
&mut delay,
match recording_type.unwrap() {
RecordingType::LongRecording => {
tc2_agent_state::LONG_AUDIO_RECORDING
}
RecordingType::TestRecording => {
tc2_agent_state::TEST_AUDIO_RECORDING
}
_ => 0,
},
if device_config.config().audio_mode != AudioMode::AudioOnly {
Some(tc2_agent_state::THERMAL_MODE)
} else {
None
},
);

restart(watchdog);
} else {
shared_i2c.clear_alarm(&mut delay);
reschedule = true;
clear_audio_alarm(&mut flash_storage);
let mut peripherals: Peripherals = unsafe { Peripherals::steal() };

if thermal_requested_audio {
//if audio requested from thermal, the alarm will be re scheduled there
let _ = shared_i2c.tc2_agent_clear_and_set_flag(
offload_flash_storage_and_events(
&mut flash_storage,
&mut pi_spi,
&mut peripherals.RESETS,
&mut peripherals.DMA,
clock_freq,
&mut shared_i2c,
&mut delay,
tc2_agent_state::TAKE_AUDIO,
tc2_agent_state::THERMAL_MODE,
timer,
&mut event_logger,
&synced_date_time,
Some(watchdog),
true,
);
info!("Audio taken in thermal window clearing flag");

restart(watchdog);
}
_ => {
shared_i2c.clear_alarm(&mut delay);
reschedule = true;
clear_audio_alarm(&mut flash_storage);
if thermal_requested_audio {
//if audio requested from thermal, the alarm will be re scheduled there
let _ = shared_i2c.tc2_agent_clear_and_set_flag(
&mut delay,
tc2_agent_state::TAKE_AUDIO,
Some(tc2_agent_state::THERMAL_MODE),
);
info!("Audio taken in thermal window clearing flag");
restart(watchdog);
}
}
}
}
}
Expand Down Expand Up @@ -696,7 +723,12 @@ pub fn schedule_audio_rec(
error!("Failed to disable alarm");
return Err(());
}
let mut rng = RNG::<WyRand, u16>::new(synced_date_time.date_time_utc.timestamp() as u64);
let seed = if device_config.config().audio_seed == 0 {
synced_date_time.date_time_utc.timestamp() as u64
} else {
device_config.config().audio_seed as u64
};
let mut rng = RNG::<WyRand, u16>::new(seed);
let r = rng.generate();
let r_max: u16 = 65535u16;
let short_chance: u16 = r_max / 4;
Expand Down
18 changes: 9 additions & 9 deletions src/core1_task.rs
Original file line number Diff line number Diff line change
Expand Up @@ -410,17 +410,17 @@ pub fn core_1_task(
&mut flash_storage,
);
//changing from no audio to audio mode and then clicking test rec quickly
let test_rec = shared_i2c
.tc2_agent_requested_test_audio_rec(&mut delay)
.map_err(|e| error!("Error setting recording flag on attiny: {}", e));
if let Ok(test_rec) = test_rec {
if test_rec {
sio.fifo.write_blocking(Core1Task::RequestReset.into());
loop {
// Wait to be reset
nop();
match shared_i2c.tc2_agent_requested_audio_recording(&mut delay) {
Ok(test_rec) => {
if test_rec.is_some() {
sio.fifo.write_blocking(Core1Task::RequestReset.into());
loop {
// Wait to be reset
nop();
}
}
}
Err(e) => error!("Error getting tc2 agent state: {}", e),
}
}

Expand Down
4 changes: 4 additions & 0 deletions src/device_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ pub struct DeviceConfigInner {
pub is_continuous_recorder: bool,
pub use_low_power_mode: bool,
pub audio_mode: AudioMode,
pub audio_seed: u32,
}

impl DeviceConfigInner {
Expand Down Expand Up @@ -260,6 +261,7 @@ impl Default for DeviceConfig {
is_continuous_recorder: false,
use_low_power_mode: false,
audio_mode: AudioMode::Disabled,
audio_seed: 0,
},
motion_detection_mask: DetectionMask::new(None),
cursor_position: 0,
Expand Down Expand Up @@ -290,6 +292,7 @@ impl DeviceConfig {
let audio_mode = AudioMode::try_from(cursor.read_u8())
.ok()
.unwrap_or(AudioMode::Disabled);
let audio_seed = cursor.read_u32();
let latitude = cursor.read_f32();
let longitude = cursor.read_f32();
let has_location_timestamp = cursor.read_bool();
Expand Down Expand Up @@ -329,6 +332,7 @@ impl DeviceConfig {
is_continuous_recorder,
use_low_power_mode,
audio_mode,
audio_seed,
},
cursor.position(),
))
Expand Down
3 changes: 2 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,8 @@ fn main() -> ! {
let in_window = config.time_is_in_recording_window(&date_time, &None);
if in_window {
is_audio = (state
& (tc2_agent_state::TAKE_AUDIO
& (tc2_agent_state::LONG_AUDIO_RECORDING
| tc2_agent_state::TAKE_AUDIO
| tc2_agent_state::TEST_AUDIO_RECORDING))
> 0;
if is_audio {
Expand Down
Loading

0 comments on commit 5d8883a

Please sign in to comment.