Subversion Repositories HomeAutomation

Rev

Rev 88 | Rev 96 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | SVN | RSS feed

  1. /*********************************************************************
  2.  *
  3.  *                  Main application
  4.  *
  5.  *********************************************************************
  6.  * FileName:        $HeadURL: https://svn.auml.se/svn/HomeAutomation/trunk/EmbeddedSoftware/PIC/canBoot/Source/Main.c $
  7.  * Last changed:    $LastChangedDate: 2006-11-14 12:50:16 +0100 (Tue, 14 Nov 2006) $
  8.  * By:              $LastChangedBy: johboh $
  9.  * Revision:        $Revision: 91 $
  10.  ********************************************************************/
  11.  
  12. #include <compiler.h>
  13. #include <stackTasks.h>
  14. #include <CANdefs.h>
  15. #include <CAN.h>
  16. #include <boot.h>
  17. #include <funcdefs.h>
  18.  
  19. /** V E C T O R  R E M A P P I N G *******************************************/
  20.  
  21. #pragma code _HIGH_INTERRUPT_VECTOR = 0x000008
  22. void _high_ISR (void)
  23. {
  24.     _asm goto RM_HIGH_INTERRUPT_VECTOR _endasm
  25. }
  26.  
  27. #pragma code _LOW_INTERRUPT_VECTOR = 0x000018
  28. void _low_ISR (void)
  29. {
  30.     _asm goto RM_LOW_INTERRUPT_VECTOR _endasm
  31. }
  32.  
  33. #pragma code
  34.  
  35.  
  36. #ifdef USE_CAN
  37.     #include <CAN.h>
  38. #endif
  39.  
  40. static CAN_PROTO_MESSAGE cm;
  41. static BYTE ful=0;
  42. static DWORD cnt =0;
  43.  
  44. static void mainInit(void);
  45. static BOOL canGetPacket(void);
  46. void TBLWT_Func(void);
  47. void TBLWTPOSTINC_Func (void);
  48. void TBLRD_Func(void);
  49.  
  50. #define TICK_SUB_COUNTER_10MS 312
  51. #define PACKET_TIMEOUT 14
  52. #define BOOTLOADER_INIT_TIMOUT 500
  53.  
  54. DWORD tickCounter = 0;
  55. DWORD tickSubCounter = 0;
  56.  
  57. DWORD tickGet(void);
  58.  
  59. void main()
  60. {
  61.     static PROGRAM_STATE pgs = pgsWATING_START;
  62.     static DWORD t = 0;
  63.     static WORD programmerSid=0;
  64.    
  65.     static BYTE errMsg = ERR_NO_ERROR;
  66.     static PROGRAM_STATE afterAckPgs = pgsWATING_START;
  67.     static DWORD pgmAddress = 0;
  68.     static BYTE bytesReceived = 0;
  69.  
  70.     DWORD tBoot;
  71.    
  72.     static BYTE pgmData[64];
  73.  
  74.     static BYTE tmp;
  75.  
  76.     // Inits
  77.     mainInit();
  78.  
  79.     #ifdef USE_CAN
  80.         canInit();
  81.     #endif
  82.  
  83.     tBoot = tickGet();
  84.    
  85.  
  86.     for(;;)
  87.     {
  88.         BYTE i;
  89.         CAN_PROTO_MESSAGE outCm;
  90.         BOOL hasPacket = canGetPacket();
  91.  
  92.         tickSubCounter++;
  93.         if (tickSubCounter>TICK_SUB_COUNTER_10MS)
  94.         {
  95.             tickCounter++;
  96.             tickSubCounter=0;
  97.             ClrWdt();
  98.         }
  99.  
  100.         switch(pgs)
  101.         {
  102.             case pgsWATING_START:
  103.                 // Check if there is bootloader start packet
  104.                 if (hasPacket==TRUE && cm.funct==FUNCT_BOOTLOADER && cm.funcc==FUNCC_BOOT_INIT && ((((unsigned int)cm.data[RID_HIGH_INDEX])<<8)+cm.data[RID_LOW_INDEX])==MY_ID && cm.nid==MY_NID)
  105.                 {
  106.                     // Has new start packet
  107.                     pgmAddress      = (((DWORD)cm.data[ADDRU_INDEX])<<16)+(((DWORD)cm.data[ADDRH_INDEX])<<8)+((DWORD)cm.data[ADDRL_INDEX]);
  108.                     programmerSid   = cm.sid;
  109.                     t               = tickGet();
  110.                     errMsg          = ERR_NO_ERROR;
  111.                     afterAckPgs     = pgsWAIT_FIRST_PGM_PACKET;
  112.                     pgs             = pgsSEND_ACK;
  113.                     // save pgm adress.
  114.                    
  115.                 }
  116.  
  117.                 // Bootloader timeout
  118.                 if ((tickGet()-tBoot)>BOOTLOADER_INIT_TIMOUT)
  119.                 {
  120.                     pgs = pgsDONE;
  121.                 }
  122.             break;         
  123.  
  124.             case pgsSEND_ACK:
  125.                 // send ack
  126.                 outCm.funct             = FUNCT_BOOTLOADER;
  127.                 outCm.funcc             = FUNCC_BOOT_ACK;
  128.                 outCm.nid               = MY_NID;
  129.                 outCm.sid               = MY_ID;
  130.                 outCm.data_length       = 8;
  131.                 outCm.data[ERR_INDEX]   = errMsg;
  132.                 t                       = tickGet();
  133.                 pgs                     = afterAckPgs;
  134.  
  135.                 while(!canSendMessage(outCm,PRIO_HIGH));
  136.             break;
  137.  
  138.  
  139.             case pgsWAIT_FIRST_PGM_PACKET:
  140.                 // wait for first pgm packet.
  141.                 if ((tickGet()-t)>PACKET_TIMEOUT)
  142.                 {
  143.                     // Timeout, resend ack.
  144.                     errMsg          = ERR_NO_ERROR;
  145.                     afterAckPgs     = pgsWAIT_FIRST_PGM_PACKET;
  146.                     pgs             = pgsSEND_ACK;
  147.                 }
  148.  
  149.                 // If programming packet...
  150.                 if (hasPacket==TRUE && cm.funct==FUNCT_BOOTLOADER && (cm.funcc & 0x3)==FUNCC_BOOT_PGM && cm.nid==MY_NID && cm.sid==programmerSid)
  151.                 {
  152.                     BYTE localIndex = (BYTE)((cm.funcc & 0x1C)>>2)*8;
  153.  
  154.                     // Save bytes in memory, setup start adress etc..
  155.                     bytesReceived   = 8;       
  156.                     pgmData[localIndex+0]=cm.data[0]; pgmData[localIndex+1]=cm.data[1]; pgmData[localIndex+2]=cm.data[2]; pgmData[localIndex+3]=cm.data[3];
  157.                     pgmData[localIndex+4]=cm.data[4]; pgmData[localIndex+5]=cm.data[5]; pgmData[localIndex+6]=cm.data[6]; pgmData[localIndex+7]=cm.data[7];
  158.                
  159.                     pgs             = pgsWAIT_PGM_PACKET;
  160.                 }
  161.  
  162.  
  163.             break;
  164.  
  165.  
  166.             case pgsWAIT_PGM_PACKET:
  167.        
  168.            
  169.                 // If programming packet...
  170.                 if (hasPacket==TRUE && cm.funct==FUNCT_BOOTLOADER && (cm.funcc & 0x3)==FUNCC_BOOT_PGM && cm.nid==MY_NID && cm.sid==programmerSid)
  171.                 {
  172.                     BYTE localIndex = (BYTE)((cm.funcc & 0x1C)>>2)*8;
  173.                     // Save bytes in memory, inc received bytes.
  174.                     pgmData[localIndex+0]=cm.data[0]; pgmData[localIndex+1]=cm.data[1]; pgmData[localIndex+2]=cm.data[2]; pgmData[localIndex+3]=cm.data[3];
  175.                     pgmData[localIndex+4]=cm.data[4]; pgmData[localIndex+5]=cm.data[5]; pgmData[localIndex+6]=cm.data[6]; pgmData[localIndex+7]=cm.data[7];
  176.                    
  177.                     bytesReceived   += 8;
  178.                     pgs              = pgsWAIT_PGM_PACKET;
  179.                 }
  180.  
  181.                 // If adress packet (control packet)..
  182.                 if (hasPacket==TRUE && cm.funct==FUNCT_BOOTLOADER && cm.funcc==FUNCC_BOOT_ADDR && cm.nid==MY_NID && cm.sid==programmerSid)
  183.                 {
  184.                     // Send ack and goto wait first packet.
  185.                     // save adress.
  186.                     errMsg          = ERR_NO_ERROR;
  187.                     afterAckPgs     = pgsWAIT_FIRST_PGM_PACKET;
  188.                     pgs             = pgsSEND_ACK;
  189.                 }
  190.                
  191.                 // If end packet...
  192.                 if (hasPacket==TRUE && cm.funct==FUNCT_BOOTLOADER && cm.funcc==FUNCC_BOOT_DONE && cm.nid==MY_NID && cm.sid==programmerSid)
  193.                 {
  194.                     // write program.
  195.                     // If no bytes received at all, assume end.
  196.                     // If not 64 bytes received, send error ack and wait for first packet.
  197.                     // If 64, write.
  198.  
  199.                     if (bytesReceived==0)
  200.                     {
  201.                         // No received, done.
  202.                         errMsg          = ERR_NO_ERROR;
  203.                         afterAckPgs     = pgsDONE;
  204.                         pgs             = pgsSEND_ACK;
  205.                     }
  206.                     else if (bytesReceived!=64)
  207.                     {
  208.                         errMsg          = ERR_ERROR;
  209.                         afterAckPgs     = pgsWAIT_FIRST_PGM_PACKET;
  210.                         pgs             = pgsSEND_ACK;
  211.                     }
  212.                     else
  213.                     {
  214.                         pgs              = pgsWRITE_PROGRAM;
  215.                         afterAckPgs     = pgsDONE;
  216.                     }
  217.                 }
  218.  
  219.                 // If bytes received 64, write..
  220.                 if (bytesReceived==64)
  221.                 {
  222.                     LED0_IO=~LED0_IO;
  223.                     pgs              = pgsWRITE_PROGRAM;
  224.                     afterAckPgs     = pgsWAIT_PGM_PACKET;
  225.                     // TODO! Send ack more than once..
  226.                 }
  227.  
  228.  
  229.             break;
  230.  
  231.  
  232.             case pgsWRITE_PROGRAM:
  233.  
  234.                 ClrWdt();
  235.  
  236.                 // Write program and send ack.
  237.  
  238.                 // Check addr limit
  239.                 if (pgmAddress<RM_RESET_VECTOR)
  240.                 {              
  241.                     errMsg          = ERR_ERROR;
  242.                     pgs             = pgsSEND_ACK;
  243.                     //Not allowed to write here!
  244.                    
  245.                 }
  246.  
  247.                 //Load Table pointer registers with base address to erase.
  248.                 TBLPTRU = (BYTE)((pgmAddress & 0xFF0000)>>16);
  249.                 TBLPTRH = (BYTE)((pgmAddress & 0xFF00)>>8);
  250.                 TBLPTRL = (BYTE)(pgmAddress & 0xFF);
  251.  
  252.                 // point to Flash program memory
  253.                 EECON1bits.EEPGD = 1;
  254.                 // access Flash program memory
  255.                 EECON1bits.CFGS = 0;
  256.                 // enable write to memory
  257.                 EECON1bits.WREN = 1;
  258.                 // enable Row Erase operation
  259.                 EECON1bits.FREE = 1;
  260.                 // disable interrupts
  261.                 INTCONbits.GIE = 0;
  262.  
  263.                 // Do it!
  264.                 EECON2 = 0x55;
  265.                 EECON2 = 0xAA;
  266.                 EECON1bits.WR = 1;
  267.  
  268.                 // enable interrupts
  269.                 INTCONbits.GIE = 1;
  270.                
  271.                 //Load Table pointer registers with base address to program.
  272.                 TBLPTRU = (BYTE)((pgmAddress & 0xFF0000)>>16);
  273.                 TBLPTRH = (BYTE)((pgmAddress & 0xFF00)>>8);
  274.                 TBLPTRL = (BYTE)(pgmAddress & 0xFF);
  275.  
  276.                 // Load bytes
  277.                 for(i=0;i<63;i++)
  278.                 {
  279.                     TABLAT=pgmData[i];
  280.                     TBLWTPOSTINC_Func();
  281.                 }
  282.                 TABLAT=pgmData[63];
  283.                 TBLWT_Func();
  284.  
  285.  
  286.                 // point to Flash program memory
  287.                 EECON1bits.EEPGD = 1;
  288.                 // access Flash program memory
  289.                 EECON1bits.CFGS = 0;
  290.                 // enable write to memory
  291.                 EECON1bits.WREN = 1;
  292.                 // disable interrupts
  293.                 INTCONbits.GIE = 0;
  294.                
  295.                 // Do it!
  296.                 EECON2 = 0x55;
  297.                 EECON2 = 0xAA;
  298.                 EECON1bits.WR = 1;
  299.  
  300.                 // enable interrupts
  301.                 INTCONbits.GIE = 1;
  302.  
  303.                 // disable write to memory
  304.                 EECON1bits.WREN = 0;
  305.  
  306.                 pgmAddress     += 64;
  307.                 bytesReceived   = 0;
  308.                 errMsg          = ERR_NO_ERROR;
  309.                 pgs             = pgsSEND_ACK;
  310.  
  311.             break;
  312.  
  313.  
  314.             case pgsDONE:
  315.                 _asm  goto RM_RESET_VECTOR _endasm
  316.             break;
  317.  
  318.        
  319.  
  320.  
  321.             default:
  322.                 pgs = pgsWATING_START;
  323.             break;
  324.         }
  325.    
  326.  
  327.     }
  328. }
  329.  
  330.  
  331. /*
  332. *   Function: mainInit
  333. *
  334. *   Input:  none
  335. *   Output: none
  336. *   Pre-conditions: none
  337. *   Affects: Se code
  338. *   Depends: none.
  339. */
  340. void mainInit()
  341. {
  342.     LED0_TRIS=0;   
  343.  
  344.     // Enable internal PORTB pull-ups
  345.     INTCON2bits.RBPU = 0;
  346.    
  347.     // Enable Interrupts
  348.     INTCONbits.GIEH = 1;
  349.     INTCONbits.GIEL = 1;
  350.  
  351.     // Enable interrupt prirority
  352.     RCONbits.IPEN=1;
  353.    
  354.  
  355. }
  356.  
  357.  
  358.  
  359. /// CAN-------------------------------------------------------
  360.  
  361.  
  362. #ifdef USE_CAN
  363.  
  364.  
  365. /*
  366. *   Function: canInit
  367. *
  368. *   Input:  none
  369. *   Output: none
  370. *   Pre-conditions: none
  371. *   Affects: Changes can registers.
  372. *   Depends: none.
  373. */
  374. void canInit()
  375. {
  376.     CANCON = 0x80; //request config mode
  377.     while ((CANSTAT & 0xE0) != 0x80 ); //wait for config mode request
  378.  
  379.     // BAUD AND TQS
  380.  
  381.     BRGCON1=0;
  382.    
  383.     // Sync_Seq = 2 x TQ = 1
  384.     BRGCON1bits.SJW1=0;
  385.     BRGCON1bits.SJW0=1;
  386.    
  387.     // Setting BRP.
  388.     BRGCON1=BRGCON1|CAN_BRP;
  389.    
  390.     // Maximum PHEG1
  391.     BRGCON2bits.SEG2PHTS = 1;
  392.    
  393.     // Phase_Seg1 = 2 x TQ = 1
  394.     BRGCON2bits.SEG1PH2 = 0;
  395.     BRGCON2bits.SEG1PH1 = 0;
  396.     BRGCON2bits.SEG1PH0 = 1;
  397.    
  398.     // Prop_Seq = 2 x TQ = 1
  399.     BRGCON2bits.PRSEG2 = 0;
  400.     BRGCON2bits.PRSEG1 = 0;
  401.     BRGCON2bits.PRSEG0 = 1;
  402.    
  403.     //  Enableing bus wake-up
  404.     BRGCON3bits.WAKDIS = 0;
  405.    
  406.     // Dont use filter when wakeup
  407.     BRGCON3bits.WAKFIL = 0;
  408.    
  409.     // Phase_Seg2 = 2 x TQ = 1
  410.     BRGCON3bits.SEG2PH2 = 0;
  411.     BRGCON3bits.SEG2PH1 = 0;
  412.     BRGCON3bits.SEG2PH0 = 1;
  413.  
  414.     ECANCON=0;
  415.     ECANCONbits.MDSEL1 = 0;
  416.     ECANCONbits.MDSEL0 = 1;
  417.  
  418.  
  419.     // FILTERS AND MASKS
  420.     RXB0CONbits.RXM1=1;
  421.     RXB0CONbits.RXM0=0;
  422.  
  423.  
  424.     // INTERRUPTS
  425.    
  426.     // Diable transmit interrupt
  427.     TXBIE = 0;
  428.  
  429.     //rx no interrupt
  430.     PIR3 = 0;
  431.     PIE3 = 0;
  432.  
  433.  
  434.     // Programmable no buffers interrupt
  435.     BIE0  = 0x00;  
  436.  
  437.  
  438.     //loopback mode or not
  439.     #ifdef CAN_LOOPBACK_MODE
  440.         CANCON = 0x40;//request loopback mode
  441.         while ((CANSTAT & 0xE0) != 0x40 );//wait for loopback mode
  442.     #else
  443.         CANCON = 0x00;//request normal mode
  444.         while ((CANSTAT & 0xE0) != 0x00 );//wait for normal mode
  445.     #endif
  446.  
  447. }
  448.  
  449.  
  450.  
  451.  
  452. /*
  453. *   Function: canGetPacket
  454. *
  455. *   Input:  none
  456. *   Output: none
  457. *   Pre-conditions: a call to canISR and an packet is available and banked to RXB0
  458. *   Affects: Calls canParse() function in main for parsing received packet.
  459. *   Depends: none.
  460. */
  461. BOOL canGetPacket()
  462. {
  463.  
  464.         // Get which buffer that is ful.
  465.              if (RXB0CONbits.RXFUL) { ECANCON=(ECANCON&0b00000)|0b10000;  }
  466.         else if (RXB1CONbits.RXFUL) { ECANCON=(ECANCON&0b00000)|0b10001;  }
  467.         else if (B0CONbits.RXFUL)   { ECANCON=(ECANCON&0b00000)|0b10010;  }
  468.         else if (B1CONbits.RXFUL)   { ECANCON=(ECANCON&0b00000)|0b10011;  }
  469.         else if (B2CONbits.RXFUL)   { ECANCON=(ECANCON&0b00000)|0b10100;  }
  470.         else if (B3CONbits.RXFUL)   { ECANCON=(ECANCON&0b00000)|0b10101;  }
  471.         else if (B4CONbits.RXFUL)   { ECANCON=(ECANCON&0b00000)|0b10110;  }
  472.         else if (B5CONbits.RXFUL)   { ECANCON=(ECANCON&0b00000)|0b10111;  }
  473.         else return FALSE;
  474.  
  475.  
  476.         //RXB0SIDH 28 27 26 25 24 23 22 21
  477.         //RXB0SIDL 20 19 18 xx xx xx 17 16
  478.         //RXB0EIDH 15 14 13 12 11 10 09 08
  479.         //RXB0EIDL 07 06 05 04 03 02 01 00
  480.  
  481.         //funct xx xx xx xx 28 27 26 25
  482.         //funcc xx xx xx xx xx xx 24 23 22 21 20 19 18 17 16 15
  483.         //nid   xx xx 14 13 12 11 10 09
  484.         //sid   xx xx xx xx xx xx xx 08 07 06 05 04 03 02 01 00
  485.  
  486.  
  487.         cm.funct=((RXB0SIDH & 0xF0)>>4);
  488.         cm.funcc=(((WORD)(RXB0SIDH & 0x0F))<<6)+(((WORD)(RXB0SIDL & 0xE0))>>2)+(((WORD)(RXB0SIDL & 0x03))<<1)+(((WORD)(RXB0EIDH & 0x80))>>7);
  489.         cm.nid=((RXB0EIDH & 0x7E)>>1);
  490.         cm.sid=(((WORD)(RXB0EIDH & 0x01))<<8)+RXB0EIDL;
  491.  
  492.  
  493.         // Data length
  494.         cm.data_length=(RXB0DLCbits.DLC3<<3)+(RXB0DLCbits.DLC2<<2)+(RXB0DLCbits.DLC1<<1)+RXB0DLCbits.DLC0;
  495.  
  496.         // Data one bye one, for speed
  497.         cm.data[0]=RXB0D0;  cm.data[1]=RXB0D1;
  498.         cm.data[2]=RXB0D2;  cm.data[3]=RXB0D3;
  499.         cm.data[4]=RXB0D4;  cm.data[5]=RXB0D5;
  500.         cm.data[6]=RXB0D6;  cm.data[7]=RXB0D7;
  501.  
  502.         // Clear ful status
  503.         RXB0CONbits.RXFUL=0;
  504.  
  505.         return TRUE;
  506. }
  507.  
  508.  
  509. /*
  510. *   Function: canSendMessage
  511. *
  512. *   Input:  CAN_MESSAGE to send
  513. *   Output: True if packet scheduled sucess, false otherwise.
  514. *   Pre-conditions: canInit
  515. *   Affects: ..
  516. *   Depends: ..
  517. */
  518. BOOL canSendMessage(CAN_PROTO_MESSAGE cm,CAN_PRIORITY prio)
  519. {
  520.    
  521.     if ( TXB0CONbits.TXREQ == 0 )  { ECANCON=(ECANCON&0b00000)|0b00011; }
  522.     if ( TXB1CONbits.TXREQ == 0 )  { ECANCON=(ECANCON&0b00000)|0b00100; }
  523.     if ( TXB2CONbits.TXREQ == 0 )  { ECANCON=(ECANCON&0b00000)|0b00101; }
  524.     // None of the transmit buffers were empty.
  525.     else { return FALSE;}
  526.  
  527.     if (prio<0 || prio>3) prio = 0;
  528.  
  529.  
  530.         //RXB0SIDH 28 27 26 25 24 23 22 21
  531.         //RXB0SIDL 20 19 18 xx xx xx 17 16
  532.         //RXB0EIDH 15 14 13 12 11 10 09 08
  533.         //RXB0EIDL 07 06 05 04 03 02 01 00
  534.  
  535.         //funct xx xx xx xx 28 27 26 25
  536.         //funcc xx xx xx xx xx xx 24 23 22 21 20 19 18 17 16 15
  537.         //nid   xx xx 14 13 12 11 10 09
  538.         //sid   xx xx xx xx xx xx xx 08 07 06 05 04 03 02 01 00
  539.  
  540.         RXB0SIDH = (BYTE)((cm.funct & 0x0F)<<4)+(BYTE)((cm.funcc & 0x03C0)>>6);
  541.         RXB0SIDL = (BYTE)((cm.funcc & 0x003F)<<2)+(BYTE)((cm.funcc & 0x0006)>>1);
  542.         RXB0EIDH = (BYTE)((cm.funcc & 0x0001)<<7)+(BYTE)((cm.nid & 0x3F)<<1)+(BYTE)((cm.sid & 0x0100)>>8);
  543.         RXB0EIDL = (BYTE)((cm.sid & 0x00FF));
  544.  
  545.         // Data length
  546.         RXB0DLC = 0;
  547.         if (cm.data_length>8) RXB0DLC=8; else RXB0DLC=cm.data_length;
  548.        
  549.         // NOT Remote request
  550.         _asm
  551.             bcf RXB0DLC, 6, 0
  552.         _endasm
  553.  
  554.  
  555.         // Data one bye one, for speed
  556.         RXB0D0=cm.data[0];  RXB0D1=cm.data[1];
  557.         RXB0D2=cm.data[2];  RXB0D3=cm.data[3];
  558.         RXB0D4=cm.data[4];  RXB0D5=cm.data[5];
  559.         RXB0D6=cm.data[6];  RXB0D7=cm.data[7];
  560.  
  561.         // set extended or not
  562.         RXB0SIDLbits.EXID=1;
  563.  
  564.         // Priority
  565.         RXB0CON = (RXB0CON & 0b11111100) | prio;
  566.  
  567.         // mark as redy to transmit
  568.         _asm
  569.             bsf RXB0CON, 3, 0
  570.         _endasm
  571.  
  572.         return TRUE;
  573.  
  574. }
  575.  
  576.  
  577.  
  578. #endif //USE_CAN
  579.  
  580.  
  581.  
  582.  
  583. void TBLRD_Func()
  584. {
  585. _asm
  586.     TBLRD
  587. _endasm
  588. }
  589.  
  590. void TBLWT_Func()
  591. {
  592. _asm
  593.     TBLWT
  594. _endasm
  595. }
  596.  
  597.  
  598. void TBLWTPOSTINC_Func (void){
  599. _asm
  600.     TBLWTPOSTINC
  601. _endasm
  602. }
  603.  
  604. DWORD tickGet()
  605. {
  606.     return tickCounter;
  607. }
  608.  
  609.  
  610. #pragma code user = RM_RESET_VECTOR
  611.