Unfinished Bitness

Finishing bits of technology, vintage and new.

  • About
  • Contact

FujiNet Time in C (CC65)

Posted by Ripdubski on 2023.02.11
Posted in: Atari, Programming. Tagged: 8 bit, APETIME, C (CC65), FujINet. Leave a comment

FujiNet is a fantastic device for the Atari 8 bit line of computers which provides WiFi, and SD card storage among other things, all over SIO.  One of the functions provided is APETIME support, a protocol developed by AtariMax as part of their Atari Peripheral Emulator (APE).

In the last post I demonstrated my BASIC and Action! versions of a program to get the time from the FujiNet device using APETIME. The procedure is documented here (https://github.com/FujiNetWIFI/fujinet-platformio/wiki/Accessing-the-Real-Time-Clock).  At the time of this writing there was no complete C example, only an example of the call.

After completing the conversion of my Action! library to C, and starting a new project where I needed to get the time from FujiNet from C, I thought it would be a good time to create a version of the FujiNet time program I had written in BASIC and Action!.  This post details my solution.  I wrote the routine into a function which can be called from the main program at any point.  It only requires passing a pointer to a  6 byte array.

To call the SIO routine, I used inline assembly to execute the jump.

As with my Action! source, the routine that gets the time from FujiNet is the FNGTime() function (FujiNet Get Time).  It first sets up the SIO call by assigning appropriate values into the DCB (Device Control Block) memory location.  Using CC65 v2.19+ libraries allows setting the DCB via equates using an OS structure as defined in “atari.h” include file, with no need for the Poke function.  It sets the buffer location (DBUF), to the address of the byte array passed in.

Last it calls the SIO vector using the SIOV function.

The main routine sets aside 6 bytes of storage, calls the FNGTime() function with the address of the storage array, then prints the result in a friendly fashion.

// ------------------------------------------------------------
// Program: fujitime.c
// Desc...: Gets date/time from FujiNet
// Author.: Ripdubski
// Date...: 2023.02.09
// Notes..: cl65 -v [-O] -t atarixl fujitime.c -o fujitime.xex
// ------------------------------------------------------------

// Pull in include files
#include <stdio.h>
#include <atari.h>
#include <conio.h>
#include <unistd.h>

// -----------------------------------
// Proc..: void SIOV(void)
// Desc..: OS SIO Vector
// -----------------------------------
void SIOV(void)
{
    __asm__ ("JSR $E459");
}

// -----------------------------------
// Proc..: void FNGTime(char *bA)
// Desc..: Get date/time from FujiNet
// via APETIME protocol
// Return: 6 bytes DMYHMS into bA
// -----------------------------------
void FNGTime(char *bA)
{
    // Setup SIO call using byte array address
    // by putting values into the DCB.
    // APETime=Device 69 ($45), Unit 1
    // Time command=147 ($93)
    // Get 6 bytes, timeout just over 15s
    OS.dcb.ddevic = 0x45;
    OS.dcb.dunit  = 0x01;
    OS.dcb.dcomnd = 0x93;
    OS.dcb.dstats = 0x40;
    OS.dcb.dbuf   = (void *) bA;
    OS.dcb.dtimlo = 15;
    OS.dcb.dunuse = 0;
    OS.dcb.dbyt   = (unsigned int) 6;

    // Call SIO
    SIOV();
}

// -----------------------------------
// Main Routine
// -----------------------------------
void main(void)
{
    // Storage for 6 bytes preset to 0
    char bDT[7]={ 0, 0, 0, 0, 0, 0 };

    // Call time routine with the storage array
    FNGTime(bDT);

    // What time is it?
    printf("\nDate: 20%d.%d.%d\n", bDT[2], bDT[1], bDT[0]);
    printf("Time: %d:%d:%d\n", bDT[3], bDT[4], bDT[5]);

    // Wait for a keystroke
    printf("Press any key to continue...\n");
    while (! kbhit()) {};
}

I’m going to include the FNGTime() function in my C library which was converted from my Action! library in 2022.  This will happen in a future release.

Share this:

  • Click to email a link to a friend (Opens in new window)
  • Click to share on Facebook (Opens in new window)
  • Click to share on LinkedIn (Opens in new window)
  • Click to share on Pinterest (Opens in new window)
  • Click to share on Pocket (Opens in new window)
  • Click to share on Reddit (Opens in new window)
  • Click to share on Twitter (Opens in new window)

Like this:

Like Loading...

C Style! – Action! Library Conversion 10

Posted by Ripdubski on 2022.09.02
Posted in: Atari, Programming. Tagged: 8 bit, C (CC65). Leave a comment

All the gadgets up until now have been mildly user interactive. In this post I finally tackle the biggest, and likely most useful, gadget – GInput(). This is the string input routine that allows type restricted (numeric, alphabetic, alpha-numeric, or any text) string input. The string editing size can be smaller than the string itself and the string will scroll left or right as the cursor is moved. There are some special keys tossed in to get to start of the string, end of the string, clearing the string, inserting and deleting characters. At the time of this writing, the C version hasn’t been fully tested for the last three cases mentioned, but will be by the time the library is published.

The code for GInput() is quite large in relation to the other gadgets, but it does quite a bit.

Here is a demo program showing how the gadget is called:

// ------------------------------------------------------------
// Program: ginput.c
// Desc...: A8 Library Input Test
// Author.: Ripdubski
// Date...: 202208
// Notes..: cl65 -v [-O] -t atarixl ginput.c -o ginput.xex
// ------------------------------------------------------------

// Pull in include files
#include <stdio.h>
#include <conio.h>
#include <unistd.h>
#include <string.h>
#include <atari.h>

#include "a8defines.h"
#include "a8defwin.h"
#include "a8libmisc.c"
#include "a8libstr.c"
#include "a8libwin.c"
#include "a8libgadg.c"
#include "a8libmenu.c"


// ------------------------------------------------------------
// Func...: void DoInput(void)
// Desc...: Displays input demo
// ------------------------------------------------------------
void DoInput(void)
{
    byte bW;
    unsigned char cA[41], cB[41], cC[41], cD[41];

    // Assign default string values
    strcpy(cA,  "-100.00                                 ");
    strcpy(cB,  "This string has something to edit in it!");
    strcpy(cC,  "                                        ");
    sprintf(cD, "%cAny character string!%c                 ", CHBALL, CHBALL);

    // Open window & draw form
    bW = WOpen(2, 6, 36, 10, WOFF);
    WOrn(bW, WPTOP, WPLFT, "Input Test");

    WPrint(bW, 1, 1, WOFF, "Data Fields");
    WPrint(bW, 2, 3, WOFF, "Numer:");
    WPrint(bW, 2, 4, WOFF, "Alpha:");
    WPrint(bW, 2, 5, WOFF, "AlNum:");
    WPrint(bW, 2, 6, WOFF, "Any..:");

    // Display fields as is 
    // WPrint will truncate what doesn't fit (27 chars for this window).
    WPrint(bW, 8, 3, WOFF, cA);
    WPrint(bW, 8, 4, WOFF, cB);
    WPrint(bW, 8, 5, WOFF, cC);
    WPrint(bW, 8, 6, WOFF, cD);

    // Input each in succession
    // 27 is the maximum width to display of the 40 lengths
    GInput(bW, 8, 3, GNUMER, 27, cA);
    GInput(bW, 8, 4, GALPHA, 27, cB);
    GInput(bW, 8, 5, GALNUM, 27, cC);
    GInput(bW, 8, 6, GANY,   27, cD);

    // Wait for a key
    WPrint(bW, WPCNT, 8, WOFF, "press any key");
    WaitKCX(WOFF);

    // Close window
    WClose(bW);
}


// ------------------------------------------------------------
// Func...: void main(void)
// Desc...: Main routine
// ------------------------------------------------------------
void main(void)
{
    // Variables
    byte bW1, bW2, bC, bD;
    unsigned char *pcM[9] =
      { " Alert        ", " Progress     ", " Buttons      ", " Checkboxes   ", " Radio Button ", " Spinner      ", " Input        ", " Quit         " };

    // Setup screen
    WInit();
    WBack(14);

    // Open windows
    bW1 = WOpen(0, 0, 40, 3, WON);
    WPrint(bW1, WPCNT, 1, WOFF, "CC65 A8 Library Test");
    bW2 = WOpen(12, 6, 16, 12, WOFF);
    WOrn(bW2, WPTOP, WPCNT, "Menu");

    // Set done to false
    bD = FALSE;

    // Loop until done (Quit selected)
    while (! bD) {
        // Call menu
        bC = MenuV(bW2, 1, 2, WON, 1, 8, pcM);

        // Process choice
        switch (bC)
        {
            case 1: GAlert("Alert! menu option 1 selected!");
                    break;

            case 2: GAlert("Alert! menu option 2 selected!");
                    break;

            case 3: GAlert("Alert! menu option 3 selected!");
                    break;

            case 4: GAlert("Alert! menu option 4 selected!");
                    break;

            case 5: GAlert("Alert! menu option 5 selected!");
                    break;

            case 6: GAlert("Alert! menu option 6 selected!");
                    break;

            case 7: DoInput();
                    break;

            case 8: bD = TRUE;
                    break;
        }
    }

    // Wait for a keypress
    while (! kbhit()) { };

    // Close windows
    WClose(bW2);
    WClose(bW1);

    // Exit
    return;
}

Here is a screenshot of it in use (the cursor is active on the s in the word has of the Alpha field):

Share this:

  • Click to email a link to a friend (Opens in new window)
  • Click to share on Facebook (Opens in new window)
  • Click to share on LinkedIn (Opens in new window)
  • Click to share on Pinterest (Opens in new window)
  • Click to share on Pocket (Opens in new window)
  • Click to share on Reddit (Opens in new window)
  • Click to share on Twitter (Opens in new window)

Like this:

Like Loading...

C Style! – Action! Library Conversion 9

Posted by Ripdubski on 2022.09.01
Posted in: Atari, Programming. Tagged: 8 bit, C (CC65). Leave a comment

This time I cover the conversion of the numeric spinner input. It allows for a number to be chosen where the user does not enter it directly, but rather changes the value by pressing keys representing increment and decrement. It only allows for value between 0 and 250. Values above 250 are reserved for form control, such as ESC and TAB. I feel like this is fine since no one will want to cycle up/down into thousands or more, and most likely this will be used from 0 to 100. I contemplated a top limit of 100, but decided to allow up to 250. This was also the last gadget I wrote for my Action! library.

In the demo program, the user is allowed to change the Value field from 5 to 100. Once accepted, the new value is displayed below in the New field.

Here is the demo program showing how its called:

// ------------------------------------------------------------
// Program: gspin.c
// Desc...: A8 Library Window Menu Test
// Author.: Ripdubski
// Date...: 202208
// Notes..: cl65 -v [-O] -t atarixl gspin.c -o gspin.xex
// ------------------------------------------------------------

// Pull in include files
#include <stdio.h>
#include <conio.h>
#include <unistd.h>
#include <string.h>
#include <atari.h>

#include "a8defines.h"
#include "a8defwin.h"
#include "a8libmisc.c"
#include "a8libstr.c"
#include "a8libwin.c"
#include "a8libgadg.c"
#include "a8libmenu.c"


// ------------------------------------------------------------
// Func...: void DoSpin(void)
// Desc...: Displays spinner demo
// ------------------------------------------------------------
void DoSpin(void)
{
    byte bW, bC, bV;
    unsigned char cL[4];

    // Set default value
    bV = 10;

    // Open window
    bW = WOpen(8, 7, 24, 9, WOFF);
    WOrn(bW, WPTOP, WPLFT, "Spinner");
    WPrint(bW, 2, 2, WOFF, "Value:");
    WPrint(bW, 4, 4, WOFF,   "New:");

    // Display spinner and get returned value
    // Min value=5, max value=100
    bC = GSpin(bW, 8, 2, 5, 100, bV);

    // What was returned?
    if (bC == XESC)
    {
        GAlert(" Escaped Out! ");
    }
    else if (bC == XTAB)
    {
        GAlert(" Tabbed Out! ");
    }
    else
    {
        // Show the new value
        sprintf(cL, "%3d", bC);
        WPrint(bW, 8, 4, WOFF, cL);
    }

    // Wait for a key
    WPrint(bW, WPCNT, 6, WOFF, "Press any key.");
    WaitKCX(WOFF);

    // Close window
    WClose(bW);
}


// ------------------------------------------------------------
// Func...: void main(void)
// Desc...: Main routine
// ------------------------------------------------------------
void main(void)
{
    // Variables
    byte bW1, bW2, bC, bD;
    unsigned char *pcM[8] =
      { " Alert        ", " Progress     ", " Buttons      ", " Checkboxes   ", " Radio Button ", " Spinner      ", " Quit         " };

    // Setup screen
    WInit();
    WBack(14);

    // Open windows
    bW1 = WOpen(0, 0, 40, 3, WON);
    WPrint(bW1, WPCNT, 1, WOFF, "CC65 A8 Library Test");
    bW2 = WOpen(12, 6, 16, 11, WOFF);
    WOrn(bW2, WPTOP, WPCNT, "Menu");

    // Set done to false
    bD = FALSE;

    // Loop until done (Quit selected)
    while (! bD) {
        // Call menu
        bC = MenuV(bW2, 1, 2, WON, 1, 7, pcM);

        // Process choice
        switch (bC)
        {
            case 1: GAlert("Alert! menu option 1 selected!");
                    break;

            case 2: GAlert("Alert! menu option 2 selected!");
                    break;

            case 3: GAlert("Alert! menu option 3 selected!");
                    break;

            case 4: GAlert("Alert! menu option 4 selected!");
                    break;

            case 5: GAlert("Alert! menu option 5 selected!");
                    break;

            case 6: DoSpin();
                    break;

            case 7: bD = TRUE;
                    break;
        }
    }

    // Wait for a keypress
    while (! kbhit()) { };

    // Close windows
    WClose(bW2);
    WClose(bW1);

    // Exit
    return;
}

Here is a screenshot of its use:

Share this:

  • Click to email a link to a friend (Opens in new window)
  • Click to share on Facebook (Opens in new window)
  • Click to share on LinkedIn (Opens in new window)
  • Click to share on Pinterest (Opens in new window)
  • Click to share on Pocket (Opens in new window)
  • Click to share on Reddit (Opens in new window)
  • Click to share on Twitter (Opens in new window)

Like this:

Like Loading...

C Style! – Action! Library Conversion 8

Posted by Ripdubski on 2022.08.31
Posted in: Atari, Programming. Tagged: 8 bit, C (CC65). Leave a comment

In this post I set out to convert the checkbox routine GCheck(). This displays a checkbox, and allows the user to check or uncheck it.

Here is the demo program showing how to call it:

// ------------------------------------------------------------
// Program: gcheck.c
// Desc...: A8 Library Gadget Checkbox Test
// Author.: Ripdubski
// Date...: 202208
// Notes..: cl65 -v [-O] -t atarixl gcheck.c -o gcheck.xex
// ------------------------------------------------------------

// Pull in include files
#include <stdio.h>
#include <conio.h>
#include <unistd.h>
#include <string.h>
#include <atari.h>

#include "a8defines.h"
#include "a8defwin.h"
#include "a8libmisc.c"
#include "a8libstr.c"
#include "a8libwin.c"
#include "a8libgadg.c"
#include "a8libmenu.c"


// ------------------------------------------------------------
// Func...: void DoCheck(void)
// Desc...: Displays checkbox demo
// ------------------------------------------------------------
void DoCheck(void)
{
    byte bW, bD, bF;
    // Vars used for selections and previous selections
    byte bca, bcb, bcc, bcap, bcbp, bccp;

    // Set defaults for previous selections (initial item status)
    bcap = GCOFF;
    bcbp = GCOFF;
    bccp = GCON;

    // Open window
    bW = WOpen(9, 10, 22, 6, WOFF);
    WOrn(bW, WPTOP, WPLFT, "Checkboxes");
    WPrint(bW, 1, 1, WOFF, "Select your weapons:");
    WPrint(bW, 6, 2, WOFF, "Action!");
    WPrint(bW, 6, 3, WOFF, "BASIC");
    WPrint(bW, 6, 4, WOFF, "C");

    // Display only with previous/default/initial value
    bF = GCheck(bW, 2, 2, GDISP, bcap);
    bF = GCheck(bW, 2, 3, GDISP, bcbp);
    bF = GCheck(bW, 2, 4, GDISP, bccp);

    GAlert(" Check all and TAB to quit. ");

    // Continue until exited
    bF = FALSE;
    while (! bF)
    {
        // Stay on this check until ESC, TAB
        bD = FALSE;
        while (! bD)
        {
            // Call checkbox with edit and previous value
            bca = GCheck(bW, 2, 2, GEDIT, bcap);

            // Check returned value
            if ((bca == XESC) || (bca == XTAB))
            {
                // Allow exit of loop for this checkbox
                bD = TRUE;
            }
            else
            {
                // Set previous value to the current value
                bcap = bca;
            }
        }

        // Stay on this check until ESC, TAB
        bD = FALSE;
        while (! bD)
        {
            // Call checkbox with edit and previous value
            bcb = GCheck(bW, 2, 3, GEDIT, bcbp);

            // Check returned value
            if ((bcb == XESC) || (bcb == XTAB))
            {
                // Allow exit of loop for this checkbox
                bD = TRUE;
            }
            else
            {
                // Set previous value to the current value
                bcbp = bcb;
            }
        }

        // Stay on this check until ESC, TAB
        bD = FALSE;
        while (! bD)
        {
            // Call checkbox with edit and previous value
            bcc = GCheck(bW, 2, 4, GEDIT, bccp);

            // Check returned value
            if ((bcc == XESC) || (bcc == XTAB))
            {
                // Allow exit of loop for this checkbox
                bD = TRUE;
            }
            else
            {
                // Set previous value to the current value
                bccp = bcc;
            }
        }

        // Leave loop wonce all checked - DEMO
        if ((bcap == GCON) && (bcbp == GCON) && (bccp == GCON))
        {
            bF = TRUE;
        }
    }

    GAlert(" All options checked! ");

    // Close window
    WClose(bW);

    return;
}


// ------------------------------------------------------------
// Func...: void main(void)
// Desc...: Main routine
// ------------------------------------------------------------
void main(void)
{
    // Variables
    byte bW1, bW2, bC, bD;
    unsigned char *pcM[7] = { " Alert        ", " Progress     ", " Buttons      ", " Checkboxes   ", " Radio Button ", " Quit         " };

    // Setup screen
    WInit();
    WBack(14);

    // Open windows
    bW1 = WOpen(0, 0, 40, 3, WON);
    WPrint(bW1, WPCNT, 1, WOFF, "CC65 A8 Library Test");
    bW2 = WOpen(12, 6, 16, 10, WOFF);
    WOrn(bW2, WPTOP, WPCNT, "Menu");

    // Set done to false
    bD = FALSE;

    // Loop until done (Quit selected)
    while (! bD) {
        // Call menu
        bC = MenuV(bW2, 1, 2, WON, 1, 6, pcM);

        // Process choice
        switch (bC)
        {
            case 1: GAlert("Alert! menu option 1 selected!");
                    break;

            case 2: GAlert("Alert! menu option 2 selected!");
                    break;

            case 3: GAlert("Alert! menu option 3 selected!");
                    break;

            case 4: DoCheck();
                    break;

            case 5: GAlert("Alert! menu option 5 selected!");
                    break;

            case 6: bD = TRUE;
                    break;
        }
    }

    // Wait for a keypress
    while (! kbhit()) { };

    // Close windows
    WClose(bW2);
    WClose(bW1);

    // Exit
    return;
}

Here is a screenshot of it in use:

Share this:

  • Click to email a link to a friend (Opens in new window)
  • Click to share on Facebook (Opens in new window)
  • Click to share on LinkedIn (Opens in new window)
  • Click to share on Pinterest (Opens in new window)
  • Click to share on Pocket (Opens in new window)
  • Click to share on Reddit (Opens in new window)
  • Click to share on Twitter (Opens in new window)

Like this:

Like Loading...

C Style! – Action! Library Conversion 7

Posted by Ripdubski on 2022.08.30
Posted in: Atari, Programming. Tagged: 8 bit, C (CC65). Leave a comment

With a basic button set now working, I set my sights on converting my Action! library radio button routine. This is the GRadio() function. It displays a set of radio buttons either horizontally or vertically. I made a minor alteration in how navigation/selection is handled in the C version. In the Action! version, space would establish a button as selected but not exit until Enter was pressed. After using it a bit and never having been completely satisfied, I chose to have Space select and exit. Navigation feels smoother with this minor change.

To enable form drawing before activating any controls, it is necessary to call the function with a flag telling it to only display the choices and exit. You call it again with an edit flag when it is ready to be activated. After a radio button is edited, it should be called again with the display only flag to clean up – meaning to revert the selection if ESC was pressed, or show the new selection. There is no difference here in how it worked in my Action! library.

It’s noteworthy to mention that each of the interactive gadgets will return special values if ESC or TAB are pressed. This enables you to write a looping routing to process different input gadget elements as a form and allow the user to TAB through each control – much like modern GUI’s. In the demo program here you can see the handling of these keys which prevent the exit of the loop/form until both sets of radio buttons have the 3rd option selected.

Here is the demo program showing how the function is called for both orientations.

// ------------------------------------------------------------
// Program: gradio.c
// Desc...: A8 Library Gadget Radio Button Test
// Author.: Ripdubski
// Date...: 202208
// Notes..: cl65 -v [-O] -t atarixl gradio.c -o gradio.xex
// ------------------------------------------------------------

// Pull in include files
#include <stdio.h>
#include <conio.h>
#include <unistd.h>
#include <string.h>
#include <atari.h>

#include "a8defines.h"
#include "a8defwin.h"
#include "a8libmisc.c"
#include "a8libstr.c"
#include "a8libwin.c"
#include "a8libgadg.c"
#include "a8libmenu.c"


// ------------------------------------------------------------
// Func...: void DoRadio(void)
// Desc...: Displays radio button demo
// ------------------------------------------------------------
void DoRadio(void)
{
    byte bW, bra, brb, brap, brbp;
    unsigned char *rA[4] = { "One", "Two", "Three" };
    unsigned char *rB[4] = { "Choice A", "Choice B", "Choice C" };

    // Set defaults for selection and previous selection
    bra = 1;
    brb = 1;
    brap = bra;
    brbp = brb;

    // Open window
    bW = WOpen(2, 5, 36, 12, WOFF);
    WOrn(bW, WPTOP, WPLFT, "Radio Button Test");

    // Show horizontal buttons
    WPrint(bW, 1, 2, WOFF, "Radio Buttons (horiz)");
    GRadio(bW, 2, 3, GHORZ, GDISP, brap, 3, rA);

    // Show veritcal buttons
    WPrint(bW, 1, 5, WOFF, "Radio Buttons (vert)");
    GRadio(bW, 2, 6, GVERT, GDISP, brbp, 3, rB);

    WPrint(bW, 1, 10, WOFF, "Pick 3rd choices to exit.");

    // Loop until accepted or cancelled
    while ((bra != 3) || (brb != 3))
    {
        // Display horiz buttons and get choice
        bra = GRadio(bW, 2, 3, GHORZ, GEDIT, brap, 3, rA);

        // If not bypass, set previous selected value
        if ((bra != XESC) && (bra != XTAB))
        {
            brap = bra;
        }

        // Redisplay buttons
        GRadio(bW, 2, 3, GHORZ, GDISP, brap, 3, rA);

        // Display vert buttons and get choice
        brb = GRadio(bW, 2, 6, GVERT, GEDIT, brbp, 3, rB);

        // If not bypass, set previous selected value
        if ((brb != XESC) && (brb != XTAB))
        {
            brbp = brb;
        }

        // Redisplay buttons
        GRadio(bW, 2, 6, GVERT, GDISP, brbp, 3, rB);
    }

    // Close window
    WClose(bW);
}


// ------------------------------------------------------------
// Func...: void main(void)
// Desc...: Main routine
// ------------------------------------------------------------
void main(void)
{
    // Variables
    byte bW1, bW2, bC, bD;
    unsigned char *pcM[7] = { " Alert        ", " Progress     ", " Buttons      ", " Checkboxes   ", " Radio Button ", " Quit         " };

    // Setup screen
    WInit();
    WBack(14);

    // Open windows
    bW1 = WOpen(0, 0, 40, 3, WON);
    WPrint(bW1, WPCNT, 1, WOFF, "CC65 A8 Library Test");
    bW2 = WOpen(12, 6, 16, 10, WOFF);
    WOrn(bW2, WPTOP, WPCNT, "Menu");

    // Set done to false
    bD = FALSE;

    // Loop until done (Quit selected)
    while (! bD) {
        // Call menu
        bC = MenuV(bW2, 1, 2, WON, 1, 6, pcM);

        // Process choice
        switch (bC)
        {
            case 1: GAlert("Alert! menu option 1 selected!");
                    break;

            case 2: GAlert("Alert! menu option 2 selected!");
                    break;

            case 3: GAlert("Alert! menu option 3 selected!");
                    break;

            case 4: GAlert("Alert! menu option 4 selected!");
                    break;

            case 5: DoRadio();
                    break;

            case 6: bD = TRUE;
                    break;
        }
    }

    // Wait for a keypress
    while (! kbhit()) { };

    // Close windows
    WClose(bW2);
    WClose(bW1);

    // Exit
    return;
}

Here is a screenshot of it in use:

Share this:

  • Click to email a link to a friend (Opens in new window)
  • Click to share on Facebook (Opens in new window)
  • Click to share on LinkedIn (Opens in new window)
  • Click to share on Pinterest (Opens in new window)
  • Click to share on Pocket (Opens in new window)
  • Click to share on Reddit (Opens in new window)
  • Click to share on Twitter (Opens in new window)

Like this:

Like Loading...

C Style! – Action! Library Conversion 6

Posted by Ripdubski on 2022.08.29
Posted in: Atari, Programming. Tagged: 8 bit, C (CC65). Leave a comment

In the previous post I converted the non-interactive gadget GProc(). In this post I move to the most basic of user interaction: buttons (like OK, Cancel) via function GButton(). The button labels and quantity are up to you, as well as the default button selection.

The programmer is required to specify any ornaments for the buttons, if so desired. As the user moves between buttons, the active one is displayed in inverse video. The implementation in C is actually quite simpler than an Action! due to C’s advanced handling of arrays of strings. The source code will be released once the entire library has been converted – at that point you can compare if you are so inclined.

Here is a program demonstrating its use:

// ------------------------------------------------------------
// Program: gbutton.c
// Desc...: A8 Library Gadget Button Test
// Author.: Ripdubski
// Date...: 202208
// Notes..: cl65 -v [-O] -t atarixl gbutton.c -o gbutton.xex
// ------------------------------------------------------------

// Pull in include files
#include <stdio.h>
#include <conio.h>
#include <unistd.h>
#include <string.h>
#include <atari.h>

#include "a8defines.h"
#include "a8defwin.h"
#include "a8libmisc.c"
#include "a8libstr.c"
#include "a8libwin.c"
#include "a8libgadg.c"
#include "a8libmenu.c"


// ------------------------------------------------------------
// Func...: void DoButt(void)
// Desc...: Displays button demo
// ------------------------------------------------------------
void DoButt(void)
{
    byte bC, bW;
    unsigned char *cS[3] = { "[ Ok ]", "[ Cancel ]" };

    // Open window
    bW = WOpen(9, 10, 22, 6, WOFF);
    WOrn(bW, WPTOP, WPLFT, "Buttons");
    WPrint(bW, 2, 2, WOFF, "Select a button:");

    // Call the button handler with all buttons defined
    bC = GButton(bW, 5, 4, 2, 2, cS);

    // Close window
    WClose(bW);

    return;
}


// ------------------------------------------------------------
// Func...: void main(void)
// Desc...: Main routine
// ------------------------------------------------------------
void main(void)
{
    // Variables
    byte bW1, bW2, bC, bD;
    unsigned char *pcM[7] = { " Alert        ", " Progress     ", " Buttons      ", " Checkboxes   ", " Radio Button ", " Quit         " };

    // Setup screen
    WInit();
    WBack(14);

    // Open windows
    bW1 = WOpen(0, 0, 40, 3, WON);
    WPrint(bW1, WPCNT, 1, WOFF, "CC65 A8 Library Test");
    bW2 = WOpen(12, 6, 16, 10, WOFF);
    WOrn(bW2, WPTOP, WPCNT, "Menu");

    // Set done to false
    bD = FALSE;

    // Loop until done (Quit selected)
    while (! bD) {
        // Call menu
        bC = MenuV(bW2, 1, 2, WON, 1, 6, pcM);

        // Process choice
        switch (bC)
        {
            case 1: GAlert("Alert! menu option 1 selected!");
                    break;

            case 2: GAlert("Alert! menu option 2 selected!");
                    break;

            case 3: DoButt();
                    break;

            case 4: GAlert("Alert! menu option 4 selected!");
                    break;

            case 5: GAlert("Alert! menu option 5 selected!");
                    break;

            case 6: bD = TRUE;
                    break;
        }
    }

    // Wait for a keypress
    while (! kbhit()) { };

    // Close windows
    WClose(bW2);
    WClose(bW1);

    // Exit
    return;
}

Here is a screenshot of it running:

Share this:

  • Click to email a link to a friend (Opens in new window)
  • Click to share on Facebook (Opens in new window)
  • Click to share on LinkedIn (Opens in new window)
  • Click to share on Pinterest (Opens in new window)
  • Click to share on Pocket (Opens in new window)
  • Click to share on Reddit (Opens in new window)
  • Click to share on Twitter (Opens in new window)

Like this:

Like Loading...

C Style! – Action! Library Conversion 5

Posted by Ripdubski on 2022.08.28
Posted in: Atari, Programming. Tagged: 8 bit, C (CC65). Leave a comment

In the next set of posts I’ll be converting my Action! libraries Gadget routines. Gadgets are what I refer to as the widgets used in conjunction with the windowing library to create form based input. Think of a gadget as an input mechanism like a button (OK, Cancel, etc), a radio button (where only 1 over several choices can be selected), a checkbox, etc. The first one I converted is not so much as an input control, but a way to show progress to a user during a slow operation. This is the GProg() function.

This function is called with the placement location within an already opened window handle, and the value (0 to 100) to display.

Here is the code that demonstrates:

// ------------------------------------------------------------
// Program: gprog.c
// Desc...: A8 Library Progress Gadget Test
// Author.: Ripdubski
// Date...: 202208
// Notes..: cl65 -v [-O] -t atarixl gprog.c -o gprog.xex
// ------------------------------------------------------------

// Pull in include files
#include <stdio.h>
#include <conio.h>
#include <unistd.h>
#include <string.h>
#include <atari.h>

#include "a8defines.h"
#include "a8defwin.h"
#include "a8libmisc.c"
#include "a8libstr.c"
#include "a8libwin.c"
#include "a8libgadg.c"
#include "a8libmenu.c"


// ------------------------------------------------------------
// Func...: void DoProg(void)
// Desc...: Displays progress bar demo
// ------------------------------------------------------------
void DoProg(void)
{
    byte bL, bW;

    // Open window
    bW = WOpen(9, 10, 22, 4, WOFF);
    WOrn(bW, WPTOP, WPLFT, "Progress");

    // Loop through progress
    for (bL=1; bL <= 100; bL+=5)
    {
        // Display the progress bar and wait 1 second
        GProg(bW, 1, 2, bL);
        sleep(1);
    }

    // Close window
    WClose(bW);

    return;
}


// ------------------------------------------------------------
// Func...: void main(void)
// Desc...: Main routine
// ------------------------------------------------------------
void main(void)
{
    // Variables
    byte bW1, bW2, bC, bD;
    unsigned char *pcM[7] = { " Alert        ", " Progress     ", " Buttons      ", " Checkboxes   ", " Radio Button ", " Quit         " };

    // Setup screen
    WInit();
    WBack(14);

    // Open windows
    bW1 = WOpen(0, 0, 40, 3, WON);
    WPrint(bW1, WPCNT, 1, WOFF, "CC65 A8 Library Test");
    bW2 = WOpen(12, 6, 16, 10, WOFF);
    WOrn(bW2, WPTOP, WPCNT, "Menu");

    // Set done to false
    bD = FALSE;

    // Loop until done (Quit selected)
    while (! bD) {
        // Call menu
        bC = MenuV(bW2, 1, 2, WON, 1, 6, pcM);

        // Process choice
        switch (bC)
        {
            case 1: GAlert("Alert! menu option 1 selected!");
                    break;

            case 2: DoProg();
                    break;

            case 3: GAlert("Alert! menu option 3 selected!");
                    break;

            case 4: GAlert("Alert! menu option 4 selected!");
                    break;

            case 5: GAlert("Alert! menu option 5 selected!");
                    break;

            case 6: bD = TRUE;
                    break;
        }
    }

    // Wait for a keypress
    while (! kbhit()) { };

    // Close windows
    WClose(bW2);
    WClose(bW1);

    // Exit
    return;
}

Here is a screenshot showing what it looks like.

Share this:

  • Click to email a link to a friend (Opens in new window)
  • Click to share on Facebook (Opens in new window)
  • Click to share on LinkedIn (Opens in new window)
  • Click to share on Pinterest (Opens in new window)
  • Click to share on Pocket (Opens in new window)
  • Click to share on Reddit (Opens in new window)
  • Click to share on Twitter (Opens in new window)

Like this:

Like Loading...

Action! Library v1.51

Posted by Ripdubski on 2022.08.27
Posted in: Atari, Programming. Tagged: 8 bit, Action!. 1 Comment

(edit: license change, new atr, and github link)

As I worked on converting my Action! library to C for use with CC65, I stumbled on a few typos which resulted in minor bugs. This release addresses those and provides a minor update to the manual as well. This version supercedes all previous versions.

The attached file has a “.odt” extension due to upload restrictions. Simply download it, rename it so “.ATR” is the only extension. The API documentation is in PDF format.

Version 1.6 will include the FujiNet and SQL bindings. I do not have an ETA on that release yet.

Downloads

A GitHub page has been established for code distribution. You can download the release there, or using the links below.

GitHub link:

https://github.com/Ripjetski6502/A8ActionLibrary

Library ATR file (ActionLibV151.ATR): (updated 2022.09.10 with new license)

ActionLibV151.atrDownload

Library PDF API Document (ActionLibReference_151-D.pdf):

ActionLibReference_151-DDownload

Here is a video of a sample application written using the library and its latest features, while it is from V1.4, it is essentially the same now:

Enjoy.

Share this:

  • Click to email a link to a friend (Opens in new window)
  • Click to share on Facebook (Opens in new window)
  • Click to share on LinkedIn (Opens in new window)
  • Click to share on Pinterest (Opens in new window)
  • Click to share on Pocket (Opens in new window)
  • Click to share on Reddit (Opens in new window)
  • Click to share on Twitter (Opens in new window)

Like this:

Like Loading...

C Style! – Action! Library Conversion 4

Posted by Ripdubski on 2022.08.27
Posted in: Atari, Programming. Tagged: 8 bit, C (CC65). Leave a comment

With the core Action! Library window routines complete, I moved to converting the menu routine, and the first gadget. The menu routine converted is MenuV(), which is a vertical stacked menu. The first gadget to be converted is GAlert() which simply displays a message in a window and waits for a keypress.

As a reminder the actual library source code is being withheld until the conversion is completed. Here is the source for the sample program which demonstrates calling the routines. The command line used to compile is noted in the header comment:

// ------------------------------------------------------------
// Program: menuv.c
// Desc...: A8 Library Menu and Alert Test
// Author.: Ripdubski
// Date...: 202208
// Notes..: cl65 -v [-O] -t atarixl menuv.c -o menuv.xex
// ------------------------------------------------------------

// Pull in include files
#include <stdio.h>
#include <conio.h>
#include <unistd.h>
#include <string.h>
#include <atari.h>

// Converted Action! library files
// Redacted until full conversion complete.
#include "a8defines.h"
#include "a8defwin.h"
#include "a8libmisc.c"
#include "a8libstr.c"
#include "a8libwin.c"
#include "a8libgadg.c"
#include "a8libmenu.c"


// ------------------------------------------------------------
// Func...: void main(void)
// Desc...: Main routine
// ------------------------------------------------------------
void main(void)
{
    // Variables
    byte bW1, bW2, bC, bD;
    unsigned char *pcM[7] = { " Alert        ", " Progress     ", " Buttons      ", " Checkboxes   ", " Radio Button ", " Quit         " };

    // Setup screen
    WInit();
    WBack(14);

    // Open windows
    bW1 = WOpen(0, 0, 40, 3, WON);
    WPrint(bW1, WPCNT, 1, WOFF, "CC65 A8 Menu Test");
    bW2 = WOpen(12, 6, 16, 10, WOFF);
    WOrn(bW2, WPTOP, WPCNT, "Menu");

    // Set done to false
    bD = FALSE;

    // Loop until done (Quit selected)
    while (! bD) 
    {
        // Call menu
        bC = MenuV(bW2, 1, 2, WON, 1, 6, pcM);

        // Process choice
        switch (bC)
        {
            // For each option, show an alert using the GAlert gadget.
            case 1: GAlert("Alert! menu option 1 selected!");
                    break;

            case 2: GAlert("Alert! menu option 2 selected!");
                    break;

            case 3: GAlert("Alert! menu option 3 selected!");
                    break;

            case 4: GAlert("Alert! menu option 4 selected!");
                    break;

            case 5: GAlert("Alert! menu option 5 selected!");
                    break;

            // Quit option, set exit to true
            case 6: bD = TRUE;
                    break;
        }
    }

    // Wait for a keypress
    while (! kbhit()) { };

    // Close windows
    WClose(bW2);
    WClose(bW1);

    // Exit
    return;
}

Screenshot of the MenuV() function being used:

Screenshot of the GAlert() gadget being used:

Share this:

  • Click to email a link to a friend (Opens in new window)
  • Click to share on Facebook (Opens in new window)
  • Click to share on LinkedIn (Opens in new window)
  • Click to share on Pinterest (Opens in new window)
  • Click to share on Pocket (Opens in new window)
  • Click to share on Reddit (Opens in new window)
  • Click to share on Twitter (Opens in new window)

Like this:

Like Loading...

C Style! – Action! Library Conversion 3

Posted by Ripdubski on 2022.08.26
Posted in: Atari, Programming. Tagged: 8 bit, C (CC65). Leave a comment

With the ATASCII to Internal code routines converted from my Action! library and now working, as well as the libraries wait functions, I was able to start on the windowing library routines. The only larger part of the library are the window gadgets which I’ll get to in future posts.

First I converted the WInit() function which clears all the memory for the window system, and sets all the handle information to its defaults, setups of the screen by clearing it, and setting the left margin to 0.

I then started converting WBack() which sets the background display character. It uses memset to accomplish this so it is very quick. With that working, I then did the basic WOpen() function which simply saves and clears the area of the screen the window will occupy, via memcpy and memset, and then draws the window frame. I then completed the WClose() routine which restores the contents of the screen the window covered, again via memcpy. The use of memcpy and memset makes the routines very fast, even with calling StrAI() routines to get the display to internal code first.

Once the window open and close was working, I moved to implement WPos() and WPut(). WPos() moves the window system virtual cursor to a coordinate within the given window, or it can be used to position the physical cursor to an absolute position (same as CC65 gotoxy() function). The WPut() function allows you to place a single character in a given window.

Next I completed the WPrint() routine, which is used to print text into a given window. During this conversion, I changed the call slightly from Action!’s. I did it to make it a little more flexible in regards to displaying inverse text and coding in CC65 on the Mac which doesn’t allow entry of ATASCII characters into the source code.

With WPrint() complete, I moved to WOrn() which allows the placement of ornaments onto the top and bottom window frames in either the left, right, or center positions.

Next I converted the WStatus() function which returns if a window handle is in use or not. I then built a loop into the test program to display the status of each window handle.

With all that working I converted the WClr() function from my Action! library. This function clears the contents of the window (inside the frame). I then put some wait for key pauses in the test/demo program to validate everything worked as expected.

Here is the source code for the test/demo program. As in the last post, the use of byte is present, which represents an unsigned char. unsigned char’s should be used in loops where possible with CC65 because their access is quicker, making the loops execution time faster. There is a full explanation on the CC65 website:

// ------------------------------------------------------------
// Program: testwin.c
// Desc...: A8 Library Windows Test
// Author.: Ripdubski
// Date...: 202208
// Notes..: cl65 -v [-O] -t atarixl testwin.c -o testwin.xex
// ------------------------------------------------------------

// Pull in include files
#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <atari.h>

// The next 4 are part of the converted Action! library.
#include "a8defines.h"
#include "a8defwin.h"
#include "a8libstr.c"
#include "a8libwin.c"


// ------------------------------------------------------------
// Func...: void main(void)
// Desc...: Main routine
// ------------------------------------------------------------
void main(void)
{
    // Variables
    byte bW1, bW2, bL;
    unsigned char cL[40];

    // Initialize window system, and setup screen
    WInit();
    WBack(14);

    // Open title window
    bW1 = WOpen(0, 0, 40, 3, WON);
    WPrint(bW1, WPCNT, 1, WOFF, "CC65 Window Test");

    // Open status window, display ornaments, and divider
    bW2 = WOpen(4, 6, 32, 14, WOFF);
    WOrn(bW2, WPTOP, WPLFT, "TL");
    WOrn(bW2, WPTOP, WPRGT, "TR");
    WOrn(bW2, WPTOP, WPCNT, "Status");
    WOrn(bW2, WPBOT, WPLFT, "BL");
    WOrn(bW2, WPBOT, WPRGT, "BR");
    WDiv(bW2, 11, WON);
    WPrint(bW2, WPCNT, 12, WOFF, "Divided Window");

    // Use WPOS and WPUT in both inverse and regular windows
    WPos(bW1, 38, 1);
    WPut(bW1, 49);   // 1
    WPos(bW2, 30, 1);
    WPut(bW2, 50);   // 2

    // Get and display status of each window handle
    for (bL=0; bL < 10; bL++)
    {
        // Get window status
        // Create formatted display string in char array
        if (WStat(bL) == WON)
        {
            sprintf(cL, "Window %d = In Use", bL);
        }
        else
        {
            sprintf(cL, "Window %d = Not Used", bL);
        }
        // Print the string to the window
        WPrint(bW2, 1, bL+1, WOFF, cL);
    }

    // Wait for a keypress (just used conio function)
    cgetc();

    // Turn off divider
    WDiv(bW2, 11, WOFF);

    // Wait for a keypress
    cgetc();

    // Clear window
    WClr(bW2);

    // Wait for a keypress
    while (! kbhit()) { };

    // Close windows
    WClose(bW2);
    WClose(bW1);

    // Exit
    return;
}

Screenshot of all the window functions being used:

Breakdown of what is being shown:

The background is painted with a period character using WBack() function.

The title window at the top is flagged to be opened in inverse with the WOpen() call.

The text “CC65 Window Test” is printed on the 1st row of the window with the CENTER flag enabled in the call to WPrint().

The status window is opened as the second window. The WOrn() function is used to set the “Status” title ornament in the center on the top of the frame.

The “TL” ornament is displayed on the frame using the WOrn() function called with TOP and LEFT.

The “TR” ornament is displayed on the frame using the WOrn() function called with TOP and RIGHT.

The “BL” ornament is displayed on the frame using the WOrn() function called with BOTTOM and LEFT.

The “BR” ornament is displayed on the frame using the WOrn() function called with BOTTOM and RIGHT.

The lower window divider is created using the WDiv() function.

The “Divided Window” test is printed on the last row of the window with the CENTER flag enabled in the call to WPrint().

The “1” and the “2” in the upper right corners of each window are displayed using the WPut() function.

Each text line (“Window x = <status>”) is displayed using WPrint().

Share this:

  • Click to email a link to a friend (Opens in new window)
  • Click to share on Facebook (Opens in new window)
  • Click to share on LinkedIn (Opens in new window)
  • Click to share on Pinterest (Opens in new window)
  • Click to share on Pocket (Opens in new window)
  • Click to share on Reddit (Opens in new window)
  • Click to share on Twitter (Opens in new window)

Like this:

Like Loading...

Posts navigation

← Older Entries
  • Follow Unfinished Bitness on WordPress.com
  • Enter your email address to follow this blog and receive notifications of new posts by email.

    Join 42 other subscribers
  • Recent Posts

    • FujiNet Time in C (CC65)
    • C Style! – Action! Library Conversion 10
    • C Style! – Action! Library Conversion 9
    • C Style! – Action! Library Conversion 8
    • C Style! – Action! Library Conversion 7
  • Categories

    • Apple
    • Atari
    • Audio
    • BBS
    • Bookmarks
    • DD-WRT
    • General
    • Google
    • iOS
    • MSDOS
    • NAS
    • Notes
    • OSX
    • Programming
    • Router
    • Security
  • Tags

    1Password 8 bit 12v 110v 6502 Action! Alpine APETIME Assembly Atari 400 Atari 800 Atari XE Atari XL BASIC Bookmarks boombox BootScript C (CC65) Car Audio CDA7893 CIO CX430 DD-WRT Delicious DHCP DiskStation DNSMasq EverNote Fitbit FujINet ghetto-blaster Google GTO605C HTTP Server iCloud instruction IOCB iOS iTunes JBL Local DNS Mac OS X Mac OSX Migrate Opcode OSX Perl SimpleNote Synology Windows
  • Archives

    • February 2023
    • September 2022
    • August 2022
    • July 2022
    • June 2022
    • December 2021
    • February 2021
    • December 2020
    • September 2020
    • October 2019
    • May 2018
    • April 2018
    • June 2017
    • April 2017
    • February 2017
    • December 2016
    • September 2016
    • August 2016
    • July 2016
    • June 2016
    • May 2016
    • April 2016
    • September 2015
    • August 2015
    • July 2015
    • May 2015
    • April 2015
    • March 2015
    • February 2015
    • January 2015
    • December 2014
    • November 2014
    • October 2014
    • September 2014
    • August 2014
    • July 2014
    • June 2014
    • May 2014
    • April 2014
    • March 2014
    • February 2014
    • December 2013
    • October 2013
    • June 2013
    • May 2013
    • March 2013
    • February 2013
    • January 2013
  • Meta

    • Register
    • Log in
    • Entries feed
    • Comments feed
    • WordPress.com
Blog at WordPress.com.
Unfinished Bitness
Blog at WordPress.com.
  • Follow Following
    • Unfinished Bitness
    • Join 42 other followers
    • Already have a WordPress.com account? Log in now.
    • Unfinished Bitness
    • Customize
    • Follow Following
    • Sign up
    • Log in
    • Report this content
    • View site in Reader
    • Manage subscriptions
    • Collapse this bar
 

Loading Comments...
 

    %d bloggers like this: