latest posts

Intro

NeXTstation Turbo Rom
A while back in Summer 2011, I had this strange desire to obtain "classic" computers from every manufacturer that I had grown up hearing things about, obviously couldn't afford. Anyone following my blogs knows I have amassed quite a collection of Silicon Graphics machines along with a few DEC, Sun and late PowerPC-era Apple machines (G4 and G5). One manufacturer that had previously alluded me was NeXT. While still living at my parent's house back in 2004 I had an opportunity to purchase a NeXTcube, the pinacle of NeXT computers. Unfortunately, as an undergrad college student, I just couldn't justify the $300 at the time for a 33mhz computer that I might turn on every now and then. Fast forward a few years to 2011 shortly after Steve Jobs passed away, the prices on eBay for NeXT computers skyrocketed. It could have just been a coincidence, coupled with the fact that there were supposedly only 50,000 NeXT computers built between 1989 and 1993. Fast forward another couple years, prices seemed to have almost hit rock bottom for the NeXTstation Turbo, so I finally broke down and got one in near mint condition.

Inside Look

For those looking into purchasing a NeXTstation computer, a couple things to know before diving in:

-There are 4 models of the NeXTstation: regular (mono), Color, Turbo and Color Turbo. The main differences outside of supporting color in the Color models (4096 colors btw), is the speed of the Motorola 68040 (33mhz for Turbo models, 25mhz for non) and the maximum amount of ram the motherboard can take. For the Turbo models 128mb of ram is supported (72pin SIMMS, also compatible with the later year 68040 Macintosh models). For the non-Turbo models you're limited to 32mb of ram.

-The power supply is extremely picky amount how much draw your hard drive can utilize. I thankfully read a ton of posts regarding the maximum power draw which is extremely low (no Maxtor Atlas 15k II Ultra 320 drives unfortunately). By default, any drive with the older SCSI I 50pin internal connector should be fine. Another element is the heat output of a 15k drive for instance. There is only a single fan in the NeXTstation. Also the partitions have a 4gb limit, so if you have a larger drive, just remember to partition it in 4gb blocks

-By default there is no "VGA" connector, thankfully I was able to procure a Y-VGA Cable (one end to the NeXTstation, one to my monitor and one to the Soundbox) so I could use an Acer LED I had laying around.

Onto my NeXTstation Turbo machine specifically:

-Motorola 68040 33mhz CPU
-128MB of RAM
-2gb Quantum Fireball SCSI I Hard Drive
-2.88MB 3.5" Floppy Drive

NeXTstation Turbo - Inside
NeXTstation Turbo Rom
NeXTstation Turbo - RAM
Specifically for the Turbo models you'll need 72pin 70ns SIMMs (on a historical side note in December 1992 an 8MB SIMM went for $225). On eBay right now you can get 4x32mb SIMMs for $40 shipped, so keep an eye out. On a side note, a quick way to know if it's a Turbo board or not is if there are only 4 ram sockets instead of the 8 on non- turbo boards.

NeXTstation Turbo - Back
Note the 8P8C 10baseT ethernet connector - very handy to have it built-in compared to other machines of this era that still only had AUI or BNC connectors.
NeXTstation Turbo - Hard Drive
50pin SCSI I drives are used, which aren't anywhere close to the speed I'm used to in my SGI or Sun machines with a Maxtor Atlas 15k II Ultra 320 drive
NeXTstation Turbo - Power Supply

NeXTstep

Having never used NeXTstep, I was unprepared for what to expect. The only operating systems from that era I've used are Windows 3.x, MS-DOS and IRIX 5.3. I know 3.3 came out in February 1995, but it seems as though that really only updated the CPU Architecture support rather than a feature release, so I'll be comparing it to operating systems released around October 1993 (when 3.2 was released).

Turning on the NeXTstation via the power button on the keyboard (shown below), you're presented with a few startup screens before the login prompt:

NeXTstation Turbo - Power Button

NeXTstation Turbo - Boot Sequence

NeXTstation Turbo - NeXTstep Boot Sequence

NeXTstation Turbo - NeXTstep Login Prompt

Immediately I came to the realization I hadn't used a monochrome computer ever as the first computer I ever used (a Tandy 1000) had 16 color support, though games like Falcon and Test Drive I remember playing in black and white. Upon logging in, I noticed the computer as Jobs had wanted, was silent outside of the hard drive spinning. The interface, similar to IRIX, offered something similar to IRIX's Toolchest, but different functionality mapping to keyboard shortcuts. Something I didn't really didn't note at first was the command button below the space bar on the keyboard. By holding down the command button and s for instance in the text editor would save. Similar to the Control+S we're used to today, but easier to execute in my opinion with your left thumb.

One of the first things I did was try NFS Mounting. I created a mount on my Windows Server 2012 R2 NAS with semi-recent ports of GCC, BASH and other "standard" software. Sure enough it was picked up by NeXTstep and I was copying files between the machines. Kind of interesting that machines of different architectures (x86- 64 vs m68k) and 20 years apart, communicating over the same protocol have 0 issues.

For those curious, I've made local copies of the latest versions of GCC and Bash available here:
Bash
CC Tools for GCC
GCC 3.4.6
Updated Headers for GCC

Installing packages is a bit more modern than I was used to with IRIX. Each "package" has a modern installer, as opposed to tardists in IRIX.

NeXTstation Turbo - Installing BASH

One thing to note when installing Bash (or any other shell), update the /etc/shells file with the path to the new shell like so:
NeXTstation Turbo - Adjusting Shells

Without updating that file, you won't be able to utilize the new shell when adding/modifying users in the GUI.

What's NeXT?

Yesterday I started working on the jcBENCH port for NeXTstep/m68k, I should have that wrapped up within a week. I am very interested in seeing how it compares to a 33mhz MIPS R3000 Silicon Graphics Indigo that came out a year before the NeXTstation (July 1991), albiet at a little bit higher price ($7,995 vs $6,500), but offered color and additional video options.
Jumping back into MonoDroid development the last couple days at work after having not touched it in almost a year, I knew I was going to be rusty. Interestingly enough I'm finding it much closer to Windows Phone development than I remembered. Having had no luck in finding MonoDroid for Windows Phone Developers I figured I'd start an ongoing post.

Open a Browser

In Windows Phone you would open a Web Browser with the following function: [csharp] private void openBrowser(string url) { var task = new WebBrowserTask(); task.Uri = new Uri(url); task.Show(); } [/csharp] However in MonoDroid you have to do this: [csharp] private void openBrowser(string url) { var browserIntent = new Intent(Intent.ActionView, Android.Net.Uri.Parse(url)); StartActivity(browserIntent); } [/csharp]

New Line in TextView

In Windows Phone in your XAML you'd do something like this to insert a new line into your TextBlock: [csharp] <TextBlock>This line is awesome<LineBreak/>but this one is better</TextBlock> [/csharp] However in MonoDroid you need to be sure to set the singleLine property to false like so: [csharp] <TextView android:layout_width="fill_parent" android:singleLine="false" android:text="This line is awesome\r\nbut this one is better" /> [/csharp]

Login form (aka tapping enter goes to next field, with the last field hiding the keyboard)

In your XAML on Windows Phone you might have something like the following: [csharp] <StackPanel Orientation="Vertical"> <TextBox x:Name="TextBoxUsername" /> <TextBox x:Name="TextBoxPassword" /> </StackPanel> [/csharp] And then in your code behind: [csharp] public LoginPage() { InitializeComponent(); TextBoxUsername.KeyDown += TextBoxUsername_KeyDown; TextBoxPassword.KeyDown += TextBoxPassword_KeyDown; } void TextBoxUsername_KeyDown(object sender, KeyEventArgs e) { if (e.Key == Key.Enter) { TextBoxPassword.Focus(); } } void TextBoxPassword_KeyDown(object sender, KeyEventArgs e) { if (e.Key == Key.Enter) { Focus(); } } [/csharp] Basically upon hitting the enter key while in the TextBoxUsername field it will set the focus to the TextBoxPassword field. Upon hitting enter in the TextBoxPassword field, it will set the focus to the main page and close the keyboard. For MonoDroid, it is a little different. In your axml: [csharp] <EditText android:id="@+id/TextBoxUsername" android:imeOptions="actionNext" android:singleLine="true" android:layout_width="fill_parent" android:layout_height="wrap_content" /> <EditText android:id="@+id/TextBoxPassword" android:imeOptions="actionDone" android:singleLine="true" android:layout_width="fill_parent" android:layout_height="wrap_content" /> [/csharp] The key part is the android:imeOptions values, actionNext will move the focus to the next EditText field and the actionDone will send the done command back to your keylisteners etc. In your Activity code behind, you need to add this override. Update the Resource.Id.xxxxxxx with the name of the field you want the keyboard to hide upon hitting enter: [csharp] public override bool DispatchKeyEvent(KeyEvent e) { if (CurrentFocus.Id == Resource.Id.TextBoxPasswordKey && (e.KeyCode == Keycode.NumpadEnter || e.KeyCode == Keycode.Enter)) { var imm = GetSystemService(Context.InputMethodService) as InputMethodManager; if (imm != null) { imm.HideSoftInputFromWindow(this.CurrentFocus.WindowToken, 0); } return true; } return base.DispatchKeyEvent(e); } [/csharp] I should also note you'll need the using Android.Views.InputMethods; line added to your code behind as well.

Capturing Images via the Camera

In Windows Phone capturing images from your Library or Taking a new picture is pretty trivial, assuming you have a Button to choose/take the picture: [csharp] PhotoChooserTask _pcTask = null; private byte[] _pictureBytes; public PictureUpload() { InitializeComponent(); _pcTask = new PhotoChooserTask(); _pcTask.Completed += new EventHandler<PhotoResult>(_pcTask_Completed); } void _pcTask_Completed(object sender, PhotoResult e) { if (e.TaskResult == TaskResult.OK) { MemoryStream ms = new MemoryStream(); e.ChosenPhoto.CopyTo(ms); _pictureBytes = ms.ToArray(); ms.Dispose(); } } private void btnChooseImage_Click(object sender, RoutedEventArgs e) { _pcTask.ShowCamera = true; _pcTask.Show(); } [/csharp] From there just upload the _pictureBytes to your WCF Service or wherever. In MonoDroid as expected is a little different, assuming you have a button click event to take the picture and an ImageView to display the image: [csharp] private string _imageUri; // Global variable to access the image's Uri later void btnChooseImage_Click(object sender, EventArgs e) { var uri = ContentResolver.Insert(isMounted ? Android.Provider.MediaStore.Images.Media.ExternalContentUri : Android.Provider.MediaStore.Images.Media.InternalContentUri, new ContentValues()); _imageUri = uri.ToString(); var i = new Intent(Android.Provider.MediaStore.ActionImageCapture); i.PutExtra(Android.Provider.MediaStore.ExtraOutput, uri); StartActivityForResult(i, 0); } protected override void OnActivityResult(int requestCode, Result resultCode, Intent data) { if (resultCode == Result.Ok && requestCode == 0) { imageView = FindViewById<ImageView>(Resource.Id.ivThumbnail); imageView.DrawingCacheEnabled = true; imageView.SetImageURI(Android.Net.Uri.Parse(_imageUri)); } } [/csharp] At this point you have the picture taken and the Uri of the image. In your Layout: [csharp] <Button android:text="Choose Image" android:id="@+id/btnChooseImage" android:layout_width="fill_parent" android:layout_height="wrap_content" /> <ImageView android:id="@+id/ivThumbnail" android:layout_width="300dp" android:layout_height="150dp" /> [/csharp]

Loading a picture from local storage and avoiding the dreaded java.lang.outofmemory exception

A fairly common scenario, maybe pulling an image from the code described above, now you want to upload it some where? In the Windows Phone above in addition to taking/capturing the picture, we have a byte[] with the data, on MonoDroid it is a little different. A situation I ran into on my HTC Vivid was a java.lang.outofmemory exception. Further investigation, apparently Android has a 24mb VM limit per app (and some devices it is set to 16mb). Doing some research, I came across Twig's post. As expected it was in Java, so I converted it over to MonoDroid and added some additional features to fit my needs. So literally this function will return a scaled Bitmap object for you to turn around and convert to a Byte[]. The function: [csharp] private Android.Graphics.Bitmap loadBitmapFromURI(Android.Net.Uri uri, int maxDimension) { var inputStream = ContentResolver.OpenInputStream(uri); var bfOptions = new Android.Graphics.BitmapFactory.Options(); bfOptions.InJustDecodeBounds = true; var bitmap = Android.Graphics.BitmapFactory.DecodeStream(inputStream, null, bfOptions); inputStream.Close(); var resizeScale = 1; if (bfOptions.OutHeight > maxDimension || bfOptions.OutWidth > maxDimension) { resizeScale = (int)Math.Pow(2, (int)Math.Round(Math.Log(maxDimension / (double)Math.Max(bfOptions.OutHeight, bfOptions.OutWidth)) / Math.Log(0.5))); } bfOptions = new Android.Graphics.BitmapFactory.Options(); bfOptions.InSampleSize = resizeScale; inputStream = ContentResolver.OpenInputStream(uri); bitmap = Android.Graphics.BitmapFactory.DecodeStream(inputStream, null, bfOptions); inputStream.Close(); return bitmap; } [/csharp] For a practical use, loading the image, scaling if necessary and then getting a Byte[]: [csharp] var bitmap = loadBitmapFromURI(Android.Net.Uri.Parse(_imageUri), 800); var ms = new MemoryStream(); bitmap.Compress(Android.Graphics.Bitmap.CompressFormat.Jpeg, 100, ms); [/csharp] At this point doing a ms.ToArray() will get you to the same point the Windows Phone code above did, so if you had a WCF Service, you could at this point upload the byte array just as you could with a Windows Phone above.

Transparent Background on a ListView, LayoutView etc?

In Windows Phone you can set the Background or Foreground properties to simply Transparent like so: [csharp] <StackPanel Background="Transparent" Orientation="Vertical"> <TextBlock>Transparentcy is awesome</TextBlock> </StackPanel> [/csharp] In MonoDroid it's simply "@null" like so for the ListView [csharp] <ListView android:background="@null" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:text="Transparentcy is awesome" android:gravity="center" /> [/csharp]

Locking Orientation

In Windows Phone you can set your page's orientation to be forced into Landscape or Portrait in your xaml like so: [csharp] <phone:PhoneApplicationPage SupportedOrientations="Portrait" Orientation="Portrait"> [/csharp] In MonoDroid I couldn't figure out a better way to do it than the following line inside your Activity's OnCreate function like so: [csharp] protected override void OnCreate(Bundle bundle) { base.OnCreate(bundle); RequestedOrientation = ScreenOrientation.Portrait; } [/csharp] On a side note, you'll need to add this line to the top of your Activity if it isn't already there: using Android.Content.PM;