Merge branch 'master' of git@scm.dev.nokia.troll.no:creator/mainline

This commit is contained in:
dt
2009-08-21 18:02:58 +02:00
56 changed files with 777 additions and 481 deletions

View File

@@ -426,6 +426,7 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
cmd = am->registerAction(m_showInFinder, ProjectExplorer::Constants::SHOWINFINDER, cmd = am->registerAction(m_showInFinder, ProjectExplorer::Constants::SHOWINFINDER,
globalcontext); globalcontext);
mfilec->addAction(cmd, Constants::G_FILE_OPEN); mfilec->addAction(cmd, Constants::G_FILE_OPEN);
mfolder->addAction(cmd, Constants::G_FOLDER_FILES);
#endif #endif
// Open With menu // Open With menu
@@ -592,6 +593,7 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
globalcontext); globalcontext);
mproject->addAction(cmd, Constants::G_PROJECT_FILES); mproject->addAction(cmd, Constants::G_PROJECT_FILES);
msubProject->addAction(cmd, Constants::G_PROJECT_FILES); msubProject->addAction(cmd, Constants::G_PROJECT_FILES);
mfolder->addAction(cmd, Constants::G_FOLDER_FILES);
// add existing file action // add existing file action
m_addExistingFilesAction = new QAction(tr("Add Existing Files..."), this); m_addExistingFilesAction = new QAction(tr("Add Existing Files..."), this);
@@ -599,6 +601,7 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
globalcontext); globalcontext);
mproject->addAction(cmd, Constants::G_PROJECT_FILES); mproject->addAction(cmd, Constants::G_PROJECT_FILES);
msubProject->addAction(cmd, Constants::G_PROJECT_FILES); msubProject->addAction(cmd, Constants::G_PROJECT_FILES);
mfolder->addAction(cmd, Constants::G_FOLDER_FILES);
// remove file action // remove file action
m_removeFileAction = new QAction(tr("Remove File..."), this); m_removeFileAction = new QAction(tr("Remove File..."), this);
@@ -1676,9 +1679,9 @@ void ProjectExplorerPlugin::updateContextMenuActions()
void ProjectExplorerPlugin::addNewFile() void ProjectExplorerPlugin::addNewFile()
{ {
if (!m_currentNode && m_currentNode->nodeType() == ProjectNodeType) QTC_ASSERT(m_currentNode, return)
return; QFileInfo fi(m_currentNode->path());
const QString location = QFileInfo(m_currentNode->path()).dir().absolutePath(); const QString location = (fi.isDir() ? fi.absoluteFilePath() : fi.absolutePath());
Core::ICore::instance()->showNewItemDialog(tr("New File", "Title of dialog"), Core::ICore::instance()->showNewItemDialog(tr("New File", "Title of dialog"),
Core::IWizard::wizardsOfKind(Core::IWizard::FileWizard) Core::IWizard::wizardsOfKind(Core::IWizard::FileWizard)
+ Core::IWizard::wizardsOfKind(Core::IWizard::ClassWizard), + Core::IWizard::wizardsOfKind(Core::IWizard::ClassWizard),
@@ -1687,11 +1690,12 @@ void ProjectExplorerPlugin::addNewFile()
void ProjectExplorerPlugin::addExistingFiles() void ProjectExplorerPlugin::addExistingFiles()
{ {
if (!m_currentNode && m_currentNode->nodeType() == ProjectNodeType) QTC_ASSERT(m_currentNode, return)
return;
ProjectNode *projectNode = qobject_cast<ProjectNode*>(m_currentNode); ProjectNode *projectNode = qobject_cast<ProjectNode*>(m_currentNode->projectNode());
Core::ICore *core = Core::ICore::instance(); Core::ICore *core = Core::ICore::instance();
const QString dir = QFileInfo(m_currentNode->path()).dir().absolutePath(); QFileInfo fi(m_currentNode->path());
const QString dir = (fi.isDir() ? fi.absoluteFilePath() : fi.absolutePath());
QStringList fileNames = QFileDialog::getOpenFileNames(core->mainWindow(), tr("Add Existing Files"), dir); QStringList fileNames = QFileDialog::getOpenFileNames(core->mainWindow(), tr("Add Existing Files"), dir);
if (fileNames.isEmpty()) if (fileNames.isEmpty())
return; return;
@@ -1741,8 +1745,7 @@ void ProjectExplorerPlugin::addExistingFiles()
void ProjectExplorerPlugin::openFile() void ProjectExplorerPlugin::openFile()
{ {
if (!m_currentNode) QTC_ASSERT(m_currentNode, return)
return;
Core::EditorManager *em = Core::EditorManager::instance(); Core::EditorManager *em = Core::EditorManager::instance();
em->openEditor(m_currentNode->path()); em->openEditor(m_currentNode->path());
em->ensureEditorManagerVisible(); em->ensureEditorManagerVisible();
@@ -1751,8 +1754,7 @@ void ProjectExplorerPlugin::openFile()
#ifdef Q_OS_MAC #ifdef Q_OS_MAC
void ProjectExplorerPlugin::showInFinder() void ProjectExplorerPlugin::showInFinder()
{ {
if (!m_currentNode) QTC_ASSERT(m_currentNode, return)
return;
QProcess::execute("/usr/bin/osascript", QStringList() QProcess::execute("/usr/bin/osascript", QStringList()
<< "-e" << "-e"
<< QString("tell application \"Finder\" to reveal POSIX file \"%1\"") << QString("tell application \"Finder\" to reveal POSIX file \"%1\"")
@@ -1765,8 +1767,7 @@ void ProjectExplorerPlugin::showInFinder()
void ProjectExplorerPlugin::removeFile() void ProjectExplorerPlugin::removeFile()
{ {
if (!m_currentNode && m_currentNode->nodeType() == FileNodeType) QTC_ASSERT(m_currentNode && m_currentNode->nodeType() == FileNodeType, return)
return;
FileNode *fileNode = qobject_cast<FileNode*>(m_currentNode); FileNode *fileNode = qobject_cast<FileNode*>(m_currentNode);
Core::ICore *core = Core::ICore::instance(); Core::ICore *core = Core::ICore::instance();
@@ -1937,7 +1938,7 @@ void ProjectExplorerPlugin::populateOpenWithMenu()
} }
} // matches } // matches
} }
m_openWithMenu->setEnabled(anyMatches); m_openWithMenu->setEnabled(anyMatches);
} }
void ProjectExplorerPlugin::openWithMenuTriggered(QAction *action) void ProjectExplorerPlugin::openWithMenuTriggered(QAction *action)

View File

@@ -961,11 +961,15 @@ FolderNode *FlatModel::visibleFolderNode(FolderNode *node) const
bool FlatModel::filter(Node *node) const bool FlatModel::filter(Node *node) const
{ {
bool isHidden = false; bool isHidden = false;
if (ProjectNode *projectNode = qobject_cast<ProjectNode*>(node)) { if (node->nodeType() == SessionNodeType) {
isHidden = false;
} else if (ProjectNode *projectNode = qobject_cast<ProjectNode*>(node)) {
if (m_filterProjects && projectNode->parentFolderNode() != m_rootNode) if (m_filterProjects && projectNode->parentFolderNode() != m_rootNode)
isHidden = !projectNode->hasTargets(); isHidden = !projectNode->hasTargets();
} } else if (node->nodeType() == FolderNodeType) {
if (FileNode *fileNode = qobject_cast<FileNode*>(node)) { if (m_filterProjects)
isHidden = true;
} else if (FileNode *fileNode = qobject_cast<FileNode*>(node)) {
if (m_filterGeneratedFiles) if (m_filterGeneratedFiles)
isHidden = fileNode->isGenerated(); isHidden = fileNode->isGenerated();
} }

View File

@@ -153,7 +153,11 @@ FolderNode::FolderNode(const QString &folderPath)
: Node(FolderNodeType, folderPath), : Node(FolderNodeType, folderPath),
m_folderName(folderPath) m_folderName(folderPath)
{ {
m_icon = QApplication::style()->standardIcon(QStyle::SP_DirIcon); static QIcon dirIcon;
if (dirIcon.isNull()) {
dirIcon = QApplication::style()->standardIcon(QStyle::SP_DirIcon);
}
m_icon = dirIcon;
} }
FolderNode::~FolderNode() FolderNode::~FolderNode()
@@ -549,8 +553,13 @@ void ProjectNode::watcherDestroyed(QObject *watcher)
/*! /*!
Sort pointers to FileNodes Sort pointers to FileNodes
*/ */
bool ProjectNode::sortNodesByPath(Node *f1, Node *f2) { bool ProjectNode::sortNodesByPath(Node *n1, Node *n2) {
return f1->path() < f2->path(); return n1->path() < n2->path();
}
bool ProjectNode::sortFolderNodesByName(FolderNode *f1, FolderNode *f2)
{
return f1->name() < f2->name();
} }
/*! /*!

View File

@@ -136,10 +136,10 @@ public:
virtual void accept(NodesVisitor *visitor); virtual void accept(NodesVisitor *visitor);
protected:
void setFolderName(const QString &name); void setFolderName(const QString &name);
void setIcon(const QIcon &icon); void setIcon(const QIcon &icon);
protected:
QList<FolderNode*> m_subFolderNodes; QList<FolderNode*> m_subFolderNodes;
QList<FileNode*> m_fileNodes; QList<FileNode*> m_fileNodes;
@@ -193,6 +193,7 @@ public:
void accept(NodesVisitor *visitor); void accept(NodesVisitor *visitor);
static bool sortNodesByPath(Node *n1, Node *n2); static bool sortNodesByPath(Node *n1, Node *n2);
static bool sortFolderNodesByName(FolderNode *f1, FolderNode *f2);
protected: protected:
// this is just the in-memory representation, a subclass // this is just the in-memory representation, a subclass

Binary file not shown.

After

Width:  |  Height:  |  Size: 311 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 223 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 676 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 267 B

View File

@@ -116,6 +116,217 @@ void Qt4PriFileNode::scheduleUpdate()
m_qt4ProFileNode->scheduleUpdate(); m_qt4ProFileNode->scheduleUpdate();
} }
namespace Qt4ProjectManager {
namespace Internal {
struct InternalNode
{
QMap<QString, InternalNode*> subnodes;
QStringList files;
ProjectExplorer::FileType type;
QString fullName;
QIcon icon;
~InternalNode()
{
qDeleteAll(subnodes);
}
// Creates a tree structure from a list of absolute file paths.
// Empty directories are compressed into a single entry with a longer path.
// * project
// * /absolute/path
// * file1
// * relative
// * path1
// * file1
// * file2
// * path2
// * file1
void create(const QString &projectDir, const QStringList &newFilePaths, ProjectExplorer::FileType type)
{
static const QChar separator = QChar('/');
const QString projectDirWithSeparator = projectDir + separator;
int projectDirWithSeparatorLength = projectDirWithSeparator.length();
foreach (const QString &file, newFilePaths) {
QString fileWithoutPrefix;
bool isRelative;
if (file.startsWith(projectDirWithSeparator)) {
isRelative = true;
fileWithoutPrefix = file.mid(projectDirWithSeparatorLength);
} else {
isRelative = false;
fileWithoutPrefix = file;
}
QStringList parts = fileWithoutPrefix.split(separator, QString::SkipEmptyParts);
if (!isRelative && parts.count() > 0)
parts[0].prepend(separator);
QStringListIterator it(parts);
InternalNode *currentNode = this;
QString path = (isRelative ? projectDir : "");
while (it.hasNext()) {
const QString &key = it.next();
path += separator + key;
if (it.hasNext()) { // key is directory
if (!currentNode->subnodes.contains(key)) {
InternalNode *val = new InternalNode;
val->type = type;
val->fullName = path;
currentNode->subnodes.insert(key, val);
currentNode = val;
} else {
currentNode = currentNode->subnodes.value(key);
}
} else { // key is filename
currentNode->files.append(file);
}
}
}
this->compress();
}
// Removes folder nodes with only a single sub folder in it
void compress()
{
static const QChar separator = QChar('/');
QMap<QString, InternalNode*> newSubnodes;
QMapIterator<QString, InternalNode*> i(subnodes);
while (i.hasNext()) {
i.next();
i.value()->compress();
if (i.value()->files.isEmpty() && i.value()->subnodes.size() == 1) {
QString key = i.value()->subnodes.keys().at(0);
newSubnodes.insert(i.key()+separator+key, i.value()->subnodes.value(key));
i.value()->subnodes.clear();
delete i.value();
} else {
newSubnodes.insert(i.key(), i.value());
}
}
subnodes = newSubnodes;
}
// Makes the projectNode's subtree below the given folder match this internal node's subtree
void updateSubFolders(Qt4PriFileNode *projectNode, ProjectExplorer::FolderNode *folder)
{
updateFiles(projectNode, folder, type);
// update folders
QList<FolderNode *> existingFolderNodes;
foreach (FolderNode *node, folder->subFolderNodes()) {
if (node->nodeType() != ProjectNodeType)
existingFolderNodes << node;
}
QList<FolderNode *> foldersToRemove;
QList<FolderNode *> foldersToAdd;
QList<InternalNode *> internalNodesToUpdate;
QList<FolderNode *> folderNodesToUpdate;
// newFolders is already sorted
qSort(existingFolderNodes.begin(), existingFolderNodes.end(), ProjectNode::sortFolderNodesByName);
QList<FolderNode*>::const_iterator existingNodeIter = existingFolderNodes.constBegin();
QMap<QString, InternalNode*>::const_iterator newNodeIter = subnodes.constBegin();;
while (existingNodeIter != existingFolderNodes.constEnd()
&& newNodeIter != subnodes.constEnd()) {
if ((*existingNodeIter)->name() < newNodeIter.key()) {
foldersToRemove << *existingNodeIter;
++existingNodeIter;
} else if ((*existingNodeIter)->name() > newNodeIter.key()) {
FolderNode *newNode = new FolderNode(newNodeIter.value()->fullName);
newNode->setFolderName(newNodeIter.key());
if (!newNodeIter.value()->icon.isNull())
newNode->setIcon(newNodeIter.value()->icon);
foldersToAdd << newNode;
internalNodesToUpdate << newNodeIter.value();
folderNodesToUpdate << newNode;
++newNodeIter;
} else { // *existingNodeIter->path() == *newPathIter
internalNodesToUpdate << newNodeIter.value();
folderNodesToUpdate << *existingNodeIter;
++existingNodeIter;
++newNodeIter;
}
}
while (existingNodeIter != existingFolderNodes.constEnd()) {
foldersToRemove << *existingNodeIter;
++existingNodeIter;
}
while (newNodeIter != subnodes.constEnd()) {
FolderNode *newNode = new FolderNode(newNodeIter.value()->fullName);
newNode->setFolderName(newNodeIter.key());
if (!newNodeIter.value()->icon.isNull())
newNode->setIcon(newNodeIter.value()->icon);
foldersToAdd << newNode;
internalNodesToUpdate << newNodeIter.value();
folderNodesToUpdate << newNode;
++newNodeIter;
}
if (!foldersToRemove.isEmpty())
projectNode->removeFolderNodes(foldersToRemove, folder);
if (!foldersToAdd.isEmpty())
projectNode->addFolderNodes(foldersToAdd, folder);
QList<FolderNode *>::const_iterator folderIt = folderNodesToUpdate.constBegin();
QList<InternalNode *>::const_iterator iNodeIt = internalNodesToUpdate.constBegin();
while (folderIt != folderNodesToUpdate.constEnd()
&& iNodeIt != internalNodesToUpdate.constEnd()) {
(*iNodeIt)->updateSubFolders(projectNode, *folderIt);
++folderIt;
++iNodeIt;
}
}
// Makes the folder's files match this internal node's file list
void updateFiles(Qt4PriFileNode *projectNode, FolderNode *folder, FileType type)
{
QList<FileNode*> existingFileNodes;
foreach (FileNode *fileNode, folder->fileNodes()) {
if (fileNode->fileType() == type && !fileNode->isGenerated())
existingFileNodes << fileNode;
}
QList<FileNode*> filesToRemove;
QList<FileNode*> filesToAdd;
qSort(files);
qSort(existingFileNodes.begin(), existingFileNodes.end(), ProjectNode::sortNodesByPath);
QList<FileNode*>::const_iterator existingNodeIter = existingFileNodes.constBegin();
QList<QString>::const_iterator newPathIter = files.constBegin();
while (existingNodeIter != existingFileNodes.constEnd()
&& newPathIter != files.constEnd()) {
if ((*existingNodeIter)->path() < *newPathIter) {
filesToRemove << *existingNodeIter;
++existingNodeIter;
} else if ((*existingNodeIter)->path() > *newPathIter) {
filesToAdd << new FileNode(*newPathIter, type, false);
++newPathIter;
} else { // *existingNodeIter->path() == *newPathIter
++existingNodeIter;
++newPathIter;
}
}
while (existingNodeIter != existingFileNodes.constEnd()) {
filesToRemove << *existingNodeIter;
++existingNodeIter;
}
while (newPathIter != files.constEnd()) {
filesToAdd << new FileNode(*newPathIter, type, false);
++newPathIter;
}
if (!filesToRemove.isEmpty())
projectNode->removeFileNodes(filesToRemove, folder);
if (!filesToAdd.isEmpty())
projectNode->addFileNodes(filesToAdd, folder);
}
};
} // Internal namespace
} // namespace
void Qt4PriFileNode::update(ProFile *includeFile, ProFileReader *reader) void Qt4PriFileNode::update(ProFile *includeFile, ProFileReader *reader)
{ {
Q_ASSERT(includeFile); Q_ASSERT(includeFile);
@@ -131,6 +342,30 @@ void Qt4PriFileNode::update(ProFile *includeFile, ProFileReader *reader)
<< ProjectExplorer::FormType << ProjectExplorer::FormType
<< ProjectExplorer::ResourceType << ProjectExplorer::ResourceType
<< ProjectExplorer::UnknownFileType); << ProjectExplorer::UnknownFileType);
static QStringList fileTypeNames =
QStringList() << tr("Headers")
<< tr("Sources")
<< tr("Forms")
<< tr("Resources")
<< tr("Other files");
static QList<QIcon> fileTypeIcons;
if (fileTypeIcons.isEmpty()) {
QStringList iconPaths;
iconPaths << ":/qt4projectmanager/images/headers.png"
<< ":/qt4projectmanager/images/sources.png"
<< ":/qt4projectmanager/images/forms.png"
<< ":/qt4projectmanager/images/qt_qrc.png"
<< ":/qt4projectmanager/images/unknown.png";
foreach (const QString &iconPath, iconPaths) {
QIcon dirIcon;
Core::FileIconProvider *iconProvider = Core::FileIconProvider::instance();
QPixmap dirIconPixmap = iconProvider->overlayIcon(QStyle::SP_DirIcon,
QIcon(iconPath),
QSize(16, 16));
dirIcon.addPixmap(dirIconPixmap);
fileTypeIcons.append(dirIcon);
}
}
const QString &projectDir = m_qt4ProFileNode->m_projectDir; const QString &projectDir = m_qt4ProFileNode->m_projectDir;
@@ -140,8 +375,11 @@ void Qt4PriFileNode::update(ProFile *includeFile, ProFileReader *reader)
baseVPaths += reader->absolutePathValues("DEPENDPATH", projectDir); baseVPaths += reader->absolutePathValues("DEPENDPATH", projectDir);
baseVPaths.removeDuplicates(); baseVPaths.removeDuplicates();
InternalNode contents;
// update files // update files
foreach (FileType type, fileTypes) { for (int i = 0; i < fileTypes.size(); ++i) {
FileType type = fileTypes.at(i);
const QStringList qmakeVariables = varNames(type); const QStringList qmakeVariables = varNames(type);
QStringList newFilePaths; QStringList newFilePaths;
@@ -157,47 +395,17 @@ void Qt4PriFileNode::update(ProFile *includeFile, ProFileReader *reader)
} }
newFilePaths.removeDuplicates(); newFilePaths.removeDuplicates();
QList<FileNode*> existingFileNodes; if (!newFilePaths.isEmpty()) {
foreach (FileNode *fileNode, fileNodes()) { InternalNode *subfolder = new InternalNode;
if (fileNode->fileType() == type && !fileNode->isGenerated()) subfolder->type = type;
existingFileNodes << fileNode; subfolder->icon = fileTypeIcons.at(i);
subfolder->fullName = m_projectDir;
contents.subnodes.insert(fileTypeNames.at(i), subfolder);
// create the hierarchy with subdirectories
subfolder->create(m_projectDir, newFilePaths, type);
} }
QList<FileNode*> toRemove;
QList<FileNode*> toAdd;
qSort(newFilePaths);
qSort(existingFileNodes.begin(), existingFileNodes.end(), ProjectNode::sortNodesByPath);
QList<FileNode*>::const_iterator existingNodeIter = existingFileNodes.constBegin();
QList<QString>::const_iterator newPathIter = newFilePaths.constBegin();
while (existingNodeIter != existingFileNodes.constEnd()
&& newPathIter != newFilePaths.constEnd()) {
if ((*existingNodeIter)->path() < *newPathIter) {
toRemove << *existingNodeIter;
++existingNodeIter;
} else if ((*existingNodeIter)->path() > *newPathIter) {
toAdd << new FileNode(*newPathIter, type, false);
++newPathIter;
} else { // *existingNodeIter->path() == *newPathIter
++existingNodeIter;
++newPathIter;
}
}
while (existingNodeIter != existingFileNodes.constEnd()) {
toRemove << *existingNodeIter;
++existingNodeIter;
}
while (newPathIter != newFilePaths.constEnd()) {
toAdd << new FileNode(*newPathIter, type, false);
++newPathIter;
}
if (!toRemove.isEmpty())
removeFileNodes(toRemove, this);
if (!toAdd.isEmpty())
addFileNodes(toAdd, this);
} }
contents.updateSubFolders(this, this);
} }
QList<ProjectNode::ProjectAction> Qt4PriFileNode::supportedActions() const QList<ProjectNode::ProjectAction> Qt4PriFileNode::supportedActions() const
@@ -1084,7 +1292,7 @@ void Qt4ProFileNode::createUiCodeModelSupport()
foreach (FileNode *uiFile, uiFiles) { foreach (FileNode *uiFile, uiFiles) {
QString uiHeaderFilePath QString uiHeaderFilePath
= QString("%1/ui_%2.h").arg(uiDir, QFileInfo(uiFile->path()).completeBaseName()); = QString("%1/ui_%2.h").arg(uiDir, QFileInfo(uiFile->path()).completeBaseName());
uiHeaderFilePath = QDir::cleanPath(uiHeaderFilePath); uiHeaderFilePath = QDir::cleanPath(uiHeaderFilePath);
// qDebug()<<"code model support for "<<uiFile->path()<<" "<<uiHeaderFilePath; // qDebug()<<"code model support for "<<uiFile->path()<<" "<<uiHeaderFilePath;
QMap<QString, Qt4UiCodeModelSupport *>::iterator it = oldCodeModelSupport.find(uiFile->path()); QMap<QString, Qt4UiCodeModelSupport *>::iterator it = oldCodeModelSupport.find(uiFile->path());

View File

@@ -104,6 +104,7 @@ enum Qt4Variable {
class Qt4PriFileNode; class Qt4PriFileNode;
class Qt4ProFileNode; class Qt4ProFileNode;
struct InternalNode;
// Implements ProjectNode for qt4 pro files // Implements ProjectNode for qt4 pro files
class Qt4PriFileNode : public ProjectExplorer::ProjectNode class Qt4PriFileNode : public ProjectExplorer::ProjectNode
@@ -175,6 +176,8 @@ private:
// managed by Qt4ProFileNode // managed by Qt4ProFileNode
friend class Qt4ProFileNode; friend class Qt4ProFileNode;
// internal temporary subtree representation
friend class InternalNode;
}; };
// Implements ProjectNode for qt4 pro files // Implements ProjectNode for qt4 pro files

View File

@@ -1,9 +1,14 @@
<RCC> <RCC>
<qresource prefix="/qt4projectmanager" > <qresource prefix="/qt4projectmanager">
<file>images/window.png</file> <file>images/window.png</file>
<file>images/run_qmake.png</file> <file>images/run_qmake.png</file>
<file>images/run_qmake_small.png</file> <file>images/run_qmake_small.png</file>
<file>images/qt_project.png</file> <file>images/qt_project.png</file>
<file>Qt4ProjectManager.mimetypes.xml</file> <file>Qt4ProjectManager.mimetypes.xml</file>
<file>images/forms.png</file>
<file>images/headers.png</file>
<file>images/qt_qrc.png</file>
<file>images/sources.png</file>
<file>images/unknown.png</file>
</qresource> </qresource>
</RCC> </RCC>

View File

@@ -0,0 +1,2 @@
SOURCES += $$PWD/sources/prifileinc.cpp
HEADERS += $$PWD/headers/prifileinc.h

View File

@@ -0,0 +1,48 @@
#-------------------------------------------------
#
# Project created by QtCreator 2009-05-12T12:31:37
#
#-------------------------------------------------
TARGET = projecttree
TEMPLATE = app
include(prifile/prifile.pri)
SOURCES += main.cpp\
widget.cpp \
/etc/cups/cupsd.conf \
/etc/cups/printers.conf \
/etc/apache2/mime.types \
/etc/apache2/extra/httpd-info.conf \
../projecttree_data1/a/foo.cpp \
../projecttree_data1/b/foo.cpp \
../projecttree_data2/a/bar.cpp \
../projecttree_data2/a/sub/bar2.cpp \
../projecttree_data3/path/bar.cpp \
subpath/a/foo.cpp \
subpath/b/foo.cpp \
sub2/a/bar.cpp \
sub2/a/sub/bar2.cpp \
uniquesub/path/bar.cpp \
sources/foo.cpp \
sources/bar.cpp
HEADERS += main.h\
widget.h \
../projecttree_data1/a/foo.h \
../projecttree_data1/b/foo.h \
../projecttree_data2/a/bar.h \
../projecttree_data2/a/sub/bar2.h \
../projecttree_data3/path/bar.h \
subpath/a/foo.h \
subpath/b/foo.h \
sub2/a/bar.h \
sub2/a/sub/bar2.h \
uniquesub/path/bar.h \
headers/foo.h \
headers/bar.h
FORMS += widget.ui
RESOURCES += resource.qrc
OTHER_FILES += foo.txt

View File

@@ -28,6 +28,7 @@
**************************************************************************/ **************************************************************************/
#include "trkutils.h" #include "trkutils.h"
#include "trkdevice.h"
#include <QtCore/QPointer> #include <QtCore/QPointer>
#include <QtCore/QCoreApplication> #include <QtCore/QCoreApplication>
@@ -40,50 +41,6 @@
#include <QtNetwork/QLocalServer> #include <QtNetwork/QLocalServer>
#include <QtNetwork/QLocalSocket> #include <QtNetwork/QLocalSocket>
#ifdef Q_OS_WIN
#include <windows.h>
// Non-blocking replacement for win-api ReadFile function
BOOL WINAPI TryReadFile(HANDLE hFile,
LPVOID lpBuffer,
DWORD nNumberOfBytesToRead,
LPDWORD lpNumberOfBytesRead,
LPOVERLAPPED lpOverlapped)
{
COMSTAT comStat;
if(!ClearCommError(hFile, NULL, &comStat)){
qDebug() << "ClearCommError() failed";
return FALSE;
}
if (!comStat.cbInQue)
return FALSE;
return ReadFile(hFile,
lpBuffer,
qMin(comStat.cbInQue, nNumberOfBytesToRead),
lpNumberOfBytesRead,
lpOverlapped);
}
// Format windows error from GetLastError() value.
QString winErrorMessage(unsigned long error)
{
QString rc = QString::fromLatin1("#%1: ").arg(error);
ushort *lpMsgBuf;
const int len = FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, error, 0, (LPTSTR)&lpMsgBuf, 0, NULL);
if (len) {
rc = QString::fromUtf16(lpMsgBuf, len);
LocalFree(lpMsgBuf);
} else {
rc += QString::fromLatin1("<unknown error>");
}
return rc;
}
#endif
#ifdef Q_OS_UNIX #ifdef Q_OS_UNIX
#include <signal.h> #include <signal.h>
@@ -97,9 +54,6 @@ void signalHandler(int)
using namespace trk; using namespace trk;
enum { TRK_SYNC = 0x7f };
enum { KnownRegisters = RegisterPSGdb + 1}; enum { KnownRegisters = RegisterPSGdb + 1};
static const char *registerNames[KnownRegisters] = static const char *registerNames[KnownRegisters] =
@@ -137,13 +91,13 @@ struct AdapterOptions {
QString trkServer; QString trkServer;
}; };
#define CB(s) &Adapter::s
class Adapter : public QObject class Adapter : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
typedef TrkFunctor1<const TrkResult &> Callback;
Adapter(); Adapter();
~Adapter(); ~Adapter();
void setGdbServerName(const QString &name); void setGdbServerName(const QString &name);
@@ -154,38 +108,22 @@ public:
void setUseSocket(bool s) { m_useSocket = s; } void setUseSocket(bool s) { m_useSocket = s; }
bool startServer(); bool startServer();
private slots:
void handleResult(const trk::TrkResult &data);
private: private:
// //
// TRK // TRK
// //
Q_SLOT void readFromTrk();
typedef void (Adapter::*TrkCallBack)(const TrkResult &);
struct TrkMessage
{
TrkMessage() : code(0), token(0), callBack(0), invokeOnFailure(0) {}
byte code;
byte token;
QByteArray data;
QVariant cookie;
TrkCallBack callBack;
bool invokeOnFailure;
};
bool openTrkPort(const QString &port, QString *errorMessage); // or server name for local server bool openTrkPort(const QString &port, QString *errorMessage); // or server name for local server
void sendTrkMessage(byte code, void sendTrkMessage(byte code,
TrkCallBack calBack = 0, Callback callBack = Callback(),
const QByteArray &data = QByteArray(), const QByteArray &data = QByteArray(),
const QVariant &cookie = QVariant(), const QVariant &cookie = QVariant(),
bool invokeOnFailure = false); bool invokeOnFailure = false);
// adds message to 'send' queue
void queueTrkMessage(const TrkMessage &msg); // convenience messages
void tryTrkWrite();
void tryTrkRead();
// actually writes a message to the device
void trkWrite(const TrkMessage &msg);
// convienience messages
void sendTrkInitialPing(); void sendTrkInitialPing();
void sendTrkContinue(); void sendTrkContinue();
void waitForTrkFinished(); void waitForTrkFinished();
@@ -194,10 +132,7 @@ private:
// kill process and breakpoints // kill process and breakpoints
void cleanUp(); void cleanUp();
void timerEvent(QTimerEvent *ev); void handleCpuType(const TrkResult &result);
byte nextTrkWriteToken();
void handleCpuType(const TrkResult &result);
void handleCreateProcess(const TrkResult &result); void handleCreateProcess(const TrkResult &result);
void handleClearBreakpoint(const TrkResult &result); void handleClearBreakpoint(const TrkResult &result);
void handleSignalContinue(const TrkResult &result); void handleSignalContinue(const TrkResult &result);
@@ -216,25 +151,17 @@ private:
void reportToGdb(const TrkResult &result); void reportToGdb(const TrkResult &result);
void clearTrkBreakpoint(const Breakpoint &bp); void clearTrkBreakpoint(const Breakpoint &bp);
void handleResult(const TrkResult &data);
void readMemory(uint addr, uint len); void readMemory(uint addr, uint len);
void startInferiorIfNeeded(); void startInferiorIfNeeded();
void interruptInferior(); void interruptInferior();
#ifdef Q_OS_WIN QSharedPointer<TrkWriteQueueDevice> m_trkDevice;
HANDLE m_winComDevice; QSharedPointer<QIODevice> m_socket;
#endif QSharedPointer<TrkWriteQueueIODevice> m_socketDevice;
QLocalSocket *m_socketDevice;
QString m_trkServerName; QString m_trkServerName;
QByteArray m_trkReadBuffer; QByteArray m_trkReadBuffer;
unsigned char m_trkWriteToken;
QQueue<TrkMessage> m_trkWriteQueue;
QHash<byte, TrkMessage> m_writtenTrkMessages;
QByteArray m_trkReadQueue;
bool m_trkWriteBusy;
QList<Breakpoint> m_breakpoints; QList<Breakpoint> m_breakpoints;
// //
@@ -268,12 +195,6 @@ private:
}; };
Adapter::Adapter() : Adapter::Adapter() :
#ifdef Q_OS_WIN
m_winComDevice(NULL),
#endif
m_socketDevice(0),
m_trkWriteToken(0),
m_trkWriteBusy(false),
m_gdbConnection(0), m_gdbConnection(0),
m_gdbServerPort(0), m_gdbServerPort(0),
m_gdbAckMode(true), m_gdbAckMode(true),
@@ -283,20 +204,14 @@ Adapter::Adapter() :
m_serialFrame(true), m_serialFrame(true),
m_startInferiorTriggered(false) m_startInferiorTriggered(false)
{ {
startTimer(100);
} }
Adapter::~Adapter() Adapter::~Adapter()
{ {
// Trk // Trk
#ifdef Q_OS_WIN if (!m_socket.isNull())
if (m_winComDevice) if (QLocalSocket *sock = qobject_cast<QLocalSocket *>(m_socket.data()))
CloseHandle(m_winComDevice); sock->abort();
#endif
if (m_socketDevice) {
m_socketDevice->abort();
delete m_socketDevice;
}
// Gdb // Gdb
m_gdbServer.close(); m_gdbServer.close();
@@ -325,9 +240,9 @@ bool Adapter::startServer()
sendTrkInitialPing(); sendTrkInitialPing();
sendTrkMessage(0x01); // Connect sendTrkMessage(0x01); // Connect
sendTrkMessage(0x05, CB(handleSupportMask)); sendTrkMessage(0x05, Callback(this, &Adapter::handleSupportMask));
sendTrkMessage(0x06, CB(handleCpuType)); sendTrkMessage(0x06, Callback(this, &Adapter::handleCpuType));
sendTrkMessage(0x04, CB(handleTrkVersions)); // Versions sendTrkMessage(0x04, Callback(this, &Adapter::handleTrkVersions)); // Versions
//sendTrkMessage(0x09); // Unrecognized command //sendTrkMessage(0x09); // Unrecognized command
//sendTrkMessage(0x4a, 0, //sendTrkMessage(0x4a, 0,
// "10 " + formatString("C:\\data\\usingdlls.sisx")); // Open File // "10 " + formatString("C:\\data\\usingdlls.sisx")); // Open File
@@ -491,7 +406,7 @@ void Adapter::sendGdbMessage(const QByteArray &msg, const QByteArray &logNote)
void Adapter::sendGdbMessageAfterSync(const QByteArray &msg, const QByteArray &logNote) void Adapter::sendGdbMessageAfterSync(const QByteArray &msg, const QByteArray &logNote)
{ {
QByteArray ba = msg + char(1) + logNote; QByteArray ba = msg + char(1) + logNote;
sendTrkMessage(TRK_SYNC, CB(reportToGdb), "", ba); // Answer gdb sendTrkMessage(TRK_WRITE_QUEUE_NOOP_CODE, Callback(this, &Adapter::reportToGdb), "", ba); // Answer gdb
} }
void Adapter::reportToGdb(const TrkResult &result) void Adapter::reportToGdb(const TrkResult &result)
@@ -545,7 +460,7 @@ void Adapter::handleGdbResponse(const QByteArray &response)
appendInt(&ba, 0); // end address appendInt(&ba, 0); // end address
appendInt(&ba, m_session.pid); appendInt(&ba, m_session.pid);
appendInt(&ba, m_session.tid); appendInt(&ba, m_session.tid);
sendTrkMessage(0x18, 0, ba); sendTrkMessage(0x18, Callback(), ba);
// FIXME: should be triggered by real stop // FIXME: should be triggered by real stop
//sendGdbMessageAfterSync("S11", "target stopped"); //sendGdbMessageAfterSync("S11", "target stopped");
} }
@@ -561,7 +476,7 @@ void Adapter::handleGdbResponse(const QByteArray &response)
QByteArray ba; QByteArray ba;
appendInt(&ba, m_session.pid); appendInt(&ba, m_session.pid);
appendInt(&ba, m_session.tid); appendInt(&ba, m_session.tid);
sendTrkMessage(0x18, CB(handleSignalContinue), ba, signalNumber); // Continue sendTrkMessage(0x18, Callback(this, &Adapter::handleSignalContinue), ba, signalNumber); // Continue
} }
else if (response.startsWith("D")) { else if (response.startsWith("D")) {
@@ -582,7 +497,7 @@ void Adapter::handleGdbResponse(const QByteArray &response)
appendShort(&ba, RegisterCount - 1); // last register appendShort(&ba, RegisterCount - 1); // last register
appendInt(&ba, m_session.pid); appendInt(&ba, m_session.pid);
appendInt(&ba, m_session.tid); appendInt(&ba, m_session.tid);
sendTrkMessage(0x12, CB(handleAndReportReadRegisters), ba, QVariant(), true); sendTrkMessage(0x12, Callback(this, &Adapter::handleAndReportReadRegisters), ba, QVariant(), true);
} }
else if (response.startsWith("Hc")) { else if (response.startsWith("Hc")) {
@@ -615,7 +530,7 @@ void Adapter::handleGdbResponse(const QByteArray &response)
QByteArray ba; QByteArray ba;
appendByte(&ba, 0); // Sub-command: Delete Process appendByte(&ba, 0); // Sub-command: Delete Process
appendInt(&ba, m_session.pid); appendInt(&ba, m_session.pid);
sendTrkMessage(0x41, 0, ba, "Delete process"); // Delete Item sendTrkMessage(0x41, Callback(), ba, "Delete process"); // Delete Item
sendGdbMessageAfterSync("", "process killed"); sendGdbMessageAfterSync("", "process killed");
} }
@@ -793,7 +708,7 @@ void Adapter::handleGdbResponse(const QByteArray &response)
appendInt(&ba, m_snapshot.registers[RegisterPC] + 4); // end address appendInt(&ba, m_snapshot.registers[RegisterPC] + 4); // end address
appendInt(&ba, m_session.pid); appendInt(&ba, m_session.pid);
appendInt(&ba, m_session.tid); appendInt(&ba, m_session.tid);
sendTrkMessage(0x19, 0, ba, "Step range"); sendTrkMessage(0x19, Callback(), ba, "Step range");
// FIXME: should be triggered by "real" stop" // FIXME: should be triggered by "real" stop"
//sendGdbMessageAfterSync("S05", "target halted"); //sendGdbMessageAfterSync("S05", "target halted");
} }
@@ -815,7 +730,7 @@ void Adapter::handleGdbResponse(const QByteArray &response)
QByteArray ba; QByteArray ba;
appendByte(&ba, 0); // Sub-command: Delete Process appendByte(&ba, 0); // Sub-command: Delete Process
appendInt(&ba, m_session.pid); appendInt(&ba, m_session.pid);
sendTrkMessage(0x41, 0, ba, "Delete process"); // Delete Item sendTrkMessage(0x41, Callback(), ba, "Delete process"); // Delete Item
sendGdbMessageAfterSync("", "process killed"); sendGdbMessageAfterSync("", "process killed");
} }
@@ -850,7 +765,7 @@ void Adapter::handleGdbResponse(const QByteArray &response)
appendInt(&ba, m_session.pid); appendInt(&ba, m_session.pid);
appendInt(&ba, 0xFFFFFFFF); appendInt(&ba, 0xFFFFFFFF);
sendTrkMessage(0x1B, CB(handleAndReportSetBreakpoint), ba); sendTrkMessage(0x1B, Callback(this, &Adapter::handleAndReportSetBreakpoint), ba);
//m_session.toekn //m_session.toekn
//---TRK------------------------------------------------------ //---TRK------------------------------------------------------
@@ -864,95 +779,47 @@ void Adapter::handleGdbResponse(const QByteArray &response)
} }
} }
void Adapter::readFromTrk()
{
//QByteArray ba = m_gdbConnection->readAll();
//logMessage("Read from gdb: " + ba);
}
bool Adapter::openTrkPort(const QString &port, QString *errorMessage) bool Adapter::openTrkPort(const QString &port, QString *errorMessage)
{ {
if (m_useSocket) { if (m_useSocket) {
m_socketDevice = new QLocalSocket(this); QLocalSocket *socket = new QLocalSocket;
m_socketDevice->connectToServer(port); socket->connectToServer(port);
const bool rc = m_socketDevice->waitForConnected(); if (!socket->waitForConnected()) {
if (!rc) *errorMessage = "Unable to connect to TRK server " + m_trkServerName + ' ' + m_socket->errorString();
*errorMessage = "Unable to connect to TRK server " + m_trkServerName + ' ' + m_socketDevice->errorString(); delete socket;
return rc; return false;
}
m_socket = QSharedPointer<QIODevice>(socket);
m_socketDevice = QSharedPointer<TrkWriteQueueIODevice>(new TrkWriteQueueIODevice(m_socket));
connect(m_socketDevice.data(), SIGNAL(messageReceived(trk::TrkResult)), this, SLOT(handleResult(trk::TrkResult)));
if (m_verbose > 1)
m_socketDevice->setVerbose(true);
m_socketDevice->setSerialFrame(m_serialFrame);
return true;
} }
#ifdef Q_OS_WIN m_trkDevice = QSharedPointer<TrkWriteQueueDevice>(new TrkWriteQueueDevice);
m_winComDevice = CreateFile(port.toStdWString().c_str(), connect(m_trkDevice.data(), SIGNAL(messageReceived(trk::TrkResult)), this, SLOT(handleResult(trk::TrkResult)));
GENERIC_READ | GENERIC_WRITE, if (m_verbose > 1)
0, m_trkDevice->setVerbose(true);
NULL, m_trkDevice->setSerialFrame(m_serialFrame);
OPEN_EXISTING, return m_trkDevice->open(port, errorMessage);
FILE_ATTRIBUTE_NORMAL,
NULL);
if (INVALID_HANDLE_VALUE == m_winComDevice){
*errorMessage = "Could not open device " + port + ' ' + winErrorMessage(GetLastError());
return false;
}
return true;
#else
logMessage("Not implemented", true);
return false;
#endif
#if 0
m_socketDevice = new Win_QextSerialPort(port);
m_socketDevice->setBaudRate(BAUD115200);
m_socketDevice->setDataBits(DATA_8);
m_socketDevice->setParity(PAR_NONE);
//m_socketDevice->setStopBits(STO);
m_socketDevice->setFlowControl(FLOW_OFF);
m_socketDevice->setTimeout(0, 500);
if (!m_socketDevice->open(QIODevice::ReadWrite)) {
QByteArray ba = m_socketDevice->errorString().toLatin1();
logMessage("Could not open device " << ba);
return false;
}
return true
#endif
} }
void Adapter::timerEvent(QTimerEvent *) void Adapter::sendTrkMessage(byte code, Callback callBack,
{
//qDebug(".");
tryTrkWrite();
tryTrkRead();
}
byte Adapter::nextTrkWriteToken()
{
++m_trkWriteToken;
if (m_trkWriteToken == 0)
++m_trkWriteToken;
return m_trkWriteToken;
}
void Adapter::sendTrkMessage(byte code, TrkCallBack callBack,
const QByteArray &data, const QVariant &cookie, bool invokeOnFailure) const QByteArray &data, const QVariant &cookie, bool invokeOnFailure)
{ {
TrkMessage msg; if (m_useSocket)
msg.code = code; m_socketDevice->sendTrkMessage(code, callBack, data, cookie, invokeOnFailure);
// Tokens must be strictly sequential else
if (msg.code != TRK_SYNC) m_trkDevice->sendTrkMessage(code, callBack, data, cookie, invokeOnFailure);
msg.token = nextTrkWriteToken();
msg.callBack = callBack;
msg.data = data;
msg.cookie = cookie;
msg.invokeOnFailure = invokeOnFailure;
queueTrkMessage(msg);
} }
void Adapter::sendTrkInitialPing() void Adapter::sendTrkInitialPing()
{ {
TrkMessage msg; if (m_useSocket)
msg.code = 0x00; // Ping m_socketDevice->sendTrkInitialPing();
msg.token = 0; // reset sequence count else
queueTrkMessage(msg); m_trkDevice->sendTrkInitialPing();
} }
void Adapter::sendTrkContinue() void Adapter::sendTrkContinue()
@@ -960,165 +827,39 @@ void Adapter::sendTrkContinue()
QByteArray ba; QByteArray ba;
appendInt(&ba, m_session.pid); appendInt(&ba, m_session.pid);
appendInt(&ba, m_session.tid); appendInt(&ba, m_session.tid);
sendTrkMessage(0x18, 0, ba, "CONTINUE"); sendTrkMessage(0x18, Callback(), ba, "CONTINUE");
} }
void Adapter::waitForTrkFinished() void Adapter::waitForTrkFinished()
{ {
TrkMessage msg;
// initiate one last roundtrip to ensure all is flushed // initiate one last roundtrip to ensure all is flushed
msg.code = 0x00; // Ping sendTrkMessage(0x0, Callback(this, &Adapter::handleWaitForFinished));
msg.token = nextTrkWriteToken();
msg.callBack = CB(handleWaitForFinished);
queueTrkMessage(msg);
} }
void Adapter::sendTrkAck(byte token) void Adapter::sendTrkAck(byte token)
{ {
logMessage(QString("SENDING ACKNOWLEDGEMENT FOR TOKEN %1").arg(int(token))); logMessage(QString("SENDING ACKNOWLEDGEMENT FOR TOKEN %1").arg(int(token)));
TrkMessage msg; if (m_useSocket)
msg.code = 0x80; m_socketDevice->sendTrkAck(token);
msg.token = token; else
msg.data.append('\0'); m_trkDevice->sendTrkAck(token);
// The acknowledgement must not be queued!
//queueMessage(msg);
trkWrite(msg);
// 01 90 00 07 7e 80 01 00 7d 5e 7e
} }
void Adapter::queueTrkMessage(const TrkMessage &msg)
{
m_trkWriteQueue.append(msg);
}
void Adapter::tryTrkWrite()
{
if (m_trkWriteBusy)
return;
if (m_trkWriteQueue.isEmpty())
return;
TrkMessage msg = m_trkWriteQueue.dequeue();
if (msg.code == TRK_SYNC) {
logMessage(QString::fromLatin1("TRK SYNC [token=%1]").arg(msg.token));
TrkResult result;
result.code = msg.code;
result.token = msg.token;
result.data = msg.data;
result.cookie = msg.cookie;
TrkCallBack cb = msg.callBack;
if (cb)
(this->*cb)(result);
} else {
trkWrite(msg);
}
}
void Adapter::trkWrite(const TrkMessage &msg)
{
QByteArray ba = frameMessage(msg.code, msg.token, msg.data, m_serialFrame);
m_writtenTrkMessages.insert(msg.token, msg);
m_trkWriteBusy = true;
if (m_verbose > 1) {
const QString logMsg = QString::fromLatin1("WRITE: 0x%1 [token=%2]: %3").arg(msg.code, 0, 16).arg(msg.token).arg(stringFromArray(ba));
logMessage(logMsg);
}
if (m_useSocket) {
if (!m_socketDevice->write(ba))
logMessage("WRITE ERROR: " + m_socketDevice->errorString());
m_socketDevice->flush();
} else {
#ifdef Q_OS_WIN
DWORD charsWritten;
if (!WriteFile(m_winComDevice, ba.data(), ba.size(), &charsWritten, NULL))
logMessage("WRITE ERROR: " + winErrorMessage(GetLastError()));
FlushFileBuffers(m_winComDevice);
#endif
}
}
void Adapter::tryTrkRead()
{
//logMessage("TRY READ: " << m_socketDevice->bytesAvailable()
// << stringFromArray(m_trkReadQueue);
if (m_useSocket) {
if (m_socketDevice->bytesAvailable() == 0 && m_trkReadQueue.isEmpty())
return;
QByteArray res = m_socketDevice->readAll();
m_trkReadQueue.append(res);
} else {
#ifdef Q_OS_WIN
const DWORD BUFFERSIZE = 1024;
char buffer[BUFFERSIZE];
DWORD charsRead;
DWORD totalCharsRead = 0;
while (TryReadFile(m_winComDevice, buffer, BUFFERSIZE, &charsRead, NULL)) {
m_trkReadQueue.append(buffer, charsRead);
totalCharsRead += charsRead;
if (isValidTrkResult(m_trkReadQueue, m_serialFrame))
break;
}
if (!totalCharsRead)
return;
#endif // USE_NATIVE
}
if (m_trkReadQueue.size() < 9) {
logMessage("ERROR READBUFFER INVALID (1): "
+ stringFromArray(m_trkReadQueue));
m_trkReadQueue.clear();
return;
}
TrkResult r;
while (extractResult(&m_trkReadQueue, m_serialFrame, &r))
handleResult(r);
m_trkWriteBusy = false;
}
void Adapter::handleResult(const TrkResult &result) void Adapter::handleResult(const TrkResult &result)
{ {
if (result.isDebugOutput) {
logMessage(QLatin1String("APPLICATION OUTPUT: ") + QString::fromAscii(result.data));
return;
}
QByteArray prefix = "READ BUF: "; QByteArray prefix = "READ BUF: ";
QByteArray str = result.toString().toUtf8(); QByteArray str = result.toString().toUtf8();
switch (result.code) { switch (result.code) {
case 0x80: { // ACK case 0x80: // ACK
//logMessage(prefix + "ACK: " + str);
if (const int ec = result.errorCode())
logMessage(QString::fromLatin1("READ BUF ACK/ERR %1 for token=%2").arg(ec).arg(result.token), true);
if (!m_writtenTrkMessages.contains(result.token)) {
logMessage("NO ENTRY FOUND!");
}
TrkMessage msg = m_writtenTrkMessages.take(result.token);
TrkResult result1 = result;
result1.cookie = msg.cookie;
TrkCallBack cb = msg.callBack;
if (cb) {
(this->*cb)(result1);
} else {
QString msg = result.cookie.toString();
if (!msg.isEmpty())
logMessage("HANDLE: " + msg + stringFromArray(result.data));
}
break; break;
}
case 0xff: { // NAK. This mostly means transmission error, not command failed. case 0xff: { // NAK. This mostly means transmission error, not command failed.
const TrkMessage writtenMsg = m_writtenTrkMessages.take(result.token);
QString logMsg; QString logMsg;
QTextStream(&logMsg) << prefix << "NAK: for 0x" << QString::number(int(writtenMsg.code), 16) QTextStream(&logMsg) << prefix << "NAK: for token=" << result.token << " ERROR: " << errorMessage(result.data.at(0)) << ' ' << str;
<< " token=" << result.token << " ERROR: " << errorMessage(result.data.at(0)) << ' ' << str;
logMessage(logMsg, true); logMessage(logMsg, true);
// Invoke failure if desired
if (writtenMsg.callBack && writtenMsg.invokeOnFailure) {
TrkResult result1 = result;
result1.cookie = writtenMsg.cookie;
(this->*writtenMsg.callBack)(result1);
}
break; break;
} }
case 0x90: { // Notified Stopped case 0x90: { // Notified Stopped
@@ -1258,10 +999,10 @@ void Adapter::handleCreateProcess(const TrkResult &result)
// Command: 0x42 Read Info // Command: 0x42 Read Info
// [42 0C 00 06 00 00 00 00 00 14 50 6F 6C 79 6D 6F // [42 0C 00 06 00 00 00 00 00 14 50 6F 6C 79 6D 6F
// 72 70 68 69 63 44 4C 4C 32 2E 64 6C 6C 00] // 72 70 68 69 63 44 4C 4C 32 2E 64 6C 6C 00]
sendTrkMessage(0x42, CB(handleReadInfo), sendTrkMessage(0x42, Callback(this, &Adapter::handleReadInfo),
"00 06 00 00 00 00 00 14 50 6F 6C 79 6D 6F " "00 06 00 00 00 00 00 14 50 6F 6C 79 6D 6F "
"72 70 68 69 63 44 4C 4C 32 2E 64 6C 6C 00"); "72 70 68 69 63 44 4C 4C 32 2E 64 6C 6C 00");
//sendTrkMessage(0x42, CB(handleReadInfo), //sendTrkMessage(0x42, Callback(this, &Adapter::handleReadInfo),
// "00 01 00 00 00 00"); // "00 01 00 00 00 00");
//---TRK------------------------------------------------------ //---TRK------------------------------------------------------
// Command: 0x80 Acknowledge // Command: 0x80 Acknowledge
@@ -1273,7 +1014,7 @@ void Adapter::handleCreateProcess(const TrkResult &result)
// Command: 0x42 Read Info // Command: 0x42 Read Info
// [42 0D 00 06 00 00 00 00 00 14 50 6F 6C 79 6D 6F // [42 0D 00 06 00 00 00 00 00 14 50 6F 6C 79 6D 6F
// 72 70 68 69 63 44 4C 4C 31 2E 64 6C 6C 00] // 72 70 68 69 63 44 4C 4C 31 2E 64 6C 6C 00]
sendTrkMessage(0x42, CB(handleReadInfo), sendTrkMessage(0x42, Callback(this, &Adapter::handleReadInfo),
"00 06 00 00 00 00 00 14 50 6F 6C 79 6D 6F " "00 06 00 00 00 00 00 14 50 6F 6C 79 6D 6F "
"72 70 68 69 63 44 4C 4C 31 2E 64 6C 6C 00"); "72 70 68 69 63 44 4C 4C 31 2E 64 6C 6C 00");
//---TRK------------------------------------------------------ //---TRK------------------------------------------------------
@@ -1282,7 +1023,7 @@ void Adapter::handleCreateProcess(const TrkResult &result)
// [80 0D 20] // [80 0D 20]
#endif #endif
//sendTrkMessage(0x18, CB(handleStop), //sendTrkMessage(0x18, Callback(this, &Adapter::handleStop),
// "01 " + formatInt(m_session.pid) + formatInt(m_session.tid)); // "01 " + formatInt(m_session.pid) + formatInt(m_session.tid));
//---IDE------------------------------------------------------ //---IDE------------------------------------------------------
@@ -1293,8 +1034,8 @@ void Adapter::handleCreateProcess(const TrkResult &result)
QByteArray ba; QByteArray ba;
appendInt(&ba, m_session.pid); appendInt(&ba, m_session.pid);
appendInt(&ba, m_session.tid); appendInt(&ba, m_session.tid);
sendTrkMessage(0x18, CB(handleContinue), ba); sendTrkMessage(0x18, Callback(this, &Adapter::handleContinue), ba);
//sendTrkMessage(0x18, CB(handleContinue), //sendTrkMessage(0x18, Callback(this, &Adapter::handleContinue),
// formatInt(m_session.pid) + "ff ff ff ff"); // formatInt(m_session.pid) + "ff ff ff ff");
//---TRK------------------------------------------------------ //---TRK------------------------------------------------------
// Command: 0x80 Acknowledge // Command: 0x80 Acknowledge
@@ -1423,7 +1164,7 @@ void Adapter::clearTrkBreakpoint(const Breakpoint &bp)
appendByte(&ba, 0x00); appendByte(&ba, 0x00);
appendShort(&ba, bp.number); appendShort(&ba, bp.number);
appendInt(&ba, m_session.codeseg + bp.offset); appendInt(&ba, m_session.codeseg + bp.offset);
sendTrkMessage(0x1C, CB(handleClearBreakpoint), ba); sendTrkMessage(0x1C, Callback(this, &Adapter::handleClearBreakpoint), ba);
} }
void Adapter::handleClearBreakpoint(const TrkResult &result) void Adapter::handleClearBreakpoint(const TrkResult &result)
@@ -1497,7 +1238,7 @@ void Adapter::cleanUp()
appendByte(&ba, 0x00); appendByte(&ba, 0x00);
appendByte(&ba, 0x00); appendByte(&ba, 0x00);
appendInt(&ba, m_session.pid); appendInt(&ba, m_session.pid);
sendTrkMessage(0x41, 0, ba, "Delete process"); sendTrkMessage(0x41, Callback(), ba, "Delete process");
//---TRK------------------------------------------------------ //---TRK------------------------------------------------------
// Command: 0x80 Acknowledge // Command: 0x80 Acknowledge
@@ -1507,7 +1248,7 @@ void Adapter::cleanUp()
foreach (const Breakpoint &bp, m_breakpoints) foreach (const Breakpoint &bp, m_breakpoints)
clearTrkBreakpoint(bp); clearTrkBreakpoint(bp);
sendTrkMessage(0x02, CB(handleDisconnect)); sendTrkMessage(0x02, Callback(this, &Adapter::handleDisconnect));
m_startInferiorTriggered = false; m_startInferiorTriggered = false;
//---IDE------------------------------------------------------ //---IDE------------------------------------------------------
// Command: 0x1C Clear Break // Command: 0x1C Clear Break
@@ -1538,7 +1279,7 @@ void Adapter::cleanUp()
//---IDE------------------------------------------------------ //---IDE------------------------------------------------------
// Command: 0x02 Disconnect // Command: 0x02 Disconnect
// [02 27] // [02 27]
// sendTrkMessage(0x02, CB(handleDisconnect)); // sendTrkMessage(0x02, Callback(this, &Adapter::handleDisconnect));
//---TRK------------------------------------------------------ //---TRK------------------------------------------------------
// Command: 0x80 Acknowledge // Command: 0x80 Acknowledge
// Error: 0x00 // Error: 0x00
@@ -1565,11 +1306,11 @@ void Adapter::readMemory(uint addr, uint len)
appendInt(&ba, m_session.pid); appendInt(&ba, m_session.pid);
appendInt(&ba, m_session.tid); appendInt(&ba, m_session.tid);
// Read Memory // Read Memory
sendTrkMessage(0x10, CB(handleReadMemory), ba, QVariant(blockaddr), true); sendTrkMessage(0x10, Callback(this, &Adapter::handleReadMemory), ba, QVariant(blockaddr), true);
} }
} }
qulonglong cookie = (qulonglong(addr) << 32) + len; qulonglong cookie = (qulonglong(addr) << 32) + len;
sendTrkMessage(TRK_SYNC, CB(reportReadMemory), QByteArray(), cookie); sendTrkMessage(TRK_WRITE_QUEUE_NOOP_CODE, Callback(this, &Adapter::reportReadMemory), QByteArray(), cookie);
} }
void Adapter::startInferiorIfNeeded() void Adapter::startInferiorIfNeeded()
@@ -1589,7 +1330,7 @@ void Adapter::startInferiorIfNeeded()
QByteArray file("C:\\sys\\bin\\filebrowseapp.exe"); QByteArray file("C:\\sys\\bin\\filebrowseapp.exe");
appendString(&ba, file, TargetByteOrder); appendString(&ba, file, TargetByteOrder);
sendTrkMessage(0x40, CB(handleCreateProcess), ba); // Create Item sendTrkMessage(0x40, Callback(this, &Adapter::handleCreateProcess), ba); // Create Item
} }
void Adapter::interruptInferior() void Adapter::interruptInferior()
@@ -1599,7 +1340,7 @@ void Adapter::interruptInferior()
appendByte(&ba, 1); appendByte(&ba, 1);
appendInt(&ba, m_session.pid); appendInt(&ba, m_session.pid);
appendInt(&ba, m_session.tid); // threadID: 4 bytes Variable number of bytes. appendInt(&ba, m_session.tid); // threadID: 4 bytes Variable number of bytes.
sendTrkMessage(0x1A, 0, ba, "Interrupting..."); sendTrkMessage(0x1A, Callback(), ba, "Interrupting...");
} }
static bool readAdapterArgs(const QStringList &args, AdapterOptions *o) static bool readAdapterArgs(const QStringList &args, AdapterOptions *o)

View File

@@ -4,8 +4,11 @@ TEMPLATE = app
QT = core network QT = core network
win32:CONFIG+=console win32:CONFIG+=console
HEADERS += trkutils.h HEADERS += trkutils.h \
trkfunctor.h \
trkdevice.h \
SOURCES += \ SOURCES += \
adapter.cpp \ adapter.cpp \
trkutils.cpp trkutils.cpp \
trkdevice.cpp

View File

@@ -67,7 +67,7 @@ LauncherPrivate::LauncherPrivate() :
Launcher::Launcher() : Launcher::Launcher() :
d(new LauncherPrivate) d(new LauncherPrivate)
{ {
connect(&d->m_device, SIGNAL(messageReceived(TrkResult)), this, SLOT(handleResult(TrkResult))); connect(&d->m_device, SIGNAL(messageReceived(trk::TrkResult)), this, SLOT(handleResult(trk::TrkResult)));
} }
Launcher::~Launcher() Launcher::~Launcher()
@@ -147,7 +147,7 @@ void Launcher::installAndRun()
void Launcher::logMessage(const QString &msg) void Launcher::logMessage(const QString &msg)
{ {
if (d->m_verbose) if (d->m_verbose)
qDebug() << "ADAPTER: " << qPrintable(msg); qDebug() << "LAUNCHER: " << qPrintable(msg);
} }
void Launcher::waitForTrkFinished(const TrkResult &result) void Launcher::waitForTrkFinished(const TrkResult &result)
@@ -239,7 +239,7 @@ void Launcher::handleResult(const TrkResult &result)
case TrkNotifyDeleted: { // NotifyDeleted case TrkNotifyDeleted: { // NotifyDeleted
const ushort itemType = (unsigned char)result.data.at(1); const ushort itemType = (unsigned char)result.data.at(1);
const ushort len = result.data.size() > 12 ? extractShort(result.data.data() + 10) : ushort(0); const ushort len = result.data.size() > 12 ? extractShort(result.data.data() + 10) : ushort(0);
const QString name = len ? QString::fromAscii(result.data.mid(13, len)) : QString(); const QString name = len ? QString::fromAscii(result.data.mid(12, len)) : QString();
logMessage(QString::fromLatin1("%1 %2 UNLOAD: %3"). logMessage(QString::fromLatin1("%1 %2 UNLOAD: %3").
arg(QString::fromAscii(prefix)).arg(itemType ? QLatin1String("LIB") : QLatin1String("PROCESS")). arg(QString::fromAscii(prefix)).arg(itemType ? QLatin1String("LIB") : QLatin1String("PROCESS")).
arg(name)); arg(name));

View File

@@ -67,7 +67,7 @@ public slots:
void terminate(); void terminate();
private slots: private slots:
void handleResult(const TrkResult &data); void handleResult(const trk::TrkResult &data);
private: private:
void tryTrkRead(); void tryTrkRead();

View File

@@ -21,10 +21,15 @@ Usage: run.pl -av -aq -tv -tq -l [COM]
Options: Options:
-av Adapter verbose -av Adapter verbose
-aq Adapter quiet -aq Adapter quiet
-af Adapter turn off serial frame
-tv TrkServer verbose -tv TrkServer verbose
-tq TrkServer quiet -tq TrkServer quiet
trkserver simulator will be run unless COM is specified trkserver simulator will be run unless COM is specified
Bluetooth:
rfcomm listen /dev/rfcomm0 1 \$PWD/run.pl -av -af {}
EOF EOF
# ------- Parse arguments # ------- Parse arguments
@@ -36,11 +41,16 @@ for (my $i = 0; $i < $argCount; $i++) {
push(@ADAPTER_OPTIONS, '-v'); push(@ADAPTER_OPTIONS, '-v');
} elsif ($a eq '-aq') { } elsif ($a eq '-aq') {
push(@ADAPTER_OPTIONS, '-q'); push(@ADAPTER_OPTIONS, '-q');
} elsif ($a eq '-af') {
push(@ADAPTER_OPTIONS, '-f');
} elsif ($a eq '-tv') { } elsif ($a eq '-tv') {
push(@TRKSERVEROPTIONS, '-v'); push(@TRKSERVEROPTIONS, '-v');
} elsif ($a eq '-tq') { } elsif ($a eq '-tq') {
push(@TRKSERVEROPTIONS, '-q'); push(@TRKSERVEROPTIONS, '-q');
} elsif ($a eq '-h') { } elsif ($a eq '-h') {
print $usage;
exit(0);
} else {
print $usage; print $usage;
exit(1); exit(1);
} }

View File

@@ -35,6 +35,7 @@
#include <QtCore/QQueue> #include <QtCore/QQueue>
#include <QtCore/QHash> #include <QtCore/QHash>
#include <QtCore/QMap> #include <QtCore/QMap>
#include <QtCore/QSharedPointer>
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
# include <windows.h> # include <windows.h>
@@ -312,10 +313,13 @@ void TrkDevice::tryTrkRead()
} }
#endif // Q_OS_WIN #endif // Q_OS_WIN
TrkResult r; TrkResult r;
while (extractResult(&d->trkReadBuffer, d->serialFrame, &r)) { QByteArray rawData;
while (extractResult(&d->trkReadBuffer, d->serialFrame, &r, &rawData)) {
if (d->verbose) if (d->verbose)
qDebug() << "Read TrkResult " << r.data.toHex(); qDebug() << "Read TrkResult " << r.data.toHex();
emit messageReceived(r); emit messageReceived(r);
if (!rawData.isEmpty())
emit rawDataReceived(rawData);
} }
} }
@@ -359,28 +363,149 @@ TrkMessage::TrkMessage(unsigned char c,
} }
// ------- TrkWriteQueueDevice // ------- TrkWriteQueueDevice
typedef QSharedPointer<TrkMessage> SharedPointerTrkMessage;
struct TrkWriteQueueDevicePrivate { /* Mixin class that manages a write queue of Trk messages. */
typedef QMap<unsigned char, TrkMessage> TokenMessageMap;
TrkWriteQueueDevicePrivate(); class TrkWriteQueue {
public:
typedef TrkWriteQueueDevice::Callback Callback;
TrkWriteQueue();
// Enqueue messages.
void queueTrkMessage(unsigned char code, Callback callback,
const QByteArray &data, const QVariant &cookie,
bool invokeOnNAK);
void queueTrkInitialPing();
// Call this from the device read notification with the results.
void slotHandleResult(const TrkResult &result);
// This can be called periodically in a timer to retrieve
// the pending messages to be sent.
bool pendingMessage(SharedPointerTrkMessage *message = 0);
// Notify the queue about the success of the write operation
// after taking the pendingMessage off.
void notifyWriteResult(bool ok);
// Factory function for ack message
static SharedPointerTrkMessage trkAck(unsigned char token);
private:
typedef QMap<unsigned char, SharedPointerTrkMessage> TokenMessageMap;
unsigned char nextTrkWriteToken();
unsigned char trkWriteToken; unsigned char trkWriteToken;
QQueue<TrkMessage> trkWriteQueue; QQueue<SharedPointerTrkMessage> trkWriteQueue;
TokenMessageMap writtenTrkMessages; TokenMessageMap writtenTrkMessages;
bool trkWriteBusy; bool trkWriteBusy;
}; };
TrkWriteQueueDevicePrivate::TrkWriteQueueDevicePrivate() : TrkWriteQueue::TrkWriteQueue() :
trkWriteToken(0), trkWriteToken(0),
trkWriteBusy(false) trkWriteBusy(false)
{ {
} }
unsigned char TrkWriteQueue::nextTrkWriteToken()
{
++trkWriteToken;
if (trkWriteToken == 0)
++trkWriteToken;
return trkWriteToken;
}
void TrkWriteQueue::queueTrkMessage(unsigned char code, Callback callback,
const QByteArray &data, const QVariant &cookie,
bool invokeOnNAK)
{
const unsigned char token = code == TRK_WRITE_QUEUE_NOOP_CODE ?
(unsigned char)(0) : nextTrkWriteToken();
SharedPointerTrkMessage msg(new TrkMessage(code, token, callback));
msg->data = data;
msg->cookie = cookie;
msg->invokeOnNAK = invokeOnNAK;
trkWriteQueue.append(msg);
}
bool TrkWriteQueue::pendingMessage(SharedPointerTrkMessage *message)
{
// Invoked from timer, try to flush out message queue
if (trkWriteBusy || trkWriteQueue.isEmpty())
return false;
// Handle the noop message, just invoke CB
if (trkWriteQueue.front()->code == TRK_WRITE_QUEUE_NOOP_CODE) {
const SharedPointerTrkMessage noopMessage = trkWriteQueue.dequeue();
if (noopMessage->callback) {
TrkResult result;
result.code = noopMessage->code;
result.token = noopMessage->token;
result.data = noopMessage->data;
result.cookie = noopMessage->cookie;
noopMessage->callback(result);
}
}
// Check again for real messages
if (trkWriteQueue.isEmpty())
return false;
if (message)
*message = trkWriteQueue.front();
return true;
}
void TrkWriteQueue::notifyWriteResult(bool ok)
{
// On success, dequeue message and await result
if (ok) {
const SharedPointerTrkMessage firstMsg = trkWriteQueue.dequeue();
writtenTrkMessages.insert(firstMsg->token, firstMsg);
trkWriteBusy = true;
}
}
void TrkWriteQueue::slotHandleResult(const TrkResult &result)
{
trkWriteBusy = false;
if (result.code != TrkNotifyAck && result.code != TrkNotifyNak)
return;
// Find which request the message belongs to and invoke callback
// if ACK or on NAK if desired.
const TokenMessageMap::iterator it = writtenTrkMessages.find(result.token);
if (it == writtenTrkMessages.end())
return;
const bool invokeCB = it.value()->callback
&& (result.code == TrkNotifyAck || it.value()->invokeOnNAK);
if (invokeCB) {
TrkResult result1 = result;
result1.cookie = it.value()->cookie;
it.value()->callback(result1);
}
writtenTrkMessages.erase(it);
}
SharedPointerTrkMessage TrkWriteQueue::trkAck(unsigned char token)
{
SharedPointerTrkMessage msg(new TrkMessage(0x80, token));
msg->token = token;
msg->data.append('\0');
return msg;
}
void TrkWriteQueue::queueTrkInitialPing()
{
const SharedPointerTrkMessage msg(new TrkMessage(0, 0)); // Ping, reset sequence count
trkWriteQueue.append(msg);
}
// -----------------------
TrkWriteQueueDevice::TrkWriteQueueDevice(QObject *parent) : TrkWriteQueueDevice::TrkWriteQueueDevice(QObject *parent) :
TrkDevice(parent), TrkDevice(parent),
qd(new TrkWriteQueueDevicePrivate) qd(new TrkWriteQueue)
{ {
connect(this, SIGNAL(messageReceived(TrkResult)), this, SLOT(slotHandleResult(TrkResult))); connect(this, SIGNAL(messageReceived(trk::TrkResult)), this, SLOT(slotHandleResult(trk::TrkResult)));
} }
TrkWriteQueueDevice::~TrkWriteQueueDevice() TrkWriteQueueDevice::~TrkWriteQueueDevice()
@@ -388,56 +513,34 @@ TrkWriteQueueDevice::~TrkWriteQueueDevice()
delete qd; delete qd;
} }
unsigned char TrkWriteQueueDevice::nextTrkWriteToken()
{
++qd->trkWriteToken;
if (qd->trkWriteToken == 0)
++qd->trkWriteToken;
return qd->trkWriteToken;
}
void TrkWriteQueueDevice::sendTrkMessage(unsigned char code, Callback callback, void TrkWriteQueueDevice::sendTrkMessage(unsigned char code, Callback callback,
const QByteArray &data, const QVariant &cookie, const QByteArray &data, const QVariant &cookie,
bool invokeOnNAK) bool invokeOnNAK)
{ {
TrkMessage msg(code, nextTrkWriteToken(), callback); qd->queueTrkMessage(code, callback, data, cookie, invokeOnNAK);
msg.data = data;
msg.cookie = cookie;
msg.invokeOnNAK = invokeOnNAK;
queueTrkMessage(msg);
} }
void TrkWriteQueueDevice::sendTrkInitialPing() void TrkWriteQueueDevice::sendTrkInitialPing()
{ {
const TrkMessage msg(0, 0); // Ping, reset sequence count qd->queueTrkInitialPing();
queueTrkMessage(msg);
} }
bool TrkWriteQueueDevice::sendTrkAck(unsigned char token) bool TrkWriteQueueDevice::sendTrkAck(unsigned char token)
{ {
TrkMessage msg(0x80, token);
msg.token = token;
msg.data.append('\0');
// The acknowledgement must not be queued! // The acknowledgement must not be queued!
return trkWriteRawMessage(msg); const SharedPointerTrkMessage ack = TrkWriteQueue::trkAck(token);
return trkWriteRawMessage(*ack);
// 01 90 00 07 7e 80 01 00 7d 5e 7e // 01 90 00 07 7e 80 01 00 7d 5e 7e
} }
void TrkWriteQueueDevice::queueTrkMessage(const TrkMessage &msg)
{
qd->trkWriteQueue.append(msg);
}
void TrkWriteQueueDevice::tryTrkWrite() void TrkWriteQueueDevice::tryTrkWrite()
{ {
// Invoked from timer, try to flush out message queue if (!qd->pendingMessage())
if (qd->trkWriteBusy)
return; return;
if (qd->trkWriteQueue.isEmpty()) SharedPointerTrkMessage message;
return; qd->pendingMessage(&message);
const bool success = trkWriteRawMessage(*message);
const TrkMessage msg = qd->trkWriteQueue.dequeue(); qd->notifyWriteResult(success);
trkWrite(msg);
} }
bool TrkWriteQueueDevice::trkWriteRawMessage(const TrkMessage &msg) bool TrkWriteQueueDevice::trkWriteRawMessage(const TrkMessage &msg)
@@ -452,13 +555,6 @@ bool TrkWriteQueueDevice::trkWriteRawMessage(const TrkMessage &msg)
return rc; return rc;
} }
bool TrkWriteQueueDevice::trkWrite(const TrkMessage &msg)
{
qd->writtenTrkMessages.insert(msg.token, msg);
qd->trkWriteBusy = true;
return trkWriteRawMessage(msg);
}
void TrkWriteQueueDevice::timerEvent(QTimerEvent *ev) void TrkWriteQueueDevice::timerEvent(QTimerEvent *ev)
{ {
tryTrkWrite(); tryTrkWrite();
@@ -467,23 +563,128 @@ void TrkWriteQueueDevice::timerEvent(QTimerEvent *ev)
void TrkWriteQueueDevice::slotHandleResult(const TrkResult &result) void TrkWriteQueueDevice::slotHandleResult(const TrkResult &result)
{ {
qd->trkWriteBusy = false; qd->slotHandleResult(result);
if (result.code != TrkNotifyAck && result.code != TrkNotifyNak) }
return;
// Find which request the message belongs to and invoke callback
// if ACK or on NAK if desired.
const TrkWriteQueueDevicePrivate::TokenMessageMap::iterator it = qd->writtenTrkMessages.find(result.token);
if (it == qd->writtenTrkMessages.end())
return;
const bool invokeCB = it.value().callback
&& (result.code == TrkNotifyAck || it.value().invokeOnNAK);
if (invokeCB) { // ----------- TrkWriteQueueDevice
TrkResult result1 = result;
result1.cookie = it.value().cookie; struct TrkWriteQueueIODevicePrivate {
it.value().callback(result1); TrkWriteQueueIODevicePrivate(const QSharedPointer<QIODevice> &d);
const QSharedPointer<QIODevice> device;
TrkWriteQueue queue;
QByteArray readBuffer;
bool serialFrame;
bool verbose;
};
TrkWriteQueueIODevicePrivate::TrkWriteQueueIODevicePrivate(const QSharedPointer<QIODevice> &d) :
device(d),
serialFrame(true),
verbose(false)
{
}
TrkWriteQueueIODevice::TrkWriteQueueIODevice(const QSharedPointer<QIODevice> &device,
QObject *parent) :
QObject(parent),
d(new TrkWriteQueueIODevicePrivate(device))
{
startTimer(TimerInterval);
}
TrkWriteQueueIODevice::~TrkWriteQueueIODevice()
{
delete d;
}
bool TrkWriteQueueIODevice::serialFrame() const
{
return d->serialFrame;
}
void TrkWriteQueueIODevice::setSerialFrame(bool f)
{
d->serialFrame = f;
}
bool TrkWriteQueueIODevice::verbose() const
{
return d->verbose;
}
void TrkWriteQueueIODevice::setVerbose(bool b)
{
d->verbose = b;
}
void TrkWriteQueueIODevice::sendTrkMessage(unsigned char code, Callback callback,
const QByteArray &data, const QVariant &cookie,
bool invokeOnNAK)
{
d->queue.queueTrkMessage(code, callback, data, cookie, invokeOnNAK);
}
void TrkWriteQueueIODevice::sendTrkInitialPing()
{
d->queue.queueTrkInitialPing();
}
bool TrkWriteQueueIODevice::sendTrkAck(unsigned char token)
{
// The acknowledgement must not be queued!
const SharedPointerTrkMessage ack = TrkWriteQueue::trkAck(token);
return trkWriteRawMessage(*ack);
// 01 90 00 07 7e 80 01 00 7d 5e 7e
}
void TrkWriteQueueIODevice::timerEvent(QTimerEvent *)
{
tryTrkWrite();
tryTrkRead();
}
void TrkWriteQueueIODevice::tryTrkWrite()
{
if (!d->queue.pendingMessage())
return;
SharedPointerTrkMessage message;
d->queue.pendingMessage(&message);
const bool success = trkWriteRawMessage(*message);
d->queue.notifyWriteResult(success);
}
bool TrkWriteQueueIODevice::trkWriteRawMessage(const TrkMessage &msg)
{
const QByteArray ba = frameMessage(msg.code, msg.token, msg.data, serialFrame());
if (verbose())
qDebug() << ("WRITE: " + stringFromArray(ba));
const bool ok = d->device->write(ba) != -1;
if (!ok) {
const QString msg = QString::fromLatin1("Unable to write %1 bytes: %2:").arg(ba.size()).arg(d->device->errorString());
qWarning("%s\n", qPrintable(msg));
}
return ok;
}
void TrkWriteQueueIODevice::tryTrkRead()
{
const quint64 bytesAvailable = d->device->bytesAvailable();
if (!bytesAvailable)
return;
const QByteArray newData = d->device->read(bytesAvailable);
if (d->verbose)
qDebug() << "READ " << newData.toHex();
d->readBuffer.append(newData);
TrkResult r;
QByteArray rawData;
while (extractResult(&(d->readBuffer), d->serialFrame, &r, &rawData)) {
d->queue.slotHandleResult(r);
emit messageReceived(r);
if (!rawData.isEmpty())
emit rawDataReceived(rawData);
} }
qd->writtenTrkMessages.erase(it);
} }
} // namespace tr } // namespace tr

View File

@@ -35,13 +35,19 @@
#include <QtCore/QObject> #include <QtCore/QObject>
#include <QtCore/QVariant> #include <QtCore/QVariant>
#include <QtCore/QByteArray> #include <QtCore/QByteArray>
#include <QtCore/QSharedPointer>
QT_BEGIN_NAMESPACE
class QIODevice;
QT_END_NAMESPACE
namespace trk { namespace trk {
struct TrkResult; struct TrkResult;
struct TrkMessage; struct TrkMessage;
struct TrkDevicePrivate; struct TrkDevicePrivate;
struct TrkWriteQueueDevicePrivate; class TrkWriteQueue;
struct TrkWriteQueueIODevicePrivate;
/* TrkDevice: Implements a Windows COM or Linux device for /* TrkDevice: Implements a Windows COM or Linux device for
* Trk communications. Provides synchronous write and asynchronous * Trk communications. Provides synchronous write and asynchronous
@@ -74,7 +80,9 @@ public:
bool write(const QByteArray &data, QString *errorMessage); bool write(const QByteArray &data, QString *errorMessage);
signals: signals:
void messageReceived(const TrkResult&); void messageReceived(const trk::TrkResult&);
// Emitted with the contents of messages enclosed in 07e, not for log output
void rawDataReceived(const QByteArray &data);
void error(const QString &s); void error(const QString &s);
protected: protected:
@@ -89,7 +97,12 @@ private:
/* TrkWriteQueueDevice: Extends TrkDevice by write message queue allowing /* TrkWriteQueueDevice: Extends TrkDevice by write message queue allowing
* for queueing messages with a notification callback. If the message receives * for queueing messages with a notification callback. If the message receives
* an ACK, the callback is invoked. */ * an ACK, the callback is invoked.
* The special message TRK_WRITE_QUEUE_NOOP_CODE code can be used for synchronisation.
* The respective message will not be sent, the callback is just invoked. */
enum { TRK_WRITE_QUEUE_NOOP_CODE = 0x7f };
class TrkWriteQueueDevice : public TrkDevice class TrkWriteQueueDevice : public TrkDevice
{ {
Q_OBJECT Q_OBJECT
@@ -115,21 +128,64 @@ public:
bool sendTrkAck(unsigned char token); bool sendTrkAck(unsigned char token);
private slots: private slots:
void slotHandleResult(const TrkResult &); void slotHandleResult(const trk::TrkResult &);
protected: protected:
virtual void timerEvent(QTimerEvent *ev); virtual void timerEvent(QTimerEvent *ev);
private: private:
unsigned char nextTrkWriteToken();
void queueTrkMessage(const TrkMessage &msg);
void tryTrkWrite(); void tryTrkWrite();
bool trkWriteRawMessage(const TrkMessage &msg); bool trkWriteRawMessage(const TrkMessage &msg);
bool trkWrite(const TrkMessage &msg);
TrkWriteQueueDevicePrivate *qd; TrkWriteQueue *qd;
}; };
/* A Trk queueing device wrapping around a QIODevice (otherwise
* mimicking TrkWriteQueueDevice).
* Can be used to forward Trk over a network or to simulate things. */
class TrkWriteQueueIODevice : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(TrkWriteQueueIODevice)
Q_PROPERTY(bool serialFrame READ serialFrame WRITE setSerialFrame)
Q_PROPERTY(bool verbose READ verbose WRITE setVerbose)
public:
typedef TrkFunctor1<const TrkResult &> Callback;
explicit TrkWriteQueueIODevice(const QSharedPointer<QIODevice> &device,
QObject *parent = 0);
virtual ~TrkWriteQueueIODevice();
bool serialFrame() const;
void setSerialFrame(bool f);
bool verbose() const;
void setVerbose(bool b);
void sendTrkMessage(unsigned char code,
Callback callback = Callback(),
const QByteArray &data = QByteArray(),
const QVariant &cookie = QVariant(),
bool invokeOnNAK = false);
void sendTrkInitialPing();
bool sendTrkAck(unsigned char token);
signals:
void messageReceived(const trk::TrkResult&);
// Emitted with the contents of messages enclosed in 07e, not for log output
void rawDataReceived(const QByteArray &data);
protected:
virtual void timerEvent(QTimerEvent *ev);
private:
void tryTrkRead();
void tryTrkWrite();
bool trkWriteRawMessage(const TrkMessage &msg);
TrkWriteQueueIODevicePrivate *d;
};
} // namespace trk } // namespace trk

View File

@@ -122,9 +122,11 @@ ushort isValidTrkResult(const QByteArray &buffer, bool serialFrame)
return firstDelimiterPos != -1 ? firstDelimiterPos : buffer.size(); return firstDelimiterPos != -1 ? firstDelimiterPos : buffer.size();
} }
bool extractResult(QByteArray *buffer, bool serialFrame, TrkResult *result) bool extractResult(QByteArray *buffer, bool serialFrame, TrkResult *result, QByteArray *rawData)
{ {
result->clear(); result->clear();
if(rawData)
rawData->clear();
const ushort len = isValidTrkResult(*buffer, serialFrame); const ushort len = isValidTrkResult(*buffer, serialFrame);
if (!len) if (!len)
return false; return false;
@@ -140,6 +142,8 @@ bool extractResult(QByteArray *buffer, bool serialFrame, TrkResult *result)
// FIXME: what happens if the length contains 0xfe? // FIXME: what happens if the length contains 0xfe?
// Assume for now that it passes unencoded! // Assume for now that it passes unencoded!
const QByteArray data = decode7d(buffer->mid(delimiterPos + 1, len - 2)); const QByteArray data = decode7d(buffer->mid(delimiterPos + 1, len - 2));
if(rawData)
*rawData = data;
*buffer->remove(0, delimiterPos + len); *buffer->remove(0, delimiterPos + len);
byte sum = 0; byte sum = 0;

View File

@@ -188,7 +188,7 @@ struct TrkResult
// the serial frame [0x01 0x90 <len>] and 0x7e encoded7d(ba) 0x7e // the serial frame [0x01 0x90 <len>] and 0x7e encoded7d(ba) 0x7e
QByteArray frameMessage(byte command, byte token, const QByteArray &data, bool serialFrame); QByteArray frameMessage(byte command, byte token, const QByteArray &data, bool serialFrame);
ushort isValidTrkResult(const QByteArray &buffer, bool serialFrame); ushort isValidTrkResult(const QByteArray &buffer, bool serialFrame);
bool extractResult(QByteArray *buffer, bool serialFrame, TrkResult *r); bool extractResult(QByteArray *buffer, bool serialFrame, TrkResult *r, QByteArray *rawData = 0);
QByteArray errorMessage(byte code); QByteArray errorMessage(byte code);
QByteArray hexNumber(uint n, int digits = 0); QByteArray hexNumber(uint n, int digits = 0);
uint swapEndian(uint in); uint swapEndian(uint in);