diff --git a/data/fault_list.csv b/data/fault_list.csv
new file mode 100644
index 0000000000000000000000000000000000000000..aff4f3d879cf4618d98f3174d8edcd44bb5d33f6
--- /dev/null
+++ b/data/fault_list.csv
@@ -0,0 +1,2 @@
+"Category","Name (letters,numbers,underscores,NO SPACES, all caps!)","Description","Generated Name(autogenerated column!)"
+"ANAKIN","TEST_FAULT","This fault is for testing","F_ANAKIN_TEST_FAULT"
diff --git a/sbs b/sbs
index 246b5796d250c74aa841d3833fa3184698f2c7f3..1bb6f735a51497241c419d1149ef134b740e980e 100755
--- a/sbs
+++ b/sbs
@@ -63,8 +63,7 @@ parser.add_option("-c", "--clean", help="Run a 'make clean'", dest="clean",
 parser.add_option("-b", "--board", help="Build a specific board", dest="board")
 parser.add_option("-l", "--list", help="List all build configurations", dest="list",
     default=False, action='store_true')
-
-
+parser.add_option("-g", "--gen-faults", help="Generate fault list header files and exit", dest="genhdr", default=False, action='store_true')
 parser.add_option("-v", "--verbose", help="Print a verbose output", dest="log", 
         action="store_true")
 parser.add_option("-j", "--jobs", 
@@ -75,6 +74,12 @@ parser.add_option("-j", "--jobs",
 
 banner()
 
+if options.genhdr == True:
+    d1 = "data/fault_list.csv"
+    d2 = "src/shared/diagnostic/FaultCounterData.h"
+    os.system("/usr/bin/python scripts/gen_fault_headers.py %s %s" %(d1,d2))
+    exit(0)
+
 conf = cp.RawConfigParser()
 conf.read("sbs.conf")
 
diff --git a/scripts/gen_fault_headers.py b/scripts/gen_fault_headers.py
new file mode 100755
index 0000000000000000000000000000000000000000..c697b19e4241511b4dad2ec9479f8ef275403835
--- /dev/null
+++ b/scripts/gen_fault_headers.py
@@ -0,0 +1,241 @@
+#!/usr/bin/python
+
+# Copyright (c) 2017 Skyward Experimental Rocketry
+# Authors: Alain Carlucci
+# 
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+# 
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+# 
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+
+import csv,string,hashlib,datetime,sys
+
+if len(sys.argv) != 3:
+    print("Usage: %s <CSV File> <Output header file>" % (sys.argv[0]))
+    exit(-1)
+
+headerLine = None
+
+newLines = []
+
+lineCtr = 0
+curCatId = 0
+categories={}
+enums={}
+
+import hashlib
+
+def fileHash(filename):
+    h = hashlib.sha1()
+    with open(filename, 'rb', buffering=0) as f:
+        for b in iter(lambda : f.read(128*1024), b''):
+            h.update(b)
+    return h.hexdigest()
+
+def genEnum(name, s, inc):
+    a = ('''enum class %s
+{
+''') % (name,);
+    cnt = 0
+    for i in s:
+        if inc:
+            a += "    " + i + " = " + str(cnt) + ",\n"
+        else:
+            a += "    " + i + " = " + str(s[i]) + ",\n"
+        cnt += 1
+    a += "};\n"
+    return a
+
+def genHeaderFile(fileName,csvFile):
+    print("[*] Generating header file (%s)" %(fileName,))
+    content = ('''/* Copyright (c) 2017 Skyward Experimental Rocketry
+ * Authors: Alain Carlucci
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/*
+ ******************************************************************************
+ *                  THIS FILE IS AUTOGENERATED. DO NOT EDIT.                  *
+ ******************************************************************************
+ */
+
+// CSV File:         %s
+// SHA1 of CSV File: %s
+// Autogen date:     %s
+
+#include <cstdint>
+
+#ifndef SKYWARD_FAULT_CTRL_LIST_H
+#define SKYWARD_FAULT_CTRL_LIST_H
+
+namespace FaultCounter
+{
+
+''') % (csvFile, fileHash(csvFile), datetime.datetime.now())
+    content += genEnum("FaultCategory", categories, False)
+    content += "\n"
+    content += genEnum("Fault", enums, True)
+    content += '''
+
+// Usage: categoryID = FaultCounter::FaultToCategory[faultID];
+static const uint32_t FaultToCategory[] = 
+{
+    '''
+    colCnt = 0
+    for i in enums:
+        content += "%d, " % (categories[enums[i]], )
+        colCnt += 1
+        if colCnt == 20:
+            content += "\n    "
+            colCnt = 0
+    content += '''
+}; /* CategoryMapping */
+
+} /* FaultCounter */
+
+#endif /* SKYWARD_FAULT_CTRL_LIST_H */
+
+'''
+    try:
+        with open(fileName, "w") as f:
+            f.write(content)
+        print("[+] Written %d lines in %s" % (len(content.split("\n")), fileName))
+    except:
+        print("[!] Cannot open %s for writing.", fileName)
+        exit(-1)
+
+
+def checkForGoodName(n):
+    if len(n) == 0:
+        return False
+
+    if n[0] not in string.ascii_uppercase:
+        return False
+
+    for x in n:
+        if x not in string.ascii_uppercase + string.digits + '_':
+            return False
+
+    if n[-1] not in string.ascii_uppercase + string.digits:
+        return False
+
+    return True
+
+def genEnumName(cat,name):
+    ctr = 2
+    
+    genBName = "F_" + cat + "_" + name
+    genName = genBName
+
+    while genName in enums:
+        genName = genBName + "_" + str(ctr) 
+        ctr += 1
+
+    return genName
+
+# return False: csv file is ok
+# return True: csv file must be updated
+def handleLine(r):
+    global lineCtr,categories,newLines,enums,curCatId
+
+    if len(r) != 4:
+        print("[!] Parsing error at line %d. I'm expecting 4 fields" % (lineCtr,))
+        exit(-1)
+
+    curCat = r[0].strip().upper()
+    curName = r[1].strip().upper()
+    curDesc = r[2].strip()
+    curEnum = r[3].strip().upper()
+
+    if checkForGoodName(curCat) == False:
+        print("[!] Invalid category at line %d." % (lineCtr,))
+        exit(-1)
+
+    if checkForGoodName(curName) == False:
+        print("[!] Invalid name at line %d." % (lineCtr,))
+        exit(-1)
+
+    if len(curEnum) > 0 and (checkForGoodName(curEnum) == False or curEnum in enums):
+        print("[!] Invalid generated name at line %d." % (lineCtr,))
+        exit(-1)
+
+    retVal = False
+    if len(curEnum) == 0:
+        curEnum = genEnumName(curCat, curName)
+        retVal = True
+
+    if curCat not in categories:
+        print("[+] Added category '%s'" % (curCat,))
+        categories[curCat] = curCatId
+        curCatId += 1
+
+    print("[+] Added %s in category %s" %(curEnum,curCat))
+    enums[curEnum] = curCat
+
+    newLines.append([curCat, curName, curDesc, curEnum])
+    return retVal
+
+mustUpdate = False
+print("[*] Opening %s..." % (sys.argv[1],))
+try:
+    with open(sys.argv[1], "r") as csvfile:
+        r = csv.reader(csvfile, delimiter=',', quotechar='"')
+        for row in r:
+            lineCtr += 1
+            if headerLine is None:
+                headerLine = row
+                continue
+            if handleLine(row):
+                mustUpdate = True
+except Exception as e:
+    print("[!] Cannot open %s for reading: %s!" %(sys.argv[1],str(e)))
+    exit(-1)
+
+if not mustUpdate:
+    print("[+] No need to update the csv file.")
+else:
+    print("[*] Updating %s..." % (sys.argv[1],))
+
+    try:
+        with open(sys.argv[1], "w") as csvfile:
+            r = csv.writer(csvfile, delimiter=',', quotechar='"', quoting=csv.QUOTE_ALL)
+            r.writerow(headerLine)
+            for row in newLines:
+                r.writerow(row)
+            print("[+] Successfully updated csv file")
+    except:
+        print("[!] Cannot open %s for writing!" %(sys.argv[1],))
+        exit(-1)
+
+genHeaderFile(sys.argv[2], sys.argv[1])
diff --git a/src/shared/diagnostic/FaultCounterData.h b/src/shared/diagnostic/FaultCounterData.h
new file mode 100644
index 0000000000000000000000000000000000000000..73d0f02590ca6000b86d80402e4e9ee25f3b04ab
--- /dev/null
+++ b/src/shared/diagnostic/FaultCounterData.h
@@ -0,0 +1,61 @@
+/* Copyright (c) 2017 Skyward Experimental Rocketry
+ * Authors: Alain Carlucci
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/*
+ ******************************************************************************
+ *                  THIS FILE IS AUTOGENERATED. DO NOT EDIT.                  *
+ ******************************************************************************
+ */
+
+// CSV File:         data/fault_list.csv
+// SHA1 of CSV File: e9a518af53ac91c2e57142fda140689918338c66
+// Autogen date:     2017-09-16 19:03:30.061175
+
+#include <cstdint>
+
+#ifndef SKYWARD_FAULT_CTRL_LIST_H
+#define SKYWARD_FAULT_CTRL_LIST_H
+
+namespace FaultCounter
+{
+
+enum class FaultCategory
+{
+    ANAKIN = 0,
+};
+
+enum class Fault
+{
+    F_ANAKIN_TEST_FAULT = 0,
+};
+
+
+// Usage: categoryID = FaultCounter::FaultToCategory[faultID];
+static const uint32_t FaultToCategory[] = 
+{
+    0, 
+}; /* CategoryMapping */
+
+} /* FaultCounter */
+
+#endif /* SKYWARD_FAULT_CTRL_LIST_H */
+