Feb
16
2009
0

FYP Technology: CFSocketRef

It’s been a few days since I’ve posted, and I haven’t managed to get a lot of work done in the last couple of day either, between SkyCon on Saturday, doing something weird to my neck Friday night (and the pain’s not gone away since), and managing to catch a cold yesterday.

On Thursday or Friday I spent a bit of time figuring out how to copy the framebuffer into local memory, encode into some compressed format, and get that data off over the network. Turns out it’s pretty easy to do with Ogre!

// This pixel format is totally arbitrary
Ogre::PixelFormat pf = Ogre::PF_R8G8B8;
// Pixelbox to receive the framebuffer contents. 480x320x1
//   (i.e., 2D box the size of the iPod's screen)
Ogre::PixelBox pb( 480, 320, 1, pf, pbBuffer);
 
// Copy the framebuffer into the pixelbox
mTexture->copyContentsToMemory( pb, Ogre::RenderTarget::FB_AUTO );
 
// Create a new image and give it the pixelbox as its content
Ogre::Image im;
im.loadDynamicImage( pbBuffer, 480, 320, pf );
// Encode the image as a PNG and grab a pointer to the resulting datastream
Ogre::DataStreamPtr ds = im.encode( "png" );
 
// create a buffer on the stack and copy the stream in there
unsigned char* b = new unsigned char[ds->size()];
ds->read( b, ds->size() );
 
// tell the IO subsystem to send it off over the network
YkdIOSubsystem::getSingleton().sendImage( b, (int)ds->size() );

Obviously there’s a whole lot of copying going on here that doesn’t need to be done, but it works as a basic prototype (albeit with about 4.5 fps.. the copyContentsToMemory() on the RenderTexture take half the time and the sending of the image blocks right now).

On the receiving side (the iPod), the image was coming through ok (as verified by the second, third and fourth bytes of the received data being ‘PNG’). However, the UIImage wasn’t updating at all. When I’d press the home button, I’d briefly see the image, but not while actually running.

After some poking around various forums, I saw a mention of trouble updating UIKit components from other threads. I had a single NSThread doing recvfrom() on a BSD socket, then making changes to the UI based on the messages it received. This morning I got rid of the NSThread and set up a CFSocketRef to run in the main NSRunLoop instead, and it works! When data is available to be read, a callback is fired and in that callback I can do whatever I want to the UI.

Here’s how the CFSocketRef is set up:

// boring old BSD socket
int serverSocket = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
 
// This is vital so the callback can get a reference to "self"
CFSocketContext socketCtxt = { 0, self, NULL, NULL, NULL };
// set up a CFSocketRef using the existing socket created above with socket()
CFSocketRef sockRef = CFSocketCreateWithNative ( kCFAllocatorDefault, serverSocket, kCFSocketReadCallBack, &recvData, &socketCtxt );
 
// Add the CFSocketRef to the main run loop
CFRunLoopSourceRef runLoopSource = CFSocketCreateRunLoopSource( kCFAllocatorDefault, sockRef, 0 );
CFRunLoopAddSource( CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopDefaultMode );
 
// Clean up...
CFRelease( runLoopSource );
CFRelease( sockRef );

Here’s what the callback (&recvData above) looks like:

static void recvData(CFSocketRef socket, CFSocketCallBackType type, 
					 CFDataRef address, const void *data, void *info) {
	if ( type != kCFSocketReadCallBack ) return;
	// send a message to "info": "self" from the context originally used in CFSocketCreateWithNative()
	//   YkRemote's recvDataFromSocket: will perform recvfrom(), and hopefully it won't need to block.
	[(YkRemote*)info recvDataFromSocket:socket];
}

It’s my first time hopping back and forth between an Objective-C method and a C function like that, but it worked!

With this set-up, all UIKit calls are in the main thread and my problems have all disappeared.

No comments »
Written by ダニエル氏 in: University |
Feb
11
2009
0

Wordpress 2.7.1 Auto-update

Wow, Wordpress 2.7’s self-update really works! It also “updated” my customisations on the theme, so the banner is nuked. I have a backup but have been meaning to make a new one anyway. Hopefully I can pull something together over the next day or so.

No comments »
Written by ダニエル氏 in: Uncategorized |
Feb
11
2009
0

Embarrassing myself…

In 2006 I wrote some code to work out the coordinates of a point on the circumference of a circle based on an angle. This was so I could draw this nice clock in PHP:

Clock!

It should display the current time in Ireland (though my server’s clock seems about 4 minutes behind).

The following code calculates the point at angle $angle on the circumference of the circle of radius $r centred on (0,0).

function findposc($angle, $r)
{
    if ($angle > 180) $ang = $angle - 180;
    $ang = 90-$angle;
 
    $m = tan(deg2rad($ang));
    $x = sqrt(($r*$r) / (1+($m*$m)));
    $y = $m*$x;
 
    if ($angle>180) {
        $x = $x*(-1);
        $y = $y*(-1);
    }
 
    return $res;
}

Look at it! It’s embarrassing! I don’t even know what “$m” is supposed to be! I remember sitting down and working it out on paper, but I don’t know how my understanding of trigonometry was so horrible considering I had just done the leaving cert. 90-$angle? Why?? $y ends up being this (pseudo-code, and $angle is in radians):

$y = tan($angle) * (sqrt(($radius^2) / (1+(tan^2($angle)))

Looks badass, I know, but what Y really should be is:

$y = $radius * cos($angle)

I honestly couldn’t sleep the night I saw this code. I went to bed and after going over and over the trig in my head for about 20 minutes, I had to get up and rewrite it. Here’s the proper version in Java:

Point2D.Double calcPointOnCircle( double angle, double radius )
{
       double angleAsRad = angle / (180/Math.PI);
 
       Double x = radius * Math.sin( angleAsRad );
       Double y = -radius * Math.cos( angleAsRad );
 
       return new Point2D.Double( x, y );
}

… and then I could sleep.

No comments »
Written by ダニエル氏 in: Uncategorized |
Feb
11
2009
2

FYP Development: “(?) is totally broken and I can’t fix it!”

There have been a few occasions where something is totally, unexplainably broken. I usually spend a few hours working on it, stepping through the entire execution of what is invariably multithreaded code, and just cannot find what’s wrong.

A few days ago, my job queue just wasn’t working nicely with collision callbacks. You can attach “collision listeners” to rigid bodies in Havok, so when they collide, your implementation of the collision listener gets called. The problem I was seeing was that one callback in the listener seemed to cause one or two other callbacks to get fired when it was processed. So every time a worker thread processed a job, the queue would stay the same size.

After a while, I just decided I’d comment it out, ignore it, and hope that it would get fixed automatigically at some stage later. After doing some work on areas of code related to the listener today, I uncommented the buggy code and it worked! The job queue never gets more than one entry in it now!

This has happened a few times, and I’m a big supporter of ignoring buggy code after a certain amount of effort doesn’t fix it. I’ll just write a note about it somewhere, leave it alone, and when I check in on the broken code a few days later something else has fixed it.

I believe this is thanks to all the refactoring I do. Cleaning up how objects interact with each other usually ends up working wonders for fixing “weird” behaviour.

2 comments »
Written by ダニエル氏 in: University |
Feb
10
2009
0

FYP Technology: YkdMultithreading

I wasn’t expecting multithreading to be such a big part of the FYP, but it’s turned out to be something I find really exciting and I’ve been spending a lot of time on it. It’s looking like a multithreading library might fall out of this! Here’s there headers for the code. So far I have the following classes:

YkdLockManager

As I discussed before, this class looks after locking various objects. Since the post I wrote on it a few days ago, I’ve implemented shared locks, so objects don’t just have lock(), but instead have lockForRead() and lockForWrite(). This means that multiple objects can get a lock at the same time if they’re only reading, but when one requests write access it can get it exclusively.

YkdLockManager uses a shared lock internally too. When a mutex is requested, it requests read-only access on the queue and searches for it. If it finds it, then it unlocks and returns. If it doesn’t find it, it “upgrades” its lock to exclusive access for write (this might take a while if other threads have ownership). Once it attains write access, it creates a new mutex and adds it to the queue, then unlocks and returns.

boost::shared_mutex* YkdLockManager::getMutex(void* object)
{
	// pointer to the mutex we'll return eventually.
	// I use this as "it->second" should be done while this thread 
	//     has read access, making "return it->second" impossible.
	boost::shared_mutex *mutex;
 
	// Request read-only access
	mLockMapLock.lock_shared();
	// Search the map for the object
	std::map<void*, boost::shared_mutex*>::iterator it = mLockMap.find( object );
 
	// If not found..
	if ( it == mLockMap.end() )
	{
		// upgrade the lock to an exclusive lock for write access
		mLockMapLock.lock_upgrade();
		mutex = new boost::shared_mutex();
		// perform write operation
		mLockMap[object] = mutex;
		// surrender ownership
		mLockMapLock.unlock_upgrade();
 
		return mutex;
	}
 
	mutex = it->second;
 
	// surrender ownership
	mLockMapLock.unlock_shared();
	return mutex;
}

YkdJobQueue

The job queue is basically an std::deque (double-ended queue) of boost function pointers. This means that you can add any method call at all to the queue, so anything can become a job. If you’re calling a method but don’t need results from it right away, you can just put it into the job queue and a worker thread will pick it up. Just to be clear, boost::bind will wrap anything into a function pointer, so parameter passing and everything is ok (though it’s worth giving a moment’s thought to the fact that referenced objects might disappear before the thread gets started if you’re not careful).

typedef boost::function0<void> YkdJobPtr;
// ... later ...
std::deque< YkdJobPtr > mQueue;

YkdJobQueue::getJob() is blocking. When it’s called, it will use boost::condition::wait() to block until a job is available. The call is unblocked when YkdJobQueue::addJob() adds a job to the queue and calls boost::condition::notify_one(), which wakes up one of the threads waiting for a job to be available.

void YkdJobQueue::addJob( YkdJobPtr job )
{
	// Take ownership of mQueue
	boost::mutex::scoped_lock lock( mQueueMutex );
 
	// Add new job to the queue
	mQueue.push_back( job );
 
	// Notify some other thread that data is available
	mNotEmpty.notify_one();
}
 
YkdJobPtr YkdJobQueue::getJob()
{
	// Take ownership of mQueue
	boost::mutex::scoped_lock lock( mQueueMutex );
 
	// wait for something to arrive
	while ( mQueue.empty() )
	{
		mNotEmpty.wait( lock );
	}
 
	// Return the front and pop it off
	YkdJobPtr job = mQueue.front();
	mQueue.pop_front();
 
	return job;
}

YkdThreadPool

The thread pool just spawns worker threads and delete them when its destructor is called. Worker threads’ destructors interrupt and join them.

YkdWorkerThread

The worker threads don’t do much beyond grabbing a job, running it, and grabbing another job until it’s interrupted. Not much going on, but I like how interruption is disabled while the job is actually running and enabled while waiting for a job to be available.

void YkdWorkerThread::YkdWorkerThreadMain()
{
	for ( ;; )
	{
		// Grab a new job. This is a blocking call.
		YkdJobPtr job = YkdJobQueue::getSingletonPtr()->getJob();
 
		// Don't allow interruption until the job is done.
		boost::this_thread::disable_interruption di;
 
		// Run the job
		job();
	}
}
No comments »
Written by ダニエル氏 in: University |
Feb
09
2009
0

CS4226: Clocks!

Today we were given the spec for the second CS4226 Distributed Systems assignment, the whole thing was about threading, which is really all I’ve been doing in the FYP for the last few days, so it was pretty fun and a nice distraction to get it done. I also got to poke around AWT a bit which was interesting. It’s amazing how much faster I can get stuff done in Java than I can with C++.

Here’s a screenshot of the application running four threads, each updating clocks at different intervals:


lab2-4a

No comments »
Written by ダニエル氏 in: University |
Feb
07
2009
0

FYP Technology: YkdLockManager

YkdLockManager is an idea that had been bouncing around for a while but I threw it together today and it’s working well. (By the way, Ykd is the class prefix for YakumoDemo.)

My code has lots of threads everywhere, and that means that I need to lock a lot of objects a lot of the time. What would be really nice is if every object I’m using, from all five or so SDKs, had methods which allowed me to lock and unlock them. Since that’s not realistic, the solution I came up with was YkdLockManager, which is basically a wrapper around an std::map of void pointers and mutexes.

Here’s an abstraction of what the class definition looks like:

class YkdLockManager
{
public:
	void lock( void* object );
	void unlock( void* object );
 
	boost::mutex* getMutex(void* object);
 
private:
	std::map<void*, boost::mutex*> mLockMap;
	boost::mutex mLockMapLock;
 
};

I’ve taken away the singleton code to keep the expression of intention of the class clearer, but it does implement the singleton pattern so I can do something like the following from anywhere in code:

YkdLockManager::getSingleton().lock( this );

… and later unlock it in a similar fashion. So now every object in my code can be locked or unlocked, by passing its memory address into YkdLockManager.

All lock() and unlock() do is call getMutex() and then call lock() or unlock() respectively on the mutex that’s returned.

Here’s what getMutex() does:

boost::mutex* YkdLockManager::getMutex(void* object){
	boost::mutex::scoped_lock lock( mLockMapLock );
 
	// find the mutex in the map
	std::map<void*, boost::mutex*>::iterator it = mLockMap.find( object );
 
	// if it wasn't found...
	if ( it == mLockMap.end() )
	{
		// create a new mutex for the object, add it, and return it
		boost::mutex *mutex = new boost::mutex();
		mLockMap[object] = mutex;
		return mutex;
	}
 
	// if it was found, return the associated mutex
	return it->second;
}

Look back at mLockMapLock: while writing the class I realised that it’s inherently going to be called by multiple threads at the same time (that’s the whole point), so what if two threads call lock() at the same time on the same object for the first time, and they both go to create the necessary mutex? That won’t do, so I have to lock the map before doing any operations on it… hence a lock-map lock is in order.

As painful as it is to debug all this stuff, it really is exciting when every thread is co-operating nicely with all the others.

No comments »
Written by ダニエル氏 in: University |
Feb
06
2009
0

FYP Development: Monitor #3

My experience of iPhone development has become less pleasant as my project has grown, and I think a lot of it has to do with working on all the code (and with Interface Builder) in just 13″ inches of screen. In an attempt to resolve that, I’ve set up a third monitor on my desk for the MacBook. Here’s what I have running on my desk now:

  • Left: 20″ 1600×1200 Dell LCD for OS X
  • Centre: 22″ 1680×1050 Philips LCD for Windows (main)
  • Right: 17″ 1280×1024 Dell LCD for Windows (aux)

On the main display I’ll usually have what I’m focusing on, be it code or debugging or 3ds Max. On the aux display I’ll have documentation or email client open usually. I’m writing this in a window on it now.

I also have 2 keyboards and 2 mice, which is proving tricky to get totally comfortable with. I’ve done it before with a curved desk, so I can swivel from one machine to the other, but it’s not so easy on a desk like this. What would be ideal is some sort of stand which could elevate one keyboard over the other a few inches. For writing code, I don’t think the discomfort of missing wrist support would be so much of a problem, since my elbows are supported in the chair anyway.

No comments »
Written by ダニエル氏 in: University |
Feb
05
2009
0

FYP Technology: WinAPI and UIKit Junk

I spent a lot of time today not getting a lot of work done, but spending a lot of time mucking about in what I wouldn’t describe as enjoyable APIs. The first is the win32 API, which no-one likes anyway. A few hours of work involved looking through a few .rc files from other projects and finding where I was going wrong with mine, and then the following few of lines of code:

HWND hwnd = 0;
HINSTANCE hInst = GetModuleHandle(NULL);
mWindow->getCustomAttribute( "WINDOW", &hwnd ); // mWindow is an Ogre window
 
// IDI_APPICON is defined in Resource.h, generated from Yakumo.rc
SendMessage( hwnd, WM_SETICON, ICON_BIG, (LPARAM)LoadIcon(hInst, MAKEINTRESOURCE(IDI_APPICON)) );
SendMessage( hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(hInst, MAKEINTRESOURCE(IDI_APPICON)) );

This changed my application’s icon in Alt+Tab and in the corner of the window. A small result for the amount of time it took.

The latter half of the day was spent with UIKit, and especially struggling with Interface Builder. That involved a whole lot of guessing and looking at Apple’s sample projects until I found one that was organised a bit like my own, and figured out where I was going wrong. Turns out I needed to have my custom UIView’s UIViewController (MainViewController) added to the main UIWindow’s XIB file, not in with the UIView’s XIB. Also, instead of loading the MainViewController from its own XIB file when it’s displayed at runtime, I set up an outlet from the UIViewController which displays MainViewController (that is, BrowserController), connecting to MainViewController. That way it instantiates it itself automagically and I can just use the reference at runtime without worrying about loading it from its XIB.

This allowed me get a workaround sorted out for the trouble I’ve been having with shouldAutorotateToInterfaceOrientation:. Right now I’m struggling with this piece of code:

- (void) didLoseConnection
{	
	[[UIAccelerometer sharedAccelerometer] setDelegate:nil];
	UIAlertView *mbox = [[[UIAlertView alloc] initWithTitle:@"Error" message:@"Game connection lost." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] autorelease];
	[mbox show];
	[self dismissModalViewControllerAnimated:YES];
}

It should display an alert box and then make the MainViewController disappear… but the screen dims like it’s about to show an alert box but just freezes… (update: solution is here)

Here’s how I’m displaying MainViewController using the outlet:

[self presentModalViewController:mainViewController animated:YES];
No comments »
Written by ダニエル氏 in: University |

Powered by WordPress | Theme: Aeros 2.0 by TheBuckmaker.com