error - ReadAcceptorDetails() method

Support for the Milan Intelligent interface, sold by Money Controls as the Paylink USB unit and for the earlier PCI card version.

Moderators: aardvark, davebush, Admin

Post Reply
dd31
Posts: 4
Joined: Thu Jul 20, 2006 12:15 pm

error - ReadAcceptorDetails() method

Post by dd31 »

I'm working on a .NET project using a paylink with acceptors and dispensors.
I have to use the ReadDispenserDetails() and ReadAcceptorDetails() methods of the aesimhei.dll win32 dll in a .NET project using c#.

The ReadDispenserDetails() method call works well (the DispensorBlock struct is well filled with good values).

The problem is the call of ReadAcceptorDetails() method.

I instanciate the AcceptorBlock struct with .net types equivalent to C types :
- char (8 bits) replaced with System.Byte (8 bits) instead of System.Char (16 bits in .net)
- long (32 bits) replaced with System.Int32

When I call this method, a fatal error return E_INVALID_ARG.

So I try different types of data in the struct AcceptorBlock (signed and unsigned for testing), but the problem persists.

Is there someone who has already used the win32 dll on a .net project ?
Is Call of the ReadAcceptorDetails() method successfull ?
Does a .NET assembly equivalent to the aesimhei.dll win32 dll still exist ?

Thanks.

Here is the c# code used :

Code: Select all

 // Definition des structures
        public struct AcceptorCoin
        {
            public System.Int32 Value;                // Value of this coin
            public System.Int32 Inhibit;              // Set by PC: this coin is inhibited
            public System.Int32 Count;                // Total number read "ever"
            public System.Int32 Path;                 // Set by PC: this coin's chosen output path
            public System.Int32 PathCount;            // Number "ever" sent down the chosen Path
            public System.Int32 PathSwitchLevel;      // Set by PC: PathCount level to switch coin to default path
            public System.Byte DefaultPath;          // Set by PC: Default path for this specific coin
            public System.Byte FutureExpansion;      // Set by PC: for future use
            public System.Byte HeldInEscrow;         // count of this note / coin in escrow (usually max 1)
            public System.Byte CurrencySet;          // Currency set to which this coin belongs
        } 

        
        public struct AcceptorBlock
        {
            public System.Int32 Unit;              // Specification of this unit
            public System.Int32 Status;            // AcceptorStatuses - zero if device OK
            public System.Int32 NoOfCoins;         // The number of different coins handled
            public System.Int32 InterfaceNumber;   // The bus / connection
            public System.Int32 UnitAddress;       // For addressable units
            public System.Int32 DefaultPath;
            public System.Int32 EventCount;        // Count of events (e.g. rejects) for this acceptor
            public System.Byte[] Currency;          // Main currency code reported
            public AcceptorCoin[] Coin ;             // (only NoOfCoins are set up)
        }

        //Get Acceptor infos ( Acceptor connected on the paylink)
        [DllImport("Aesimhei.dll", CharSet = CharSet.Auto, EntryPoint = "ReadAcceptorDetails")]
        public static extern System.Boolean ReadAcceptorDetails(System.Int32 Number, ref AcceptorBlock Snapshot);

        System.Int32 AcceptorNo = 0;

 // Call of the win32 dll method
        System.Int32 OpenStatus = OpenMHE();

        // Instanciate AcceptorBlock structure 
        AcceptorBlock o_acc_block = new AcceptorBlock();
        o_acc_block.Currency = new System.Byte[4];
        o_acc_block.Coin = new AcceptorCoin[255];

 // Call of the win32 dll method to get first acceptor details
 // Fatal error : E_INVALID_ARG
        ret = ReadAcceptorDetails(AcceptorNo, ref o_acc_block);
davebush
Posts: 492
Joined: Fri Oct 22, 2004 12:20 pm

Post by davebush »

I’ve consulted with another customer who has implemented this with .NET, and he reports that the ‘C’ style array of structures is very incompatible with .NET.

The following .NET fragment is his implementation of ReadAcceptorDetails and WriteAcceptorDetails, I'm afraid you're essentially on your own if it's not clear.

Code: Select all

    [ StructLayout( LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1 )]  
      public class Acceptor
    {
      internal uint number;

      public Acceptor( uint Number )
      {
        number =  Number;
      }
      public const int MaxCoins = 256;// Maximum coins or notes handled by any device

      static internal int Sizeof( int NoCoins)
      {
        return 7*4 + 4 + NoCoins*Coin.Sizeof;
      } 

      [ StructLayout( LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1 )]  
        public class Coin
      {
        internal const int Sizeof = 5*4 + 4;

        internal System.Int32 _value;           // Value of this coin
        public bool           Inhibit;          // Set by PC: this coin is inhibited
        internal System.Int32 _count;           // Total number read "ever"
        public System.Int32   Path;             // Set by PC: this coin's chosen output path
        internal System.Int32 _pathCount;       // Number "ever" sent down the chosen Path
        public System.Int32   PathSwitchLevel;  // Set by PC: PathCount level to switch coin to default path
        public System.Byte    DefaultPath;      // Set by PC: Default path for this specific coin
        public System.Byte    FutureExpansion;  // Set by PC: for future use
        internal System.Byte  _heldInEscrow;      // count of this note / coin in escrow (usually max 1)
        internal System.Byte  _currencySet;     // Currency set to which this coin belongs

        public System.Int32 Value
        {
          get
          {
            return _value;
          }
        }
        public  System.Int32 Count
        {
          get
          {
            return _count;
          }
        }
        public System.Int32 PathCount
        {
          get
          {
            return _pathCount;
          }
        }
        public System.Byte  HeldInEscrow
        {
          get
          {
            return _heldInEscrow;
          }
        }
        public System.Byte  CurrencySet
        {
          get
          {
            return _currencySet;
          }
        }
      }

      public System.Int32 _unit;              // Specification of this unit
      public System.Int32 _status;            // AcceptorStatuses - zero if device OK
      public System.Int32 _noOfCoins;       // The number of different coins handled
      public System.Int32 _interfaceNumber; // The bus / connection
      public System.Int32 _unitAddress;     // For addressable units
      public System.Int32 DefaultPath;      
      public System.Int32 _rejectCount;     // Count of coins / notes rejected
      public string       _currency;          // As String * 4  Currency code reported by an intelligent acceptor
      public Coin[]       Coins;            // Only NoOfCoins are set up but all 256 must be present

      public System.Int32 Unit
      {
        get
        {
          return _unit;
        }
      }
      public System.Int32 Status
      {
        get
        {
          return _status;
        }
      }
      public System.Int32 NoOfCoins
      {
        get
        {
          return _noOfCoins;
        }

      }
      public System.Int32 InterfaceNumber
      {
        get
        {
          return _interfaceNumber;
        }
      }
      public System.Int32 UnitAddress
      {
        get
        {
          return _unitAddress;
        }
      }
      public System.Int32 RejectCount
      {
        get
        {
          return _rejectCount;
        }
      }
      public string Currency
      {
        get
        {
          return _currency;
        }
      }
    }
    

    public Acceptor ReadAcceptor( uint Number)
    {
      MHE.Acceptor acceptorBlock = new Acceptor( Number );
      // create a memory acceptorBlock for the MHE interface to use
      System.IntPtr pSnapshot = Marshal.AllocHGlobal(Acceptor.Sizeof(Acceptor.MaxCoins));
      try
      {
        int result = Imhei.ReadAcceptorDetails( (System.Int32)Number, pSnapshot);
      
        // return false if the acceptor doesn't exist
        if( !Convert.ToBoolean(result) )
        {
          return null;
        }

        // marshal the values returned into an instance of the class
        int offset = 0;

        acceptorBlock._unit = Marshal.ReadInt32(pSnapshot, offset);
        offset += Marshal.SizeOf(acceptorBlock._unit);
        acceptorBlock._status = Marshal.ReadInt32(pSnapshot, offset);
        offset += Marshal.SizeOf(acceptorBlock._status);
        acceptorBlock._noOfCoins = Marshal.ReadInt32(pSnapshot, offset);        // The number of different coins handled
        offset += Marshal.SizeOf(acceptorBlock._noOfCoins);
        acceptorBlock._interfaceNumber = Marshal.ReadInt32(pSnapshot, offset);  // The bus / connection
        offset += Marshal.SizeOf(acceptorBlock._interfaceNumber);
        acceptorBlock._unitAddress = Marshal.ReadInt32(pSnapshot, offset);      // For addressable units
        offset += Marshal.SizeOf(acceptorBlock._unitAddress);
        acceptorBlock.DefaultPath = Marshal.ReadInt32(pSnapshot, offset);      
        offset += Marshal.SizeOf(acceptorBlock.DefaultPath);
        acceptorBlock._rejectCount = Marshal.ReadInt32(pSnapshot, offset);      // Count of coins / notes rejected
        offset += Marshal.SizeOf(acceptorBlock._rejectCount);

        System.Byte[] buffer = new Byte[4];
        for( int i=0; i < 4; ++i )
        {
          buffer[i] = Marshal.ReadByte(pSnapshot, offset++);
          if( buffer[i] == 0)
          {
            acceptorBlock._currency = System.Text.Encoding.ASCII.GetString(buffer,0,i);
            // no break to consume all 4 bytes;
          }
        }
    
        acceptorBlock.Coins = new Acceptor.Coin[acceptorBlock.NoOfCoins];
        for(int i=0; i < acceptorBlock.NoOfCoins; ++i)
        {
          Acceptor.Coin coin = new Acceptor.Coin();

          coin._value = Marshal.ReadInt32(pSnapshot, offset);
          offset += Marshal.SizeOf(coin._value);
          coin.Inhibit = (Marshal.ReadInt32(pSnapshot, offset) != 0);         // Set by PC: this coin is inhibited
          offset += Marshal.SizeOf(coin.Inhibit);
          coin._count = Marshal.ReadInt32(pSnapshot, offset);           // Total number read "ever"
          offset += Marshal.SizeOf(coin._count);
          coin.Path = Marshal.ReadInt32(pSnapshot, offset);             // Set by PC: this coin's chosen output path
          offset += Marshal.SizeOf(coin.Path);
          coin._pathCount = Marshal.ReadInt32(pSnapshot, offset);       // Number "ever" sent down the chosen Path
          offset += Marshal.SizeOf(coin._pathCount);
          coin.PathSwitchLevel = Marshal.ReadInt32(pSnapshot, offset);  // Set by PC: PathCount level to switch coin to default path
          offset += Marshal.SizeOf(coin.PathSwitchLevel);

          coin.DefaultPath = Marshal.ReadByte(pSnapshot, offset);     // Set by PC: Default path for this specific coin
          offset += Marshal.SizeOf(coin.DefaultPath);
          coin.FutureExpansion = Marshal.ReadByte(pSnapshot, offset); // Set by PC: for future use
          offset += Marshal.SizeOf(coin.FutureExpansion);
          coin._heldInEscrow = Marshal.ReadByte(pSnapshot, offset);     // count of this note / coin in escrow (usually max 1)
          offset += Marshal.SizeOf(coin._heldInEscrow);
          coin._currencySet = Marshal.ReadByte(pSnapshot, offset);      // Currency set to which this coin belongs
          offset += Marshal.SizeOf(coin._currencySet);

          acceptorBlock.Coins[i] = coin;
        }
      }
      finally
      {
        // no matter what happens in the try we'll free the memory
        Marshal.FreeHGlobal(pSnapshot);
      }

      return acceptorBlock;
    }

    public void WriteAcceptor( Acceptor Acceptor)
    {
      System.IntPtr pSnapshot = Marshal.AllocHGlobal(Acceptor.Sizeof(Acceptor.MaxCoins));
      try
      {
        int offset = 0;
        Marshal.WriteInt32(pSnapshot, offset, Acceptor.Unit);
        offset += Marshal.SizeOf(Acceptor.Unit);
        Marshal.WriteInt32(pSnapshot, offset, Acceptor.Status);
        offset += Marshal.SizeOf(Acceptor.Status);
        Marshal.WriteInt32(pSnapshot, offset, Acceptor.NoOfCoins);        // The number of different coins handled
        offset += Marshal.SizeOf(Acceptor.NoOfCoins);
        Marshal.WriteInt32(pSnapshot, offset, Acceptor.InterfaceNumber);  // The bus / connection
        offset += Marshal.SizeOf(Acceptor.InterfaceNumber);
        Marshal.WriteInt32(pSnapshot, offset, Acceptor.UnitAddress);      // For addressable units
        offset += Marshal.SizeOf(Acceptor.UnitAddress);
        Marshal.WriteInt32(pSnapshot, offset, Acceptor.DefaultPath);      
        offset += Marshal.SizeOf(Acceptor.DefaultPath);
        Marshal.WriteInt32(pSnapshot, offset, Acceptor.RejectCount);      // Count of coins / notes rejected
        offset += Marshal.SizeOf(Acceptor.RejectCount);

        char[] buffer = Acceptor.Currency.ToCharArray();
        for( int i=0; i < 4; ++i )
        {
          char c = '\0';
          if( i < buffer.Length )
          {
            if( buffer[i] != 0 )
              c = buffer[i];
          }
          Marshal.WriteByte(pSnapshot,offset++,(byte)c);
        }


        foreach(Acceptor.Coin coin in Acceptor.Coins)
        {
          Marshal.WriteInt32(pSnapshot, offset, coin._value);
          offset += Marshal.SizeOf(coin._value);
          Marshal.WriteInt32(pSnapshot, offset, Convert.ToInt32(coin.Inhibit));         // Set by PC: this coin is inhibited
          offset += Marshal.SizeOf(coin.Inhibit);
          Marshal.WriteInt32(pSnapshot, offset, coin._count);           // Total number read "ever"
          offset += Marshal.SizeOf(coin._count);
          Marshal.WriteInt32(pSnapshot, offset, coin.Path);             // Set by PC: this coin's chosen output path
          offset += Marshal.SizeOf(coin.Path);
          Marshal.WriteInt32(pSnapshot, offset, coin._pathCount);       // Number "ever" sent down the chosen Path
          offset += Marshal.SizeOf(coin._pathCount);
          Marshal.WriteInt32(pSnapshot, offset, coin.PathSwitchLevel);  // Set by PC: PathCount level to switch coin to default path
          offset += Marshal.SizeOf(coin.PathSwitchLevel);

          Marshal.WriteByte(pSnapshot, offset, coin.DefaultPath);     // Set by PC: Default path for this specific coin
          offset += Marshal.SizeOf(coin.DefaultPath);
          Marshal.WriteByte(pSnapshot, offset, coin.FutureExpansion); // Set by PC: for future use
          offset += Marshal.SizeOf(coin.FutureExpansion);
          Marshal.WriteByte(pSnapshot, offset, coin._heldInEscrow);     // count of this note / coin in escrow (usually max 1)
          offset += Marshal.SizeOf(coin._heldInEscrow);
          Marshal.WriteByte(pSnapshot, offset, coin._currencySet);      // Currency set to which this coin belongs
          offset += Marshal.SizeOf(coin._currencySet);
        }

        Imhei.WriteAcceptorDetails(Acceptor.number, pSnapshot);
      }
      finally
      {
        // no matter what happens in the try  we'll free the memory
        Marshal.FreeHGlobal(pSnapshot);
      }
    }
Aardvark software developer. Please put all communication on the problem through the board for the benefit of others.
dd31
Posts: 4
Joined: Thu Jul 20, 2006 12:15 pm

Post by dd31 »

I’ve consulted with another customer who has implemented this with .NET, and he reports that the ‘C’ style array of structures is very incompatible with .NET.

The following .NET fragment is his implementation of ReadAcceptorDetails and WriteAcceptorDetails, I'm afraid you're essentially on your own if it's not clear.
Thanks so much for your answer.
But I miss parts of code ?
Is your code complete ?
davebush
Posts: 492
Joined: Fri Oct 22, 2004 12:20 pm

Post by davebush »

I'm sorry, but as I have no knowledge of .NET I can't answer that directly. If you can be more specific as to your problem with the code I'll try to get an answer.
Aardvark software developer. Please put all communication on the problem through the board for the benefit of others.
dd31
Posts: 4
Joined: Thu Jul 20, 2006 12:15 pm

Post by dd31 »

I've got more details regarding my question.
I miss the .NET fragment of ReadDispenserDetails() class (the same like you tell me the ReadAcceptorDetails class but now I need the ReadDispenserDetails class).
I need the coincount value above all :D .
If it's possible, it would be so kind :wink:
Thanks so much.
davebush
Posts: 492
Joined: Fri Oct 22, 2004 12:20 pm

Post by davebush »

This is pretty simple, you just define the c# copy of the C struct and use the DLL calls:

Code: Select all

    [ StructLayout( LayoutKind.Sequential, CharSet=CharSet.Auto )]  
      public class Dispenser
    {
      public enum CoinStatus
      {
        // Coin Count Status Values
        COIN_NONE = 0,// No dispenser coin reporting
        COIN_LOW = 1,// Less than the low sensor level
        COIN_MID = 2,// Above low sensor but below high
        COIN_HIGH = 3,// High sensor level reported

        ACCURATE = -1,// Coin Count reported by Dispenser
        ACCURATE_FULL = -2 // Coin Count As reported by Dispenser, is over limit.
      }

      public System.UInt32    Unit;// Specification of this unit
      public System.UInt32    Status;// AcceptorStatuses - zero if device OK. This takes the same values As PayStatus()
      public System.UInt32    InterfaceNumber;// The bus / connection
      public System.UInt32    UnitAddress;// For addressable units
      public System.UInt32    Value;// The value of the coins in this dispensor
      public System.UInt32    Count;// Number dispensed since interface commissioned
      private System.UInt32   _inhibit;
      public System.UInt32    Currency;// Currency code reported by an intelligent acceptor
      public System.UInt32    CoinCount;// The number of coins in the dispenser
      public CoinStatus CoinCountStatus;// Flags Relating to Coin Count (See above)

      public bool Inhibit
      {
        get
        {
          return (_inhibit != 0);
        }
        set
        {
          _inhibit = Convert.ToUInt32(value);
        }
      }
    }

    public Dispenser ReadDispenser(int Number)
    {
      Dispenser dispenser = new Dispenser();
      if( Imhei.ReadDispenserDetails( Number, dispenser) != 0)
      {
        return dispenser;
      }
      return null;
    }

    public void WriteDispenser(int Number, Dispenser Dispenser)
    {
      Imhei.WriteDispenserDetails(Number, Dispenser);
    }

    public void IndicatorOn(int IndicatorNumber)
    {
      Imhei.IndicatorOn( IndicatorNumber );
    }
I hope this helps.
Aardvark software developer. Please put all communication on the problem through the board for the benefit of others.
dd31
Posts: 4
Joined: Thu Jul 20, 2006 12:15 pm

Post by dd31 »

I have tried a lot of solutions but I still cannot read the CoinCount Value (always 0) when I call ReadDispenserDetails.

On the Paylink are connected :
-> Dispensers :
A Hopper ( 2€)
A global Euro ( 4 dispenser tubes : 0.50€, 0.20€, 0.10€; 0.05€ ).
-> Acceptors :
A Lumina ans an acceptor SR3

The problem is with dispensers.

Here are the Results :
--------------------------------------------------------------------------------------
Driver Log AESWDriver.exe in starting (before calls to readDispenserDetails) :

11:46:02.28 Opening Genoa USB unit...
11:46:02.61 OK, ID: 0x0403 0xde50
11:46:02.61 Description: Genoa USB Hub
11:46:02.61 Manufacturer: Aardvark (AE)
11:46:03.11 Memory Reset
11:46:03.26 Memory Resynchronise
11:46:03.26 /N 0, Address 8, Value 20 at 12cc setup
11:46:03.26 DP: Hopper S/N 0, Address 8, Value 10 at 12fc setup
11:46:03.26 DP: Hopper S/N 0, Address 8, Value 5 at 132c setup
11:46:03.26 DP: Interface memory set up
11:46:03.26 Exec: DP App. task took 132 msec
11:46:03.26 USB:PC has updated basic area @ 100!!!
11:46:03.40 Update @100, 37=>0
11:46:03.40 Update @104, 37=>0
11:46:03.40 USB unit re-synch complete
11:46:03.40 129c setup
11:46:03.40 DP: Hopper S/N 0, Address 8, Value 20 at 12cc setup
11:46:03.40 DP: Hopper S/N 0, Address 8, Value 10 at 12fc setup
11:46:03.40 DP: Hopper S/N 0, Address 8, Value 5 at 132c setup
11:46:03.40 DP: Interface memory set up
11:46:03.40 Exec: DP App. task took 135 msec
11:46:03.41 8144 bytes memory free
--------------------------------------------------------------------------------------
Results obtained with the SDK demo.exe program ( Dispensers form )

Value : 200
Adress : 9
Coins paid : 962
Contents (CoinCount) : Low
Status : empty

Value : 50
Adress : 8
Coins paid : 133
Contents (CoinCount) : 5
Status : Idle OK

Value : 20
Adress : 8
Coins paid : 3
Contents (CoinCount) : 18
Status : Idle OK

Value : 10
Adress : 8
Coins paid : 6
Contents (CoinCount) : 38
Status : Idle OK

Value : 5
Adress : 8
Coins paid : 2
Contents (CoinCount) : 28
Status : Idle OK
These values are OK.
--------------------------------------------------------------------------------------
Results obtained in .net project using spies in Visual C# :

DispenserDetails {MONETIQUE.Classes.Dispenser} MONETIQUE.Classes.Dispenser
_inhibit 0 uint
CoinCount 0 uint
CoinCountStatus COIN_NONE MONETIQUE.Classes.Dispenser.CoinStatus
Count 962 uint
Currency 0 uint
Inhibit false bool
InterfaceNumber 2 uint
Status 4294967295 uint
Unit 16908545 uint
UnitAddress 9 uint
Value 200 uint

DispenserDetails {MONETIQUE.Classes.Dispenser} MONETIQUE.Classes.Dispenser
_inhibit 0 uint
CoinCount 0 uint
CoinCountStatus COIN_NONE MONETIQUE.Classes.Dispenser.CoinStatus
Count 133 uint
Currency 0 uint
Inhibit false bool
InterfaceNumber 9 uint
Status 1 uint
Unit 17367040 uint
UnitAddress 8 uint
Value 50 uint

DispenserDetails {MONETIQUE.Classes.Dispenser} MONETIQUE.Classes.Dispenser
_inhibit 0 uint
CoinCount 0 uint
CoinCountStatus COIN_NONE MONETIQUE.Classes.Dispenser.CoinStatus
Count 3 uint
Currency 0 uint
Inhibit false bool
InterfaceNumber 9 uint
Status 1 uint
Unit 17367040 uint
UnitAddress 8 uint
Value 20 uint

DispenserDetails {MONETIQUE.Classes.Dispenser} MONETIQUE.Classes.Dispenser
_inhibit 0 uint
CoinCount 0 uint
CoinCountStatus COIN_NONE MONETIQUE.Classes.Dispenser.CoinStatus
Count 6 uint
Currency 0 uint
Inhibit false bool
InterfaceNumber 9 uint
Status 1 uint
Unit 17367040 uint
UnitAddress 8 uint
Value 10 uint

DispenserDetails {MONETIQUE.Classes.Dispenser} MONETIQUE.Classes.Dispenser
_inhibit 0 uint
CoinCount 0 uint
CoinCountStatus COIN_NONE MONETIQUE.Classes.Dispenser.CoinStatus
Count 2 uint
Currency 0 uint
Inhibit false bool
InterfaceNumber 9 uint
Status 1 uint
Unit 17367040 uint
UnitAddress 8 uint
Value 5 uint
You can see that Currency and CoinCount values in .net code are always 0.

Here is my .net Code :
I have followed your advices

Code: Select all

----------------------------------------------------------------------
Class MONETIQUE.Classes.Dispenser :
----------------------------------------------------------------------

    [ StructLayout( LayoutKind.Sequential, CharSet=CharSet.Auto )] 
    public class Dispenser
    {
      public enum CoinStatus
      {
        // Coin Count Status Values
        COIN_NONE = 0,// No dispenser coin reporting
        COIN_LOW = 1,// Less than the low sensor level
        COIN_MID = 2,// Above low sensor but below high
        COIN_HIGH = 3,// High sensor level reported

        ACCURATE = -1,// Coin Count reported by Dispenser
        ACCURATE_FULL = -2 // Coin Count As reported by Dispenser, is over limit.
      }

      public System.UInt32    Unit;// Specification of this unit
      public System.UInt32    Status;// AcceptorStatuses - zero if device OK. This takes the same values As PayStatus()
      public System.UInt32    InterfaceNumber;// The bus / connection
      public System.UInt32    UnitAddress;// For addressable units
      public System.UInt32    Value;// The value of the coins in this dispensor
      public System.UInt32    Count;// Number dispensed since interface commissioned
      private System.UInt32   _inhibit;
      public System.UInt32    Currency;// Currency code reported by an intelligent acceptor
      public System.UInt32    CoinCount;// The number of coins in the dispenser
      public CoinStatus CoinCountStatus;// Flags Relating to Coin Count (See above)

      public bool Inhibit
      {
        get
        {
          return (_inhibit != 0);
        }
        set
        {
          _inhibit = Convert.ToUInt32(value);
        }
      }
    }

--------------------------------------------------------------------------------------
In my Program I do :
--------------------------------------------------------------------------------------

I have tested my last import dll code :

Code: Select all

[DllImport("aesimhei.dll", CharSet = CharSet.Auto, EntryPoint = "ReadDispenserDetails")]
public static extern System.Boolean ReadDispenserDetails(System.Int32 Number, MONETIQUE.Classes.Dispenser myDispenser);
and your code import dll code that I found in another post : ( http://www.aardvark.eu.com/downloads/so ... %20Net.zip )

Code: Select all

[DllImport("aesimhei.dll", EntryPoint="_ReadDispenserDetails@8")]
public static extern System.Int32 ReadDispenserDetails(System.Int32 Number, [In]MONETIQUE.Classes.Dispenser Snapshot);

so I call the ReadDispenserDetails method :

Code: Select all

// Test to read all dispensers connected to paylink
public void test_read_dispensers()
{
	System.Int32 openRes = OpenMHE();
	MONETIQUE.Classes.Dispenser DispenserDetails = new MONETIQUE.Classes.Dispenser();
	System.Int32 DispenserNo = new System.Int32();

	for (DispenserNo = 0; ReadDispenserDetails(DispenserNo, DispenserDetails); ++DispenserNo)	
	{
		MessageBox.Show("Read dispenser " + Convert.ToString(DispenserNo) );	
	}
}

-----------------------------------------------------------------------------------------

Finally, I tried to use your .net dll generated by your .net project

So I add your .net dll Aesimhei.dll in my project references
and used this method to test values :

Code: Select all

public void testDLLDispensers()
{
	System.Int32 OpenStatus = OpenMHE();	
	System.Int32 ReadResult ;	

	Aardvark.MHE.Dispenser o_disp = new Aardvark.MHE.Dispenser();
	Aardvark.MHE manager = new Aardvark.MHE();
            
	ReadResult = Aardvark.Imhei.ReadDispenserDetails(0, o_disp);
	ReadResult = Aardvark.Imhei.ReadDispenserDetails(1, o_disp);
	ReadResult = Aardvark.Imhei.ReadDispenserDetails(2, o_disp);
	ReadResult = Aardvark.Imhei.ReadDispenserDetails(3, o_disp);
	ReadResult = Aardvark.Imhei.ReadDispenserDetails(4, o_disp);
	ReadResult = Aardvark.Imhei.ReadDispenserDetails(5, o_disp);
}
I obtain the same results : CoinCount and Currency have the value 0.


---------------------------------------------------------------------------

I give you the MilaDiag result (for instance) :
I have installed the last firmware and result is the same.
AES Intelligent Money Handling Equipment Interface
OS Version 5.1
Checking Driver File:

Checking DLL:
Found at: C:\WINDOWS\system32\AesIMHEI.dll
Timestamp : Tue Mar 07 17:15:00 2006
Version 1,3,2,2

Checking Device Access:
AES Intelligent Money Handling Equpiment:
Interface 6, code version 04010a06
Can't test memory as an application is running
Device Checked - OK

Checking Application access through DLL:
Open successful

Firmware Release Type: Full
Firmware Code Version: 1.10.6


Dispensers on the system are:
Dispenser 0: MCL Serial Compact Hopper
Coin Value 200, Number Paid 962,
Inhibit 0, Currency 0, Address 9
Dispenser 1: Unknown
Coin Value 50, Number Paid 133,
Inhibit 0, Currency 0, Address 8
Dispenser 2: Unknown
Coin Value 20, Number Paid 3,
Inhibit 0, Currency 0, Address 8
Dispenser 3: Unknown
Coin Value 10, Number Paid 6,
Inhibit 0, Currency 0, Address 8
Dispenser 4: Unknown
Coin Value 5, Number Paid 2,
Inhibit 0, Currency 0, Address 8

I don't understand why others values are ok but not CoinCount values.
When you run your code, do you have correct values in CoinCount attribute ?


Thanks for your reply.
davebush
Posts: 492
Joined: Fri Oct 22, 2004 12:20 pm

Post by davebush »

Your remaing problem is easy to diagnose - and I hope for you to fix.

The data structures supported by Paylink and aesimhei.dll evolve over time - the last change was to add in the CoinCount and CoinCountStatus fields.

If this new DLL is run with old programs, then it has to avoid updating these new fields as they do not exisit in the calling program.

The way we deal with this is transparent to C programs. The relevant parts of the C header files are:

Code: Select all

#define ORIGINAL_VERSION    0x10001
#define DISPENSER_UPDATE    0x10002
#define INTERFACE_VERSION   DISPENSER_UPDATE
::
::
::
long DLL OpenMHEVersion(long InterfaceVersion) ;
#define OpenMHE()(INTERFACE_VERSION)
What this does is to automatically arange that when the user calls OpenMHE() the version of the data described by the header file is passed to the "real" call of OpenMHEVersion().

Obviously, the .NET implementation you are using ends up calling OpenMHEVersion() with ORIGINAL_VERSION rather than DISPENSER_UPDATE.

Now you know the problem, I trust you'll have no problem making the change.

P.S. Please remember that the accuracy of these fields is down to the changer, Pylink merely tells you what it reports. They tend not to be very reliable at low values.
Aardvark software developer. Please put all communication on the problem through the board for the benefit of others.
Post Reply