diff --git a/srp_analysis/Cargo.toml b/srp_analysis/Cargo.toml
index 2ffa9443aa21086a1bccfef0958561522ee89b6d..ecc718b979526e3b664f1280dc29db7b21d0052b 100644
--- a/srp_analysis/Cargo.toml
+++ b/srp_analysis/Cargo.toml
@@ -8,3 +8,5 @@ edition = "2018"
 
 [dependencies]
 structopt = { version = "0.3"}
+serde = { version = "1.0", features = ["derive"] }
+serde_json = "1.0"
diff --git a/srp_analysis/analysis.json b/srp_analysis/analysis.json
new file mode 100644
index 0000000000000000000000000000000000000000..347b242596fc92e21f1c6da33f64d9db961f0e69
--- /dev/null
+++ b/srp_analysis/analysis.json
@@ -0,0 +1 @@
+[{"id":"T1","prio":1,"deadline":100,"inter_arrival":100,"trace":{"id":"T1","start":0,"end":10,"inner":[]}},{"id":"T2","prio":2,"deadline":200,"inter_arrival":200,"trace":{"id":"T2","start":0,"end":30,"inner":[{"id":"R1","start":10,"end":20,"inner":[{"id":"R2","start":12,"end":16,"inner":[]}]},{"id":"R1","start":22,"end":28,"inner":[]}]}},{"id":"T3","prio":3,"deadline":50,"inter_arrival":50,"trace":{"id":"T3","start":0,"end":30,"inner":[{"id":"R2","start":10,"end":20,"inner":[]}]}}]
diff --git a/srp_analysis/src/common.rs b/srp_analysis/src/common.rs
index 48cebacf4e28f43d3a4f51dc2b12199bd4dd838c..dd0a0462728c109f2443cc5fcfdc9ae6144905d7 100644
--- a/srp_analysis/src/common.rs
+++ b/srp_analysis/src/common.rs
@@ -1,8 +1,10 @@
 use std::collections::{HashMap, HashSet};
+use serde::{Serialize, Deserialize};
+
 
 // common data structures
 
-#[derive(Debug, Clone)]
+#[derive(Serialize, Deserialize, Debug, Clone)]
 pub struct Task {
     pub id: String,
     pub prio: u8,
@@ -11,7 +13,7 @@ pub struct Task {
     pub trace: Trace,
 }
 
-#[derive(Debug, Clone)]
+#[derive(Serialize, Deserialize, Debug, Clone)]
 pub struct Trace {
     pub id: String,
     pub start: u32,
diff --git a/srp_analysis/src/main.rs b/srp_analysis/src/main.rs
index d303ec278ff3970999f231794c81b565b3ff0bd4..b4a52257014976836917402bd5505679053182ca 100644
--- a/srp_analysis/src/main.rs
+++ b/srp_analysis/src/main.rs
@@ -7,6 +7,9 @@ use srp_analyser::*;
 use std::path::PathBuf;
 use structopt::StructOpt;
 
+use std::fs::File;
+use std::io::prelude::*;
+
 
 #[derive(Debug, StructOpt)]
 #[structopt(name = "srp_analysis", about = "Preforms srp analysis.")]
@@ -31,7 +34,7 @@ fn main() {
     println!("{:?}", opt);
     
     let tasks: Tasks = match opt.input {
-        Some(_file) => create_tasks(), // TODO: Implement so that the tasks can be read from file.
+        Some(file) => load_tasks(file),
         None => create_tasks(),
     };
     
@@ -39,7 +42,9 @@ fn main() {
     let analysis = analyse(&tasks, &ip, &tr, opt.approx);
 
     match opt.output {
-        Some(_file) => (), // TODO: Implement so that the analysis can be saved to file.
+        Some(file) => {
+            write_to_file(serde_json::to_string(&analysis).unwrap(), file);
+        }, // TODO: Implement so that the analysis can be saved to html.
         None => {
             println!("tasks {:?}", &tasks);
             println!("tot_util {}", total_load_factor(&tasks));
@@ -55,6 +60,25 @@ fn main() {
 }
 
 
+fn write_to_file(contents: String, file: PathBuf) -> std::io::Result<()> {
+    let mut file = File::create(file)?;
+    file.write_all(contents.as_bytes())?;
+    Ok(())
+}
+
+fn load_tasks(file: PathBuf) -> Tasks {
+    let mut serialized = String::new();
+    read_from_file(&mut serialized, file);
+    return serde_json::from_str(&serialized).unwrap();
+}
+
+fn read_from_file(contents: &mut String, filename: PathBuf) -> std::io::Result<()> {
+    let mut file = File::open(filename)?;
+    file.read_to_string(contents)?;
+    Ok(())
+}
+
+
 fn create_tasks() -> Tasks {
     let t1 = Task {
         id: "T1".to_string(),
diff --git a/srp_analysis/src/srp_analyser.rs b/srp_analysis/src/srp_analyser.rs
index 4cb4524b94f1e87aeba526ccfb1590d193f671d8..8047622117c80fa672d08fc114b9bb1eba9ba6fa 100644
--- a/srp_analysis/src/srp_analyser.rs
+++ b/srp_analysis/src/srp_analyser.rs
@@ -1,4 +1,15 @@
 use super::common::*;
+use serde::{Serialize, Deserialize};
+
+
+#[derive(Serialize, Deserialize, Debug, Clone)]
+pub struct AnalysedTask {
+    pub task: Task,
+    pub response_time: u32,
+    pub wcet: u32,
+    pub block_time: u32,
+    pub preemtion_time: u32,
+}
 
 
 /*
@@ -170,14 +181,16 @@ pub fn interference_time(task: &Task, tasks: &Tasks, ip: &IdPrio, tr: &TaskResou
  * Note: Finally, make a function that iterates over the task set and returns a vector with containing:
 Vec<Task, R(t), C(t), B(t), I(t)>. Just a simple println! of that vector gives the essential information on the analysis.
  */
-pub fn analyse(tasks: &Tasks, ip: &IdPrio, tr: &TaskResources, approx: bool) -> Vec<(Task, u32, u32, u32, u32)> {
-    let mut analysis: Vec<(Task, u32, u32, u32, u32)> = vec!();
+pub fn analyse(tasks: &Tasks, ip: &IdPrio, tr: &TaskResources, approx: bool) -> Vec<AnalysedTask> {
+    let mut analysis: Vec<AnalysedTask> = vec!();
     for t in tasks {
-        let r_t = response_time(t, tasks, ip, tr, approx);
-        let c_t = wcet(&t.trace);
-        let b_t = block_time(t, tasks, ip, tr);
-        let i_t = interference_time(t, tasks, ip, tr, approx).unwrap();
-        analysis.push((t.clone(), r_t, c_t, b_t, i_t));
+        analysis.push(AnalysedTask {
+            task: t.clone(),
+            response_time: response_time(t, tasks, ip, tr, approx),
+            wcet: wcet(&t.trace),
+            block_time: block_time(t, tasks, ip, tr),
+            preemtion_time: interference_time(t, tasks, ip, tr, approx).unwrap(),
+        });
     }
     return analysis;
 }