forked from qt-creator/qt-creator
Merge branch 'master' of git@scm.dev.nokia.troll.no:creator/mainline
This commit is contained in:
@@ -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)
|
||||||
|
@@ -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();
|
||||||
}
|
}
|
||||||
|
@@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@@ -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
|
||||||
|
BIN
src/plugins/qt4projectmanager/images/forms.png
Normal file
BIN
src/plugins/qt4projectmanager/images/forms.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 311 B |
BIN
src/plugins/qt4projectmanager/images/headers.png
Normal file
BIN
src/plugins/qt4projectmanager/images/headers.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 223 B |
BIN
src/plugins/qt4projectmanager/images/qt_qrc.png
Normal file
BIN
src/plugins/qt4projectmanager/images/qt_qrc.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 676 B |
BIN
src/plugins/qt4projectmanager/images/sources.png
Normal file
BIN
src/plugins/qt4projectmanager/images/sources.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 208 B |
BIN
src/plugins/qt4projectmanager/images/unknown.png
Normal file
BIN
src/plugins/qt4projectmanager/images/unknown.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 267 B |
@@ -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());
|
||||||
|
@@ -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
|
||||||
|
@@ -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>
|
||||||
|
0
tests/manual/qt4projectmanager/projecttree/foo.txt
Normal file
0
tests/manual/qt4projectmanager/projecttree/foo.txt
Normal file
0
tests/manual/qt4projectmanager/projecttree/main.cpp
Normal file
0
tests/manual/qt4projectmanager/projecttree/main.cpp
Normal file
0
tests/manual/qt4projectmanager/projecttree/main.h
Normal file
0
tests/manual/qt4projectmanager/projecttree/main.h
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
SOURCES += $$PWD/sources/prifileinc.cpp
|
||||||
|
HEADERS += $$PWD/headers/prifileinc.h
|
48
tests/manual/qt4projectmanager/projecttree/projecttree.pro
Normal file
48
tests/manual/qt4projectmanager/projecttree/projecttree.pro
Normal 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
|
0
tests/manual/qt4projectmanager/projecttree/widget.h
Normal file
0
tests/manual/qt4projectmanager/projecttree/widget.h
Normal 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)
|
||||||
|
@@ -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
|
||||||
|
@@ -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));
|
||||||
|
@@ -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();
|
||||||
|
@@ -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);
|
||||||
}
|
}
|
||||||
|
@@ -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
|
||||||
|
@@ -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
|
||||||
|
|
||||||
|
@@ -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;
|
||||||
|
@@ -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);
|
||||||
|
Reference in New Issue
Block a user