Description

The DCM stands for “Device Controller Monitor”, and as the name suggests, it is the interface that allows users to control the pacemaker device. The pacemaker has several modes, each for a certain situation; for ex. mode for when the patient is at rest vs mode for when the patient is running. Each mode requires different parameters to be set so that the pacemaker functions according to the needs of its patient. The pacemaker is the primary tool to do this; it can set or retrieve parameter data from the pacemaker without being too invasive. This makes it a lot more convenient for doctors to adjust the pacemaker’s behaviours during follow-ups with their patient. This is also safer for the patient since they don’t have to pull the pacemaker out of their body. The DCM also allows doctors to verify the behaviour of the pacemaker through the electrocardiogram which visualizes the heart’s electrical activity. The DCM was implemented entirely in Python using a handful of libraries, most notably: Tkinter, PySerial, and Matplotlib.

Images

DCM welcome/landing page
Registration page for new users
Login page for existing users
DCM parameter input window, current mode = AOOR
Successfully sending data to pacemaker and verifying it
Atrial and ventricular chamber data from pacemaker plotted in ECG

Notes

This is the DCM part of the pacemaker project for my SFWRENG 3K04 course at McMaster during my 3rd year. I worked on this project in a group of 6 which was split into two teams: a team of 4 focused on programming the pacemaker, and a team of 2 focused on the DCM (which I was a part of). The course taught me about the importance of software design principles, architecture, documentation, and testing. All of these concepts had to be implemented in the course project in one way or another.

Some of the software design principles that I learned and implemented in the project include modularity, coupling, cohesion, OOP, USES relationship, and information hiding. The DCM design was split up into several modules, each responsible for a specific function of the DCM and independent of the other modules (for the most part). For example, the “registerPage” module is responsible for setting up the DCM’s registration page and has functions committed to placing GUI elements for the user to enter their username and password as well as verifying and writing the data entered.

A challenge that my team faced was connecting the DCM windows to one another as Tkinter requires a reference to a Tkinter window in order to connect it with others. This could have been done by placing each window into one module and passing the references as global variables, however we tried this and the code got messy quickly. Instead we opted to use OOP, each window is its own object of which an instance can be created and passed to the module of the top level window that it connects to. For example, the welcome page (top level) creates instances of the login and registration pages in order to connect them with the rest of the DCM.

There was still some level of dependence between modules as they had to connect with one another and in some cases use each other's functions. This meant I had to consider USES relationships between each module, for ex. the “pmParams” module uses functions from the “paramChecking” and “pacemakerModes” modules, which in turn uses the “writePMParams” module. Each function also had to be implemented with information hiding in mind so that they wouldn’t affect the behaviour of module’s using them. Information hiding is the idea of hiding a system’s (or function in this case) implementation from users. This makes it easier for users to use the system as they only need to know what they can input and what they should expect as an output. Furthermore, any changes to the implementation of the function won’t affect the modules that have used them as they only have to provide inputs to the function.

The implementation of these principles made debugging and testing the DCM a lot simpler. Each module could be tested separately because of the low coupling between modules. Any bugs that were encountered during the testing of a module could be found in that module because of this property. Furthermore, the USES relationship told me what order to test the modules in as I couldn’t test the parents (users) before testing the childrens (used). Most functions could be tested through black-box tests as they could be given inputs and provided outputs which could be analyzed to make sure the behaviour is as expected.

The development period had its fair share of problems outside of just missing brackets and semicolons during debugging. There were a few challenges with working in a team of 6, especially since it was my first time working in a team this large and we had to split the team in two to work on different parts of the project. These challenges got more difficult with COVID interfering with the regular operations of the course and making it difficult for the team to meet in person.

In the past, this course was in-person but thanks to COVID everything had to be pushed online and thus multiple changes had to be made to the requirements of the course project. To start, the course project began a lot later than it should have because the pacemaker development kits had to be shipped to students internationally and so we had to wait for everybody to get their kits. This timeline change led to some modifications to the project specification documentations, however these changes were not properly communicated by the TA’s (teacher’s assistants) which led to confusion within groups. In my case, I believed we had to account for all the pacemaker parameters and did so in the DCM. However when I met with my group later that week I was told that wasn’t the case and instead the specifications had been changed during a lab session I didn’t attend which led to a disagreement. In order to clear up the mistake we consulted the head TA which clarified that my teammates were indeed correct and led to the specification document getting updated.

COVID also made it difficult for communication between teams. When the course was in-person, teams would meet up in assigned lab sessions to work on the pacemaker where they could get live feedback from each other and even consult TAs. With everything now being online, our group had to find a new workflow and method of communication between each other and TAs. As a team we elected to have one mandatory meeting every week on the Discord app where we would discuss each sub-team’s progress and any points we needed clarifications from the TAs on. We communicated more often in our sub-teams to discuss what each member was working on, clarification with each other’s implementations, and choosing a version control platform (my partner and I chose Github). During the integration phase (where the DCM had to properly communicate with the pacemaker to have a working system) at least one member from both teams had to be present.

Thanks to the struggles and the experience I’ve gained from this course, I feel that I’ve become a stronger programmer and team member. I’ve strived to implement these software principles in whatever software project I’ve worked on ever since (like my team’s OEC device). I’ve also made sure that I’m communicating regularly with my teammates to make sure everyone is on the same page. I do wish that I could improve certain aspects of the project which had to be rushed due to time constraints like the UI of the DCM and the readability of the code. Unfortunately, I don’t think I’ll get the chance to change much since the pacemaker kits had to be returned after the course was finished. Nonetheless, I still have the experience and knowledge that I’ve gained from the course and I’m grateful for it.

Visit my GitHub repo for the project’s code and more information.