001    // Class for handling interrupts.
002    // Copyright (c) National Instruments 2008.  All Rights Reserved.
003    
004    package edu.wpi.first.wpilibj.fpga;
005    
006    import com.ni.rio.*;
007    import com.sun.cldc.jna.ptr.IntByReference;
008    
009    public class tInterruptManager extends tSystem
010    {
011    
012       private static final int kFPGA_INTERRUPT_BASE_ADDRESS = 0x8000;
013       private static final int kFPGA_INTERRUPT_ACKNOWLEDGE_ADDRESS = (kFPGA_INTERRUPT_BASE_ADDRESS + 0xC);
014    
015       //tInterruptHandler m_handler;
016       private int m_interruptMask;
017       //int _taskId;
018       private IntByReference m_rioContext;
019       private boolean m_watcher;
020       private boolean m_enabled;
021       //void *m_userParam;
022    
023       // maintain the interrupts that are already dealt with.
024       private static int m_globalInterruptMask = 0;
025       //static SEM_ID m_globalInterruptMaskSemaphore = semMCreate(SEM_Q_PRIORITY | SEM_DELETE_SAFE | SEM_INVERSION_SAFE);
026    
027       public tInterruptManager (int interruptMask, boolean watcher)
028       {
029          super();
030          if (status.isFatal()) return;
031    
032          //m_handler = NULL;
033          m_interruptMask = interruptMask;
034          //m_taskId = INVALID_TASK_ID;
035          m_rioContext = new IntByReference(0);
036          m_watcher = watcher;
037          m_enabled = false;
038          //m_userParam = NULL;
039    
040          // Allocate the appropriate resources in the RIO driver.
041          NiFpga.reserveIrqContext(m_DeviceHandle, m_rioContext, status);
042       }
043    
044       protected void finalize()
045       {
046    
047    //      if (!m_watcher && isEnabled())
048    //      {
049    //         // Rendezvous with thread
050    //         disable();
051    //      }
052    
053          // Free the resources in the RIO driver
054          NiFpga.unreserveIrqContext(m_DeviceHandle, m_rioContext, status);
055          super.finalize();
056       }
057    
058       public int watch(int timeoutInMs)
059       {
060          if (!m_watcher)
061          {
062             status.setStatus(NiRioStatus.kRIOStatusIrrelevantAttribute);
063             return 0;
064          }
065    
066          reserve();
067          if (status.isFatal()) return 0;
068    
069          // Acknowldge any pending interrupts.
070          acknowledge();
071    
072          int intsAsserted = NiFpga.waitOnIrqs(m_DeviceHandle, m_rioContext, m_interruptMask, timeoutInMs, status);
073          acknowledge();
074          unreserve();
075    
076          return intsAsserted;
077       }
078    
079       protected void acknowledge()
080       {
081          NiFpga.writeU32(m_DeviceHandle, kFPGA_INTERRUPT_ACKNOWLEDGE_ADDRESS, m_interruptMask, status);
082       }
083    
084       protected void reserve()
085       {
086          // TODO: synchronize me
087          //semTake(_globalInterruptMaskSemaphore, WAIT_FOREVER);
088          if ((m_globalInterruptMask & m_interruptMask) != 0 || m_enabled)
089          {
090             // Don't look at this interrupt if someone else already is.
091             status.setStatus(NiRioStatus.kRIOStatusEventEnabled);
092          }
093          else
094          {
095             m_globalInterruptMask |= m_interruptMask;
096             m_enabled = true;
097          }
098          //semGive(_globalInterruptMaskSemaphore);
099       }
100    
101       protected void unreserve()
102       {
103          // TODO: synchronize me
104          //semTake(_globalInterruptMaskSemaphore, WAIT_FOREVER);
105          if (!m_enabled)
106          {
107             // Don't try to disable if we were never enabled.
108             status.setStatus(NiRioStatus.kRIOStatusEventNotEnabled);
109          }
110          else
111          {
112             m_enabled = false;
113             m_globalInterruptMask &= ~m_interruptMask;
114          }
115          //semGive(_globalInterruptMaskSemaphore);
116       }
117    
118    }