I use P/Invoke, not C++/CLI and am working on Visual Studio 2017.
My app is WPF.NET – 32 bit, written in C#. The app loads successfully its 32-bit DLL when I run it on my PCx64, but it crashes when I run it on a virtual machine (64 or 32). I think couldn't add the DLL...and don't know why.
My DLL is written on C++ and includes a class, with some functions written on Assembler. May be the problem comes from it?
MyClass.cpp:
int MyClass::Foo_1()
{
__asm
{
mov eax, 0
}
}
void MyClass::SetFoo_1()
{
resultEAX = new int;
int a = -1;
try
{
a = Foo_1();
}
catch (int e) { }
if (a == 0) {
*resultEAX = 0;
}
else {
*resultEAX = 1;
}
}
MyClass.h:
#ifndef MYCLASS_H
#define MYCLASS_H
class __declspec(dllexport) MyClass {
public:
int * resultEAX ;
int Foo1();
void SetFoo_1();
int GetEAX();
};
#endif
MyClassCaller.h:
extern "C" {
#endif
__declspec(dllexport) MyClass* Create();
__declspec(dllexport) void Dispose(MyClass* a_pObject);
__declspec(dllexport) void SetFoo_1(MyClass* a_pObject);
__eclspec(dllexport) int GetEAX(MyClass* a_pObject);
#ifdef __cplusplus
}
#endif
MyClassCaller.cpp:
Graphics* Create()
{
return new MyClass();
}
void Dispose(MyClass * a_pObject)
{
if (a_pObject != NULL)
{
delete a_pObject;
a_pObject = NULL;
}
}
void SetFoo_1(MyClass * a_pObject)
{
if (a_pObject != nullptr)
{
a_pObject->SetFoo_1();
}
}
int GetEAX(MyClass * a_pObject)
{
if (a_pObject != NULL)
{
return a_pObject->GetEAX();
}
return 0;
}
And I call the class from WPF.NET using managed C# code:
IntPtr pMyClass = MyClassHandling.Create();
Int32 a = 0;
Int64 b = 0;
long c = 0;
long rslt = 0;
try
{
MyClassHandling.SetFoo_1(pMyClass);
if (Environment.Is64BitOperatingSystem)
{
//"SysWOW64"
b = MyClassHandling.GetEAX(pMyClass);
//……
}
else
{
//"system32"
a = pMyClassHandling.GetEAX(pGraphics);
//…
}
MyClassHandling.Dispose (pGraphics);
pMyClass = IntPtr.Zero;
[DllImport("SomeAssemblerFunctions.dll")]
static public extern IntPtr Create();
[DllImport("SomeAssemblerFunctions.dll")]
static public extern void Dispose(IntPtr pGraphicsObject);
[DllImport("SomeAssemblerFunctions.dll", EntryPoint = "SetGraphicMode1")]
static public extern void SetFoo_1(IntPtr pGraphicsObject);
[DllImport("SomeAssemblerFunctions.dll", EntryPoint = "GetEAX")]
static public extern int GetEAX(IntPtr pGraphicsObject);
Related
I load a dll with win32 LoadLibrary, and when I am done with it, I call FreeLibrary, destorying all the memory allocated in the dll ect... Actually, memory leak problem only occures with std containers. It seems they are not willing to release their memory on destroy. Here is the code that leaks.
namespace ToolKit
{
class Game : public GamePlugin
{
public:
void Init(ToolKit::Main* master);
void Destroy();
void Frame(float deltaTime, Viewport* viewport);
void Resize(int width, int height);
void Event(SDL_Event event);
std::vector<int> point; // If I remove this line, no leaks are reported.
};
}
extern "C" TK_GAME_API ToolKit::Game * __stdcall GetInstance()
{
return new ToolKit::Game(); // Instance is deleted in the caller process than FreeLibrary() is called.
}
All functions are no-op in GamePlugin, and the process is not reporting any memory issue if there is no std container. I trap the leak in here. For the completion, I am sharing my standart CRT memory dump code.
int main(int argc, char* argv[])
{
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
return ToolKit_Main(argc, argv);
}
Load and unload code for the dll
void PluginManager::Load(const String& name)
{
HINSTANCE hinstLib;
TKPROC ProcAdd;
BOOL fRunTimeLinkSuccess = FALSE;
String dllName = name;
hinstLib = LoadLibrary(dllName.c_str());
if (hinstLib != NULL)
{
m_moduleHandle = (void*)hinstLib;
ProcAdd = (TKPROC)GetProcAddress(hinstLib, "GetInstance");
if (NULL != ProcAdd)
{
fRunTimeLinkSuccess = TRUE;
m_plugin = (ProcAdd)();
m_plugin->Init(ToolKit::Main::GetInstance());
}
}
if (!fRunTimeLinkSuccess)
{
m_reporterFn("Can not load plugin module " + dllName);
}
}
void PluginManager::Unload()
{
if (m_plugin)
{
m_plugin->Destroy();
SafeDel(m_plugin);
}
if (m_moduleHandle)
{
FreeLibrary((HINSTANCE)m_moduleHandle);
m_moduleHandle = nullptr;
}
}
Inorder to add some more clarification to the question, I am describing the program flow here:
PluginManager::Load loads the dll
GetInstance function is fetched from the dll
GetInstance return a plugin instance and it is stored in m_plugin
PluginManager::Unload deletes m_plugin and free the dll.
Here is the minimalcase that reproduces the leak.
Process side:
#include <stdio.h>
#include <cstdlib>
#include <crtdbg.h>
#include <string>
#include <functional>
#include <Windows.h>
#include "Plugin.h"
using namespace std;
class PluginManager
{
public:
void Load(const string& plugin);
void Unload();
public:
GamePlugin* m_plugin = nullptr;
void* m_moduleHandle = nullptr;
};
typedef GamePlugin* (__cdecl* TKPROC)();
void PluginManager::Load(const string& name)
{
HINSTANCE hinstLib;
TKPROC ProcAdd;
hinstLib = LoadLibrary(name.c_str());
if (hinstLib != NULL)
{
m_moduleHandle = (void*)hinstLib;
ProcAdd = (TKPROC)GetProcAddress(hinstLib, "GetInstance");
if (NULL != ProcAdd)
{
m_plugin = (ProcAdd)();
m_plugin->Init();
}
}
}
void PluginManager::Unload()
{
if (m_plugin)
{
m_plugin->Destroy();
delete m_plugin;
}
if (m_moduleHandle)
{
FreeLibrary((HINSTANCE)m_moduleHandle);
m_moduleHandle = nullptr;
}
}
int main(int argc, char* argv[])
{
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
PluginManager* pm = new PluginManager();
pm->Load("plugin.dll");
pm->Unload();
delete pm;
return 0;
}
Plugin interface:
#pragma once
#ifdef _WIN32
# ifdef TK_EXPORTS
# define TK_GAME_API __declspec(dllexport)
# else
# define TK_GAME_API __declspec(dllimport)
# endif
#elif
# define TK_GAME_API
#endif
struct GamePlugin
{
virtual void Init() = 0;
virtual void Destroy() = 0;
virtual void Frame() = 0;
};
DLL side:
#define TK_EXPORTS
#include "Plugin.h"
#include <vector>
class Game : public GamePlugin
{
public:
void Init() {}
void Destroy() {}
void Frame() {}
std::vector<int> point;
};
extern "C" TK_GAME_API GamePlugin * __stdcall GetInstance()
{
return new Game();
}
Exactly the same, if we remove the std::vector<int> point, there is no leak.
As can be seen in the minimal case, I am creating the plugin instance in the dll however deleting it in the process / executable. Eventough the memory is being freed, it gets reported as leak because that memory allocated within the dll and not freed there. Wow what a hassle was that ....
There are better ways of doing this, but in case some one lives the same problem, here is a quick fix.
Process:
void PluginManager::Unload()
{
if (m_plugin)
{
m_plugin->Destroy();
m_plugin = nullptr; // Clear the memory in where it is allocated.
}
if (m_moduleHandle)
{
FreeLibrary((HINSTANCE)m_moduleHandle);
m_moduleHandle = nullptr;
}
}
DLL:
void Destroy() { delete this; } // Now CRT Debug is happy. No false leak repots.
I am getting this error:
Linking CXX executable muse3.exe
driver/libmuse_driver.a(qttimer.obj):qttimer.cpp:(.rdata$.refptr._ZTVN8MusECore10InnerTimerE[.refptr._ZTVN8MusECore10InnerTimerE]+0x0): undefined reference to `vtable for MusECore::InnerTimer'
collect2.exe: error: ld returned 1 exit status
mingw32-make[2]: *** [muse\CMakeFiles\muse.dir\build.make:212: muse/muse3.exe] Error 1
mingw32-make[1]: *** [CMakeFiles/Makefile2:600: muse/CMakeFiles/muse.dir/all] Error 2
mingw32-make: *** [Makefile:151: all] Error 2
I understand that the message is a little unclear and the issue is probably with some method.
Here is my .h file:
#ifndef __QTTIMER_H__
#define __QTTIMER_H__
#include <fcntl.h>
#include <QThread>
#include <QBasicTimer>
#include <QTimerEvent>
#include "timerdev.h"
namespace MusECore {
//---------------------------------------------------------
// QtTimer
//---------------------------------------------------------
class InnerTimer : public QObject {
Q_OBJECT
int writePipe;
long int tickCount;
QBasicTimer timer;
public:
void setupTimer(int fd, int timeoutms);
~InnerTimer();
long int getTick();
bool isRunning() { return timer.isActive(); }
protected:
void timerEvent(QTimerEvent *event);
};
class QtTimer : public Timer, public QThread {
int writePipe;
int readPipe;
bool keepRunning;
InnerTimer *innerTimer;
int timeoutms;
public:
QtTimer();
virtual ~QtTimer();
virtual signed int initTimer(unsigned long init);
virtual long unsigned int setTimerResolution(unsigned long resolution);
virtual long unsigned int getTimerResolution();
virtual long unsigned int setTimerFreq(unsigned long freq);
virtual long unsigned int getTimerFreq();
virtual bool startTimer();
virtual bool stopTimer();
virtual long unsigned int getTimerTicks(bool printTicks=false);
void setFindBestTimer(bool ) { }
private:
virtual void run();
};
} // namespace MusECore
#endif //__QTTIMER_H__
And here is the .cpp file:
#include <cstdio>
#include <unistd.h>
#include <fcntl.h>
#include "qttimer.h"
#ifndef TIMER_DEBUG
#define TIMER_DEBUG 1
#endif
#ifdef _WIN32
#define pipe(fds) _pipe(fds, 4096, _O_BINARY)
#endif
namespace MusECore {
QtTimer::QtTimer()
{
if(TIMER_DEBUG)
fprintf(stderr,"QtTimer::QtTimer(this=%p) called\n",this);
innerTimer = NULL;
timeoutms = 10;
readPipe=-1;
writePipe=-1;
}
QtTimer::~QtTimer()
{
if(TIMER_DEBUG)
fprintf(stderr,"QtTimer::~QtTimer(this=%p) called\n",this);
exit(); // thread exit
}
signed int QtTimer::initTimer(unsigned long)
{
if(TIMER_DEBUG)
printf("QtTimer::initTimer(this=%p)\n",this);
int filedes[2]; // 0 - reading 1 - writing
if (pipe(filedes) == -1) {
perror("QtTimer - creating pipe failed");
exit(-1);
}
#ifndef _WIN32
int rv = fcntl(filedes[1], F_SETFL, O_NONBLOCK);
if (rv == -1)
perror("set pipe O_NONBLOCK");
#endif
if (pipe(filedes) == -1) {
perror("QtTimer - creating pipe1");
exit(-1);
}
writePipe = filedes[1];
readPipe = filedes[0];
return filedes[0];
}
long unsigned int QtTimer::setTimerResolution(unsigned long)
{
return 0;
}
long unsigned int QtTimer::setTimerFreq(unsigned long freq)
{
if (freq > 1000)
freq = 1000;
if (freq < 100)
freq = 100;
timeoutms = 1000/freq;
return 1000/timeoutms;
}
long unsigned int QtTimer::getTimerResolution()
{
return 20;
}
long unsigned int QtTimer::getTimerFreq()
{
return 1000/timeoutms;
}
bool QtTimer::startTimer()
{
QThread::start();
return true;
}
bool QtTimer::stopTimer()
{
QThread::quit();
return true;
}
unsigned long int QtTimer::getTimerTicks(bool /*printTicks*/)
{
if(TIMER_DEBUG)
printf("getTimerTicks()\n");
unsigned long int nn;
if (readPipe==-1) {
fprintf(stderr,"QtTimer::getTimerTicks(): no pipe open to read!\n");
return 0;
}
if (read(readPipe, &nn, sizeof(char)) != sizeof(char)) {
fprintf(stderr,"QtTimer::getTimerTicks(): error reading pipe\n");
return 0;
}
//return nn;
return innerTimer != 0 ? innerTimer->getTick() : 0;
}
void QtTimer::run()
{
//bool keepRunning = true;
innerTimer = new InnerTimer();
innerTimer->setupTimer(writePipe, timeoutms); // make sure it is running in the right thread
exec();
}
void InnerTimer::setupTimer(int fd, int timeoutms)
{
tickCount=0;
writePipe = fd;
timer.start(timeoutms, this);
printf("InnerTimer::setupTimer() started\n");
}
InnerTimer::~InnerTimer()
{
timer.stop();
}
void InnerTimer::timerEvent(QTimerEvent *event)
{
//if (tickCount%1000)
//printf("InnerTimer::timerEvent %ld ++++++++++++++++++++++\n",tickCount);
if (event->timerId() == timer.timerId()) {
tickCount++;
write(writePipe,"t",1);
}
}
long int InnerTimer::getTick()
{
return tickCount;
}
} // namespace MusECore
I have read other posts on this error, and they mostly point to some virtual methods that were not defined. But, to me, it seems that everything is defined properly and I also have the destructor defined.
Can anybody point me out to what is wrong?
PROBLEM
I'm starting to play with Arduino IoT (ESP32). I read the GPIO configuration from a file on the SD card. I have a problem with external interrupts. I need to count the number of interrupts on a given GPIO.
I wrote a class that stores the GPIO configuration, and put the objects of this class in a global array. How can I count interrupts on a given pin, so that the result is available by using the appropriate object method?
I tried different solutions, but the problem lies in the ISR method, which must be static. This method has no access to object fields, so I do not know where and how to increment the counter of interrupts.
I divided the code into several files. I attach only the necessary to solve this problem.
This holds up my project. Please help.
Main file:
#define GPIO_CONFIG_FILE "cfg/gpio.txt"
#define WIFI_AP_CONFIG_FILE "cfg/ap.txt"
#define WIFI_STA_CONFIG_FILE "cfg/sta.txt"
#define AVAILABLE_GPIO_CNT 7
#define LED_BUILTIN_OLIMEX 33
#define BTN_BUILTIN_OLIMEX 34
#include "FS.h"
#include "SD_MMC.h"
#include "GPIO_CONFIG.h"
GPIO_CONFIG gpio[AVAILABLE_GPIO_CNT];
uint32_t gpio_int_cnt[AVAILABLE_GPIO_CNT] = {0};
void setup() {
if (checkSdCard()) {
setUpPinsFromFile(GPIO_CONFIG_FILE);
}
}
void loop() {
}
GPIO_CONFIG.h
#ifndef GPIO_CONFIG_h
#define GPIO_CONFIG_h
#include "Arduino.h"
#define ID_LENGTH 7
class GPIO_CONFIG {
public:
GPIO_CONFIG();
void setUp(const char * key);
void printConfig();
uint8_t number();
uint8_t mode();
uint16_t multiplier();
bool inversion();
char * id();
static void isr();
static uint32_t int_cnt();
private:
uint8_t gp_number;
uint8_t gp_mode;
uint16_t gp_multiplier;
uint32_t gp_init_value;
bool gp_inversion;
char gp_id[ID_LENGTH];
// const uint8_t gp_mode_array[4] = {INPUT, OUTPUT, INPUT_PULLUP};
};
#endif
GPIO_CONFIG.cpp
#include "GPIO_CONFIG.h"
GPIO_CONFIG::GPIO_CONFIG() {
gp_number = 0;
gp_multiplier = 1;
gp_inversion = false;
gp_init_value = 0;
}
void GPIO_CONFIG::setUp(const char * key) {
//nr|id|name|mode|multi|inv|init
char cfg[sizeof(key)];
for (uint8_t b = 0; b < sizeof(key); ++b) {
cfg[b] = key[b];
}
//PIN_NUMBER
char * tok = strtok(cfg, "|");
gp_number = atoi(tok);
//ID
tok = strtok(NULL, "|");
for (int b = 0; b < sizeof(tok); b++) {
if (b < ID_LENGTH) {
gp_id[b] = tok[b];
} else {
break;
}
}
gp_id[ID_LENGTH - 1] = '\0';
//NAME
strtok(NULL, "|");
//MODE
tok = strtok(NULL, "|");
gp_mode = atoi(tok);
//MULTIPLIER
tok = strtok(NULL, "|");
gp_multiplier = atoi(tok);
//INVERSION
tok = strtok(NULL, "|");
gp_inversion = (atoi(tok) > 0);
//INITIAL VALUE
tok = strtok(NULL, "|");
gp_init_value = atoi(tok);
//0-in; 1-out; 2-int
if (gp_mode != 1) {
if (gp_inversion) { //sterowanie podstawowe przez vcc
pinMode(gp_number, INPUT_PULLUP);
} else {
pinMode(gp_number, INPUT);
}
if (gp_mode > 2) {
attachInterrupt(digitalPinToInterrupt(gp_number), isr, FALLING);
}
} else {
pinMode(gp_number, OUTPUT);
}
}
void GPIO_CONFIG::printConfig() {
#ifdef DEBUG
Serial.print("GPIO_CONFIG:");
Serial.print(" -no:");
Serial.print(gp_number);
Serial.print(" -id:");
Serial.print(gp_id);
Serial.print(" -mode:");
Serial.print(gp_mode);
Serial.print(" -multi:");
Serial.print(gp_multiplier);
Serial.print(" -inv:");
Serial.print(gp_inversion);
Serial.println("");
#endif
}
uint8_t GPIO_CONFIG::number() {
return gp_number;
}
uint8_t GPIO_CONFIG::mode() {
return gp_mode;
}
uint16_t GPIO_CONFIG::multiplier() {
return gp_multiplier;
}
bool GPIO_CONFIG::inversion() {
return gp_inversion;
}
char * GPIO_CONFIG::id() {
return gp_id;
}
void GPIO_CONFIG::isr() {
// gpio_int_cnt[0]++;
}
uint32_t GPIO_CONFIG::int_cnt() {
// return gpio_int_cnt[0];
}
#EDIT 2018/01/04 08:10
I add some changes to files:
Main .ino file
isr_ptr isrptr[AVAILABLE_GPIO_CNT];
GPIO_CONFIG.h
#define AVAILABLE_GPIO_CNT 7
class GPIO_CONFIG;
typedef /*static*/ void (*isr_ptr)();
extern isr_ptr isrptr[AVAILABLE_GPIO_CNT];
extern GPIO_CONFIG gpio[AVAILABLE_GPIO_CNT];
(...)
public:
void setIndex(const uint8_t * i);
uint8_t index();
(...)
private:
uint8_t gp_index;
uint32_t gp_cnt_value;
GPIO_CONFIG.cpp
void GPIO_CONFIG::setIndex(const uint8_t * i){
gp_index = *i;
isrptr[gp_index] = &isr;
}
uint8_t GPIO_CONFIG::index(){
return gp_index;
}
void GPIO_CONFIG::setUp(const char * key) {
(...)
attachInterrupt(digitalPinToInterrupt(gp_number), isrptr[gp_index], FALLING);
(...)
}
void GPIO_CONFIG::isr() {
for(uint8_t i=0; i<AVAILABLE_GPIO_CNT; ++i){
if(&isrptr[i] == &gpio[i].isr()){ //here is my actualy problem. how can i compare this?
gpio[i].increment_cnt_value();
break;
}
}
}
uint32_t GPIO_CONFIG::int_cnt() {
return gp_cnt_value;
}
SOLUTION
Here I place short fragments which have to be modified:
GPIO_CONFIG.cpp
From isrptr[gp_index] = &isr; to isrptr[gp_index] = isr;
From if(&isrptr[i] == &gpio[i].isr){ to if(isrptr[i] == gpio[i].isr){
I've looked over your code several times and can't find your ISR(s). I know how to handle this sort of problem in simple C code: You just define an array with one element for each interrupt pin, and increment that element from its respective ISR. I don't know how to relate that to what you've shown.
The part that often causes trouble is that you usually need to define variables shared between the main code and ISR as volatile. Failing to do this can cause problems that are really hard to find, due to the compiler optimizing away things that it decides aren't changed (in the ISR or the main code).
Best regards,
I'm trying to implement a basic application on an embedded device using lwIP.
I got the basic project set up, the retarget-ing works as expected.
However when I add lwIP into the project and call lwip_init() I have no more output. If I leave out the call to lwip_init() everything is back to normal.
What's more interesting, is that if I call fopen() the same behavior appears as before, I have no other output on the serial. I get no output no matter if I use the retarget-ed printf() function or if I use the driver's function USART_SendData().
What did I got wrong?
I posted below the retarget.c file and my Main.cpp (if I un-comment either BLOCK 1 or BLOCK 2, I have no more output) along with the initialization code.
Note: the retarget-ed functions send data to USART3 and USART_SendData() sends it to USART1.
I also tried to use the ITM port for debugging, but I get the same behavior.
retarget.c:
#include <stdio.h>
#include <LibSTM/stm32f10x_usart.h>
#include <rt_sys.h>
#pragma import(__use_no_semihosting_swi)
struct __FILE { int handle; };
FILE __stdout;
FILE __stdin;
FILE __stderr;
FILE *__aeabi_stdin;
FILE *__aeabi_stdout;
FILE *__aeabi_stderr;
int fputc(int ch, FILE *f)
{
while (!(USART3->SR & 0x0080));
USART3->DR = ch;
return (ch);
}
int ferror(FILE *f)
{
return EOF;
}
void _ttywrch(int ch)
{
fputc(ch, stdout);
}
void _sys_exit(int return_code)
{
label: goto label;
}
//retargeting since otherwise lwIP inclusion produces errors
//http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka3844.html
#define DEFAULT_HANDLE 0x100
const char __stdin_name[] = "my_stdin";
const char __stdout_name[] = "my_stdout";
const char __stderr_name[] = "my_stderr";
int _sys_write(FILEHANDLE fh, const unsigned char * buf, unsigned len, int mode){
int i;
for(i=0;i<len;i++)
{
fputc(buf[i], stdout);
}
return 0;
}
FILEHANDLE _sys_open(const char* name, int openmode){
return DEFAULT_HANDLE;
}
int _sys_istty(FILEHANDLE fh){
return 0;
}
int _sys_seek(FILEHANDLE fh, long pos){
return -1;
}
long _sys_flen(FILEHANDLE fh){
return 0;
}
int _sys_close(FILEHANDLE fh){
return 0;
}
int _sys_ensure(FILEHANDLE fh){
return 0;
}
main.cpp:
#include <HW/HWSetup.h>
#include <stdio.h>
#include "lwip/init.h"
int main()
{
HWSetup();
printf("Start!\r\n");
/* //BLOCK 1
FILE *f;
f = fopen("foobar", "r");
*/
/* //BLOCK 2
lwip_init();
*/
printf("End!\r\n");
while(1){
USART_SendData(USART1, 'x');
}
}
HWSetup.cpp:
#include <HW/HWSetup.h>
#include <stdio.h>
void SetupGPIO()
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE);
}
void SetupTraces()
{
GPIO_InitTypeDef GPIO_InitStructure;
// Trace GPIO
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
// Trace USART
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = 921600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Tx;
USART_Init(USART3, &USART_InitStructure);
USART_Cmd(USART3, ENABLE);
}
void SetupUSART_RS232()
{
GPIO_InitTypeDef GPIO_InitStructure;
// USART1 GPIO
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_Init(GPIOA, &GPIO_InitStructure);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No ;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_Init(USART1,&USART_InitStructure);
}
void HWSetup()
{
SetupGPIO();
SetupUSART_RS232();
SetupTraces();
}
I also tried debugging the code, but after I step in at BX R0 (which I expect to get me into main()) I just have to stop debugging since I cannot see where it's going, nor I have any other control over the debugger:
; Reset handler
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT __main
IMPORT SystemInit
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ENDP
The following code worked for me with a LPC1788 and µVision5 with and without microlib:
//retarget minimum requirements to work with printf
#include <stdio.h>
#include <rt_misc.h>
#ifndef __MICROLIB
#pragma import(__use_no_semihosting_swi) // some projects need this, some don't like it
#endif
#include <rt_sys.h>
extern void $Super$$_sys_open(void);
extern int sendchar(int ch); //needed for printf
extern int getch(void); //needed for scanf
FILEHANDLE $Sub$$_sys_open(const char *name, int openmode)
{
return 1; /* everything goes to the same output */
}
extern void $Super$$_sys_close(void);
int $Sub$$_sys_close(FILEHANDLE fh)
{
return 0;
}
extern void $Super$$_sys_write(void);
int $Sub$$_sys_write(FILEHANDLE fh, const unsigned char *buf,
unsigned len, int mode)
{
//your_device_write(buf, len);
return 0;
}
extern void $Super$$_sys_read(void);
int $Sub$$_sys_read(FILEHANDLE fh, unsigned char *buf,
unsigned len, int mode)
{
return -1; /* not supported */
}
extern void $Super$$_ttywrch(void);
void $Sub$$_ttywrch(int ch)
{
//char c = ch;
//your_device_write(&c, 1);
sendchar(ch);
}
extern void $Super$$_sys_istty(void);
int $Sub$$_sys_istty(FILEHANDLE fh)
{
return 0; /* buffered output */
}
extern void $Super$$_sys_seek(void);
int $Sub$$_sys_seek(FILEHANDLE fh, long pos)
{
return -1; /* not supported */
}
extern void $Super$$_sys_flen(void);
long $Sub$$_sys_flen(FILEHANDLE fh)
{
return -1; /* not supported */
}
extern void $Super$$_sys_exit(void);
long $Sub$$_sys_exit(FILEHANDLE fh)
{
return -1; /* not supported */
}
//eof
hope, it helps you, too.
Don't forget to initialize uart in main, or try to put initialization in _sys_open()
I am reading a message from a socket with C++ code and am trying to plot it interactively with matplotlib, but it seems Python code will block the main thread, no matter I use show() or ion() and draw(). ion() and draw() won't block in Python.
Any idea how to plot interactively with matplotlib in C++ code?
An example would be really good.
Thanks a lot.
You may also try creating a new thread that does the call to the
blocking function, so that it does not block IO in your main program
loop. Use an array of thread objects and loop through to find an unused
one, create a thread to do the blocking calls, and have another thread
that joins them when they are completed.
This code is a quick slap-together I did to demonstrate what I mean about
using threads to get pseudo asynchronous behavior for blocking functions...
I have not compiled it or combed over it very well, it is simply to show
you how to accomplish this.
#include <pthread.h>
#include <sys/types.h>
#include <string>
#include <memory.h>
#include <malloc.h>
#define MAX_THREADS 256 // Make this as low as possible!
using namespace std;
pthread_t PTHREAD_NULL;
typedef string someTypeOrStruct;
class MyClass
{
typedef struct
{
int id;
MyClass *obj;
someTypeOrStruct input;
} thread_data;
void draw(); //Undefined in this example
bool getInput(someTypeOrStruct *); //Undefined in this example
int AsyncDraw(MyClass * obj, someTypeOrStruct &input);
static void * Joiner(MyClass * obj);
static void * DoDraw(thread_data *arg);
pthread_t thread[MAX_THREADS], JoinThread;
bool threadRunning[MAX_THREADS], StopJoinThread;
bool exitRequested;
public:
void Main();
};
bool MyClass::getInput(someTypeOrStruct *input)
{
}
void MyClass::Main()
{
exitRequested = false;
pthread_create( &JoinThread, NULL, (void *(*)(void *))MyClass::Joiner, this);
while(!exitRequested)
{
someTypeOrStruct tmpinput;
if(getInput(&tmpinput))
AsyncDraw(this, tmpinput);
}
if(JoinThread != PTHREAD_NULL)
{
StopJoinThread = true;
pthread_join(JoinThread, NULL);
}
}
void *MyClass::DoDraw(thread_data *arg)
{
if(arg == NULL) return NULL;
thread_data *data = (thread_data *) arg;
data->obj->threadRunning[data->id] = true;
// -> Do your draw here <- //
free(arg);
data->obj->threadRunning[data->id] = false; // Let the joinThread know we are done with this handle...
}
int MyClass::AsyncDraw(MyClass *obj, someTypeOrStruct &input)
{
int timeout = 10; // Adjust higher to make it try harder...
while(timeout)
{
for(int i = 0; i < MAX_THREADS; i++)
{
if(thread[i] == PTHREAD_NULL)
{
thread_data *data = (thread_data *)malloc(sizeof(thread_data));
if(data)
{
data->id = i;
data->obj = this;
data->input = input;
pthread_create( &(thread[i]), NULL,(void* (*)(void*))MyClass::DoDraw, (void *)&data);
return 1;
}
return 0;
}
}
timeout--;
}
}
void *MyClass::Joiner(MyClass * obj)
{
obj->StopJoinThread = false;
while(!obj->StopJoinThread)
{
for(int i = 0; i < MAX_THREADS; i++)
if(!obj->threadRunning[i] && obj->thread[i] != PTHREAD_NULL)
{
pthread_join(obj->thread[i], NULL);
obj->thread[i] = PTHREAD_NULL;
}
}
}
int main(int argc, char **argv)
{
MyClass base;
base.Main();
return 0;
}
This way you can continue accepting input while the draw is occurring.
~~Fixed so the above code actually compiles, make sure to add -lpthread