Continue implementing PC build

The PC build now brings up an empty Qt window. It also runs the
programmer firmware in the background in another thread. This also adds
a shell script you can use to create the USB gadget.
This commit is contained in:
Doug Brown 2021-07-25 16:21:36 -07:00
parent 1397a49921
commit 3fd01f77d8
15 changed files with 771 additions and 4 deletions

View File

@ -22,8 +22,9 @@ add_executable(SIMMProgrammer.elf ${SOURCES} ${HWSOURCES})
# Common compiler options
target_compile_options(SIMMProgrammer.elf PRIVATE
-Wall -Os -std=gnu99 -ffunction-sections -fdata-sections
-Wall -Os -ffunction-sections -fdata-sections
)
set_property(TARGET SIMMProgrammer.elf PROPERTY C_STANDARD 99)
# Common linker options
target_link_options(SIMMProgrammer.elf PRIVATE

95
hal/pc/main.cpp Normal file
View File

@ -0,0 +1,95 @@
/*
* main.cpp
*
* Created on: Jul 25, 2021
* Author: Doug
*
* Copyright (C) 2011-2021 Doug Brown
*
* 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 2
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "mainwindow.h"
#include "programmerthread.h"
#include "usbsimulationmanager.h"
extern "C"
{
#include "usbcdc_hw.h"
}
#include <QApplication>
#include <QDir>
#include <QMessageBox>
/**
* @brief Performs a bunch of sanity checks to make sure we are empowered to simulate a USB device
* @return True if we are good to go, false if an error occurred.
*
* If there's a problem, show a message informing the user what's wrong.
*/
bool DoSanityChecks(void)
{
// Make sure configfs is available
if (USBSimulationManager::configFSPath().isEmpty())
{
QMessageBox::critical(nullptr, "Mountpoint missing", "The configfs filesystem doesn't seem to be mounted on this system. Try running the following command to mount it:\n\n"
"sudo mount -t configfs configfs /sys/kernel/config\n\n");
return false;
}
if (USBSimulationManager::localGadgetDir().isEmpty())
{
QMessageBox::critical(nullptr, "USB gadget not ready", "Could not locate the simulated USB gadget. Have you run the setup_usb_simulation.sh script as root?");
return false;
}
if (USBSimulationManager::localGadgetPortDevice().isEmpty())
{
QMessageBox::critical(nullptr, "USB gadget not ready", "Could not locate the TTY device for the simulated USB gadget. Have you run the setup_usb_simulation.sh script as root?");
return false;
}
// We made it, we should be good to go.
return true;
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// Start by performing a bunch of sanity checks to make sure we actually have a simulated
if (!DoSanityChecks())
{
return EXIT_FAILURE;
}
// Start out with the simulated device disconnected
USBSimulationManager::disconnectGadget();
// Tell the simulated device which port to open
USBCDC_SetPortName(USBSimulationManager::localGadgetPortDevice().toUtf8().constData());
// Run the programmer thread. Note: this is crude -- I just leave it as a dangling object
// with no owner. This seems to be the best way to terminate the thread when closing the
// program though. If I intentionally try to stop the thread, it doesn't work properly.
ProgrammerThread *programmer = new ProgrammerThread();
programmer->start();
// Now we can initialize the system
MainWindow w;
w.show();
return a.exec();
}

66
hal/pc/mainwindow.cpp Normal file
View File

@ -0,0 +1,66 @@
/*
* mainwindow.cpp
*
* Created on: Jul 25, 2021
* Author: Doug
*
* Copyright (C) 2011-2021 Doug Brown
*
* 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 2
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "usbsimulationmanager.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_connectButton_clicked()
{
if (ui->connectButton->text() == "Connect")
{
if (USBSimulationManager::connectGadget())
{
ui->connectButton->setText("Disconnect");
}
else
{
// TODO: error
}
}
else
{
if (USBSimulationManager::disconnectGadget())
{
// TODO: reset simulator state so when we reconnect it's all fresh
ui->connectButton->setText("Connect");
}
else
{
// TODO: error
}
}
}

49
hal/pc/mainwindow.h Normal file
View File

@ -0,0 +1,49 @@
/*
* mainwindow.h
*
* Created on: Jul 25, 2021
* Author: Doug
*
* Copyright (C) 2011-2021 Doug Brown
*
* 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 2
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_connectButton_clicked();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H

45
hal/pc/mainwindow.ui Normal file
View File

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<widget class="QPushButton" name="connectButton">
<property name="geometry">
<rect>
<x>30</x>
<y>20</y>
<width>99</width>
<height>27</height>
</rect>
</property>
<property name="text">
<string>Connect</string>
</property>
</widget>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>25</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -2,3 +2,12 @@
target_include_directories(SIMMProgrammer.elf PRIVATE
hal/pc
)
# PC-specific compile options
target_compile_definitions(SIMMProgrammer.elf PRIVATE
IS_PC_BUILD=1
)
set_property(TARGET SIMMProgrammer.elf PROPERTY CMAKE_CXX_STANDARD 11)
# Link against Qt
target_link_libraries(SIMMProgrammer.elf PRIVATE Qt5::Widgets Qt5::Concurrent)

View File

@ -2,7 +2,18 @@
set(HWSOURCES
hal/pc/board.c
hal/pc/gpio.c
hal/pc/main.cpp
hal/pc/mainwindow.cpp
hal/pc/mainwindow.ui
hal/pc/parallel_bus.c
hal/pc/programmerthread.cpp
hal/pc/spi.c
hal/pc/usbcdc.c
hal/pc/usbsimulationmanager.cpp
)
# Use Qt on the PC build to create a nice GUI
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
find_package(Qt5 COMPONENTS Widgets Concurrent REQUIRED)

View File

@ -0,0 +1,38 @@
/*
* programmerthread.cpp
*
* Created on: Jul 25, 2021
* Author: Doug
*
* Copyright (C) 2011-2021 Doug Brown
*
* 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 2
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "programmerthread.h"
extern "C" int programmer_thread_main(void);
ProgrammerThread::ProgrammerThread(QObject *parent) :
QThread(parent)
{
}
void ProgrammerThread::run()
{
programmer_thread_main();
}

40
hal/pc/programmerthread.h Normal file
View File

@ -0,0 +1,40 @@
/*
* programmerthread.h
*
* Created on: Jul 25, 2021
* Author: Doug
*
* Copyright (C) 2011-2021 Doug Brown
*
* 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 2
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef PROGRAMMERTHREAD_H
#define PROGRAMMERTHREAD_H
#include <QThread>
class ProgrammerThread : public QThread
{
Q_OBJECT
public:
ProgrammerThread(QObject *parent = nullptr);
protected:
virtual void run();
};
#endif // PROGRAMMERTHREAD_H

170
hal/pc/setup_usb_simulation.sh Executable file
View File

@ -0,0 +1,170 @@
#!/bin/sh
F_ACM_MODULE_SYSFS_PATH=/sys/module/usb_f_acm
DUMMY_HCD_MODULE_SYSFS_PATH=/sys/module/dummy_hcd
SIMMPROGRAMMER_VID=0x16d0
SIMMPROGRAMMER_PID=0x06aa
find_configfs_dir() {
# Now grab the current configfs location
FOUND_DIR=$(mount | grep -m 1 "^configfs on" | sed "s/^configfs on \(.*\) type .*$/\1/")
if [ ! -d "$FOUND_DIR" ]; then
echo "Error: Something strange happened while trying to locate the configfs mountpoint. You should make sure you have configfs mounted in the usual location (/sys/kernel/config)." >&2
exit 1
fi
echo $FOUND_DIR
}
start_gadget() {
# If the acm module isn't loaded, try loading it manually
if [ ! -d $F_ACM_MODULE_SYSFS_PATH ]; then
modprobe usb_f_acm
if [ $? -ne 0 ]; then
echo "Error: Unable to load usb_f_acm kernel module." >&2
exit 1
fi
fi
# Same with dummy_hcd
if [ ! -d $DUMMY_HCD_MODULE_SYSFS_PATH ]; then
modprobe dummy_hcd
if [ $? -ne 0 ]; then
echo "Error: Unable to load dummy_hcd kernel module." >&2
echo "Note: Many Linux distributions don't come with this module by default. You may need to compile it yourself. See the README file for more details." >&2
exit 1
fi
fi
# Make sure we have a dummy_udc to use
if [ ! -d /sys/class/udc/dummy_udc.0 ]; then
echo "Error: Can't find a dummy UDC device to use in /sys/class/udc" >&2
exit 1
fi
# locate configfs, mount it if it's not already loaded
CONFIGFS_LINE_COUNT=$(mount | grep -c "^configfs on ")
if [ $CONFIGFS_LINE_COUNT -lt 1 ]; then
# Try to mount it ourselves if we couldn't
mount -t configfs configfs /sys/kernel/config
fi
# Check one more time
CONFIGFS_LINE_COUNT=$(mount | grep -c "^configfs on ")
if [ $CONFIGFS_LINE_COUNT -lt 1 ]; then
echo "Error: Unable to find configfs. Is your kernel configured with configfs support?" >&2
exit 1
fi
# Now grab the current configfs location
CONFIGFS_DIR=$(find_configfs_dir)
# Check if we have the usb_gadget subdir
if [ ! -d "$CONFIGFS_DIR/usb_gadget" ]; then
echo "Error: The configfs filesystem doesn't seem to contain a usb_gadget subdirectory. Make sure your kernel is compiled with configfs support for USB gadgets." >&2
exit 1
fi
# Make sure we can't find an existing gadget that's set up as us
cd "$CONFIGFS_DIR/usb_gadget"
for g in */; do
if [ -d "$g" ]; then
VID=$(cat "$g/idVendor")
PID=$(cat "$g/idProduct")
if [ $VID = $SIMMPROGRAMMER_VID -a $PID = $SIMMPROGRAMMER_PID ]; then
echo "Error: The gadget is already started" >&2
exit 1
fi
fi
done
# Find the first empty gadget slot to use
COUNTER=1
while [ -d "$CONFIGFS_DIR/usb_gadget/g$COUNTER" ]; do
COUNTER=$((COUNTER+1))
done
NEWGADGET="g$COUNTER"
# Create the gadget and configure it
mkdir "$CONFIGFS_DIR/usb_gadget/$NEWGADGET"
cd "$CONFIGFS_DIR/usb_gadget/$NEWGADGET"
echo 0x16d0 > idVendor
echo 0x06aa > idProduct
mkdir strings/0x0409
echo "Doug Brown" > strings/0x0409/manufacturer
echo "Mac ROM SIMM Programmer" > strings/0x0409/product
echo "0" > strings/0x0409/serialnumber
mkdir functions/acm.GS0
echo 0 > functions/acm.GS0/console
mkdir configs/c.1
ln -s functions/acm.GS0 configs/c.1/
# Set up permissions so any user can connect/disconnect the USB device.
# This will allow us to hotplug directly inside the PC build while not root.
chmod 666 UDC
# Don't plug it in yet; use connect_gadget for that
echo "Created dummy SIMM programmer gadget"
}
stop_gadget() {
FOUND_ANY=false
# Now grab the current configfs location
CONFIGFS_DIR=$(find_configfs_dir)
# Check if we have the usb_gadget subdir
if [ -d "$CONFIGFS_DIR/usb_gadget" ]; then
# Find any existing gadget that is set up as us, and destroy it
cd "$CONFIGFS_DIR/usb_gadget"
for g in */; do
if [ -d "$g" ]; then
VID=$(cat "$g/idVendor")
PID=$(cat "$g/idProduct")
if [ $VID = $SIMMPROGRAMMER_VID -a $PID = $SIMMPROGRAMMER_PID ]; then
# Disconnect the gadget if it's already connected to a UDC
CURUDC=$(cat $g/UDC)
if [ x$CURUDC != x ]; then
echo "" > $g/UDC
fi
# Then destroy the rest of it
rm $g/configs/c.1/acm.GS0
rmdir $g/configs/c.1
rmdir $g/functions/acm.GS0
rmdir $g/strings/0x0409
rmdir $g
FOUND_ANY=true
fi
fi
done
fi
if $FOUND_ANY; then
echo "Deleted dummy SIMM programmer gadget"
else
echo "Error: Couldn't find a dummy SIMM programmer gadget to delete." >&2
exit 1
fi
}
# Make sure they supplied a command
if [ $# -ne 1 ]; then
echo "Usage: $0 <start|stop>" >&2
exit 1
fi
# Make sure we are root
if [ $(whoami) != "root" ]; then
echo "This script has to be run as root." >&2
exit 1
fi
# Parse the command and run the function for it
if [ $1 = "start" ]; then
start_gadget
elif [ $1 = "stop" ]; then
stop_gadget
else
echo "Invalid command: $1" >&2
exit 1
fi

View File

@ -31,9 +31,11 @@
#include <termios.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/limits.h>
#include <string.h>
/// The emulated USB CDC serial port associated with the faked USB device
static const char *gadgetPort = "/dev/ttyGS0";
static char gadgetPort[PATH_MAX];
/// File descriptor for the port
static int gadgetfd;
@ -42,6 +44,13 @@ static int gadgetfd;
*/
void USBCDC_Init(void)
{
// Bail if we haven't initialized the gadgetPort variable yet.
// It's the responsibility of the simulation to set that up ahead of time.
if (gadgetPort[0] == 0)
{
return;
}
// Attempt to open the device end of the USB CDC gadget.
gadgetfd = open(gadgetPort, O_RDWR | O_CLOEXEC | O_NOCTTY);
if (gadgetfd < 0)
@ -151,3 +160,13 @@ void USBCDC_Flush(void)
{
tcflush(gadgetfd, TCOFLUSH);
}
/**
* @brief Sets the port name to use for the simulated CDC serial port
* @param portName The port name (typically /dev/ttyGS0)
*/
void USBCDC_SetPortName(const char *portName)
{
strncpy(gadgetPort, portName, sizeof(gadgetPort));
gadgetPort[sizeof(gadgetPort) - 1] = 0;
}

View File

@ -22,8 +22,8 @@
*
*/
#ifndef HAL_AT90USB646_USBCDC_HW_H_
#define HAL_AT90USB646_USBCDC_HW_H_
#ifndef HAL_PC_USBCDC_HW_H_
#define HAL_PC_USBCDC_HW_H_
#include "../../util.h"
#include <stdint.h>
@ -34,5 +34,6 @@ bool USBCDC_SendData(uint8_t const *data, uint16_t len);
int16_t USBCDC_ReadByte(void);
uint8_t USBCDC_ReadByteBlocking(void);
void USBCDC_Flush(void);
void USBCDC_SetPortName(const char *portName);
#endif /* HAL_AT90USB646_USBCDC_HW_H_ */

View File

@ -0,0 +1,179 @@
#include "usbsimulationmanager.h"
#include <QDir>
/// File in proc to find current mountpoints
#define MOUNTS_FILE "/proc/mounts"
/// File type to look for in mounts for configfs
#define CONFIGFS_FS_TYPE "configfs"
/// Subdirectory in configfs for usb gadget setup
#define CONFIGFS_USB_GADGET_SUBDIR "usb_gadget"
/// The vendor ID of the SIMM programmer, in string format matching configfs idVendor
#define SIMMPROGRAMMER_VID_STRING "0x16d0"
/// The product ID of the SIMM programmer, in string format matching configfs idProduct
#define SIMMPROGRAMMER_PID_STRING "0x06aa"
/**
* @brief Determines the path to configfs (if it's mounted)
* @return The path to it, or an empty string if it's not mounted
*/
QString USBSimulationManager::configFSPath()
{
// Open up /proc/mounts
QFile mounts(MOUNTS_FILE);
if (!mounts.open(QFile::ReadOnly))
{
return QString();
}
// Search for configfs as a mountpoint
QByteArray line("l");
while (!line.isEmpty())
{
line = mounts.readLine();
QList<QByteArray> components = line.split(' ');
if (components.count() >= 2 && components[0] == CONFIGFS_FS_TYPE)
{
// We found it! The second component is the mountpoint.
return QString::fromUtf8(components[1]);
}
}
// No need to close the file, it will automatically be closed when we return.
// Return an empty string if we didn't find it
return QString();
}
/**
* @brief Gets the path to the gadget directory in configfs for the SIMM programmer, if it exists
* @return The path to the gadget directory, or an empty string if we can't locate it
*/
QString USBSimulationManager::localGadgetDir()
{
QString configFSDirPath = configFSPath();
if (!configFSDirPath.isEmpty())
{
QDir dir(configFSDirPath);
if (dir.exists() && dir.cd(CONFIGFS_USB_GADGET_SUBDIR))
{
foreach (QString const &g, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot))
{
QByteArray vendor, product;
QDir gDir = dir;
gDir.cd(g);
QFile f(gDir.absoluteFilePath("idVendor"));
if (f.open(QFile::ReadOnly))
{
vendor = f.readAll().trimmed();
f.close();
}
f.setFileName(gDir.absoluteFilePath("idProduct"));
if (f.open(QFile::ReadOnly))
{
product = f.readAll().trimmed();
f.close();
}
// If it matches product and vendor ID, we can assume we got it.
if (vendor == SIMMPROGRAMMER_VID_STRING &&
product == SIMMPROGRAMMER_PID_STRING)
{
return gDir.absolutePath();
}
}
}
}
// If we can't find it, bail
return QString();
}
/*
* usbsimulationmanager.cpp
*
* Created on: Jul 25, 2021
* Author: Doug
*
* Copyright (C) 2011-2021 Doug Brown
*
* 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 2
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
/**
* @brief Gets the path to the TTY device representing the simulated port
* @return The path, or an empty string if we can't figure it out
*/
QString USBSimulationManager::localGadgetPortDevice()
{
QString g = localGadgetDir();
if (!g.isEmpty())
{
QDir gDir(g);
if (gDir.cd("functions/acm.GS0"))
{
QFile f(gDir.absoluteFilePath("port_num"));
if (f.open(QFile::ReadOnly))
{
QByteArray number = f.readAll().trimmed();
f.close();
QString path = "/dev/ttyGS" + QString::fromUtf8(number);
if (QFile::exists(path))
{
return path;
}
}
}
}
// If we can't find it, bail
return QString();
}
/**
* @brief Attempts to connect the simulated USB device to the host
* @return True on success, false on failure
*/
bool USBSimulationManager::connectGadget()
{
bool success = false;
QDir gd(localGadgetDir());
QFile controlFile(gd.absoluteFilePath("UDC"));
if (controlFile.exists() && controlFile.open(QFile::WriteOnly))
{
success = controlFile.write("dummy_udc.0\n") > 0;
controlFile.close();
}
return success;
}
/**
* @brief Attempts to connect the simulated USB device to the host
* @return True on success, false on failure
*/
bool USBSimulationManager::disconnectGadget()
{
bool success = false;
QDir gd(localGadgetDir());
QFile controlFile(gd.absoluteFilePath("UDC"));
if (controlFile.exists() && controlFile.open(QFile::WriteOnly))
{
success = controlFile.write("\n") > 0;
controlFile.close();
}
return success;
}

View File

@ -0,0 +1,40 @@
/*
* usbsimulationmanager.h
*
* Created on: Jul 25, 2021
* Author: Doug
*
* Copyright (C) 2011-2021 Doug Brown
*
* 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 2
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef USBSIMULATIONMANAGER_H
#define USBSIMULATIONMANAGER_H
#include <QString>
class USBSimulationManager
{
public:
static QString configFSPath();
static QString localGadgetDir();
static QString localGadgetPortDevice();
static bool connectGadget();
static bool disconnectGadget();
};
#endif // USBSIMULATIONMANAGER_H

4
main.c
View File

@ -42,7 +42,11 @@
*
* @return Never; the main loop is an infinite loop.
*/
#if !IS_PC_BUILD
int main(void)
#else
int programmer_thread_main(void)
#endif
{
DisableInterrupts();
Board_Init();