diff --git a/doc/fastcat_device_config_parameters.md b/doc/fastcat_device_config_parameters.md
index f6747a6..beffc0f 100644
--- a/doc/fastcat_device_config_parameters.md
+++ b/doc/fastcat_device_config_parameters.md
@@ -15,6 +15,7 @@ For every `JSD Device` there is an `Offline Device` to emulate the behavior of t
 | El3602           | Beckhoff      | 2-channel +/-10v Diff. Analog Input       |
 | El2124           | Beckhoff      | 4-channel 5v Digital Output               |
 | El2809           | Beckhoff      | 16-channel 24v Digital Output             |
+| El2828           | Beckhoff      | 8-channel 24v 2A Digital Output   
 | El4102           | Beckhoff      | 2-channel 0-10v Analog Output             |
 | Ild1900          | Micro-Epsilon | Distance Laser Sensor                     |
 | AtiFts           | ATI           | Force-Torque Sensor                       |
@@ -425,6 +426,17 @@ The permitted range values are:
   name: el2809_1
 ```
 
+## El2828 (8-channel 24v 2A Digital Output)
+
+**The El2828 device has no configuration parameters**
+
+#### Example
+
+``` yaml
+- device_class: El2828
+  name: el2828_1
+```
+
 ## El4102 (2-channel 0-10v Analog Output)
 
 **The El4102 device has no configuration parameters.**
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 6ae5d41..6810a8a 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -76,6 +76,7 @@ add_library(fastcat STATIC
     jsd/el3602.cc
     jsd/el2124.cc
     jsd/el2809.cc
+    jsd/el2828.cc
     jsd/el4102.cc
     jsd/el3162.cc
     jsd/el1008.cc
@@ -92,6 +93,7 @@ add_library(fastcat STATIC
     jsd/egd_offline.cc
     jsd/el2124_offline.cc
     jsd/el2809_offline.cc
+    jsd/el2828_offline.cc
     jsd/el4102_offline.cc
     jsd/el3208_offline.cc
     jsd/el3602_offline.cc
diff --git a/src/fcgen/fastcat_types.yaml b/src/fcgen/fastcat_types.yaml
index a4d20a0..3789099 100644
--- a/src/fcgen/fastcat_types.yaml
+++ b/src/fcgen/fastcat_types.yaml
@@ -348,6 +348,25 @@ states:
       type: uint8_t
     - name: level_ch16
       type: uint8_t
+  
+  - name: el2828
+    fields:
+    - name: level_ch1
+      type: uint8_t
+    - name: level_ch2
+      type: uint8_t
+    - name: level_ch3
+      type: uint8_t
+    - name: level_ch4
+      type: uint8_t
+    - name: level_ch5
+      type: uint8_t
+    - name: level_ch6
+      type: uint8_t
+    - name: level_ch7
+      type: uint8_t
+    - name: level_ch8
+      type: uint8_t
 
   - name: el4102
     fields:
@@ -759,6 +778,32 @@ commands:
     - name: channel_ch16
       type: uint8_t
 
+  - name: el2828_write_channel
+    fields:
+    - name: channel
+      type: uint8_t
+    - name: level
+      type: uint8_t
+
+  - name: el2828_write_all_channels
+    fields:
+    - name: channel_ch1
+      type: uint8_t
+    - name: channel_ch2
+      type: uint8_t
+    - name: channel_ch3
+      type: uint8_t
+    - name: channel_ch4
+      type: uint8_t
+    - name: channel_ch5
+      type: uint8_t
+    - name: channel_ch6
+      type: uint8_t
+    - name: channel_ch7
+      type: uint8_t
+    - name: channel_ch8
+      type: uint8_t
+
   - name: el4102_write_channel
     fields:
     - name: channel
diff --git a/src/jsd/el2828.cc b/src/jsd/el2828.cc
new file mode 100644
index 0000000..9ea07aa
--- /dev/null
+++ b/src/jsd/el2828.cc
@@ -0,0 +1,101 @@
+// Include related header (for cc files)
+#include "fastcat/jsd/el2828.h"
+
+// Include c then c++ libraries
+#include <string.h>
+
+#include <cmath>
+#include <iostream>
+
+// Include external then project includes
+#include "fastcat/yaml_parser.h"
+
+fastcat::El2828::El2828()
+{
+  MSG_DEBUG("Constructed El2828");
+
+  state_       = std::make_shared<DeviceState>();
+  state_->type = EL2828_STATE;
+}
+
+bool fastcat::El2828::ConfigFromYaml(const YAML::Node& node)
+{
+  bool retval = ConfigFromYamlCommon(node);
+  jsd_set_slave_config((jsd_t*)context_, slave_id_, jsd_slave_config_);
+  return retval;
+}
+
+bool fastcat::El2828::ConfigFromYamlCommon(const YAML::Node& node)
+{
+  if (!ParseVal(node, "name", name_)) {
+    return false;
+  }
+  state_->name = name_;
+
+  jsd_slave_config_.configuration_active = true;
+  jsd_slave_config_.driver_type          = JSD_DRIVER_TYPE_EL2828;
+  snprintf(jsd_slave_config_.name, JSD_NAME_LEN, "%s", name_.c_str());
+
+  return true;
+}
+
+bool fastcat::El2828::Read()
+{
+  const jsd_el2828_state_t* jsd_state =
+      jsd_el2828_get_state((jsd_t*)context_, slave_id_);
+
+  state_->el2828_state.level_ch1 = jsd_state->output[0];
+  state_->el2828_state.level_ch2 = jsd_state->output[1];
+  state_->el2828_state.level_ch3 = jsd_state->output[2];
+  state_->el2828_state.level_ch4 = jsd_state->output[3];
+  state_->el2828_state.level_ch5 = jsd_state->output[4];
+  state_->el2828_state.level_ch6 = jsd_state->output[5];
+  state_->el2828_state.level_ch7 = jsd_state->output[6];
+  state_->el2828_state.level_ch8 = jsd_state->output[7];
+
+  return true;
+}
+
+fastcat::FaultType fastcat::El2828::Process()
+{
+  jsd_el2828_process((jsd_t*)context_, slave_id_);
+  return NO_FAULT;
+}
+
+bool fastcat::El2828::Write(DeviceCmd& cmd)
+{
+  // If device supports async SDO requests
+  AsyncSdoRetVal sdoResult = WriteAsyncSdoRequest(cmd);
+  if (sdoResult != SDO_RET_VAL_NOT_APPLICABLE) {
+    return (sdoResult == SDO_RET_VAL_SUCCESS);
+  }
+
+  if (cmd.type == EL2828_WRITE_CHANNEL_CMD) {
+    uint8_t ch = cmd.el2828_write_channel_cmd.channel;
+    if (ch < 1 || ch > JSD_EL2828_NUM_CHANNELS) {
+      ERROR("Channel must be in range (1,%u)", JSD_EL2828_NUM_CHANNELS);
+      return false;
+    }
+
+    jsd_el2828_write_single_channel((jsd_t*)context_, slave_id_, ch - 1,
+                                    cmd.el2828_write_channel_cmd.level);
+
+  } else if (cmd.type == EL2828_WRITE_ALL_CHANNELS_CMD) {
+    uint8_t output_array[JSD_EL2828_NUM_CHANNELS] = {
+        cmd.el2828_write_all_channels_cmd.channel_ch1,
+        cmd.el2828_write_all_channels_cmd.channel_ch2,
+        cmd.el2828_write_all_channels_cmd.channel_ch3,
+        cmd.el2828_write_all_channels_cmd.channel_ch4,
+        cmd.el2828_write_all_channels_cmd.channel_ch5,
+        cmd.el2828_write_all_channels_cmd.channel_ch6,
+        cmd.el2828_write_all_channels_cmd.channel_ch7,
+        cmd.el2828_write_all_channels_cmd.channel_ch8};
+
+    jsd_el2828_write_all_channels((jsd_t*)context_, slave_id_, output_array);
+
+  } else {
+    ERROR("Bad EL2828 Command");
+    return false;
+  }
+  return true;
+}
diff --git a/src/jsd/el2828.h b/src/jsd/el2828.h
new file mode 100644
index 0000000..4119d6e
--- /dev/null
+++ b/src/jsd/el2828.h
@@ -0,0 +1,32 @@
+#ifndef FASTCAT_EL2828_H_
+#define FASTCAT_EL2828_H_
+
+// Include related header (for cc files)
+
+// Include c then c++ libraries
+
+// Include external then project includes
+#include "fastcat/jsd/jsd_device_base.h"
+#include "jsd/jsd_el2828_pub.h"
+
+namespace fastcat
+{
+class El2828 : public JsdDeviceBase
+{
+ public:
+  El2828();
+  bool      ConfigFromYaml(const YAML::Node& node) override;
+  bool      Read() override;
+  FaultType Process() override;
+  bool      Write(DeviceCmd& cmd) override;
+
+ protected:
+  bool ConfigFromYamlCommon(const YAML::Node& node);
+
+ private:
+  jsd_slave_config_t jsd_slave_config_ = {0};
+};
+
+}  // namespace fastcat
+
+#endif
diff --git a/src/jsd/el2828_offline.cc b/src/jsd/el2828_offline.cc
new file mode 100644
index 0000000..a76a1fc
--- /dev/null
+++ b/src/jsd/el2828_offline.cc
@@ -0,0 +1,100 @@
+// Include related header (for cc files)
+#include "fastcat/jsd/el2828_offline.h"
+
+// Include c then c++ libraries
+#include <string.h>
+
+#include <cmath>
+#include <iostream>
+
+// Include external then project includes
+#include "fastcat/yaml_parser.h"
+
+bool fastcat::El2828Offline::ConfigFromYaml(const YAML::Node& node)
+{
+  return ConfigFromYamlCommon(node);
+}
+
+bool fastcat::El2828Offline::Read() { return true; }
+
+fastcat::FaultType fastcat::El2828Offline::Process()
+{
+  return DeviceBase::Process();
+}
+
+bool fastcat::El2828Offline::Write(DeviceCmd& cmd)
+{
+  // If device supports async SDO requests
+  AsyncSdoRetVal sdoResult = WriteAsyncSdoRequest(cmd);
+  if (sdoResult != SDO_RET_VAL_NOT_APPLICABLE) {
+    return (sdoResult == SDO_RET_VAL_SUCCESS);
+  }
+
+  if (cmd.type == EL2828_WRITE_CHANNEL_CMD) {
+    uint8_t ch = cmd.el2828_write_channel_cmd.channel;
+    if (ch < 1 || ch > JSD_EL2828_NUM_CHANNELS) {
+      ERROR("Channel must be in range (1,%u)", JSD_EL2828_NUM_CHANNELS);
+      return false;
+    }
+    switch (cmd.el2828_write_channel_cmd.channel) {
+      case 1:
+        state_->el2828_state.level_ch1 = cmd.el2828_write_channel_cmd.level;
+        break;
+      case 2:
+        state_->el2828_state.level_ch2 = cmd.el2828_write_channel_cmd.level;
+        break;
+      case 3:
+        state_->el2828_state.level_ch3 = cmd.el2828_write_channel_cmd.level;
+        break;
+      case 4:
+        state_->el2828_state.level_ch4 = cmd.el2828_write_channel_cmd.level;
+        break;
+      case 5:
+        state_->el2828_state.level_ch5 = cmd.el2828_write_channel_cmd.level;
+        break;
+      case 6:
+        state_->el2828_state.level_ch6 = cmd.el2828_write_channel_cmd.level;
+        break;
+      case 7:
+        state_->el2828_state.level_ch7 = cmd.el2828_write_channel_cmd.level;
+        break;
+      case 8:
+        state_->el2828_state.level_ch8 = cmd.el2828_write_channel_cmd.level;
+        break;
+      default:
+        ERROR("Bad Channel value");
+        break;
+    }
+    return true;
+
+  } else if (cmd.type == EL2828_WRITE_ALL_CHANNELS_CMD) {
+    state_->el2828_state.level_ch1 =
+        cmd.el2828_write_all_channels_cmd.channel_ch1;
+
+    state_->el2828_state.level_ch2 =
+        cmd.el2828_write_all_channels_cmd.channel_ch2;
+
+    state_->el2828_state.level_ch3 =
+        cmd.el2828_write_all_channels_cmd.channel_ch3;
+
+    state_->el2828_state.level_ch4 =
+        cmd.el2828_write_all_channels_cmd.channel_ch4;
+
+    state_->el2828_state.level_ch5 =
+        cmd.el2828_write_all_channels_cmd.channel_ch5;
+
+    state_->el2828_state.level_ch6 =
+        cmd.el2828_write_all_channels_cmd.channel_ch6;
+
+    state_->el2828_state.level_ch7 =
+        cmd.el2828_write_all_channels_cmd.channel_ch7;
+
+    state_->el2828_state.level_ch8 =
+        cmd.el2828_write_all_channels_cmd.channel_ch8;
+
+  } else {
+    ERROR("Bad EL2828 Command");
+    return false;
+  }
+  return true;
+}
diff --git a/src/jsd/el2828_offline.h b/src/jsd/el2828_offline.h
new file mode 100644
index 0000000..9d19c15
--- /dev/null
+++ b/src/jsd/el2828_offline.h
@@ -0,0 +1,24 @@
+#ifndef FASTCAT_EL2828_OFFLINE_H_
+#define FASTCAT_EL2828_OFFLINE_H_
+
+// Include related header (for cc files)
+
+// Include c then c++ libraries
+
+// Include external then project includes
+#include "fastcat/jsd/el2828.h"
+
+namespace fastcat
+{
+class El2828Offline : public El2828
+{
+ public:
+  bool      ConfigFromYaml(const YAML::Node& node) override;
+  bool      Read() override;
+  FaultType Process() override;
+  bool      Write(DeviceCmd& cmd) override;
+};
+
+}  // namespace fastcat
+
+#endif
diff --git a/src/manager.cc b/src/manager.cc
index dd3ab94..02d337c 100644
--- a/src/manager.cc
+++ b/src/manager.cc
@@ -37,6 +37,8 @@
 #include "fastcat/jsd/el2124_offline.h"
 #include "fastcat/jsd/el2809.h"
 #include "fastcat/jsd/el2809_offline.h"
+#include "fastcat/jsd/el2828.h"
+#include "fastcat/jsd/el2828_offline.h"
 #include "fastcat/jsd/el3104.h"
 #include "fastcat/jsd/el3104_offline.h"
 #include "fastcat/jsd/el3162.h"
@@ -462,6 +464,9 @@ bool fastcat::Manager::ConfigJSDBusFromYaml(const YAML::Node& node,
     } else if (0 == device_class.compare("El2809")) {
       device = std::make_shared<El2809>();
 
+    } else if (0 == device_class.compare("El2828")) {
+      device = std::make_shared<El2828>();
+
     } else if (0 == device_class.compare("El4102")) {
       device = std::make_shared<El4102>();
 
@@ -692,6 +697,9 @@ bool fastcat::Manager::ConfigOfflineBusFromYaml(const YAML::Node& node,
     } else if (0 == device_class.compare("El2809")) {
       device = std::make_shared<El2809Offline>();
 
+    } else if (0 == device_class.compare("El2828")) {
+      device = std::make_shared<El2828Offline>();
+
     } else if (0 == device_class.compare("El3208")) {
       device = std::make_shared<El3208Offline>();