Jump to content

68K Toolbox Project: Retro Serial Sync


Recommended Posts

  • 68kMLA Supporter

I have an older thread that started out as a question about whether a tool for syncing via serial might exist, but since this turned into a full blown 68k Mac toolbox project, I thought I'd start a new thread to share info (and get some help!). 

 

Old thread: 

 

 

 

Link to post
Share on other sites
  • Replies 60
  • Created
  • Last Reply

Top Posters In This Topic

  • 68kMLA Supporter

Sunday March 28 Progress Update:

 

So far, what I have up is 2 versions: one running on my Big Sur M1, and one on my Mac Plus. The OS X version is headless, running in terminal. It (finally) transfers files back and forth without data loss (not including resource fork ATM). Not the fastest thing in the world of course (serial!) but faster than sneaker net. 

 

I would guess I'm about 50% of the way to v1.0. the to-do list is endless, but among the obvious ones:

- deal with memory issues on 68k Mac version. Calloc is my friend, but it is also the sworn enemy of the Memory Manager. 

- implement type/creator handling 

- implement binhex or MacBinary conversion

- make a custom LDEV so list can have variable column widths and a header

- hook up more UI stuff (progress bar, more menu actions, etc.)

- at some point, when everything else is working, figure out how to also make it work over wifi-232 modem. Sadly, I don't even know how to get a telnet going on my modern Mac, which is putting a damper on that side of things. 

- Amiga port if I'm still feeling frisky

serial_sync_20210328.jpg

Link to post
Share on other sites
  • 68kMLA Supporter

Hit a milestone today: it successfully "synced" 1 file between the OS X and 68K Mac. OS X computer has File A, 68K has no file in its sync folder. First sync pass downloads from OS X to Mac Plus. Second sync pass correctly matches the remote and local file and doesn't try to redownload or anything like that. 

 

I spent several hours (!!!) just figuring out how to modify the local file dates on the 68K Mac side. This is the painful part of working with the Toolbox for me: I'm just not familiar enough with it yet, and finding a reference to a particular problem is very hit-and-miss for me. For example, in this case, I found an example right away: Sample code is on pages 407-408 of Using the Macintosh Toolbox with C:

 

Quote

The File Manager allows the application to modify only the Finder information and creation and modification dates for a file. The remaining fields of the File Manager information are used internally by the File Manager. The application should call the routine PBSetFlnfo with the name, volume, and version number of the file in the appropriate parameters of a FileParam block. The modified Finder information and new creation and modification dates should be put into the ioFndrlnfo, ioFICrDat, and ioFIMdDat fields, respectively, of the FileParam prior to call- ing PBSetFlnfo.

<snip>

The following example illustrates the combined use of PBGetFlnfo and PBSetFlnfo to set the relevant information for a file being copied from another file. This ensures that copy has the same type and creator and crea- tion and modification dates as the original file. In addition, the file is placed into the same folder on the desktop as the original file.
/* example usinq PBGetFinfo and PBSetFinfo durinq a file copy to make the new file (file2) look like a copy of filel */
/* declare the local variables */
OSErr theErr;
FileParam flFParmBlk, f2FParmBlk;
/* we assume the FileParam blocks have already had the ioNamePtr, ioVRefNum, and ioVersNum fields filled in with information from SFPutFile and SFGetFile */


/* Get the information about the existing file, filel */ theErr = PBGetFinfo(&flFParmBlk, 0);
if(theErr) OSError("PBGetFinfo", theErr, "for filel");
/* Get the information about the new file, file2 */ theErr = PBGetFinfo(&f2FParmBlk, 0);
if(theErr) OSError("PBGetFinfo", theErr, "for file2");
/* copy the Finder Information to the new file */ f2FParmBlk.ioF1Fndrinfo.fdType = flFParmBlk.ioFlFndrinfo.fdTypei f2FParmBlk.ioF1Fndrinfo.fdCreator =
flFParmBlk.ioFlFndrinfo.fdCreator; f2FParmBlk.ioF1Fndrinfo.fdFlaqs =
flFParmBlk.ioFlFndrinfo.fdFlaqs; f2FParmBlk,ioF1Fndrinfo.fdFldr = flFParmBlk,ioFlFndrinfo.fdFldr;
/* clear the inited flaq; the Finder needs to initialize file 2
*I
f2FParmBlk.ioF1Fndrinfo.fdFlaqs &= Oxffff - cfinited;
/* copy the creation and modification dates */ f2FParmBlk.ioF1CrDat flFParmBlk.ioFlCrDat; f2FParmBLk.ioFlMdDat = flFParmBLk.ioFlMdDat;
/* call PBSetFinfo to set the information for file2 */ theErr = PBSetFinfo(&f2FParmBlk, 0);
if(theErr) OSError("PBSetFinfo", theErr, "for file2");

 

That's a bit messy from the scan, but you get the point. 

 

The thing I spent hours on? Trying to get a paramblock read in. Kept getting -43 file not found. I had vrefnums, dir IDs, etc., from when I first opened the file, but plugging them in didn't work, and also I sometimes get a bit lost in the unions used in the low level file handling code in toolbox. Finally, I stumbled across this little example in THINK C (5) Reference: 

 

image.png.9097c43dfa32a5a2813ab956e634e4c9.png

 

So this is something I'm sure every Mac developer at the time knew, but which I didn't: if I just leave the VRefNum and DirIDs blank, I can pass it a full path and it will find it. Was a 30 second fix after that. But ouch... fun with learning new (but very old) frameworks... 

 

Link to post
Share on other sites

Very cool project! If you find the time, you should post your code on github or another source sharing website, others may be able to help out, give suggestions, build on your code, etc. For example I've recently written quite a bit of serial code for the Mac and would be curious how you've written yours

Link to post
Share on other sites
  • 68kMLA Supporter

I have both the OS X and Mac 68K versions up on GitHub right now, I just have them set to private until I get a bit more stable. Not sure how realistic it would be for me to hope for collaborators (:-p) but who knows. Definitely happy to share with anyone who wants to see how it works (once it kind, of you know, works). 

 

I would definitely appreciate some critique on the serial stuff. What I have now works, but I don't know if it just works in my pretty controlled scenario, or if I will need to add a lot of cRC type checking to make it work reliably for other setups. 

Link to post
Share on other sites
  • 68kMLA Supporter

Hit another good milestone: it was able to send/receive itself for the first time (about 120K as binhex). I've been transferring smaller files for a week or so, but 68K version was running out of memory after 15-30k of transfers. Refactored today to stop creating new data packets on the fly (allocating new objects), and instead just have a permanent out and permanent in object/space, and that seems to have done the trick. 

Link to post
Share on other sites
  • 68kMLA Supporter

:?::?::?::?::?:

 

(Is there anyway to change the icon of the topic itself? I'd love to be able to change it to a question mark or something when I need help). 

 

As a reward to myself for getting the basic syncing running, I'm going to spend some time on fluff: an about box. I was casting around looking at some period about boxes for ideas on style, and noticed BBEdit had an in-app memory usage meter. Does anyone know how to do something like that? I didn't have much luck googling it (too much noise). 

 

 

Screen Shot 2021-04-04 at 4.06.05 PM.png

Link to post
Share on other sites
  • 68kMLA Supporter

After some research and experimentation, this is the formula I came up with for comparing total memory allocated, to total in use, to free. I say "total", but it's not really the total, only the heap total. The OS is allocating some stack and A5 memory on top of that, but I didn't care about that, so I didn't bother including it in my memory usage meter. 

 

long*	appl_zone = (long*)0x0118;

the_about_window->heap_memory_ = (long)ApplicationZone()->bkLim - (long)*appl_zone;
the_about_window->free_memory_ = (long)ApplicationZone()->zcbFree;
the_about_window->used_memory_ = the_about_window->heap_memory_ - the_about_window->free_memory_;

DEBUG_OUT(("AboutWindow_UpdateMemoryInfo %d: %li out of %li bytes used; %li bytes free", __LINE__, the_about_window->used_memory_, the_about_window->heap_memory_, the_about_window->free_memory_));

 

I found this a big confusing, because from reading, it seemed to me like GetZone() was going to return the start of the application zone, but in my testing, it didn't. 0x0118 is a low memory constant, which I would prefer to have avoiding calling directly, but I suppose at this point in MacOS development, there's not much risk Apple will make these globals do something different. :)

 

 

serial_sync_about_20210409.png

Link to post
Share on other sites
  • 68kMLA Supporter

Another update: 

  • Progress bars/messages!
    • makes the waiting better. 
    • haven't done the indeterminate style rendering yet, but looks pretty straightforward
  • Lots of little bug fixes
    • tons more to go, sadly
  • Better icons (but...)
    • Does anyone know if the ics# icons were used in 6.0.x? I have them defined (see snap), but they don't seem to get used by "small icon" view, or in the multifinder menu, etc. Were those maybe a 7.0 thing? 

 

serial_sync_20210411.jpg

serial_sync_icon_set.jpg

Link to post
Share on other sites
  • 68kMLA Supporter
Posted (edited)
On 4/11/2021 at 12:49 AM, Frobozz said:

Does anyone know if the ics# icons were used in 6.0.x? I have them defined (see snap), but they don't seem to get used by "small icon" view, or in the multifinder menu, etc. Were those maybe a 7.0 thing? 

 

Yup.  Look at how the small Finder icon is rendered in 6.0.x vs. 7.  Icon families in general were a 7 thing.

 

This is a good project.  I don't have much to add, but I am enjoying being along for the ride.

Edited by cheesestraws
Link to post
Share on other sites
  • 68kMLA Supporter

Nice work!  World’s most insignificant contribution:  for your icl4 I recommend using a 50% gray pattern between your chosen gray scale and white.  That is The Standard System 7 Way and it takes two clicks in ResEdit.  :) 

Link to post
Share on other sites
  • 68kMLA Supporter
Posted (edited)

I think this will get your the number of usable bytes in your heap zone, excluding the zone header (which is what you want), without checking a lo-mem global:

 

THz zone = ApplicationZone();
long totalZoneSize = (long) zone->bkLim - (long) &(zone->heapData);

 

See IM2: p. 23.

 

That said there is nothing wrong with checking TheZone (lo mem global you got at 0x118), Apple more or less guaranteed the documented low-memory globals to work, and that one is documented in Inside Mac.  I think, though, it will always just give you the same pointer you get from ApplicationZone(), since the current active heap zone (TheZone) when you run your application should always be your application heap zone. :) I use “(long) &(zone->heapData)” instead of just “(long) zone”  to very pedantically get the usable bytes after the header (zone->heapData is the first usable byte in the zone).

 

Edited by Crutch
Link to post
Share on other sites
  • 68kMLA Supporter
On 4/11/2021 at 7:40 AM, cheesestraws said:

 

Yup.  Look at how the small Finder icon is rendered in 6.0.x vs. 7.  Icon families in general were a 7 thing.

 

This is a good project.  I don't have much to add, but I am enjoying being along for the ride.

 

Thanks for that. I didn't see reference to them in the original IM, but there was a wikipedia page that said they were supported by system 6, and the whole "rebuild the desktop" thing made me unsure if I was really seeing the final result, or if the Mac just was still using an older version of the icon. I'll do a little testing on 7.1 here at some point. 

 

 

Link to post
Share on other sites
  • 68kMLA Supporter
22 hours ago, Crutch said:

Nice work!  World’s most insignificant contribution:  for your icl4 I recommend using a 50% gray pattern between your chosen gray scale and white.  That is The Standard System 7 Way and it takes two clicks in ResEdit.  :) 

 

I've been using Resorcerer a bit on this project, and man, that dithering tool is awesome (once I figured out how to use it). Done and done, thanks for suggestion. 

 

Link to post
Share on other sites
  • 68kMLA Supporter
22 hours ago, Crutch said:

I think this will get your the number of usable bytes in your heap zone, excluding the zone header (which is what you want), without checking a lo-mem global:

 


THz zone = ApplicationZone();
long totalZoneSize = (long) zone->bkLim - (long) &(zone->heapData);

 

See IM2: p. 23.

 

That said there is nothing wrong with checking TheZone (lo mem global you got at 0x118), Apple more or less guaranteed the documented low-memory globals to work, and that one is documented in Inside Mac.  I think, though, it will always just give you the same pointer you get from ApplicationZone(), since the current active heap zone (TheZone) when you run your application should always be your application heap zone. :) I use “(long) &(zone->heapData)” instead of just “(long) zone”  to very pedantically get the usable bytes after the header (zone->heapData is the first usable byte in the zone).

 

 

Thanks Crutch. I switched to what you suggested. I didn't actually see that IM bit you posted, so thanks too for that. I've got a lot more work to do on memory management down the road a here a bit, but I want to keep writing the program as "normally" (whatever that means) as I can until I build out the functionality I want, then go back and, for the Mac version, redo the memory management were necessary. Who knows, maybe I won't need to. What's the worst that could happen? 

Link to post
Share on other sites
  • 68kMLA Supporter
Posted (edited)

Is there an easy way to find out if someone has 2 colors available, or more? I want to use patterns for the progress bars if B/W, and colors or color patterns, if they have color. I've been doing a check for availability of color quickDraw on startup, then making various decisions based on that. I was hoping to use it for this as well, as here:

		// Set a PAT if B/W, or PPAT if color available
		if (global_app->color_qd_available_)
		{			
			PenPixPat(the_status_display->ppat_handle_);
		}
		else
		{
			PenPat(*the_status_display->pat_handle_);
		}

 

That works great on a Plus. But sometimes I run an emulated Mac II with B/W color mode. I would like it to use patterns instead of colors, but in the example above, it will go for the ppat, not the pat (b/W). 

 

The regular bar is a better example:

			if (global_app->color_qd_available_)
			{
				RGBForeColor(&the_status_display->color_fore_);
				PaintRect(&the_rect);
			}
			else
			{
				FillRect(&the_rect, &the_status_display->pattern_fore_);
			}

 

I suspect PPAT falls back gracefully to B/W, so I could stop painting with color and just use another PPAT I suppose, but I still am curious how we find out the number of colors available. 

 

I thought maybe the ColorTable's ctSeed or ctSize would get me there, so I tried this: 

	// TEST
	{
		CTabHandle	the_color_table_handle;
		ColorTable	the_color_table;
		long		the_seed;
		short		the_size;
		
		the_color_table_handle = GetCTable(8); // 8 is system's standard clut id??
		the_color_table = **the_color_table_handle;
		the_seed = the_color_table.ctSeed;
		the_size = the_color_table.ctSize + 1;
	}

 

But I get 8 for seed, 256 for color on my emulated MII, whether I have color mode in monitors or B/W mode. 

 

http://mirror.informatimago.com/next/developer.apple.com/documentation/mac/QuickDraw/QuickDraw-198.html#HEADING198-13

 

Quote

 (When a user uses the Monitors control panel to set a 16-bit or 32-bit direct device to use 2, 4, 16, or 256 colors as a grayscale or color device, the direct device creates a CLUT and operates like an indexed device.)

 

That makes me think I'm on the right track, but I am just not asking about the right clut. ?

 

EDIT: 

http://mirror.informatimago.com/next/developer.apple.com/documentation/mac/QuickDraw/QuickDraw-267.html

 

Quote

There are several default 'clut' resources for Macintosh computers containing 68020 and later processors. There is a default 'clut' resource for each of the standard pixel depths. The resource ID for each is the same as the pixel depth. For example, the default 'clut' resource for screens supporting 8 bits per pixel has a resource ID of 8.

Another default 'clut' resource defines the eight colors available for basic QuickDraw's eight-color system. This 'clut' resource has a resource ID of 127.

 

That explains why '8' is always '8'. So I think I'm on the right track, "just" need to figure out which clut the system is using at the moment. 

Edited by Frobozz
Added some clarifying info from another part of IM
Link to post
Share on other sites
  • 68kMLA Supporter

File this under “harder than it should be”: you can call GetMainDevice() to get a handle to the main graphics device, then test

 

(**((**gdh).gdPMap)).pixelSize == 1

 

to see if you’re in 1 bit mode. But what if the user dragged your window to a secondary screen in a different mode? What if, egads, your window straddles two screens?? Then you need to run a DeviceLoop (google that routine or check Scott Knaster’s books for an example, it runs a given ProcPtr once for every screen that intersects a given global rect). 
 

Most people back then would indeed use a ppat with a nice black/white alternative. 

 

Link to post
Share on other sites
  • 68kMLA Supporter
Posted (edited)

Oh, DeviceLoop is in IM6, I thought it wasn’t documented there ... handy.

 

Here’s a nice bit of sample code that runs a DeviceLoop without calling DeviceLoop.  It uses the same technique I recommended above to get pixel depth in there:  http://preserve.mactech.com/articles/develop/issue_10/Tanaka_final_draft.html. As I alluded to above, doing this “right” with the possibility of multiple screens at different depths adds a ton of nonsense to your code and I don’t really recommend it. Of course if you ONLY do this in the nice memory bar chart in your About box, and you ONLY appear the About box in a modal dialog that appears on the main device and can’t be moved, you can cut a few corners!  But it looks above like your About box is in a nice draggable window so ...

Edited by Crutch
Link to post
Share on other sites
  • 68kMLA Supporter

I tried the ppat avenue, but I get exactly the same results when setting color computer to B/W: a solid black. (see ppat setup below). It looks to me as if whatever the conditions are for the B/W fallback, I'm not hitting them in this case, and the Mac is looking at the color I defined, and picking the nearest color (black, not white). 

 

I'm using bar-things in both the about window (which is draggable; death to Modal!) and the main window. So people can drag them between monitors. I'm not too worried about someone using this on multiple monitors. Really, someone with a multiple monitor setup in this day and age would almost surely have something hooked into Ethernet, and wouldn't be a candidate for using this. So I think I'll skip the complication of tracking that (but that was a really interesting article; it's kind of amazing to think of some of the things Apple engineers were designing back in the day (and some of the things they didn't design in).

serial_sync_ppat_20210412.png

Link to post
Share on other sites
  • 68kMLA Supporter

I implemented the GetMainDevice() check, and that works great in testing so far. If that says color depth is 1, I use PATs, if more than 1, I used ppats. Thanks Crutch!

Link to post
Share on other sites
  • 68kMLA Supporter

Two little updates today:

  • The GetMainDevice() trap is not supported in the Mac Plus ROMs. I have been doing any testing that doesn't need serial, on a Mac II configuration in Mini vMac. It didn't complain about that, but when I tried to run it on the (real) Plus, I got an unimplemented trap error. Sure enough, that trap first appears in the 256K ROMs. 
	// check main device to see if it's in color or B/W. this we CAN rely on (except in case of multiple-monitor setup)
	// first have to check if GetMainDevice trap is even available (first appeared in 256K ROMs)
	if (NGetTrapAddress(kGetMainDeviceTrapNum, ToolTrap) != NGetTrapAddress(kUnimplementedTrapNum, ToolTrap))
	{
		the_main_device = GetMainDevice();
		global_app->bw_only_ = ( (**((**the_main_device).gdPMap)).pixelSize == 1 );
	}
	else
	{
		// assumption: if the machine only has 128k ROM, it doesn't have color.
		global_app->bw_only_ = true;
	}
  • Memory Problems! I've been tearing my hair out for a while on crash situation I was having ONLY on the Mac Plus: sometimes, on startup, it would crash. Sometimes it would beep. I thought I was really trashing the memory or something to make it beep randomly. It never crashes in that situation on an emulated Plus or Mac II, with 6.0.8 (same system). I figured I was doing something REALLY bad with memory handling, but couldn't see it. So... dumb story... it was NVIR virus. I had cleaned it out of my emulated Macs a few months ago, and forgot to do it from the Mac Plus. I think because I was using SAM on them, and it maybe only runs in 7.x, so I was mounting my Mini vMac drives in Basilisk II under 7.5.5 and cleaning them. Anyway, I got Disinfectant last night, put it on the plus, and there were like 100 infected files. Took it a while, but it cleaned them off. Now the program runs normally every time. I don't remember ever getting hit by viruses back when I was using these in daily life, so it's a bit ironic to lost time to them now, when they are dinosaurs. ARRRRRGH. 
Link to post
Share on other sites

Aside from all the grief you had in trying to test out the program, I have to say that it's amusing that after all these years you were stuck by a Mac virus. :)

 

Also, your app is very impressive.  I really enjoyed reading through your building process.  I just wish I could do this kind of stuff.

Link to post
Share on other sites
  • 68kMLA Supporter

Yes, sorry, I should have mentioned ... all the GDevice stuff only appears on the 256k ROM.  The Mac II was the first machine that allowed multiple graphics devices.

Link to post
Share on other sites
  • 68kMLA Supporter
On 4/14/2021 at 4:42 PM, olePigeon said:

 

Also, your app is very impressive.  I really enjoyed reading through your building process.  I just wish I could do this kind of stuff.

 

Thanks! This is a painful process (but kind of fun), so it helps to have any kind of feedback.  

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

×
×
  • Create New...