Zum Inhalt springen

APC in F-14


Snux

Empfohlene Beiträge

vor 49 Minuten schrieb Snux:

Maybe I make my own versions of TurnOn/TurnOff/Blink etc which check some variable that will be set if a show is running and then only call the APC.ino routines if no show running.

You could also switch to your own lamp array by letting LampPattern point to it. Then let your own Lamp On/off commands change this lamp array instead of LampColumns. The 'normal' lamp stuff can continue working in the LampColumns without interfering and if you're done you can just switch back.

 

Bearbeitet von Black Knight
Link zu diesem Kommentar
Auf anderen Seiten teilen

  • Antworten 185
  • Erstellt
  • Letzte Antwort

Top-Benutzer in diesem Thema

  • Snux

    108

  • Black Knight

    72

  • bontango

    4

  • Volley

    2

Top-Benutzer in diesem Thema

Veröffentlichte Bilder

12 hours ago, Black Knight said:

You could also switch to your own lamp array by letting LampPattern point to it.

I took a look at that but apart from the fact it gave me a headache trying to understand it, I don't think that will help with the LEDs.

I have a handler for most "things" in my code, so one for the 1-6 lamps/targets, one for the TOMCAT targets, one for bonus lighting etc etc.  Each of those handlers already accepts an event to reset the related lamps (between players for example).  If I update those to check if a show is in progress and switch the lamps off then I think it'll work.  So basically it should look like

  • set show_in_progress = true
  • pass the lamp reset event to each handler (I'll just build a function to do that, been meaning to do that anyway)
  • play the show
  • set show_in_progress = false
  • pass the lamp reset again

I'll see how that goes.

Link zu diesem Kommentar
Auf anderen Seiten teilen

May be I got it wrong, but the problem I see with this is when you want your lamps to show an animation, you have to tell every routine which might use the lamps during that time not to do it. And you still want them to keep track of what they were supposed to be doing in the meanwhile because when you switch back these changes have to show up also.

This can be avoided by letting all routines do their job as usual in the LampColumns array. However, the LampPattern pointer determines what is shown. Hence, all you have to do is:

byte MyLamps[8]

LampPattern = MyLamps;         // The status of MyLamps is shown but all other routines can still work in LampColumns
// place your lamp animation here but let it use MyLamps[]
LampPattern = LampColumns      // switches back to the normal playfield lamps

Of course this only makes sense, if you use all plafield lamps for your animation.

vor 3 Stunden schrieb Snux:

I don't think that will help with the LEDs.

That was true until last weekend. Then I've implemented the pointer LEDpattern which does exactly the same for LEDs what LampPattern does for lamps.

Note that I've also implemented a new settings named 'No of LEDs' to support up to 192 LEDs. You have to set this to 64 to make everything work as before.

Link zu diesem Kommentar
Auf anderen Seiten teilen

OK, I understand that better now.  For normal lamps, if I copy TurnOnLamp and TurnOffLamp from APC.ino and make my own versions that use MyLamps instead of LampColumns that should work.  I'll also need to call my own LED handling just for the switch on/off so it uses MyLEDs instead of LEDStatus.  Then in the code I have for shows, which is just using TurnOn/TurnOff, if I call my versions (after setting LampPattern and LEDPattern) we should be good.  I'll try that out and see how it goes.

void F14Show_TurnOnLamp(byte Lamp) {
  if (Lamp < 65) {                                    // is it a matrix lamp?
    Lamp--;
    MyLamps[Lamp / 8] |= 1<<(Lamp % 8);}
  else {                                              // lamp numbers > 64 are additional LEDs
    F14_ShowLEDhandling(3, Lamp - 65);}}

void F14_ShowLEDhandling(byte Command, byte Arg) {
  
  switch (Command) {
  
  case 3:                                             // turn on LED
    MyLEDs[Arg / 8] |= 1<<(Arg % 8);
    break;
  case 4:                                             // turn off LED
    MyLEDs[Arg / 8] &= 255-(1<<(Arg % 8));
    break;
  case 5:                                             // query LED
    return MyLEDs[Arg / 8] & 1<<(Arg % 8);
    break;
  }
}

 

29 minutes ago, Black Knight said:

You have to set this to 64 to make everything work as before.

OK :)

Link zu diesem Kommentar
Auf anderen Seiten teilen

You got it.

This pointer stuff can be confusing. It helped me to understand what an array is in C. It's just a chunk of memory with a pointer to it. That means

a = MyArray[i];

and

a = *(MyArray+i)

has the same effect.

And you cannot copy an array by saying

My2ndArray = MyArray;

All you're doing is to copy the pointer. That means

My2ndArray[i] = 5;

will actually change MyArray.

Link zu diesem Kommentar
Auf anderen Seiten teilen

That works very nicely.

LEDStatus is only available locally to the LEDHandling routine, so before switch LEDPattern I have to make a note of it's current value and put it back afterwards (I can't say LEDPattern=LEDStatus in my code as LEDStatus is undefined).

The only other change I made was to move enabling my GI (LEDs).  That was in the F14_init code but at that point the LEDs have not been initialised (they used to be), so I just moved that to the start of the attract mode instead.

One little trick you did which had me banging my head for a while.  LEDPattern.  Except it isn't LEDPattern, but for some reason I thought it was.  It's LEDpattern.  That little 'p' caught me out for a while :)

This is the code in the routine that calls the shows (I'll expand the list).  Some shows run forever in which case you need to call with step 255 to stop them.  Some run for a fixed time and then callback to this handler themselves with 255 to reset things.

void F14_LampShowPlayer(byte ShowNumber, byte Arg) {

  // point the buffers correctly
  switch (Arg) {
    case 0: // start - point the LED and Lamp buffers to the F14Show versions
      apc_LEDStatus = LEDpattern;  // make a note of where the current LED buffer is
      LEDpattern = F14_ShowLEDs;
      LampPattern = F14_ShowLamps;
      break;
    case 255: // stop
      LEDpattern = apc_LEDStatus;  // reset the buffers
      LampPattern = LampColumns;
      break;
  }
  // call the lamp show player
  switch (ShowNumber) {
    case 0:
      F14_LampShowRotate(Arg);  // rotating wheel lamp show, 0 to start, 255 will stop
      break;
  }
}

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 15 Minuten schrieb Snux:

That little 'p' caught me out for a while

Oh yeah, I know what you mean. I once confused an O with a 0 (zero) in my code and it took me quite a while to understand what the compiler was complaining about.

vor 10 Minuten schrieb Snux:

I can't say LEDPattern=LEDStatus in my code as LEDStatus is undefined

You're right, but calling LEDinit() again should do the trick also.

Link zu diesem Kommentar
Auf anderen Seiten teilen

20 minutes ago, Black Knight said:

calling LEDinit() again should do the trick

I did try that once, but it didn't work, I think because LEDinit will do a realloc of LEDStatus so it loses track of what was previously lit.  Anyway, my code seems happy as-is.

Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 37 Minuten schrieb Snux:

I think because LEDinit will do a realloc of LEDStatus so it loses track of what was previously lit.

It's because I'm deleting LEDstatus during initialization.

      for (byte i=0; i<NumOfLEDbytes; i++) {
        LEDstatus[i] = 0;}
      LEDpattern = LEDstatus;}                        // switch to standard LED array
    break;

I have to check whether the size of LEDstatus has changed and skip deleting LEDstatus if it hasn't.

Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 2 Stunden schrieb Snux:

Anyway, my code seems happy as-is.

Could you give it a try anyway? LEDinit() should work now.

Link zu diesem Kommentar
Auf anderen Seiten teilen

On 3/2/2022 at 6:24 PM, Black Knight said:

LEDinit() should work now.

No, still doesn't work.  I think the code is still running this line which is causing the issue...

LEDstatus = (byte *) realloc(LEDstatus, NumOfLEDbytes);}

I notice you made those changes for saving memory for the LEDs.  Do you have any feeling for how close we are to the limits for memory?  For program storage I've commented out the init calls in APC.ino for BK, TT, BC and PB and my compile now shows but that doesn't reflect RAM usage during execution of course.

Sketch uses 94100 bytes (17%) of program storage space. Maximum is 524288 bytes.

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 2 Stunden schrieb Snux:

I think the code is still running this line which is causing the issue...

I expected the realloc not to delete the memory, but may be I'm wrong.

vor 2 Stunden schrieb Snux:

I notice you made those changes for saving memory for the LEDs. 

That was related to the SW of the LED_exp board, because it just has 2K of RAM. 
When I started coding this stuff I didn't know that in C bool variables are just bytes with 7bit being wasted. Therefore I had to replace the bools in the LED_exp code to free up enough memory to support up to 192 LEDs.

The DUE on the other hand has 100K of RAM, so I don't expect any problems here. Nevertheless I'm also trying to avoid bool arrays here, just because it usually is a low hanging fruit.

Link zu diesem Kommentar
Auf anderen Seiten teilen

17 minutes ago, Black Knight said:

I expected the realloc not to delete the memory, but may be I'm wrong.

It might be something else, but when I used LEDinit() they all basically stopped working.  I can try to debug some more maybe and see what is happening.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Not related to the LED issue, but I've been rereading some of my code to simplify it and realised I'm doing some bad things in a few places, I've got a couple of functions that don't properly return, they actually call the original function instead (almost like a go-to, oops), so my call stack must look like a mess.  Time for some coffee and rework.

Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 10 Minuten schrieb Snux:

I've got a couple of functions that don't properly return, they actually call the original function instead

Are you sure? Can you give me an example?

If the function wouldn't somehow return then your game program would stop, because it'd never return to the main loop.

vor 12 Minuten schrieb Snux:

related to the LED issue

Looks good now, so I hope it also works for you.

Link zu diesem Kommentar
Auf anderen Seiten teilen

5 minutes ago, Black Knight said:

Can you give me an example?

It's in my own code and as you say it must be returning otherwise it would stop working.  I'm at that point where I've kept adding code and then fixing things without tidying up properly.  So in places it's getting a little confusing to read, a little timeout just to fix up a few things is good.

9 minutes ago, Black Knight said:

Looks good now, so I hope it also works for you.

Will let you know

Link zu diesem Kommentar
Auf anderen Seiten teilen

This is an example of what I mean by messy....

Suppose I have a handler, with the usual switch statement to handle the various events that might come in.

(void) F14Handler(byte Event) {

switch (Event) {
case 0:
	do something
	break;
case 1:
	do something that ejects the ball
	break;
case 2:
	decide that we need to eject the ball
	F14Handler(1);
	break;
}}

So when event 2 comes in, I'm calling the handler again with event 1 before it completes under the event 2.  Is that good practice?  Part of me thinks that it's not good, but part of me thinks actually this is fine.  I didn't have the coffee yet, maybe a glass of wine will work better :)

Link zu diesem Kommentar
Auf anderen Seiten teilen

I see, some kind of 'nested calls'.

I'm not that concerned about your stack, but about any routine specific variables especially static ones. These might be changed by the inner call which then unexpectedly also changes the value for the rest of the outer one.

Why don't you call a timer instead?

ActivateTimer(1, 1, F14Handler);

will gracefully end the current call and come back immediately after 1ms. 

Link zu diesem Kommentar
Auf anderen Seiten teilen

17 minutes ago, Black Knight said:

Why don't you call a timer instead?

Yeah, I was wondering about doing that, although I think that might give some odd results where the outer call might be expecting the change.  I'll work through it.

However I think I've found an issue with the BlinkenLights :)

The first blinking lights that I add are the Tomcat targets, with a period of 100.  I found that if I add another blink lamp with the same period it works and "joins the blink party".

If however I add a single blink lamp with a period of 50, all the blinking stops until I remove the blink then it starts again.  I also noticed that a lamp added with a period of 150 just switches on and doesn't blink at all, but it does slow down the blinking of all the others with a period supposed to be 100.  I think it probably changes their blink period to 150.  I *think* this used to work fine, but I'm not 100% sure.

I've been looking at the blink code trying to see where the issue is.  I couldn't find it, but I do have another question.  I think if I set up first a blinking lamp with period 100, then one with 150, then one with 200.  Then remove the blink with period 150.  I have a feeling that the blink with 200 will get lost (have not tested this) because the number of timers will be reduced (BlinkTimers--) without considering that the first and third should still be active.  Or maybe I'm reading the code wrong (glass of wine is working!)

Bearbeitet von Snux
Link zu diesem Kommentar
Auf anderen Seiten teilen

OK, the BlinkLamps never caused any trouble in years, so I might have messed this up by trying to pick the low hanging fruit I mentioned earlier. BlinkLamps also used a bool array before, so I thought I could fix this also after everything went so well mit the LED_exp SW.

I'm going to give this a run in the debugger tomorrow.

Link zu diesem Kommentar
Auf anderen Seiten teilen

That was one hell of a typo.

Took me a lot of time to see it even though the debugger indicated it quite clearly.

Should work again.

Link zu diesem Kommentar
Auf anderen Seiten teilen

9 hours ago, Black Knight said:

That was one hell of a typo.

& I agree, what was the % chance of finding that :)

9 hours ago, Black Knight said:

Should work again

It does, and so does LEDinit().  Thanks!

Link zu diesem Kommentar
Auf anderen Seiten teilen

So I thought I'd try some colour handling with the LEDs and hit something very odd.

Initially I just TurnOnLamp for each LED in the GI.  They come on white, which is fine.

I use LEDSetColorMode(1) as I don't want everything to change colour.  Then LEDSetColor(255,0,0).  OK so far, nothing changes as we have mode 1.  Then when I call LEDchangeColor the game stops with error 3 which is something to do with the blink handler, which doesn't make much sense.  If I comment out LEDchangecolor no crash, but obviously they don't change color.

If I use colormode 2 then the setcolor works immediately as expected, but it changes all the playfield LEDs which I don't want to do.  Any idea why LEDchangeColor is dumping out with an Error 3?  Specifically error 3, BLtimer is 0, BlinkingNo[BLtimer] is 13

Link zu diesem Kommentar
Auf anderen Seiten teilen

Erstelle ein Benutzerkonto oder melde Dich an, um zu kommentieren

Du musst ein Benutzerkonto haben, um einen Kommentar verfassen zu können

Benutzerkonto erstellen

Neues Benutzerkonto für unsere Community erstellen. Es ist einfach!

Neues Benutzerkonto erstellen

Anmelden

Du hast bereits ein Benutzerkonto? Melde Dich hier an.

Jetzt anmelden

×
×
  • Neu erstellen...

Wichtige Information

Datenschutzerklärung und Registrierungsbedingungen