diff --git a/boards/uniboard2/libraries/unb2_board/hdllib.cfg b/boards/uniboard2/libraries/unb2_board/hdllib.cfg
index a9499ba6dd3bc5a4181202fc5564a4289f50fea9..7b29809b3c742af9d2bf4bbb44f4344c246d70c9 100644
--- a/boards/uniboard2/libraries/unb2_board/hdllib.cfg
+++ b/boards/uniboard2/libraries/unb2_board/hdllib.cfg
@@ -22,6 +22,7 @@ synth_files =
     src/vhdl/unb2_board_sens_reg.vhd
     src/vhdl/mms_unb2_board_sens.vhd
     src/vhdl/unb2_board_wdi_reg.vhd
+    src/vhdl/unb2_board_qsfp_leds.vhd
     src/vhdl/ctrl_unb2_board.vhd
     src/vhdl/unb2_board_front_io.vhd
     src/vhdl/unb2_board_back_io.vhd
@@ -35,6 +36,7 @@ test_bench_files =
     tb/vhdl/tb_unb2_board_clk200_pll.vhd
     tb/vhdl/tb_unb2_board_clk25_pll.vhd
     tb/vhdl/tb_unb2_board_node_ctrl.vhd
+    tb/vhdl/tb_unb2_board_qsfp_leds.vhd
     
 # vsim -L ... -L ... ...
 modelsim_search_libraries =
diff --git a/boards/uniboard2/libraries/unb2_board/src/vhdl/unb2_board_qsfp_leds.vhd b/boards/uniboard2/libraries/unb2_board/src/vhdl/unb2_board_qsfp_leds.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..f90d2dc68961b44125a049a8e170d394778f678e
--- /dev/null
+++ b/boards/uniboard2/libraries/unb2_board/src/vhdl/unb2_board_qsfp_leds.vhd
@@ -0,0 +1,186 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright (C) 2015
+-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
+-- JIVE (Joint Institute for VLBI in Europe) <http://www.jive.nl/>
+-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program.  If not, see <http://www.gnu.org/licenses/>.
+--
+-------------------------------------------------------------------------------
+
+LIBRARY IEEE, common_lib, dp_lib;
+USE IEEE.STD_LOGIC_1164.ALL;
+USE common_lib.common_pkg.ALL;
+USE dp_lib.dp_stream_pkg.ALL;
+
+-- Purpose: Provide visual activity information via the UniBoard2 front panel QSFP LEDs.
+-- Description:
+--   The testio LED on UniBoard2 is not visible via the front panel. The
+--   front panel does have a dual colour LED for each QSFP lane. Therefore
+--   these QSFP LEDs are used to signal some application information and lane
+--   status/activity information.
+--
+--   LED lights:
+--  
+--   1) Default behaviour for all QSFP leds:
+--      . off = no FPGA image is running
+--
+--   2) For factory image:
+--      . green off
+--      . red toggling every 1 s = factory image is running (g_factory_image=TRUE)
+--  
+--   3) For a user image without Gbps lane functionality: 
+--      . red off
+--      . green toggling every 1 s = user image is running (g_factory_image=FALSE and green_on_arr(I)='0' default)
+--
+--   4) For a user image with Gbps lane functionality:
+--      . red off
+--      . green toggling every 1 s when the lane status is not OK (green_on_arr(I)=xon='0')
+--      . green on continously when the lane status is OK (green_on_arr(I)=xon='1')
+--      . green led goes off briefly off when there is an Tx or Rx packet (green_evt_arr(I).sop='1')
+--
+--   The combined colour amber (= red + green) is not used. The factory image
+--   only uses the red led and the user image only uses the green led.
+--
+--   Each QSFP carries c_quad = 4 lanes, therefore the green led LED can only
+--   signal a combined status of the lanes. The combined status eg. be:
+--   
+--     'and-status' = combined status is on when all lanes are on
+--     'or-status'  = combined status is on when at least 1 lane is on
+--
+--   Choose using 'or-status', because then the LED can give lane status
+--   information when less than all 4 lane are connected.
+--
+
+ENTITY unb2_board_qsfp_leds IS
+  GENERIC (
+    g_sim             : BOOLEAN := FALSE;        -- when true speed up led toggling in simulation
+    g_factory_image   : BOOLEAN := FALSE;        -- distinguish factory image and user images
+    g_nof_qsfp        : NATURAL := 6;            -- number of QSFP cages each with one dual led that can light red or green (or amber = red + green)
+    g_pulse_us        : NATURAL := 200           -- nof clk cycles to get us period
+  );
+  PORT (
+    rst               : IN  STD_LOGIC;
+    clk               : IN  STD_LOGIC;
+    -- internal pulser outputs
+    pulse_us          : OUT STD_LOGIC;
+    pulse_ms          : OUT STD_LOGIC;
+    pulse_s           : OUT STD_LOGIC;
+    -- lane status
+    tx_siso_arr       : IN  t_dp_siso_arr(g_nof_qsfp*c_quad-1 DOWNTO 0) := (OTHERS=>c_dp_siso_rst);
+    tx_sosi_arr       : IN  t_dp_sosi_arr(g_nof_qsfp*c_quad-1 DOWNTO 0) := (OTHERS=>c_dp_sosi_rst);
+    rx_sosi_arr       : IN  t_dp_sosi_arr(g_nof_qsfp*c_quad-1 DOWNTO 0) := (OTHERS=>c_dp_sosi_rst);
+    -- leds
+    green_led_arr     : OUT STD_LOGIC_VECTOR(g_nof_qsfp-1 DOWNTO 0);
+    red_led_arr       : OUT STD_LOGIC_VECTOR(g_nof_qsfp-1 DOWNTO 0)
+  );
+END unb2_board_qsfp_leds;
+
+
+ARCHITECTURE str OF unb2_board_qsfp_leds IS
+
+  CONSTANT c_nof_ms         : NATURAL := sel_a_b(g_sim, 1, 100);  -- force off for c_nof_ms and then on for at least c_nof_ms
+  CONSTANT c_nof_lanes      : NATURAL := g_nof_qsfp*c_quad;       -- number of transceiver lanes, fixed 4 per Quad-SFP cage
+  
+  SIGNAL i_pulse_ms         : STD_LOGIC;
+  SIGNAL i_pulse_s          : STD_LOGIC;
+  SIGNAL toggle_s           : STD_LOGIC;
+  
+  SIGNAL green_on_arr       : STD_LOGIC_VECTOR(g_nof_qsfp*c_quad-1 DOWNTO 0);
+  SIGNAL green_evt_arr      : STD_LOGIC_VECTOR(g_nof_qsfp*c_quad-1 DOWNTO 0);
+  
+  SIGNAL qsfp_on_arr        : STD_LOGIC_VECTOR(g_nof_qsfp-1 DOWNTO 0);
+  SIGNAL qsfp_evt_arr       : STD_LOGIC_VECTOR(g_nof_qsfp-1 DOWNTO 0);
+  
+BEGIN
+
+  pulse_ms <= i_pulse_ms;
+  pulse_s  <= i_pulse_s;
+
+  -- Also output the pulses, because they could be useful for other purposes in the clk clock domain as well
+  u_common_pulser_us_ms_s : ENTITY common_lib.common_pulser_us_ms_s
+  GENERIC MAP (
+    g_pulse_us  => g_pulse_us,                 -- nof clk cycles to get us period
+    g_pulse_ms  => sel_a_b(g_sim, 10, 1000),   -- nof pulse_us pulses to get ms period
+    g_pulse_s   => sel_a_b(g_sim, 10, 1000)    -- nof pulse_ms pulses to get s period
+  )
+  PORT MAP (
+    rst         => rst,
+    clk         => clk,
+    pulse_us    => pulse_us,
+    pulse_ms    => i_pulse_ms,
+    pulse_s     => i_pulse_s
+  );
+
+  u_common_toggle_s : ENTITY common_lib.common_toggle
+  PORT MAP (
+    rst         => rst,
+    clk         => clk,
+    in_dat      => i_pulse_s,
+    out_dat     => toggle_s
+  );
+  
+  gen_factory_image : IF g_factory_image=TRUE GENERATE
+    green_led_arr <= (OTHERS=>'0');
+    
+    gen_red_led_arr : FOR I IN g_nof_qsfp-1 DOWNTO 0 GENERATE
+      u_red_led_controller : ENTITY common_lib.common_led_controller
+      GENERIC MAP (
+        g_nof_ms      => c_nof_ms
+      )
+      PORT MAP (
+        rst           => rst,
+        clk           => clk,
+        -- led control
+        ctrl_input    => toggle_s,
+        -- led output
+        led           => red_led_arr(I)
+      );
+    END GENERATE;
+  END GENERATE;
+
+  gen_user_image : IF g_factory_image=FALSE GENERATE
+  
+    red_led_arr <= (OTHERS=>'0');
+    
+    gen_green_ctrl_arr : FOR I IN c_nof_lanes-1 DOWNTO 0 GENERATE
+      green_on_arr(I)  <= tx_siso_arr(I).xon                       WHEN rising_edge(clk);
+      green_evt_arr(I) <= tx_sosi_arr(I).sop OR rx_sosi_arr(I).sop WHEN rising_edge(clk);
+    END GENERATE;    
+      
+    gen_green_led_arr : FOR I IN g_nof_qsfp-1 DOWNTO 0 GENERATE
+    
+      qsfp_on_arr(I)  <= orv(green_on_arr( (I+1)*c_quad-1 DOWNTO + I*c_quad));
+      qsfp_evt_arr(I) <= orv(green_evt_arr((I+1)*c_quad-1 DOWNTO + I*c_quad));
+      
+      u_green_led_controller : ENTITY common_lib.common_led_controller
+      GENERIC MAP (
+        g_nof_ms      => c_nof_ms
+      )
+      PORT MAP (
+        rst           => rst,
+        clk           => clk,
+        pulse_ms      => i_pulse_ms,
+        -- led control
+        ctrl_on       => qsfp_on_arr(I),
+        ctrl_evt      => qsfp_evt_arr(I),
+        ctrl_input    => toggle_s,
+        -- led output
+        led           => green_led_arr(I)
+      );
+    END GENERATE;    
+  END GENERATE;
+  
+END str;
diff --git a/boards/uniboard2/libraries/unb2_board/tb/vhdl/tb_unb2_board_qsfp_leds.vhd b/boards/uniboard2/libraries/unb2_board/tb/vhdl/tb_unb2_board_qsfp_leds.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..8ca7b73ea19a6d7f63979ebb04bcd2196ff06bc8
--- /dev/null
+++ b/boards/uniboard2/libraries/unb2_board/tb/vhdl/tb_unb2_board_qsfp_leds.vhd
@@ -0,0 +1,190 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright (C) 2010
+-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
+-- JIVE (Joint Institute for VLBI in Europe) <http://www.jive.nl/>
+-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program.  If not, see <http://www.gnu.org/licenses/>.
+--
+-------------------------------------------------------------------------------
+
+-- Purpose: Test bench for unb2_board_qsfp_leds
+-- Description:
+--   The test bench is self-stopping but not self-checking. Manually obeserve
+--   in the wave window that:
+--   1) factory image:
+--      - green led is off
+--      - red led toggles
+--   2) user image
+--      - red led is off
+--      - green led toggles when any xon='0'
+--      - green led is on continously when any xon='1'
+--      - green led goes briefly off when any sop='1'
+-- Usage:
+--   > as 3
+--   > run -a
+
+LIBRARY IEEE, common_lib, dp_lib;
+USE IEEE.std_logic_1164.ALL;
+USE common_lib.common_pkg.ALL;
+USE common_lib.tb_common_pkg.ALL;
+USE dp_lib.dp_stream_pkg.ALL;
+
+ENTITY tb_unb2_board_qsfp_leds IS
+END tb_unb2_board_qsfp_leds;
+
+ARCHITECTURE tb OF tb_unb2_board_qsfp_leds IS
+
+  CONSTANT c_clk_freq_hz    : NATURAL := 200 * 10**6;
+  CONSTANT c_clk_period_ns  : NATURAL := 10**9 / c_clk_freq_hz;
+  CONSTANT c_nof_clk_per_us : NATURAL := 1000 / c_clk_period_ns;
+  
+  CONSTANT clk_period       : TIME := c_clk_period_ns * 1 ns;
+  
+  CONSTANT c_nof_qsfp       : NATURAL := 2;
+  CONSTANT c_nof_lanes      : NATURAL := c_nof_qsfp*c_quad;
+  
+  SIGNAL tb_end                  : STD_LOGIC := '0';
+  SIGNAL rst                     : STD_LOGIC;
+  SIGNAL clk                     : STD_LOGIC := '0';
+  SIGNAL pulse_us                : STD_LOGIC;
+  SIGNAL pulse_ms                : STD_LOGIC;
+  SIGNAL pulse_s                 : STD_LOGIC;
+ 
+  SIGNAL tx_siso_arr             : t_dp_siso_arr(c_nof_lanes-1 DOWNTO 0) := (OTHERS=>c_dp_siso_rst);
+  SIGNAL tx_sosi_arr             : t_dp_sosi_arr(c_nof_lanes-1 DOWNTO 0) := (OTHERS=>c_dp_sosi_rst);
+  SIGNAL rx_sosi_arr             : t_dp_sosi_arr(c_nof_lanes-1 DOWNTO 0) := (OTHERS=>c_dp_sosi_rst);
+    
+  SIGNAL dbg_xon_arr             : STD_LOGIC_VECTOR(c_nof_lanes-1 DOWNTO 0);
+  SIGNAL dbg_tx_sop_arr          : STD_LOGIC_VECTOR(c_nof_lanes-1 DOWNTO 0);
+  SIGNAL dbg_rx_sop_arr          : STD_LOGIC_VECTOR(c_nof_lanes-1 DOWNTO 0);
+  
+  SIGNAL factory_green_led_arr   : STD_LOGIC_VECTOR(c_nof_qsfp-1 DOWNTO 0);
+  SIGNAL factory_red_led_arr     : STD_LOGIC_VECTOR(c_nof_qsfp-1 DOWNTO 0);
+  
+  SIGNAL user_green_led_arr      : STD_LOGIC_VECTOR(c_nof_qsfp-1 DOWNTO 0);
+  SIGNAL user_red_led_arr        : STD_LOGIC_VECTOR(c_nof_qsfp-1 DOWNTO 0);
+  
+  -- Cannot use proc_common_gen_pulse() to create sop in array.
+  -- proc_common_gen_pulse() works for dbg_sop, dbg_sosi.sop but not for dbg_sop_slv(I) or for tx_sosi_arr(I).sop.
+  -- The compiler then gives Error: "(vcom-1450) Actual (indexed name) for formal "pulse" is not a static signal name"
+  -- It does work if the array index is from a GENERATE statement, but it does not work when it is from a LOOP statement.
+  SIGNAL dbg_sop      : STD_LOGIC;
+  SIGNAL dbg_sop_slv  : STD_LOGIC_VECTOR(c_nof_lanes-1 DOWNTO 0);
+  SIGNAL dbg_sosi : t_dp_sosi;
+  
+BEGIN
+  
+  clk <= NOT clk OR tb_end AFTER clk_period/2;
+  rst <= '1', '0' AFTER clk_period*7;
+  
+  -- Ease observation of record fields in Wave window, by mapping them to a SLV
+  dbg_xon_arr    <= func_dp_stream_arr_get(tx_siso_arr, "XON");
+  dbg_tx_sop_arr <= func_dp_stream_arr_get(tx_sosi_arr, "SOP");
+  dbg_rx_sop_arr <= func_dp_stream_arr_get(rx_sosi_arr, "SOP");
+  
+  p_stimuli : PROCESS
+  BEGIN
+    tx_siso_arr <= (OTHERS=>c_dp_siso_rst);
+    tx_sosi_arr <= (OTHERS=>c_dp_sosi_rst);
+    rx_sosi_arr <= (OTHERS=>c_dp_sosi_rst);
+    proc_common_wait_some_pulses(clk, pulse_ms, 50);
+    
+    -- Switch on each lane
+    FOR I IN 0 TO c_nof_lanes-1 LOOP
+      tx_siso_arr(I).xon <= '1';
+      proc_common_wait_some_pulses(clk, pulse_ms, 10);
+    END LOOP;
+    proc_common_wait_some_pulses(clk, pulse_ms, 50);
+    
+    -- Issue the sop of a Tx packet on each lane
+    FOR I IN 0 TO c_nof_lanes-1 LOOP
+      -- Cannot use proc_common_gen_pulse(), because index I in a LOOP is not static
+      tx_sosi_arr(I).sop <= '1';
+      WAIT UNTIL rising_edge(clk);
+      tx_sosi_arr(I).sop <= '0';
+      proc_common_wait_some_pulses(clk, pulse_ms, 10);
+    END LOOP;
+    proc_common_wait_some_pulses(clk, pulse_ms, 50);
+    
+    -- Issue the sop of an Rx packet on each lane
+    FOR I IN 0 TO c_nof_lanes-1 LOOP
+      -- Cannot use proc_common_gen_pulse(), because index I in a LOOP is not static
+      rx_sosi_arr(I).sop <= '1';
+      WAIT UNTIL rising_edge(clk);
+      rx_sosi_arr(I).sop <= '0';
+      proc_common_wait_some_pulses(clk, pulse_ms, 10);
+    END LOOP;
+    proc_common_wait_some_pulses(clk, pulse_ms, 50);
+    
+    -- Switch off each lane
+    FOR I IN 0 TO c_nof_lanes-1 LOOP
+      tx_siso_arr(I).xon <= '0';
+      proc_common_wait_some_pulses(clk, pulse_ms, 10);
+    END LOOP;
+    proc_common_wait_some_pulses(clk, pulse_ms, 50);
+    
+    tb_end <= '1';
+    proc_common_wait_some_pulses(clk, pulse_ms, 10);
+    WAIT;
+  END PROCESS;
+  
+  u_unb2_factory_qsfp_leds : ENTITY work.unb2_board_qsfp_leds
+  GENERIC MAP (
+    g_sim             => TRUE,             -- when true speed up led toggling in simulation
+    g_factory_image   => TRUE,             -- distinguish factory image and user images
+    g_nof_qsfp        => c_nof_qsfp,       -- number of QSFP cages each with one dual led that can light red or green (or amber = red + green)
+    g_pulse_us        => c_nof_clk_per_us  -- nof clk cycles to get us period
+  )
+  PORT MAP (
+    rst               => rst,
+    clk               => clk,
+    -- internal pulser outputs
+    pulse_us          => pulse_us,
+    pulse_ms          => pulse_ms,
+    pulse_s           => pulse_s,
+    -- lane status
+    tx_siso_arr       => tx_siso_arr,
+    tx_sosi_arr       => tx_sosi_arr,
+    rx_sosi_arr       => rx_sosi_arr,
+    -- leds
+    green_led_arr     => factory_green_led_arr,
+    red_led_arr       => factory_red_led_arr
+  );
+  
+  u_unb2_user_qsfp_leds : ENTITY work.unb2_board_qsfp_leds
+  GENERIC MAP (
+    g_sim             => TRUE,             -- when true speed up led toggling in simulation
+    g_factory_image   => FALSE,            -- distinguish factory image and user images
+    g_nof_qsfp        => c_nof_qsfp,       -- number of QSFP cages each with one dual led that can light red or green (or amber = red + green)
+    g_pulse_us        => c_nof_clk_per_us  -- nof clk cycles to get us period
+  )
+  PORT MAP (
+    rst               => rst,
+    clk               => clk,
+    -- internal pulser outputs
+    pulse_us          => pulse_us,
+    pulse_ms          => pulse_ms,
+    pulse_s           => pulse_s,
+    -- lane status
+    tx_siso_arr       => tx_siso_arr,
+    tx_sosi_arr       => tx_sosi_arr,
+    rx_sosi_arr       => rx_sosi_arr,
+    -- leds
+    green_led_arr     => user_green_led_arr,
+    red_led_arr       => user_red_led_arr
+  );
+  
+END tb;