I am using observer design pattern and updating the GUI from model which is working great. For each operation or function call from GUI, the model sends a series of updates at various stages to notify the GUI accordingly to do updates. This resulted in rather big if-else block in UpdateView() method. Is this how it should be or can this improved by applying another design pattern? I have split message from each function to a different handler which helps quite a bit. Note: the code is not compiled below but i took the essence of what I am doing. I have studied design patterns for a while but I am implementing it for the first time.
class Msg
{
int operation;
int opCode;
}
// in the model class
Device::Calibrate()
{
Msg msg;
msg.operation = CALIBRATE;
// ..... do some work -----
msg.opCode = DEPENDENT_MODULE_NOT_LOADED;
Notify( msg )
// .... do some work ------
msg.opCode = HARDWARE_MODULE_1_FAILED
Notify( msg )
// .... do some work ------
msg.opCode = CALIBRATION_IN_PROGRESS
Notify( msg )
// --- so on -----
}
void CMainDlg::UpdateView(const Msg * msg )
{
if( msg->operation == VERIFY ) // all message from Verify() button pressed
OnVerify( msg );
if( msg->operation == CALIBRATE ) // all messages from Calibrate button pressed
OnCalibrate();
}
void CMainDlg::OnCalibrate(const Msg * msg)
{
if (msg->opCode == DEPENDENT_MODULE_NOT_LOADED)
{
}
else if msg->opCode == HARDWARE_MODULE_1_FAILED)
{
}
else if msg->opCode == HARDWARE_MODULE_2_FAILED)
{
}
else if msg->opCode == CALIBRATION_IN_PROGRESS)
{
}
else if msg->opCode == OUTPUT_FILE_COULD_NOT_BE_CREATED)
{
}
else if msg->opCode == CALIBRATION_FAILED)
{
}
else if msg->opCode == CALIBRATION_PASSED)
{
}
}
Related
I tried to cast two messages in the onWSM function, one of the message is the accident message from TraCIDemo11p example see link; https://github.com/sommer/veins/blob/master/src/veins/modules/application/traci/TraCIDemo11p.cc and the other message I created myself.Simulation stops when handling of the accident message begins.
void MyClusterApp::onWSM(BaseFrame1609_4* frame)
{
// Your application has received a data message from another car or RSU
// code for handling the message goes here, see TraciDemo11p.cc for examples
joinMessage* wsm = check_and_cast<joinMessage*>(frame);
if (currentSubscribedServiceId == 7)
{
if(wsm->getRecipientAddress() == myId)
{
mClusterMembers.insert(wsm->getSenderId());
}
}
}
void MyClusterApp::onWSM_B(BaseFrame1609_4* frame)
{
accident* wsm = check_and_cast<accident*>(frame);
if (currentSubscribedServiceId == 8)
{
findHost()->getDisplayString().setTagArg("i", 1, "green");
if (mobility->getRoadId()[0] != ':') traciVehicle->changeRoute(wsm->getDemoData(), 9999);
if (!sentMessage) {
sentMessage = true;
wsm->setSenderAddress(myId);
wsm->setSerial(3);
for( NodeIdSetIterator it = mClusterMembers.begin(); it != mClusterMembers.end(); it++)
{
wsm->setRecipientAddress((*it));
scheduleAt(simTime() + 2 + uniform(0.01, 0.2), wsm->dup());
}
}
}
}
A runtime error occurred:
check_and_cast(): Cannot cast (veins::accident*) to type 'veins::joinMessage *' -- in module (veins::MyClusterApp) VANETScenario.node[1].appl (id=15), at t=74.797089255834s, event #711255
Launch a debugger with the following command?
nemiver --attach=4377 &
It seems that MyClusterApp::onWSM() may handle various types of messages. Therefore, I suggest use dynamic_cast to recognize the type of message - it is safe and returns nullptr when a message cannot be cast.
An example of modification:
void MyClusterApp::onWSM(BaseFrame1609_4* frame) {
joinMessage* wsm = dynamic_cast<joinMessage*>(frame);
if (wsm) {
if (currentSubscribedServiceId == 7) {
if(wsm->getRecipientAddress() == myId) {
mClusterMembers.insert(wsm->getSenderId());
}
}
} else {
// frame is not a pointer to joinMessage
}
}
Well, I'm trying to build this line of code, bit I get a compiler error. I've tryed to build without the compiler, but that didn't work either. Its about the __try and __except. Someone told me to move the code in the try block to another function. But I don't understand this:
Error 12 error C2712: Cannot use __try in functions that require
object unwinding
Error 437 error LNK1181: cannot open input file
void MSocketThread::Run()
{
__try{
//throw(pThread);
while (true) { // Waiting for SafeUDP Settting...
DWORD dwVal = WaitForSingleObject(m_KillEvent.GetEvent(), 100);
if (dwVal == WAIT_OBJECT_0) {
return;
}
else if (dwVal == WAIT_TIMEOUT) {
if (m_pSafeUDP)
break;
}
}
WSAEVENT EventArray[WSA_MAXIMUM_WAIT_EVENTS];
WORD wEventIndex = 0;
bool bSendable = false;
WSANETWORKEVENTS NetEvent;
WSAEVENT hFDEvent = WSACreateEvent();
EventArray[wEventIndex++] = hFDEvent;
EventArray[wEventIndex++] = m_ACKEvent.GetEvent();
EventArray[wEventIndex++] = m_SendEvent.GetEvent();
EventArray[wEventIndex++] = m_KillEvent.GetEvent();
WSAEventSelect(m_pSafeUDP->GetLocalSocket(), hFDEvent, FD_READ | FD_WRITE);
while (TRUE) {
DWORD dwReturn = WSAWaitForMultipleEvents(wEventIndex, EventArray, FALSE, SAFEUDP_SAFE_MANAGE_TIME, FALSE);
if (dwReturn == WSA_WAIT_TIMEOUT) { // Time
m_pSafeUDP->LockNetLink();
SafeSendManage();
m_pSafeUDP->UnlockNetLink();
}
else if (dwReturn == WSA_WAIT_EVENT_0) { // Socket Event
WSAEnumNetworkEvents(m_pSafeUDP->GetLocalSocket(), hFDEvent, &NetEvent);
if ((NetEvent.lNetworkEvents & FD_READ) == FD_READ) {
// OutputDebugString("SUDP> FD_READ \n");
m_pSafeUDP->LockNetLink();
Recv();
m_pSafeUDP->UnlockNetLink();
}
if ((NetEvent.lNetworkEvents & FD_WRITE) == FD_WRITE) {
bSendable = true;
// OutputDebugString("SUDP> FD_WRITE \n");
}
}
else if (dwReturn == WSA_WAIT_EVENT_0 + 1) { // ACK Send Event
// OutputDebugString("SUDP> ACK_EVENT \n");
FlushACK();
}
else if (dwReturn == WSA_WAIT_EVENT_0 + 2) { // Packet Send Event
// OutputDebugString("SUDP> SEND_EVENT \n");
if (bSendable == true)
FlushSend();
}
else if (dwReturn == WSA_WAIT_EVENT_0 + 3) { // Kill the Thread
break; // Stop Thread
}
}
WSACloseEvent(hFDEvent);
// Clear Queues
LockSend();
{
for (SendListItor itor = m_SendList.begin(); itor != m_SendList.end();) {
delete (*itor);
itor = m_SendList.erase(itor);
}
}
{
for (SendListItor itor = m_TempSendList.begin(); itor != m_TempSendList.end();) {
delete (*itor);
itor = m_TempSendList.erase(itor);
}
}
UnlockSend();
LockACK();
{
for (ACKSendListItor itor = m_ACKSendList.begin(); itor != m_ACKSendList.end();) {
delete (*itor);
itor = m_ACKSendList.erase(itor);
}
}
{
for (ACKSendListItor itor = m_TempACKSendList.begin(); itor != m_TempACKSendList.end();) {
delete (*itor);
itor = m_TempACKSendList.erase(itor);
}
}
UnlockACK();
}
__except (this->CrashDump(GetExceptionInformation()))
Basically, SEH and C++ unwinding aren't exactly compatible; they require the compiler to modify the function on the machine code level, and MS apparently decided not to support the modifications for the two at the same time, so any function can only support either SEH unwind actions (__except or __finally) or C++ unwind actions (catch or objects with destructors).
I suspect the problem in your case are the iterators in your loops; they might have destructors. Although iterators are usually simple and don't need destructors, this is not the case for debug iterators, which often register their existence on construction and deregister it on destruction, in order to detect invalidated iterators and other invalid usage.
The usual workaround is to split the function. Make your run function contain just this:
void MSocketThread::Run()
{
__try {
RunNoSeh();
} __except (this->CrashDump(GetExceptionInformation())) {
}
}
void MSocketThread::RunNoSeh()
{
// Code that was inside the __try goes here.
}
I have been trying to figure out how to ignore repeated keys in an xcb event loop and so far have got this:
extern xcb_connection_t *connection;
// looks like there's a leak, but in the finished product there isn't
bool poll_event(/*my_event_type e*/){
static xcb_generic_event_t *ev = nullptr;
static xcb_key_press_event_t *last_key_ev = nullptr;
if(!(ev = xcb_poll_for_event(connection)))
return false;
switch(ev->response_type & ~0x80){
case XCB_KEY_PRESS:{
xcb_key_press_event_t *kp = static_cast<decltype(kp)>(ev);
if(last_key_ev &&
((last_key_ev->response_type & ~0x80) == XCB_KEY_RELEASE) &&
(last_key_ev->detail == kp->detail) &&
(last_key_ev->time == kp->time)
){
std::free(last_key_ev);
last_key_ev = kp;
// is repeated key, ignore this event
return false;
}
std::free(last_key_ev);
last_key_ev = kp;
return true;
}
case XCB_KEY_RELEASE:{
/* same as KEY_PRESS but looking for KEY_PRESS in 'last_key_ev' */
}
default:
std::free(ev);
return true;
}
}
This doesn't work because it will only discard the second half of the repeated event pair (XCB_KEY_RELEASE then XCB_KEY_PRESS), so I get a bunch of XCB_KEY_RELEASE events rather than none. but there doesn't seem to be a function in xcb for testing if there is an event in the queue without modifying the queue itself.
I am looking for an XEventsQueued equivalent in xcb so I could test if there is an event queued straight afterward instead of using the last event that occured, but have failed to do so yet.
Have any of you done this already and be willing to pass on your wisdom in the matter?
So, #n.m said that XCB has no utility for peaking into the event queue. So I wrote my own wrapper over the xcb event queue so I could peak into the next event. Here is how I implemented it if anyone is interested:
First my event queue:
extern xcb_connection_t *connection;
struct my_event_queue_t{
xcb_generic_event_t *prev = nullptr;
xcb_generic_event_t *current = nullptr;
xcb_generic_event_t *next = nullptr;
} event_queue;
void update_event_queue(){
std::free(event_queue.prev);
event_queue.prev = event_queue.current;
event_queue.current = event_queue.next;
event_queue.next = xcb_poll_for_queued_event(connection);
}
Then the event loop:
struct my_event_type;
bool poll_event(my_event_type &ret){
static xcb_generic_event_t *xcb_ev = nullptr;
update_event_queue();
xcb_ev = event_queue.current;
if(!xcb_ev) return false;
switch(xcb_ev->response_type & ~0x80){
case XCB_KEY_RELEASE:{
static xcb_key_press_event_t *kp = nullptr;
kp = xcb_ev;
if(event_queue.next &&
((event_queue->response_type & ~0x80) == XCB_KEY_PRESS) &&
(reinterpret_cast<decltype(kp)>(xcb_ev)->time == kp->time) &&
(reinterpret_cast<decltype(kp)>(xcb_ev)->detail == kp->detail)
){
update_event_queue(); // eat repeat event
return false;
}
// update ret
return true;
}
case XCB_KEY_PRESS:{
// handle normally
// update ret
return true;
}
default:
// signify unknown event
return true;
}
}
This is how I ignore key repeats in my application, which is a toolkit for game/graphical application development. I haven't tested what sort of performance dip this gives, but it should be minimal.
Sorry if this is a repeat, but I'm trying to figure out the implementation of SoRayPickAction in Open Inventor. I'm trying to implement it so that it will, when the mouse is clicked, select a particular node so then I can translate, rotate, etc. I have three nodes: desk, lamp, and frame (picture frame). However, I don't think that my code is at all right. I also have various methods such a MouseButtonCallback (which will check if the mouse is clicked and then use a navigator) and MouseMoveCallback (same idea). So here's the code that I have, but do you have any suggestions? Right now, well, it doesn't do anything.
SbViewportRegion viewport(400,300);
SoRayPickAction m(viewport);
m.setRay(SbVec3f(0.0,0.0,0.0), SbVec3f(0.0,0.0,-1.0));
m.apply(callback_node);
const SoPickedPoint *mpp = m.getPickedPoint();
if(mpp != NULL) {
std::cout << "test" << std::endl;
}
Might you also know of an action in OpenInventor that can "place" a node in the scene, i.e. place the lamp on top of the desk, frame on the wall, etc. Is it with paths? I don't even know what I'm looking for, unfortunately. Thanks so much for your help!!
Edit: How does this look?
SoSeparator *desk2;
SoSeparator *lamp2;
SoSeparator *pic_frame2;
SoSeparator *picked;
void MouseButtonCallback(void* data, SoEventCallback* node)
{
SoHandleEventAction* action = node->getAction();
const SoMouseButtonEvent* event = static_cast<const SoMouseButtonEvent*>(action- >getEvent());
Navigator* nav = static_cast<Navigator*>(data);
if (SoMouseButtonEvent::isButtonPressEvent(event, event->getButton()))
nav->OnMouseDown(event, action);
else
nav->OnMouseUp(event, action);
const SbViewportRegion & viewportRegion = action->getViewportRegion();
SoRayPickAction pickAction(viewportRegion);
SbVec2s mousePos = event->getPosition(viewportRegion);
pickAction.setPoint(mousePos);
pickAction.setPickAll(TRUE);
pickAction.setRadius(2.0F);
pickAction.setRay(SbVec3f(0.0,0.0,0.0), SbVec3f(0.0,0.0,-1.0));
pickAction.apply(node);
const SoPickedPoint *mpp = pickAction.getPickedPoint();
if(mpp != NULL) {
SoPath *path = mpp->getPath();
if(desk2 != NULL && path->containsNode(desk2))
{ //but this doesn't respond with cout when I try to test it :(
if (SoMouseButtonEvent::isButtonPressEvent(event, event->getButton()))
*picked = *desk2;
}
else if(lamp2 != NULL && path->containsNode(lamp2))
{
if (SoMouseButtonEvent::isButtonPressEvent(event, event->getButton()))
*picked = *lamp2;
}
else if(pic_frame2 != NULL && path->containsNode(pic_frame2))
{
if (SoMouseButtonEvent::isButtonPressEvent(event, event->getButton()))
*picked = *pic_frame2;
}
action->setHandled();
}
void MouseMoveCallback(void* data, SoEventCallback* node)
{
SoHandleEventAction* action = node->getAction();
const SoLocation2Event* event = static_cast<const SoLocation2Event*>(action->getEvent());
Navigator* nav = static_cast<Navigator*>(data);
nav->OnMouseMove(event, action);
const SbViewportRegion & viewportRegion = action->getViewportRegion();
SoRayPickAction pickAction(viewportRegion);
SbVec2s mousePos = event->getPosition(viewportRegion);
pickAction.setPoint(mousePos);
pickAction.setPickAll(TRUE);
pickAction.setRadius(2.0F);
pickAction.setRay(SbVec3f(0.0,0.0,0.0), SbVec3f(0.0,0.0,-1.0));
pickAction.apply(node);
const SoPickedPoint *mpp = pickAction.getPickedPoint();
if(mpp != NULL) {
SoPath *path = mpp->getPath();
if(desk2 != NULL && path->containsNode(desk2))
{
*picked = *desk2; //can't remember how to set pointers, will figure that out
}
else if(lamp2 != NULL && path->containsNode(lamp2))
{
*picked = *lamp2;
}
else if(pic_frame2 != NULL && path->containsNode(pic_frame2))
{
*picked = *pic_frame2;
}
}
action->setHandled();
}
(part of main method)
//desk
SoTransform *desk_transform = new SoTransform;
desk_transform->translation.setValue(SbVec3f(380,340,330));
SoSeparator* desk2 = new SoSeparator();
desk2->addChild(desk_transform);
desk2->addChild(desk);
root->addChild(desk2);
SoTransformerManip* picked_transform = new SoTransformerManip();
picked_transform->translation.setValue(SbVec3f(200,340,330));
SoSeparator* pick2 = new SoSeparator();
pick2->addChild(picked_transform);
pick2->addChild(picked);
root->addChild(pick2);
std::auto_ptr<btCollisionShape> picked_shape(new btBoxShape(btVector3(10.0f, 10.0f, 10.0f)));
CollisionEngine* picked_collision = new CollisionEngine(collision_world.get(), picked_shape.get());
picked_collision->translation_in.connectFrom(&picked_transform->translation);
picked_collision->rotation_in.connectFrom(&picked_transform->rotation);
picked_transform->translation.connectFrom(&picked_collision->translation_out);
You have the picked point. You then get an SoPath as you guessed. Then see if the path contains a node you want to do something with.
SbViewportRegion viewport(400,300);
SoRayPickAction m(viewport);
m.setRay(SbVec3f(0.0,0.0,0.0), SbVec3f(0.0,0.0,-1.0));
m.apply(callback_node);
const SoPickedPoint *mpp = m.getPickedPoint();
if(mpp != NULL) {
std::cout << "test" << std::endl;
SoPath * path = pickedPoint->getPath();
if (deskSeparator != NULL && path->containsNode(deskSeparator)
{
}
else if (lampSeparator != NULL && path->containsNode(lampSeparator)
{
}
else if (radomeSeparator != NULL && path->containsNode(radomeSeparator)
{
if ( SoMouseButtonEvent::isButtonPressEvent( event, SoMouseButtonEvent::BUTTON2 )
|| ( SoMouseButtonEvent::isButtonPressEvent( event, SoMouseButtonEvent::BUTTON1 ) && event->wasShiftDown() ) )
{
modelPointMoving = true;
const SoDetail * detail = modelPickedPoint->getDetail( 0 );
int face = -1;
if ( detail && detail->isOfType( SoFaceDetail::getClassTypeId() ) )
{
const SoFaceDetail * faceDetail = static_cast<const SoFaceDetail *>( detail );
face = faceDetail->getFaceIndex();
}
updateStatusBar( face, point.getValue(), normal.getValue() );
graphicModel.postNote( pickedPoint );
break;
}
else if ( SoMouseButtonEvent::isButtonPressEvent( event, SoMouseButtonEvent::BUTTON1 ) )
{
}
else if ( SoMouseButtonEvent::isButtonReleaseEvent( event, SoMouseButtonEvent::BUTTON1 ) )
{
}
}
}
You'll eventually want to connect the pick ray to the mouse position sort of like this:
// Set an 2-pixel wide region around the pixel.
SbVec2s mousePosition = event->getPosition( viewportRegion );
pickAction.setPoint( mousePosition );
pickAction.setPickAll( TRUE );
pickAction.setRadius( 2.0F );
This is done before you .apply() the pick action of course.
I guess my code is a mixture of yours and mine but I think it should give you a start. Also, this is sitting inside a function to process mouse events:
void
RenderWindow::mouseEvent( void *, SoEventCallback * eventCallback )
{
const SoEvent *event = eventCallback->getEvent();
if ( ! event )
{
qDebug() << " ** Error in mousePressCallback: Event not found.";
return;
}
//SoType eventType = event->getTypeId();
//SbName eventTypeName = eventType.getName();
//const char * eventTypeString = eventTypeName.getString();
SoHandleEventAction * action = eventCallback->getAction();
const SbViewportRegion & viewportRegion = action->getViewportRegion();
SoRayPickAction pickAction( viewportRegion );
Up in main or a setup routine I register the mouse event (for both click action and location (moving the mouse over the viewport):
// Add a mouse event callback to catch mouse button presses.
SoEventCallback * mouseEventCallback = new SoEventCallback();
mouseEventCallback->setName( "MOUSE_EVENT_CALLBACK" );
mouseEventCallback->addEventCallback( SoMouseButtonEvent::getClassTypeId(), &::mouseEvent, static_cast<void *>( this ) );
// Add a mouse event callback to catch mouse motion.
mouseEventCallback->addEventCallback( SoLocation2Event::getClassTypeId(), &::mouseEvent, static_cast<void *>( this ) );
rootSeparator->addChild( mouseEventCallback );
Now that I look at it I wrote the chunks in reverse order ;-). Sorry.
Good Luck
I have some lua script that have some long running task like getting a web page so I make it yield then the C code handle get page job async, so the thread free to do other job and after a specify time it check back to see is the get page job finished , if so then resume the script. the problem is the thread can't resume the job after async wait.
here is my code I riped it from a class so a little messy sorry
////script:
function Loginmegaupload_com(hp, user, pass, cookie)
setURL(hp, "http://megaupload.com/?c=login")
importPost(hp, "login=1&redir=1")
addPost(hp, "username", user)
addPost(hp, "password", pass)
GetPage()
if isHeaderContain(hp, "user=") ~= nil then
SetFileLink(cookie, GetAllCookie(hp))
return 1
else
return 0
end
end
////c code
int FileSharingService::GetPage(lua_State *ls)
{
return lua_yield(ls, 0);
}
void FileSharingService::AsyncWait(Http_RequestEx *Http, lua_State *LS, boost::asio::deadline_timer* Timer)
{
if( (Http->status_code == Http_RequestEx::ERROR) || (Http->status_code == Http_RequestEx::FISNISHED))
{
if(Http->status_code == Http_RequestEx::FISNISHED)
{
int result = lua_resume(LS, 0); // here I got result == 2 mean error ?
if(result == 0)//lua script exit normal, resume success
{
delete Http;
delete Timer;
}
}
else
return;
}
else
{
Timer->expires_from_now(boost::posix_time::milliseconds(200));
Timer->async_wait(boost::bind(&FileSharingService::AsyncWait, this, Http, LS, Timer));
}
}
bool FileSharingService::Login(string URL, string User, string Pass, string &Cookie)
{
Http_RequestEx *http = new Http_RequestEx;
http->url = URL;
LuaWarper* Lua = Lua_map[boost::this_thread::get_id()]; //one main luaState per ioservice thread
lua_State *thread = lua_newthread(Lua->GetState());
boost::asio::deadline_timer *timer = new boost::asio::deadline_timer(*HClient.ioservice);
string functioname = "Login" + GetServicename(URL);
if( Lua->isFunctionAvaliable(functioname.c_str()) == false )
{
throw(FileSharingService::SERVICE_NOT_AVALIABLE);
}
else
{
lua_getglobal(thread, functioname.c_str());
lua_pushlightuserdata(thread, http);
lua_pushstring(thread, User.c_str());
lua_pushstring(thread, Pass.c_str());
lua_pushlightuserdata(thread, &Cookie);
int result = lua_resume(thread, 4);
if(result == LUA_YIELD)
{
HClient.Do(*http, false);
AsyncWait(http, thread, timer);
}
else if(result == 0)
{
//fisnished at first call
}
else
{
//yield error, will handle late
}
}
}
Sorry never mind this question, lua_resume return 2 mean error but script work just fine, asio get page work fine too, and I tracked down the line that respond for fail of lua_resume :
httpinfo.header.append(buffer, (HeaderEndIndex-buffer+2) );
if I comment that line lua_resume work as expected it return 0 mean script exit, this line don't do any thing that can affect the lua thread state it just a string assign, I checked there no overflow. so weird.