diff --git a/tc/obsw_tc_service23.py b/tc/obsw_tc_service23.py
index 9a14f9880b800cc90d35abd4e0776f6a40f73126..9f384fe3d9ac06437a79048b1c5d446550fed99a 100644
--- a/tc/obsw_tc_service23.py
+++ b/tc/obsw_tc_service23.py
@@ -5,19 +5,193 @@ Created: 21.01.2020 07:48
 @author: Jakob Meier
 """
 import math
+from enum import Enum
+
 import config.obsw_config as g
 from typing import Deque
 
-from tc.obsw_pus_tc_packer import PusTelecommand
+from tc.obsw_pus_tc_packer import PusTelecommand, TcQueueT
+from tmtc_core.utility.obsw_logger import get_logger
+
+LOGGER = get_logger()
+
+
+class FileTransferHelper:
+    """
+    This helper class fills the provided TC queue with appropriate PUS telecommands
+    to transfer a large file.
+    There are three modes which determine which telecommands will be generated:
+    1. NORMAL:      Generate telecommand to create a new file and append data packets if
+                    the file data is too large. This will be the default mode.
+    2. DELETE_OLD:  Generate telecommand to delete old file and then perform same steps as the
+                    normal mode
+    3. RENAME_OLD:  Rename old file and then perform same steps as in normal mode.
+
+    Please note that the setter functions set_data have to be used to assign data, otherwise
+    an empty file will be created. The mode is set with setter commands as well.
+    """
+    class TransferMode(Enum):
+        # Normal mode
+        NORMAL = 1
+        # Generate a command to delete the old file first
+        DELETE_OLD = 2
+        # Generate a command to rename the old file first.
+        RENAME_OLD = 3
+
+    def __init__(self, tc_queue: TcQueueT, max_size_of_app_data: int,
+                 target_repository: str, target_filename: str,
+                 object_id=g.SD_CARD_HANDLER_ID):
+        """
+        @param tc_queue: TC queue which will be filled
+        @param max_size_of_app_data: Maximum allowed app data size. Number of generated packets
+        will depend on this value
+        @param target_repository: Repository path on target.
+        @param target_filename: Filename on target
+        @param object_id:
+        """
+        self.transfer_mode = self.TransferMode.NORMAL
+        self.max_size_of_app_data = max_size_of_app_data
+        self.allowed_file_data_size = calculate_allowed_file_data_size(
+            max_size_of_app_data, target_filename, target_repository)
+        self.target_filename = target_filename
+        self.target_repository = target_repository
+        self.renamed_name = self.target_filename + "old"
+        self.object_id = object_id
+        self.tc_queue = tc_queue
+        self.file_data = bytearray()
+        self.local_filename = ""
+        # This will generate a telecommand to delete the old file, if it exists
+        self.delete_old_file = False
+        # This will generater a telecommand to rename the old file, if it exists
+        self.rename_old_file = False
+
+    def set_data(self, local_filename: str):
+        with open(local_filename, 'rb') as file:
+            self.file_data = file.read()
+
+    def set_data(self, tc_data: bytearray):
+        self.file_data = tc_data
+
+    def set_to_delete_old_file(self):
+        self.transfer_mode = self.TransferMode.DELETE_OLD
+
+    def set_to_rename_old_file(self, renamed_name: str):
+        self.transfer_mode = self.TransferMode.RENAME_OLD
+        self.renamed_name = renamed_name
+
+    def generate_packets(self, ssc: int):
+        if self.transfer_mode == self.TransferMode.DELETE_OLD:
+            command = generate_rm_file_srv23_2_packet(self.target_filename, self.target_repository,
+                                                      ssc, self.object_id)
+            ssc += 1
+            self.tc_queue.appendleft(command.pack_command_tuple())
+        elif self.transfer_mode == self.TransferMode.RENAME_OLD:
+            # not implemented yet
+            pass
+        if len(self.file_data) > self.allowed_file_data_size:
+            # Large file, create file with init_data
+            init_data = self.file_data[0:self.allowed_file_data_size]
+        else:
+            # Small file, one packet for file creation sufficient
+            command = generate_create_file_srv23_1_packet(
+                self.target_filename, self.target_repository, ssc, self.max_size_of_app_data,
+                self.file_data)
+            ssc += 1
+            self.tc_queue.appendleft(command.pack_command_tuple())
+            return
+
+        # Create large file.
+        command = generate_create_file_srv23_1_packet(
+            self.target_filename, self.target_repository, ssc, self.max_size_of_app_data,
+            init_data)
+        ssc += 1
+        self.tc_queue.appendleft(command.pack_command_tuple())
+
+        rest_of_data = self.file_data[self.allowed_file_data_size:]
+        # Generate the rest of the packets to write to large file
+        self.__generate_append_to_file_packets_automatically(rest_of_data, ssc)
+
+    def __generate_append_to_file_packets_automatically(self, data: bytearray, init_ssc: int):
+        """
+        This function generates PUS packets which is used to write data in a file.
+        A new file will be created if not already existing. If the file already exists, this might
+        lead to
+
+        If the file data is larger than the maximum allowed size of application data, this function
+        will split the data into multiple packets and increment the initial SSC number by one for
+        each packet.
+        @param data: Data which will be split up.
+        @param init_ssc: First SSC, which will be incremented for each packet.
+        """
+        header = self.object_id
+        header += bytearray(self.target_repository, 'utf-8')
+        # Add string terminator of repository path
+        header.append(0)
+        header += bytearray(self.target_filename, 'utf-8')
+        # Add string terminator of filename
+        header.append(0)
+        self.__split_large_file(header, self.max_size_of_app_data, data, init_ssc)
+
+    def __split_large_file(self, header: bytearray, size_of_data_blocks: int,
+                           data: bytearray, init_ssc: int):
+        """
+        This function splits a large file in multiple packets and packs the generated packets
+        into the member deque. This is necessary because the packet size is limited.
+        @param header: Repository and file name which will always stay the same
+        @param size_of_data_blocks: The file data blocks will have this size
+        @param data: The data to pack in multiple packets
+        @param init_ssc: The ssc of the first command, will be incremented by one for each packet.
+        """
+        number_of_packets = math.floor(len(data) / size_of_data_blocks)
+        packet_number = 0
+
+        for i in range(number_of_packets):
+            header.append(packet_number >> 8)
+            header.append(0xFF & packet_number)
+            header += data[i * size_of_data_blocks:(i + 1) * size_of_data_blocks]
+
+            commands = PusTelecommand(service=23, subservice=128, ssc=init_ssc + i,
+                                      app_data=header)
+            self.tc_queue.appendleft(commands.pack_command_tuple())
+
+            # Remove everything except the header
+            header = header[:len(header) - size_of_data_blocks - 2]
+            packet_number = packet_number + 1
+        header.append(packet_number >> 8)
+        header.append(0xFF & packet_number)
+        header += data[number_of_packets * size_of_data_blocks:len(data)]
+        commands = PusTelecommand(service=23, subservice=128, ssc=init_ssc + packet_number,
+                                  app_data=header)
+        self.tc_queue.appendleft(commands.pack_command_tuple())
 
 
-def generate_rm_file_srv23_2_packet(filename: str, repository_path: str = "",
-                                    object_id=bytearray([])):
+def generate_create_file_srv23_1_packet(
+        filename: str, repository_path: str, ssc: int, max_size_of_app_data: int,
+        initial_data=bytearray([]), object_id=g.SD_CARD_HANDLER_ID):
+    if len(initial_data) > calculate_allowed_file_data_size(
+            max_size_of_app_data, filename, repository_path):
+        LOGGER.error("generate_create_file_srv23_1_packet: Initial data too large!")
+        return None
+    data_to_pack = object_id
+    data_to_pack += bytearray(repository_path, 'utf-8')
+    # Add string terminator to repository_path
+    data_to_pack.append(0)
+    data_to_pack += bytearray(filename, 'utf-8')
+    # Add string terminator to filename
+    data_to_pack.append(0)
+
+    data_to_pack += initial_data
+    return PusTelecommand(service=23, subservice=1, ssc=ssc, app_data=data_to_pack)
+
+
+def generate_rm_file_srv23_2_packet(filename: str, repository_path: str,
+                                    ssc: int, object_id=g.SD_CARD_HANDLER_ID):
     """
     This function generates a packet which is used to delete a file on a
     file-system-capable on-board memory.
     @param filename: The name of the file to delete
     @param repository_path: The path where the directory shall be created
+    @param ssc: source sequence count
     @param object_id: The object ID of the memory handler which manages the file system
     :return The TC[23,2] PUS packet
     """
@@ -28,7 +202,7 @@ def generate_rm_file_srv23_2_packet(filename: str, repository_path: str = "",
     data_to_pack += bytearray(filename, 'utf-8')
     # Add string terminator to filename
     data_to_pack.append(0)
-    return PusTelecommand(service=23, subservice=2, ssc=21, app_data=data_to_pack)
+    return PusTelecommand(service=23, subservice=2, ssc=ssc, app_data=data_to_pack)
 
 
 def generate_mkdir_srv23_9_packet(directory_name: str, repository_path: str = "",
@@ -69,27 +243,9 @@ def generate_rmdir_srv23_10_packet(directory_name: str, repository_path: str = "
     return PusTelecommand(service=23, subservice=10, ssc=21, app_data=data_to_pack)
 
 
-def generate_service23_subservice128_packet(
-        tc_queue: Deque, repository_path: str, filename: str, max_size_of_app_data: int,
-        file_data: bytearray = bytearray([]), init_ssc: int = 0,
-        object_id: bytearray = g.SD_CARD_HANDLER_ID):
-    """
-    This function generates PUS packets which is used to write data in a file.
-    A new file will be created if not already existing. If the file already exists, this might
-    lead to
-
-    If the file data is larger than the maximum allowed size of application data, this function
-    will split the data into multiple packets and increment the initial SSC number by one for
-    each packet.
-
-    @param tc_queue: Deque containing the PusTelecommand objects to send.
-    @param repository_path: The path of the target file
-    @param filename: Name of file from which the content shall be read
-    @param max_size_of_app_data: Maximum size of one data block. The file
-    @param file_data: The data to write in the file
-    @param init_ssc: First SSC, which will be incremented for each packet.
-    @param object_id: object ID of the memory handler (e.g. SD Card Handler)
-    """
+def generate_append_to_file_srv23_128_packet(
+        filename: str, repository_path: str, ssc: int, file_data: bytearray = bytearray([]),
+        object_id=g.SD_CARD_HANDLER_ID):
     data_to_pack = object_id
     data_to_pack += bytearray(repository_path, 'utf-8')
     # Add string terminator of repository path
@@ -97,46 +253,12 @@ def generate_service23_subservice128_packet(
     data_to_pack += bytearray(filename, 'utf-8')
     # Add string terminator of filename
     data_to_pack.append(0)
-    split_large_file(tc_queue, data_to_pack, max_size_of_app_data, file_data, init_ssc)
+    data_to_pack += file_data
+    return PusTelecommand(service=23, subservice=128, ssc=ssc, app_data=data_to_pack)
 
 
-def split_large_file(tc_queue: Deque, data_to_pack: bytearray, size_of_data_blocks: int,
-                     data: bytearray, init_ssc: int):
-    """
-    This function splits a large file in multiple packets.
-    This is necessary because the packet size is limited.
-    @param tc_queue: Deque which will contain a a PusTelecommand tuple.
-    @param data_to_pack: bytearray of data. data will be split and appended to this bytearray
-    @param size_of_data_blocks: The file is splitted in data blocks of this size
-    @param data: The data to pack in multiple packets
-    @param init_ssc: The ssc of the first command, will be incremented by one for each packet.
-    @return List containing the PUS packets generated for each data block
-    """
-    number_of_packets = math.floor(len(data) / size_of_data_blocks)
-    packet_number = 0
-
-    for i in range(number_of_packets):
-        data_to_pack.append(packet_number >> 8)
-        data_to_pack.append(0xFF & packet_number)
-        data_to_pack += data[i * size_of_data_blocks:(i + 1) * size_of_data_blocks]
-
-        commands = PusTelecommand(service=23, subservice=128, ssc=init_ssc + i, app_data=data_to_pack)
-        tc_queue.appendleft(commands.pack_command_tuple())
-
-        # Last data block, packet number and data block size is removed to create new command with
-        # next data block, packet number
-        data_to_pack = data_to_pack[:len(data_to_pack) - size_of_data_blocks - 2]
-        packet_number = packet_number + 1
-    data_to_pack.append(packet_number >> 8)
-    data_to_pack.append(0xFF & packet_number)
-    data_to_pack += data[number_of_packets * size_of_data_blocks:len(data)]
-    commands = PusTelecommand(service=23, subservice=128, ssc=init_ssc + packet_number,
-                              app_data=data_to_pack)
-    tc_queue.appendleft(commands.pack_command_tuple())
-
-
-def generate_service23_subservice129_packet(repository_path: str, filename: str,
-                                            object_id: bytearray = bytearray([])):
+def generate_read_file_srv23_129_packet(repository_path: str, filename: str,
+                                        object_id: bytearray = bytearray([])):
     """
     This function generates the application data field for a PUS packet with service
     23 and subservie 129. Subservice 129 is a custom service to request the data of a file.
@@ -183,3 +305,8 @@ def pack_service23_test_into(tc_queue: Deque) -> Deque:
     # tc_queue.appendleft(command.pack_command_tuple())
     tc_queue.appendleft(("print", "\r"))
     return tc_queue
+
+
+def calculate_allowed_file_data_size(max_app_data_size: int, filename: str, repository: str):
+    # Subtract two because of '\0' terminators
+    return max_app_data_size - len(filename) - len(repository) - 2
diff --git a/utility/obsw_binary_uploader.py b/utility/obsw_binary_uploader.py
index 64cdde40a121499a84c0f67bc0e7a48a552deb5a..a731e443144d213a7eaea077f5e83b313e8f16f6 100644
--- a/utility/obsw_binary_uploader.py
+++ b/utility/obsw_binary_uploader.py
@@ -12,7 +12,7 @@ from tkinter import filedialog
 from collections import deque
 
 from tmtc_core.comIF.obsw_com_interface import CommunicationInterface
-from tc.obsw_tc_service23 import generate_service23_subservice128_packet, \
+from tc.obsw_tc_service23 import generate_append_to_file_packets_automatically, \
     generate_rmdir_srv23_10_packet
 import config.obsw_config as g
 
@@ -52,7 +52,7 @@ def perform_binary_upload(comIF: CommunicationInterface):
     generate_rmdir_srv23_10_packet()
 
     # We have to split the binary here first
-    generate_service23_subservice128_packet(tc_queue, "BIN/AT91/BL", "bl.bin", 1024, data_to_read)
+    generate_append_to_file_packets_automatically(tc_queue, "BIN/AT91/BL", "bl.bin", 1024, data_to_read)
     while tc_queue:
         (tc_packet, tc_info) = tc_queue.pop()
         comIF.send_telecommand(tc_packet, tc_info)