CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

IGT SAS (Slot Accounting System) protocol
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
PrinceNai



Joined: 31 Oct 2016
Posts: 452
Location: Montenegro

View user's profile Send private message

IGT SAS (Slot Accounting System) protocol
PostPosted: Fri Mar 04, 2022 7:28 am     Reply with quote

Hi,

First some background. In a casino where I work all the slots are connected to a host system via SAS protocol. This protocol enables the host to interrogate the machine for data and to send various configuration options to the machine. One of those options is to lock or unlock the machine. The protocol is designed in a way that the host MUST poll the machine once every 200ms - 5s otherwise the machine stops and reports it isn't connected to the host. SAS is a serial protocol with RS232 or in some cases TTL levels. My boss wants that the machine isn't playable if the player card isn't inserted. Our current system doesn't support that feature.

My question is this: if I make a gadget that will check for the card, be connected in parallel to the TX line of the host, find out when the line is idle (host not polling the machine) and so on... Can I inject the "lock" command with such a connection? Of course I first have to record the actual baud rate of the host. No reply from the machine is expected after issuing "lock" or "unlock"message, so only TX would be used.
temtronic



Joined: 01 Jul 2010
Posts: 9081
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Fri Mar 04, 2022 7:39 am     Reply with quote

yes, can be done...BUT... your PIC will be in series, NOT parallel...
machine--PIC---host
best to have a PIC with 2 HW UARTs !!
main() is fairly simple....
all machine<>host communications are 'passed through'...
if(no card) {send lock command}
...

I did similar project to interface PC keyboards to 163 key RS232 KBDs ,sighn decades ago ( think 16C84 times....)
PrinceNai



Joined: 31 Oct 2016
Posts: 452
Location: Montenegro

View user's profile Send private message

PostPosted: Fri Mar 04, 2022 8:17 am     Reply with quote

Spinning this through my head. It is true that to a man that only has a hammer every problem seems like a nail :-). I'd never thought of that solution and it is way simpler. One dual RS232 chip, TTL doesn't even need anything as long as it's a 5V powered board, 2 connectors and a small PIC (something that is old enough to work with MPLAB. 50c apiece more expensive doesn't make any difference). One HW UART would be enough, only TX from the host interests me, RX can go directly through on the board. And an IR optocoupler, the kind with the groove used to measure RPM's or something to detect the card is present in the slot.

Thanks a lot
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

Re: IGT SAS (Slot Accounting System) protocol
PostPosted: Sat Mar 05, 2022 11:48 am     Reply with quote

PrinceNai wrote:

be connected in parallel to the TX line of the host

RS-232 or TTL lines are driven, they're not open-collector.
I don't get how you can hook it in parallel. Series maybe,
using a PIC with two hardware UARTs.
PrinceNai



Joined: 31 Oct 2016
Posts: 452
Location: Montenegro

View user's profile Send private message

PostPosted: Sat Mar 05, 2022 12:24 pm     Reply with quote

Yes, serial is the way to go. I'm drawing some block diagrams and lines to and fro from the host, machine and my device. It seems that one HW UART will do, since I only need to monitor TX from the host. So the path for the signal would be: TX from the host --> RS232 converter RX1_232 --> RS232 converter TX1_TTL --> PIC RX --> propagate the signal to PIC TX and to RS232 converter RX2_TTL --> RS232 converter TX2_RS232 --> slot RX. Am I missing something?

And one question: when I get the character inside UART receive interrupt (HW UART), can I just forward it inside the interrupt routine and let the hardware take care of it?
temtronic



Joined: 01 Jul 2010
Posts: 9081
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Sat Mar 05, 2022 12:55 pm     Reply with quote

sounds 'right'.. Use a MAX232 type chip ,has 2 sets of RS232<>TTL inside !
You really need to maintain proper RS232 signals. If you don't need data going the other way, simply 'jumper' the TTL lines.

Consider having a male AND female connector on the PCB, so that if it needs to be removed the cable from the slotmachine goes into the host cable

yes ,inside the ISR you can put the incoming byte into the TX buffer to send it 'on it's way'. Using HW UART allows this.
PrinceNai



Joined: 31 Oct 2016
Posts: 452
Location: Montenegro

View user's profile Send private message

PostPosted: Sat Mar 05, 2022 1:17 pm     Reply with quote

Quote:

Consider having a male AND female connector on the PCB, so that if it needs to be removed the cable from the slotmachine goes into the host cable

And to prevent somebody to hook it the other way around. I've already ordered some boards with MAX232 chips to test it. And to return to the rant about MPLABX. Development will be done on 18f46k22 and the final product (if my boss will put € behind his wishes) will be on a way newer, smaller and cheaper PIC).

BTW, is there some way to find out what one can buy right now without going manually through every single PIC?
Ttelmah



Joined: 11 Mar 2010
Posts: 19195

View user's profile Send private message

PostPosted: Sat Mar 05, 2022 2:08 pm     Reply with quote

Seriously design on what you are going to use.

If you don't need the pins, look at the 18F26K22. However on the newer
product 'caveat'. Availability on these is much worse. So while the K22
is available, the 18F27Q10 for example is a 2023 availability....
The K22, is less than half the price of the 40pin chip.
temtronic



Joined: 01 Jul 2010
Posts: 9081
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Sat Mar 05, 2022 2:58 pm     Reply with quote

Hay Mr. T.
went to use Microchips Paramtric search tool, PIC18F chips, finally got all 72 parameters displayed.... NO UART selection !
Ok, I HAVE to be doing something wrong... thought it'd be EASY to see what PICs have 2 UARTs..then see if any are in stock somewhere...

meanwhile,I see Digikey don't have the 48k22 or 26k22 in stock...
PrinceNai



Joined: 31 Oct 2016
Posts: 452
Location: Montenegro

View user's profile Send private message

PostPosted: Sat Mar 05, 2022 6:17 pm     Reply with quote

It's funny, isn't it? Right now the factor in the design isn't the price or number of pins. It's availability. Catch me if you can, for 1,27$ or 6$ or 16$. I have 50 or so 18f46k22's lying around, but it's not close to what I need and I'd hate to waste such a workhorse for something that will use 10 pins (if I'm very, very generous with LED's) and 1,2% of ROM. That's why Microchip should put to the leftmost column of their parametric search if the part is even available. Now, not to my grandson. Or at least put in a checkbox to filter such a rare chip out. It's all "more coming soon". To me soon is tomorrow or next week, for them maybe this decade. What I see on Microchip direct is that chips are all "in production" but 99,99999% of them is out of stock . Technically you can buy, but in some alternate universe, where time passed slower and the year is still 2019.
temtronic



Joined: 01 Jul 2010
Posts: 9081
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Sat Mar 05, 2022 7:50 pm     Reply with quote

The main reason I 'jumped ship' and went from Motorola to Microchip was the 'we make millions, supply will never be an issue', back in '85ish...
The world HAS changed.
I've used the 46K22 for similar 'easy' projects. It's my 'Proof of Concept' platform PIC. Yes, way more powerful than it needs to be BUT you have them, use them. Consider your R&D time cost trying to find a small PIC that 'should' be used. Say R&D is $100 per hour (everyone here charges that or more...). You've probably spent 5 hours trying to find the 'right' PIC. That's $500 in real money. Now you need 100 pcs for the run.If a 46k22 costs you $5, you could have bought them with the R&D money that got you nowhere.
Right now, you've got a known PIC, IN YOUR HANDS, to at least get the project going forward and while it's out in 'test trials', you can see IF there's a 'baby' PIC that will do the job. Just be cautious about a new PIC ! Some have 'bugs' that may take hours or dayze to figure out...costing precious R&D time and money. Sometimes the 'old' stuff IS better !
PrinceNai



Joined: 31 Oct 2016
Posts: 452
Location: Montenegro

View user's profile Send private message

PostPosted: Sat Mar 05, 2022 11:39 pm     Reply with quote

Temtronic,

I simply don't want to use my LAST 50 or so 18f46k22's for this project. One, to develop it. For a final product I'll need 500 pieces of any PIC, be it 16 or 80 pin. I'd gladly use 18f46k22, but I just can't seem to find where to buy them. Maybe I should install "out of stock" in a socket, if CCS supports it :-)
temtronic



Joined: 01 Jul 2010
Posts: 9081
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Sun Mar 06, 2022 6:53 am     Reply with quote

sigh... guess it's time to search for a small PIC, say with 2 HW UARTS that someone has 1000 pcs in stock.Whatever your compiler + programmer are happy with. Something that you can use on future products.
Should only take a day or two staring into the screen.....3 pots of coffee..
There HAS to be SOMETHING, somewhere, that'll work....
good luck.
Jay

edit:
Went to Digikey, searched for PIC16F, lots of hits...., filter for UART, few hundred, clicked for 'descending qty' (most first). lots of PICs.
Only took a few seconds (quicker than opening Microchips search... ) !!!

LOTS of 16F887 in stock ! I don't know my PIC numbers but one of them HAS to work for you....
Ttelmah



Joined: 11 Mar 2010
Posts: 19195

View user's profile Send private message

PostPosted: Sun Mar 06, 2022 7:41 am     Reply with quote

On the search, there is a 'show all columns' option. This then gives a UART
column. Smile

On the 26K22,
Microchip themselves are showing 764 in stock,
OMO are showing them,
Chip inventory,
Sierra IC Inc,
Green Light electronics,
Heisener
Depu,
Conevo.
PrinceNai



Joined: 31 Oct 2016
Posts: 452
Location: Montenegro

View user's profile Send private message

PostPosted: Sat Mar 26, 2022 10:12 pm     Reply with quote

I followed your advice to go serial. For testing purposes I used an USB - SERIAL module and YAT terminal sending out a string every 200ms. This program happily injects a command 10 times based on the state of the card input and after that lets everything through. Now I just need to record the actual command for "lock" and "unlock" on the machine.

Code:

//#include <main.h>

#include <18F46K22.h>
#device ADC=10

#FUSES NOWDT                  //No Watch Dog Timer
#FUSES NOPUT
#FUSES NOLVP
#FUSES DEBUG

#device ICD=TRUE
#use delay(internal=32000000)
#use rs232(baud=19200,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8,stream=PORT1,errors)

char Tmp = 0;                                   // UART receive variable, intentionaly global for debugging purposes
unsigned int8 RX_Idle_Timer = 0;                // measures the time PIC's RX line is idle in increments of 16ms
unsigned int8 Tick = 0;                         // counts 16ms TMR0 interrupts
#define NumberOfTicksBeforeWork 13              // approx. 200ms
int8 Work_To_Do = 0;                            // we go through the switch statement every NumberOfTicksBeforeWork * 16,3ms or 200ms

#define START_STATE 0
#define LOCK_STATE 1                            // states
#define UNLOCK_STATE 2
#define PASS_THROUGH_STATE 3
int8 Lock_Or_Unlock = START_STATE;              // state machine variable, preset to START_STATE

#define MIN_RX_LINE_IDLE 10                     // MIN_RX_IDLE_TIME * 16,3ms is the time PIC's RX line must be idle to inject the command on TX or 163ms
#define CARD_INPUT PIN_B0                       // input pin for the card

#define REPEATS 10                              // number of times the command is repeatedly issued. Repeating is done because the machine doesn't answer and so we can't know if the machine has heard it.
int8 Command_Repeat_Counter = 0;                // counts how many times the command was sent out, compares to REPEAT
int8 CardFirstState = 1;                        // detect card variables, debouncing
int8 CardSecondState = 0;                       // intentionally different at start, to force at least two checks in the space of 16ms!!!
int8 CardCurrentState;                          // read from the card input pin
int8 CardIsPresent = FALSE;                     // variable to tell whether card is in the slot or not

int8 PreviousLockEvent;                         // indicates previous LOCK or UNLOCK event. Used to prevent repeated issuing of the same command in PASS_THROUGH_STATE if nothing changes with the card
#define MACHINE_UNLOCKED 0
#define MACHINE_LOCKED 1

// ****************************************************************************
//                                INTERRUPTS
// ****************************************************************************
#INT_RDA
void  RDA_isr(void)
{
   Tmp=fgetc(PORT1);                            // get received char and thus also clear interrupt flag               
   fputc(Tmp, PORT1);                           // send the received character forward to Tx immediatelly                   

   set_timer0(0);                               // reset timer and counter detecting idle time on the RX line of the PIC
   RX_Idle_Timer = 0;                           // to determine if the line is idle for long enough
}
// ...........................................................................
#INT_TIMER0                                     // every 16ms, increments and compares RX line idle counter with minimum required idle time, synchronises execution of main, card detection
void  TIMER0_isr(void)
{
   RX_Idle_Timer++;                             // increase counter every 16ms
   if(RX_Idle_Timer > MIN_RX_LINE_IDLE)         // the point is to detect if the RX line is idle
   {                                            // for a certain period of time (let's say 160ms, below minimum time the SAS standard demands polling the machine (between 200ms - 5s), but close
      RX_Idle_Timer = MIN_RX_LINE_IDLE;   
   }
// detect card, presumes 0 is read if the card is present
// at boot card reading is correct before switch Lock_Or_Unlock begins execution, in the first 50ms

   CardCurrentState = input_state(CARD_INPUT);  // read card
   if((CardCurrentState == 0) && (CardFirstState == 0) && (CardSecondState == 0))
   {
      CardIsPresent = TRUE;                     // card is present
   }
   
   else if((CardCurrentState == 1) && (CardFirstState == 1) && (CardSecondState == 1))
   {
      CardIsPresent = FALSE;                    // card isn't present
   }

   CardSecondState = CardFirstState;
   CardFirstState = CardCurrentState;           // move card input readings down the line
 
// count interrupts till cca. 200ms are gone                                             
   Tick++;
   if(Tick > NumberOfTicksBeforeWork)           // more than 13 x 16ms or 200ms have elapsed?
   {
      Tick = 0;
      Work_To_Do = 1;                           // yes, inform main it has some real work to do, not just spinning around like crazy
   }
}
// ............................................................................
//                              END INTERRUPTS
// ............................................................................


// ****************************************************************************
//                                MAIN
// ****************************************************************************

void main()
{
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_2);     // 16,3 ms overflow at 32MHz clock

   enable_interrupts(INT_TIMER0);
   enable_interrupts(INT_RDA);
   enable_interrupts(GLOBAL);
   port_b_pullups (0x01);
   delay_us(10);                                // Allow time for pull-ups to fully pull up
   output_float(CARD_INPUT);                    // make CARD_INPUT pin an input
   set_timer0(0);
   
   while(TRUE)
   {     
      if(Work_To_Do == 1)                       // go through states every 200ms     
      {
         Work_To_Do = 0;                        // reset
// ---------------------------------------------
// ---------------------------------------------// at start, program isn't aware what state the slot is in
         switch(Lock_Or_Unlock)                 // so it goes to START_STATE and determines if LOCK or UNLOCK command should be issued.
         {                                      // It goes there only once at the startup to get it's bearings. Maybe an extra state, but more readable for me.
// *********************************************         
            case START_STATE:                   // can go to LOCK or UNLOCK state, based on the presence of the card
            {                                   // card presence is already checked in the TMR0 interrupt routine before we even come here
               if(CardIsPresent == TRUE)        // card is in
               {
                  Lock_Or_Unlock = UNLOCK_STATE;// unlock the machine
               }
               else                             // card is not in
               {
                  Lock_Or_Unlock = LOCK_STATE;  // lock the machine
               }             
               break;
            }                 
// *********************************************         
            case PASS_THROUGH_STATE:            // can go to eiter LOCK or UNLOCK depending on the presence of the card
            {                                   // check if the card is present and unlock the machine or lock it if it's missing
               enable_interrupts(INT_RDA);      // enable RDA interrupt and pass-through of the commands from the host
               
               if((PreviousLockEvent == MACHINE_LOCKED) && (CardIsPresent == TRUE)) // machine was locked but card is now present
               {
                  Lock_Or_Unlock = UNLOCK_STATE;// unlock the machine
               }
               else if((PreviousLockEvent == MACHINE_UNLOCKED) && (CardIsPresent == FALSE)) // machine was unlocked but card is not present any more
               {
                  Lock_Or_Unlock = LOCK_STATE;  // lock the machine
               }
                                                // else just exit and return here
               break;
            }             
// *********************************************                   
            case LOCK_STATE:                    // lock the machine and go to PASS_THROUGH_STATE
            {
               if(RX_Idle_Timer >= MIN_RX_LINE_IDLE)        // command can be sent, line was idle for xxx ms. Disable #INT_RDA               
               {
                  disable_interrupts(INT_RDA);
                 
                  if(Command_Repeat_Counter < REPEATS)      // send out "unlock" command REPEATS times every 200ms
                  {                 
                     Command_Repeat_Counter++; 
                     fputs("Lock!", PORT1);     // send out the command
                  }                     
                  else                          // reset counters, change state
                  {
                     Command_Repeat_Counter = 0;            // preload the counter                                         
                     PreviousLockEvent = MACHINE_LOCKED;    // inform PASS_THROUGH_STATE that the machine was just locked
                     Lock_Or_Unlock = PASS_THROUGH_STATE;   // change state to PASS_THROUGH_STATE
                  }
               }
               break;
            }
// *********************************************           
            case UNLOCK_STATE:                  // unlock the machine and go to PASS_THROUGH_STATE
            {                                   // TX line of the host must be quiet for at least 160ms before we inject the command. RX_Idle_Timer keeps track of that.
               if(RX_Idle_Timer >= MIN_RX_LINE_IDLE)        // command can be sent, line is idle
               {
                  disable_interrupts(INT_RDA);
                  if(Command_Repeat_Counter < REPEATS)      // send out "unlock" command REPEATS times every 200ms
                  {
                     Command_Repeat_Counter++; 
                     fputs("Unlock!", PORT1);
                  }
                  else                          // reset counters, change state
                  {
                     Command_Repeat_Counter = 0;// preload the counter                     
                     PreviousLockEvent = MACHINE_UNLOCKED;
                     Lock_Or_Unlock = PASS_THROUGH_STATE;   // change state
                  }
               }                                                                                               
               break;
            }
// *********************************************           
         }                                      // switch
// ---------------------------------------------
// ---------------------------------------------     
      }                                         // if Work_To_Do     
   }                                            // while
}                                               // main


Last edited by PrinceNai on Sun Mar 27, 2022 2:18 am; edited 1 time in total
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group