樊春春 4 ay önce
ebeveyn
işleme
f00c253757

+ 2 - 0
CMakeLists.txt

@@ -32,6 +32,7 @@ file(GLOB_RECURSE C_SRCS
         ${CMAKE_CURRENT_SOURCE_DIR}/startup/gcc/startup_stm32f40_41xxx.s
         ${CMAKE_CURRENT_SOURCE_DIR}/libraries/STM32F4xx_StdPeriph_Driver/src/*.c
         ${CMAKE_CURRENT_SOURCE_DIR}/packages/multi_button/multi_button.c
+        ${CMAKE_CURRENT_SOURCE_DIR}/packages/j1939/source/*.c
         ${CMAKE_CURRENT_SOURCE_DIR}/app/*.c
         ${CMAKE_CURRENT_SOURCE_DIR}/cli/*.c
         ${CMAKE_CURRENT_SOURCE_DIR}/dev/*.c
@@ -54,6 +55,7 @@ set(INC_C_DIRS
         ${CMAKE_CURRENT_SOURCE_DIR}/libraries/CMSIS/Device/ST/STM32F4xx/Include
         ${CMAKE_CURRENT_SOURCE_DIR}/libraries/STM32F4xx_StdPeriph_Driver/inc
         ${CMAKE_CURRENT_SOURCE_DIR}/packages/multi_button
+        ${CMAKE_CURRENT_SOURCE_DIR}/packages/j1939/source
         ${CMAKE_CURRENT_SOURCE_DIR}/app
         ${CMAKE_CURRENT_SOURCE_DIR}/cli
         ${CMAKE_CURRENT_SOURCE_DIR}/dev

+ 55 - 17
dev/dev_can.c

@@ -1,4 +1,5 @@
 #include "dev_can.h"
+#include "core_cmFunc.h"
 #include "dev_iap.h"
 #include "hal_can.h"
 #include "hal_conf.h"
@@ -59,7 +60,8 @@ void product_array(uint8_t send_array[8])
 
 uint8_t push_can_message_to_queue(uint32_t id, uint8_t len, uint8_t *p_data)
 {
-    pdu_tag response_msg;
+    pdu_tag      response_msg;
+    QUEUE_STATUS result_status;
     response_msg.id.r    = id;
     response_msg.reg.dlc = len;
     memcpy(&response_msg.data.u8_buf[0], p_data, len);
@@ -74,7 +76,11 @@ uint8_t push_can_message_to_queue(uint32_t id, uint8_t len, uint8_t *p_data)
     }
 
 #if 1
-    if (en_queue(&can_tx_queue, response_msg) != Q_OK)
+    __disable_irq();
+    result_status = en_queue(&can_tx_queue, response_msg);
+    __enable_irq();
+
+    if (result_status != Q_OK)
     {
         return 0;
     }
@@ -120,7 +126,7 @@ void can_tx_callback(void)
 {
     pdu_tag tx_data;
     // de_queue(can_tx, &tx_data);
-    if (de_queue(&can_tx_queue, &tx_data) == Q_OK) // 返回值为1代表读取成功
+    if (de_queue(&can_tx_queue, tx_data) == Q_OK) // 返回值为1代表读取成功
     {
         can_tx_frame(tx_data);
         CAN_ITConfig(CAN1, CAN_IT_TME, ENABLE);
@@ -234,10 +240,14 @@ can_rx_tab can_tab[] = {
 
 };
 
+#define REG32(addr)     (*(volatile uint32_t *)(uint32_t)(addr))
+#define CAN_INTEN(canx) REG32((canx) + 0x14U)
+
 void can_start_send(void)
 {
     pdu_tag tx_msg;
-    if (RESET == CAN_GetITStatus(CAN1, CAN_IT_TME))
+
+    if (0 == ((CAN1->IER) & 0x1))
     {
 #if 0
         de_queue(can_tx, &tx_msg);
@@ -247,7 +257,7 @@ void can_start_send(void)
             CAN_ITConfig(CAN1, CAN_IT_TME, ENABLE);
         }
 #else
-        if (de_queue(&can_tx_queue, &tx_msg) == Q_OK) // 返回值为1代表读取成功
+        if (de_queue(&can_tx_queue, tx_msg) == Q_OK) // 返回值为1代表读取成功
         {
             can_tx_frame(tx_msg);
             CAN_ITConfig(CAN1, CAN_IT_TME, ENABLE);
@@ -259,23 +269,46 @@ void can_start_send(void)
 
 static uint8_t can_rx_process(void)
 {
-    uint8_t i;
-    uint8_t flg = 0;
-    pdu_tag rec_msg;
+    uint8_t      i;
+    uint8_t      flg = 0;
+    pdu_tag      rec_msg;
+    QUEUE_STATUS result;
 
     for (uint8_t j = 0; j < 15; j++)
     {
 #if 1
-        if (Q_OK == de_queue(&can_rx_queue, &rec_msg))
+        __disable_irq();
+        result = de_queue(&can_rx_queue, rec_msg);
+        __enable_irq();
+        if (Q_OK == result)
         {
             for (i = 0; i < ARR_SIZE(can_tab); i++)
             {
                 if (can_tab[i].id == rec_msg.id.r)
                 {
                     can_tab[i].p_func(rec_msg);
+                    flg = 1;
+                    break;
+                }
+                else if (can_tab[i].id == (rec_msg.id.b.pf << 8 | rec_msg.id.b.ps))
+                {
+                    can_tab[i].p_func(rec_msg);
+                    flg = 1;
+                    break;
+                }
+                else if (can_tab[i].id == rec_msg.id.b.pf)
+                {
+                    can_tab[i].p_func(rec_msg);
+                    flg = 1;
                     break;
                 }
             }
+
+            if (flg == 0)
+            {
+                // j1939_msg_push_queue(rec_msg);
+            }
+            flg = 0;
         }
 #else
         de_queue(can_rx, &rec_msg);
@@ -401,10 +434,10 @@ void can_tx_0x18010010_message(void)
     data[1] = 1;
     data[4] = 0;
     data[5] = 0;
-    push_can_message_to_queue(0x18010010, 8, data);
-    data[1] = 5;
-    push_can_message_to_queue(0x18010010, 8, data);
-    data[1] = 10;
+    // push_can_message_to_queue(0x18010010, 8, data);
+    // data[1] = 5;
+    // push_can_message_to_queue(0x18010010, 8, data);
+    // data[1] = 10;
     push_can_message_to_queue(0x18010010, 8, data);
 }
 
@@ -610,8 +643,12 @@ void can_tx_0x18011803_2_message(void)
 void send_message(void)
 {
     static volatile uint8_t times = 0;
-    times++;
-    if (times % 100 == 1)
+
+    if (times >= 100)
+    {
+        times = 0;
+    }
+    if (times % 100 == 0)
     {
         can_tx_0x18010001_message();
         can_tx_0x18010002_message();
@@ -656,12 +693,13 @@ void send_message(void)
         can_tx_0x18010012_message();
         can_tx_0x18011802_message();
         can_tx_0x18011803_message();
-        can_tx_0x18011803_2_message();
+        // can_tx_0x18011803_2_message();
     }
     else
     {
-        return;
+        // return;
     }
+    times++;
 }
 
 void dev_can_network_init(void)

+ 12 - 1
dev/dev_iap.c

@@ -20,7 +20,18 @@ unsigned char   recv_crc[2];
 unsigned char   recvdata_ema[204];
 unsigned char   recvdata_buffer[210];
 
-uint16_t firm_ver[UPGRADE_APP_DATA_SIZE]       = {IAP_CMD_JUMP_OVER};
+#define SW_VER 0x2446
+
+#define SW_VER_HI_ASCII ((('0' + ((uint8_t)((SW_VER >> 8) & 0x000F))) << 8) | \
+                         ('0' + ((uint8_t)((SW_VER >> 12) & 0x000F))))
+
+#define SW_VER_L0_ASCII ((('0' + ((uint8_t)(SW_VER & 0x000F))) << 8) | \
+                         ('0' + ((uint8_t)((SW_VER >> 4) & 0x000F))))
+
+#define PACK_TYPE       1
+#define PACK_TYPE_ASCII ((('0' + PACK_TYPE) << 8) | ('0'))
+
+uint16_t firm_ver[UPGRADE_APP_DATA_SIZE]       = {IAP_CMD_JUMP_OVER, SW_VER_HI_ASCII, SW_VER_L0_ASCII, 0xFFFF};
 uint16_t firm_ver_buff[UPGRADE_BUFF_DATA_SIZE] = {0};
 uint8_t  iap_disconnect_count                  = 0;
 /************************************************************************************************

+ 6 - 6
hal/hal_can.c

@@ -78,12 +78,12 @@ u8 hal_can1_mode_init(uint8_t tsjw, uint8_t tbs2, uint8_t tbs1, uint16_t brp, ui
     NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
     NVIC_Init(&NVIC_InitStructure);
 
-    CAN_ITConfig(CAN1, CAN_IT_TME, ENABLE); // FIFO0消息挂号中断允许.
-    NVIC_InitStructure.NVIC_IRQChannel                   = CAN1_TX_IRQn;
-    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // 主优先级为1
-    NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 0; // 次优先级为0
-    NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
-    NVIC_Init(&NVIC_InitStructure);
+    // CAN_ITConfig(CAN1, CAN_IT_TME, ENABLE); // FIFO0消息挂号中断允许.
+    // NVIC_InitStructure.NVIC_IRQChannel                   = CAN1_TX_IRQn;
+    // NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // 主优先级为1
+    // NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 0; // 次优先级为0
+    // NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
+    // NVIC_Init(&NVIC_InitStructure);
     ////////////////////////////////////////////////
 
     return 0;

+ 2 - 2
hal/queue.c

@@ -87,7 +87,7 @@ QUEUE_STATUS en_queue(p_can_queue_tag p_queue,
 }
 
 QUEUE_STATUS de_queue(p_can_queue_tag p_queue,
-                      p_pdu_tag       p_data)
+                      pdu_tag         data)
 { /* 插入元素e为Q的新的队尾元素 */
     // if ((p_queue->tail + 1) % MAX_QSIZE == p_queue->head) /* 队列满 */
     //     return ERROR;
@@ -96,7 +96,7 @@ QUEUE_STATUS de_queue(p_can_queue_tag p_queue,
     // return SUCCESS;
     if (queue_empty(p_queue))
         return Q_EMPTY;
-    *p_data       = p_queue->can_message[p_queue->tail];
+    data          = p_queue->can_message[p_queue->tail];
     p_queue->tail = (p_queue->tail + 1) % MAX_QSIZE;
     p_queue->count--;
 

+ 1 - 1
hal/queue.h

@@ -66,5 +66,5 @@ uint8_t      queue_empty(p_can_queue_tag); // 
 uint8_t      queue_full(p_can_queue_tag);
 uint8_t      get_head(can_queue_tag *p_queue, pdu_tag *data); // 获取对头数据
 QUEUE_STATUS en_queue(p_can_queue_tag, pdu_tag);              // 队列插入数据
-QUEUE_STATUS de_queue(p_can_queue_tag, p_pdu_tag);
+QUEUE_STATUS de_queue(p_can_queue_tag, pdu_tag);
 #endif

+ 339 - 0
packages/j1939/LICENSE

@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/>
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    {description}
+    Copyright (C) {year}  {fullname}
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  {signature of Ty Coon}, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.

+ 39 - 0
packages/j1939/readme.md

@@ -0,0 +1,39 @@
+# 简述
+ 1. 源代码下载:
+ > https://github.com/XeiTongXueFlyMe/J1939
+ 2. 源代码说明书Web站点:(临时,已准备建站,以后分享更多的汽车通信协议)
+ > https://xeitongxueflyme.github.io/j1939doc.github.io/
+ 3. 技术支持群:
+ > QQ群:264864184 ,为了节约时间成本,群主可以免费为大家解决最新协议栈问题(老版本,群里也有其他工程师为大家解决,群主不做答)
+
+# 历史版本变更 
+
+> 版本说明:V a,b,c
+ 1. a 代表版本号
+ 2. b 代表稳定的版本号
+ 3. c 代表基于稳定版本号上功能添加,新的功能不一定稳定
+
+> 如果是工程使用,建议使用 **V x.x.0**  例如 ***V 1.1.0*** ,***V 2.1.0***
+
+## J1939Socket API Version 2 
+
+Version  | date |Description
+------------- | ------------- | -------------
+[V2.1.0]  |2018/1/20| Version 2.1 稳定发布版。经过实用性测试,Version 2.1相对Version 1.1做了很大的改进,Version 2.1版本更加的偏向于使用,移植更加的简单,架构和注解更加的规范。API(接口)更加人性化,实用化(感谢许多同行的使用反馈)。
+[V2.0.1]  |2017/12/8| 地址竞争,动态地址分配等J1939网络功能不能使用,本版本为V2.1.0发布前的测试版本。
+
+
+## J1939Socket API Version 1   
+
+Version  | date | Description
+------------- | ------------- | -------------
+[V1.1.0]  | 2017/11/22 | Version 1.1 稳定发布版。\n * 实现了J1939-21文档规定的功能(数据链路层)。\n * 轻量级(可适应低端的MCU)建议低端的MCU采用本版本移植开发。\n * 使用示例参考附带的readme.md和<http://blog.csdn.net/xietongxueflyme> \n * 移植示例参考 <http://blog.csdn.net/xietongxueflyme> 
+[V1.0.1]  | 2017/08/04 | 完善功能,增加对TP(长帧,多组)传输的支持,\n 1.增加非阻塞API调用接口 \n * 使用示例参考附带的readme.md和<http://blog.csdn.net/xietongxueflyme> \n * 移植示例参考 <http://blog.csdn.net/xietongxueflyme> \n * 本文档不对Version 1 进行阐述。
+V1.0.0  | 2017/06/04 | 首个开源版本\n 1.增加双模式(轮询或者中断,逻辑更加简单明了)\n 2.可适应低端的MCU \n 3.支持多任务调用接口(可用于嵌入式系统)
+V0.0.1  | 2017/05/04 | 初建工程\n * 易移植(不针对特定的CAN硬件,只要满足CAN2.0B即可)
+
+[V1.1.0]: https://github.com/XeiTongXueFlyMe/J1939/releases/tag/v1.1.0  "V1.1.0下载地址"
+[V1.0.1]: https://github.com/XeiTongXueFlyMe/J1939/releases/tag/V1.01  "V1.0.1下载地址" 
+[V2.0.1]: https://github.com/XeiTongXueFlyMe/J1939/releases/tag/V2.0.1  "V2.0.1下载地址"
+[V2.1.0]: https://github.com/XeiTongXueFlyMe/J1939/releases/tag/V2.1.0  "V2.1.0下载地址"
+

+ 338 - 0
packages/j1939/source/J1939.H

@@ -0,0 +1,338 @@
+/*********************************************************************
+ *
+ *            J1939 Main Source Code
+ *
+ *********************************************************************
+ *
+ *	本程序是由XieTongXueFlyMe对现有的J1939协议文档分析,和对前辈的贡献总结,
+ * 写出的一套开源的J1939驱动。
+ *	本协议特点:
+ *		1.易移植(不针对特定的CAN硬件,只要满足CAN2.0B即可)
+ *		2.轻量级(可适应低端的MCU)
+ *		3.支持多任务调用接口(可用于嵌入式系统)
+ *		4.双模式(轮询或者中断,逻辑更加简单明了)
+ *		5.不掉帧(数据采用收发列队缓存)
+ *
+ *  源代码下载:
+ *		https://github.com/XeiTongXueFlyMe/J1939
+ *  源代码临时手册Web站点:
+ *		https://xeitongxueflyme.github.io/j1939doc.github.io/
+ *
+ * Version     Date        Description
+ * -------------------------------------------------------------------
+ * v1.0.0     2017/06/04    首个版本 Version 1 测试版发布
+ * v1.0.1     2017/08/04    完善功能
+ * v1.1.0     2017/11/22    Version 1 稳定发布版
+ * v2.0.1     2017/11/24    Version 2 测试版发布
+ * v2.0.2     2018/01/03    解决V2.0.1 遗留问题
+ * v2.1.0     2018/01/20    Version 2 稳定发布版
+ * Author               Date         changes
+ *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *XeiTongXueFlyMe       7/06/04      首个版本
+ *XeiTongXueFlyMe       7/08/04      增加对TP的支持
+ *XeiTongXueFlyMe       7/11/24      增加对多路CAN硬件的收发,和报文处理
+ *XeiTongXueFlyMe       7/11/29      增加请求和响应API
+ *XeiTongXueFlyMe       7/12/07      重做TP接受API函数
+ *XeiTongXueFlyMe       7/12/08      增加软件滤波器
+ *XeiTongXueFlyMe       8/01/03      重做接受发送API,简化协议栈初始化调用逻辑
+ **********************************************************************/
+#ifndef __J1939_H
+#define __J1939_H
+/******************************类型声明*********************************/
+#define FALSE 0
+#define TRUE  1
+
+/** 统一类型定义
+ *  不同的单片机的编译器, int,short,long 的位数可能不同
+ *
+ *  在移植J1939协议栈时,首先应该配置这里
+ */
+typedef unsigned int   j1939_uint32_t; /** < 32位无符号整形*/
+typedef int            j1939_int32_t;  /** < 32位整形*/
+typedef unsigned short j1939_uint16_t; /** < 16位无符号整形*/
+typedef unsigned char  j1939_uint8_t;  /** < 8位无符号整形*/
+typedef char           j1939_int8_t;   /** < 8位无符号整形*/
+#define J1939_NULL 0
+
+// 函数返回代码
+#define RC_SUCCESS        0 /**< 成功*/
+#define RC_QUEUEEMPTY     1 /**< 列队为空*/
+#define RC_QUEUEFULL      1 /**< 列队满*/
+#define RC_CANNOTRECEIVE  2 /**< 不能接收*/
+#define RC_CANNOTTRANSMIT 2 /**< 不能传输*/
+#define RC_PARAMERROR     3 /**< 参数错误*/
+
+// 内部常量
+#define J1939_FALSE 0 /**< 代表函数错误返回*/
+#define J1939_TRUE  1 /**< 代表函数正确返回*/
+
+// J1939 默认的优先级(参考J1939文档)
+#define J1939_CONTROL_PRIORITY     0x03 /**< J1939文档默认的优先级*/
+#define J1939_INFO_PRIORITY        0x06 /**< J1939文档默认的优先级*/
+#define J1939_PROPRIETARY_PRIORITY 0x06 /**< J1939文档默认的优先级*/
+#define J1939_REQUEST_PRIORITY     0x06 /**< J1939文档默认的优先级*/
+#define J1939_ACK_PRIORITY         0x06 /**< J1939文档默认的优先级*/
+#define J1939_TP_CM_PRIORITY       0x07 /**< J1939文档默认的优先级*/
+#define J1939_TP_DT_PRIORITY       0x07 /**< J1939文档默认的优先级*/
+
+// J1939 定义的地址
+#define J1939_GLOBAL_ADDRESS 255 /**< 全局地址*/
+#define J1939_NULL_ADDRESS   254 /**< 空地址*/
+
+// J1939协议栈的PNG请求响应,相关的定义
+#define J1939_PF_REQUEST2 201 /**< J1939协议栈的请求 PF */
+#define J1939_PF_TRANSFER 202 /**< J1939协议栈的转移 PF */
+
+#define J1939_PF_REQUEST        234 /**< 请求 或 用于握手机制*/
+#define J1939_PF_ACKNOWLEDGMENT 232 /**< 确认请求 或 用于握手机制*/
+
+#define J1939_ACK_CONTROL_BYTE            0 /**< 用于TP(长帧数据),代表确认*/
+#define J1939_NACK_CONTROL_BYTE           1 /**< 用于TP(长帧数据),PNG不被支持。否定消息*/
+#define J1939_ACCESS_DENIED_CONTROL_BYTE  2 /**< 拒绝访问,但是信息是被支持,暂时不能响应(需要再次发送请求)*/
+#define J1939_CANNOT_RESPOND_CONTROL_BYTE 3 /**< 不能做出反应,有空但是接受的缓存不够,或则发送资源被占领,暂时不能响应(需要再次发送请求)*/
+
+// TP协议的一些宏定义
+#define J1939_PF_DT    235 /**< 协议传输---数据传输 PF*/
+#define J1939_PF_TP_CM 236 /**< 协议传输---链接管理 PF*/
+
+// TP的超时时间,单位(ms)
+#define J1939_TP_Tr                  200  /**< 宏定义TP的超时时间*/
+#define J1939_TP_Th                  500  /**< 宏定义TP的超时时间*/
+#define J1939_TP_T1                  750  /**< 宏定义TP的超时时间*/
+#define J1939_TP_T2                  1250 /**< 宏定义TP的超时时间*/
+#define J1939_TP_T3                  1250 /**< 宏定义TP的超时时间*/
+#define J1939_TP_T4                  1050 /**< 宏定义TP的超时时间*/
+#define J1939_TP_TIMEOUT_NORMAL      0    /**< 未超时正常*/
+#define J1939_TP_TIMEOUT_ABNORMAL    1    /**< 超时*/
+#define J1939_RTS_CONTROL_BYTE       16   /**< TP.CM_RTS*/
+#define J1939_CTS_CONTROL_BYTE       17   /**< TP.CM_CTS*/
+#define J1939_EOMACK_CONTROL_BYTE    19   /**< 消息应答结束*/
+#define J1939_BAM_CONTROL_BYTE       32   /**< 广播公告消息*/
+#define J1939_CONNABORT_CONTROL_BYTE 255  /**< 连接中断控制字节(放弃连接)*/
+#define J1939_RESERVED_BYTE          0xFF /**< 变量的保留位的值*/
+
+// 与J1939网络层有关的定义
+#define J1939_PGN2_REQ_ADDRESS_CLAIM 0x00
+#define J1939_PGN1_REQ_ADDRESS_CLAIM 0xEA
+#define J1939_PGN0_REQ_ADDRESS_CLAIM 0x00
+
+#define J1939_PGN2_COMMANDED_ADDRESS 0x00
+#define J1939_PGN1_COMMANDED_ADDRESS 0xFE /**< 命令地址消息*/
+#define J1939_PGN0_COMMANDED_ADDRESS 0xD8 /**< 参考J1939-81 地址命令配置*/
+
+#define J1939_PF_ADDRESS_CLAIMED      238
+#define J1939_PF_CANNOT_CLAIM_ADDRESS 238
+#define J1939_PF_PROPRIETARY_A        239 /**< 专用A*/
+#define J1939_PF_PROPRIETARY_B        255 /**< 专用B*/
+
+/**< 是否对TP协议的支持(是否支持长帧(大于8字节的数据)的发送与接受)*/
+#define J1939_TP_RX_TX J1939_TRUE
+/**< TP协议的支持的最大接受发送消息长度(最大可配置为1785)*/
+#define J1939_TP_MAX_MESSAGE_LENGTH 240
+
+/**CAN节点的选择枚举
+ *
+ * 默认支持最大4路CAN硬件\n
+ */
+typedef enum
+{
+    Select_CAN_NODE_Null, /**< 不选择任何CAN硬件*/
+    Select_CAN_NODE_1,    /**< 选择CAN硬件 1*/
+    Select_CAN_NODE_2,    /**< 选择CAN硬件 2*/
+    Select_CAN_NODE_3,    /**< 选择CAN硬件 3*/
+    Select_CAN_NODE_4,    /**< 选择CAN硬件 4*/
+} CAN_NODE;
+
+#if J1939_TP_RX_TX
+/**TP的状态描述枚举
+ *
+ */
+typedef enum
+{
+    J1939_TP_NULL,   /**< 长数据传输处于空闲,只有TP系统处于空闲,才能用处理下一个发送,和接受请求*/
+    J1939_TP_RX,     /**< 长数据传输处于接收*/
+    J1939_TP_TX,     /**< 长数据传输处于发送*/
+    J1939_TP_OSBUSY, /**< 长数据传输处于繁忙,比如刚接受一整段长数据,但是CPU没来得处理,又一个长数据请求到来,为了数据不被覆盖,将状态设为本值*/
+} J1939_TP_State;
+/**TP的标志位结构体
+ *
+ * 本结构体记录了TP的状态,使用TP发送和接受的CAN硬件编号
+ */
+typedef struct
+{
+    J1939_TP_State state;          /**< TP的连接状态*/
+    CAN_NODE       TP_RX_CAN_NODE; /**< TP接受请求产生的 CAN硬件编号*/
+    CAN_NODE       TP_TX_CAN_NODE; /**< TP接受发送产生的 CAN硬件编号*/
+} J1939_TP_Flags;
+/**J1939消息对象的结构体
+ *
+ * 本结构体实现了 J1939的消息对象
+ */
+typedef struct
+{
+    j1939_uint32_t PGN;                               /**< J1939的消息对象的 PGN*/
+    j1939_uint8_t  data[J1939_TP_MAX_MESSAGE_LENGTH]; /**< J1939的消息对象的 数据*/
+    j1939_uint16_t byte_count;                        /**< J1939的消息对象的 数据大小*/
+    j1939_uint8_t  SA;                                /**< J1939的消息对象的 目标地址(发送目的地  或  接受来源地)*/
+
+} J1939_MESSAGE_T;
+/**J1939消息对象的结构体
+ *
+ * 本结构体实现了 J1939的多帧消息对象
+ */
+typedef struct
+{
+    j1939_uint8_t *data;       /**< 缓存区指针*/
+    j1939_uint16_t data_num;   /**< 缓存区大小*/
+    j1939_uint8_t  SA;         /**< J1939的消息对象的 数据 源地址*/
+    j1939_uint16_t byte_count; /**< J1939的消息对象的 数据大小*/
+    j1939_uint32_t PGN;        /**< J1939的消息对象的 PGN*/
+} TP_RX_MESSAGE;
+/**J1939_TP_Tx_Step枚举
+ *
+ * 实现了记录长帧(多帧)传输的TX 的步骤
+ */
+typedef enum
+{
+    J1939_TP_TX_WAIT,
+    J1939_TP_TX_CM_START,
+    J1939_TP_TX_CM_WAIT,
+    J1939_TP_TX_DT,
+    J1939_TP_WAIT_ACK,
+    J1939_TP_TX_ERROR,
+    J1939_TX_DONE,
+} J1939_TP_Tx_Step; // 协议的发送步骤
+/**J1939_TRANSPORT_TX_INFO 结构体
+ *
+ * 实现了长帧传输中产生的临时数据,和一些传输交换数据
+ */
+typedef struct
+{
+    J1939_MESSAGE_T  tp_tx_msg;           /**< J1939的消息对象*/
+    j1939_uint16_t   time;                /**< 时间*/
+    j1939_uint8_t    packet_offset_p;     /**< 数据包偏移指针*/
+    j1939_uint8_t    packets_total;       /**< 总共有多少个数据包*/
+    j1939_uint8_t    packets_request_num; /**< 请求发送的数据包数(接受方准备接受的数据包数)*/
+    J1939_TP_Tx_Step state;               /**< 协议的发送步骤*/
+} J1939_TRANSPORT_TX_INFO;
+/**J1939_TP_Rx_Step枚举
+ *
+ * 实现了记录长帧(多帧)传输的RX 的步骤
+ */
+typedef enum
+{
+    J1939_TP_RX_WAIT,
+    J1939_TP_RX_READ_DATA,
+    J1939_TP_RX_DATA_WAIT,
+    J1939_TP_RX_ERROR,
+    J1939_RX_DONE,
+} J1939_TP_Rx_Step; // 协议的接收步骤
+
+/**J1939_TRANSPORT_RX_INFO 结构体
+ *
+ * 实现了长帧传输中产生的临时数据,和一些传输交换数据
+ */
+typedef struct
+{
+    J1939_MESSAGE_T  tp_rx_msg;      /**< J1939的消息对象*/
+    j1939_uint8_t    osbusy;         /**< 此位置1,代表系统繁忙,cpu需要处理其他的事物,直接拒绝一切的链接请求\n 如果正在接受中,此位置1,则会发出链接保持消息帧。*/
+    j1939_uint16_t   time;           /**< 时间*/
+    j1939_uint8_t    packets_total;  /**< 总共有多少个数据包*/
+    j1939_uint8_t    packets_ok_num; /**< 已经接受的数据包数*/
+    J1939_TP_Rx_Step state;          /**< 协议的接受步骤*/
+} J1939_TRANSPORT_RX_INFO;
+
+#endif // J1939_TP_RX_TX
+
+/**
+ * @note 实现Request_PGN 的响应
+ */
+struct Request_List
+{
+    j1939_uint8_t *data;
+    j1939_uint16_t lenght;
+    j1939_uint32_t PGN;
+    CAN_NODE       Can_Node;
+    void (*update)();          /**< 在函数里需要对data更新,如果不用更新data赋值为J1939_NULL*/
+    struct Request_List *next; /**< 链表末尾,需要一直保持J1939_NULL*/
+};
+
+// J1939 Data Structures
+// J1939_MESSAGE_STRUCT旨在J1939消息块映射到设备的地址映射。 只有字段PDU格式不映射到设备寄存器。
+// 结构应该简单地使用PDUFormat和忽视PDUFormat_Top。调整将立即接收和传输之前。
+// 注:编译器创建结构从低一点的位置高一些位置,所以可能出现不匹配的设备寄存器。
+#define J1939_MSG_LENGTH  9 // 消息长度
+#define J1939_DATA_LENGTH 8 // 数据长度
+
+/** J1939_MESSAGE_UNION 结构体
+ * 实现了J1939消息对象
+ *
+ *
+ */
+union J1939_MESSAGE_UNION
+{
+    /** j1939 的 ID 组成结构体
+     *
+     */
+    struct j1939_PID
+    {
+        j1939_uint8_t  DataPage : 1;            /**< 数据页*/
+        j1939_uint8_t  Res      : 1;            /**< Res位*/
+        j1939_uint8_t  Priority : 3;            /**< 优先级*/
+        j1939_uint8_t  Reserve  : 3;            /**< 空闲*/
+        j1939_uint8_t  PDUFormat;               /**< PF*/
+        j1939_uint8_t  PDUSpecific;             /**< PS*/
+        j1939_uint8_t  SourceAddress;           /**< SA*/
+        j1939_uint8_t  DataLength : 4;          /**< 数据长度*/
+        j1939_uint8_t  RTR        : 4;          /**< RTR位*/
+        j1939_uint8_t  Data[J1939_DATA_LENGTH]; /**< 数据*/
+        j1939_uint32_t PGN        : 24;         /**< 参数群编号*/
+        j1939_uint32_t ReservePGN : 8;          /**< 空闲*/
+    };
+    struct j1939_PID Mxe;                                         /**< j1939 的 ID 组成结构体*/
+    j1939_uint8_t    Array[J1939_MSG_LENGTH + J1939_DATA_LENGTH]; /**< 联合体数组,方便快速处理结构体赋值*/
+};
+
+#define GroupExtension     PDUSpecific
+#define DestinationAddress PDUSpecific
+/** 一个宏定义,具体变量名称作用命名
+ *
+ */
+typedef union J1939_MESSAGE_UNION J1939_MESSAGE;
+
+union J1939_FLAGS_UNION
+{
+    struct
+    {
+        j1939_uint8_t TransmitMessagesdCover              : 1; // 发送数据时,J1939协议接受缓存有数据覆盖
+        j1939_uint8_t ReceivedMessagesdCoverOrDroppedNode : 3;
+        j1939_uint8_t ReceivedMessagesdCover              : 1; // 接受数据时,J1939协议接受缓存有数据覆盖
+        j1939_uint8_t ReceivedMessagesDropped             : 1; // 接受数据时,J1939协议接受缓存有数据溢出
+    };
+    j1939_uint8_t FlagVal;
+};
+
+typedef union J1939_FLAGS_UNION J1939_FLAG;
+
+/********************************************API**************************************************************/
+
+// 初始化函数
+extern void J1939_Initialization();
+// CAN驱动收发中断入口
+extern void J1939_ISR();
+// 心跳函数,定时被调用
+extern void J1939_Poll();
+// 读取单帧消息
+extern j1939_uint8_t J1939_Read_Message(J1939_MESSAGE *MsgPtr, CAN_NODE _Can_Node);
+// 发送单帧消息
+extern j1939_uint8_t J1939_Send_Message(J1939_MESSAGE *MsgPtr, CAN_NODE _Can_Node);
+// 多帧(多组)消息发送函数  (RTS/CTS传输协议)
+extern j1939_int8_t J1939_TP_TX_Message(j1939_uint32_t PGN, j1939_uint8_t DA, j1939_uint8_t *data, j1939_uint16_t data_num, CAN_NODE _Can_Node);
+// 多帧(多组)消息接受函数  (RTS/CTS传输协议)
+extern j1939_int8_t J1939_TP_RX_Message(TP_RX_MESSAGE *msg, CAN_NODE _Can_Node);
+// 请求获去一个PGN
+extern void J1939_Request_PGN(j1939_uint32_t pgn, j1939_uint8_t DA, CAN_NODE _Can_Node);
+// 创建一个PGN响应
+extern void J1939_Create_Response(j1939_uint8_t data[], j1939_uint16_t dataLenght, j1939_uint32_t PGN, void (*dataUPFun)(), CAN_NODE _Can_Node);
+
+#endif //__J1939_H

+ 1783 - 0
packages/j1939/source/J1939.c

@@ -0,0 +1,1783 @@
+/*********************************************************************
+ *
+ *            J1939 Main Source Code
+ *
+ *********************************************************************
+ *
+ *	本程序是由XieTongXueFlyMe对现有的J1939协议文档分析,和对前辈的贡献总结,
+ * 写出的一套开源的J1939驱动。
+ *	本协议特点:
+ *		1.易移植(不针对特定的CAN硬件,只要满足CAN2.0B即可)
+ *		2.轻量级(可适应低端的MCU)
+ *		3.支持多任务调用接口(可用于嵌入式系统)
+ *		4.双模式(轮询或者中断,逻辑更加简单明了)
+ *		5.不掉帧(数据采用收发列队缓存)
+ *
+ *  源代码下载:
+ *		https://github.com/XeiTongXueFlyMe/J1939
+ *  源代码临时手册Web站点:
+ *		https://xeitongxueflyme.github.io/j1939doc.github.io/
+ *
+ * Version     Date        Description
+ * -------------------------------------------------------------------
+ * v1.0.0     2017/06/04    首个版本 Version 1 测试版发布
+ * v1.0.1     2017/08/04    完善功能
+ * v1.1.0     2017/11/22    Version 1 稳定发布版
+ * v2.0.1     2017/11/24    Version 2 测试版发布
+ * v2.0.2     2018/01/03    解决V2.0.1 遗留问题
+ * v2.1.0     2018/01/20    Version 2 稳定发布版
+ * Author               Date         changes
+ *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *XeiTongXueFlyMe       7/06/04      首个版本
+ *XeiTongXueFlyMe       7/08/04      增加对TP的支持
+ *XeiTongXueFlyMe       7/11/24      增加对多路CAN硬件的收发,和报文处理
+ *XeiTongXueFlyMe       7/11/29      增加请求和响应API
+ *XeiTongXueFlyMe       7/12/07      重做TP接受API函数
+ *XeiTongXueFlyMe       7/12/08      增加软件滤波器
+ *XeiTongXueFlyMe       8/01/03      重做接受发送API,简化协议栈初始化调用逻辑
+ **********************************************************************/
+#ifndef __J1939_SOURCE
+#define __J1939_SOURCE
+#include "queue.h"
+#include <stdint.h>
+#endif
+
+#include "J1939.H"
+#include "J1939_config.H"
+
+#define J1939_TRUE       1 /**< 代表函数正确返回*/
+#define J1939_FALSE      0 /**< 代表函数错误返回*/
+#define ADDRESS_CLAIM_TX 1 /**< 进入地址竞争发送处理模式*/
+#define ADDRESS_CLAIM_RX 2 /**< 进入地址竞争接受处理模式*/
+
+// 全局变量。
+/** 设备的标称符
+ *
+ *	我们需要在"J1939_config.H"中配置
+ *	@note 在初始化中赋值,赋值参考参考1939-81文档
+ */
+j1939_uint8_t CA_Name[J1939_DATA_LENGTH];
+j1939_uint8_t CommandedAddress;
+
+j1939_uint8_t J1939_Address;
+J1939_FLAG    J1939_Flags;
+J1939_MESSAGE OneMessage;
+CAN_NODE      Can_Node;
+// 节点地址
+j1939_uint8_t NodeAddress_1;
+j1939_uint8_t NodeAddress_2;
+j1939_uint8_t NodeAddress_3;
+j1939_uint8_t NodeAddress_4;
+// 接受列队全局变量(CAN_NODE_1)
+j1939_uint8_t RXHead_1;
+j1939_uint8_t RXTail_1;
+j1939_uint8_t RXQueueCount_1;
+J1939_MESSAGE RXQueue_1[J1939_RX_QUEUE_SIZE];
+// 发送列队全局变量 (CAN_NODE_1)
+j1939_uint8_t TXHead_1;
+j1939_uint8_t TXTail_1;
+j1939_uint8_t TXQueueCount_1;
+J1939_MESSAGE TXQueue_1[J1939_TX_QUEUE_SIZE];
+// 接受列队全局变量(CAN_NODE_2)
+j1939_uint8_t RXHead_2;
+j1939_uint8_t RXTail_2;
+j1939_uint8_t RXQueueCount_2;
+J1939_MESSAGE RXQueue_2[J1939_RX_QUEUE_SIZE];
+// 发送列队全局变量 (CAN_NODE_2)
+j1939_uint8_t TXHead_2;
+j1939_uint8_t TXTail_2;
+j1939_uint8_t TXQueueCount_2;
+J1939_MESSAGE TXQueue_2[J1939_TX_QUEUE_SIZE];
+// 接受列队全局变量(CAN_NODE_3)
+j1939_uint8_t RXHead_3;
+j1939_uint8_t RXTail_3;
+j1939_uint8_t RXQueueCount_3;
+J1939_MESSAGE RXQueue_3[J1939_RX_QUEUE_SIZE];
+// 发送列队全局变量 (CAN_NODE_3)
+j1939_uint8_t TXHead_3;
+j1939_uint8_t TXTail_3;
+j1939_uint8_t TXQueueCount_3;
+J1939_MESSAGE TXQueue_3[J1939_TX_QUEUE_SIZE];
+// 接受列队全局变量(CAN_NODE_4)
+j1939_uint8_t RXHead_4;
+j1939_uint8_t RXTail_4;
+j1939_uint8_t RXQueueCount_4;
+J1939_MESSAGE RXQueue_4[J1939_RX_QUEUE_SIZE];
+// 发送列队全局变量 (CAN_NODE_4)
+j1939_uint8_t TXHead_4;
+j1939_uint8_t TXTail_4;
+j1939_uint8_t TXQueueCount_4;
+J1939_MESSAGE TXQueue_4[J1939_TX_QUEUE_SIZE];
+
+struct Request_List REQUEST_LIST;
+
+#if J1939_TP_RX_TX
+// TP协议全局变量
+J1939_TP_Flags          J1939_TP_Flags_t;
+J1939_TRANSPORT_RX_INFO TP_RX_MSG;
+J1939_TRANSPORT_TX_INFO TP_TX_MSG;
+#endif // J1939_TP_RX_TX
+
+static void          J1939_ReceiveMessages(void);
+static j1939_uint8_t J1939_TransmitMessages(void);
+
+/**
+ * @note  硬件滤波器2 或 软件滤波器  滤波配置(设置PS段)\n
+ */
+void SetAddressFilter(j1939_uint8_t Address)
+{
+    /*软件滤波*/
+#if J1939SoftwareFilterEn == J1939_TRUE
+    switch (Can_Node)
+    {
+    case Select_CAN_NODE_1:
+    {
+        NodeAddress_1 = Address;
+        break;
+    }
+    case Select_CAN_NODE_2:
+    {
+        NodeAddress_2 = Address;
+        break;
+    }
+    case Select_CAN_NODE_3:
+    {
+        NodeAddress_3 = Address;
+        break;
+    }
+    case Select_CAN_NODE_4:
+    {
+        NodeAddress_4 = Address;
+        break;
+    }
+    default:
+    {
+        break;
+    }
+    }
+#endif // J1939SoftwareFilterEn
+    /*硬件滤波*/
+    Port_SetAddressFilter(Address);
+}
+
+/**
+ * @param[in]  J1939_MESSAGE *
+ * @note 发送*MsgPtr的信息,所有的数据字段(比如数据长度、优先级、和源地址)必须已经设置。\n
+ */
+void SendOneMessage(J1939_MESSAGE *MsgPtr)
+{
+    // 设置消息的最后部分,确保DataLength规范。(参考CAN B2.0)
+    MsgPtr->Mxe.Res = 0; // 参考J1939的数据链路层(SAE J1939-21)
+    MsgPtr->Mxe.RTR = 0;
+    if (MsgPtr->Mxe.DataLength > 8)
+        MsgPtr->Mxe.DataLength = 8;
+    // 发送一帧消息,将 J1939_MESSAGE 中的所有消息加载道can模块自有的结构中
+    Port_CAN_Transmit(MsgPtr);
+}
+
+/**
+ * @param[in]  MsgPtr             用户要出队的消息
+ * @param[in]  _Can_Node          要出队的CAN硬件编号
+ * @return    RC_SUCCESS          消息出队成功
+ * @return    RC_QUEUEEMPTY       没有消息返回
+ * @note      从接受队列中读取一个信息到*MsgPtr。如果我们用的是中断,需要将中断失能,在获取接受队列数据时
+ */
+j1939_uint8_t J1939_DequeueMessage(J1939_MESSAGE *MsgPtr, CAN_NODE _Can_Node)
+{
+    j1939_uint8_t _rc = RC_SUCCESS;
+
+//***************************关接受中断********************************
+#if J1939_POLL_ECAN == J1939_FALSE
+    Port_RXinterruptDisable();
+#endif
+    switch (_Can_Node)
+    {
+    case Select_CAN_NODE_1:
+    {
+        if (RXQueueCount_1 == 0)
+        {
+            _rc = RC_QUEUEEMPTY;
+        }
+        else
+        {
+            *MsgPtr = RXQueue_1[RXHead_1];
+            RXHead_1++;
+            if (RXHead_1 >= J1939_RX_QUEUE_SIZE)
+                RXHead_1 = 0;
+            RXQueueCount_1--;
+        }
+        break;
+    }
+    case Select_CAN_NODE_2:
+    {
+        if (RXQueueCount_2 == 0)
+        {
+            _rc = RC_QUEUEEMPTY;
+        }
+        else
+        {
+            *MsgPtr = RXQueue_2[RXHead_2];
+            RXHead_2++;
+            if (RXHead_2 >= J1939_RX_QUEUE_SIZE)
+                RXHead_2 = 0;
+            RXQueueCount_2--;
+        }
+        break;
+    }
+    case Select_CAN_NODE_3:
+    {
+        if (RXQueueCount_3 == 0)
+        {
+            _rc = RC_QUEUEEMPTY;
+        }
+        else
+        {
+            *MsgPtr = RXQueue_3[RXHead_3];
+            RXHead_3++;
+            if (RXHead_3 >= J1939_RX_QUEUE_SIZE)
+                RXHead_3 = 0;
+            RXQueueCount_3--;
+        }
+        break;
+    }
+    case Select_CAN_NODE_4:
+    {
+        if (RXQueueCount_4 == 0)
+        {
+            _rc = RC_QUEUEEMPTY;
+        }
+        else
+        {
+            *MsgPtr = RXQueue_4[RXHead_4];
+            RXHead_4++;
+            if (RXHead_4 >= J1939_RX_QUEUE_SIZE)
+                RXHead_4 = 0;
+            RXQueueCount_4--;
+        }
+        break;
+    }
+    default:
+    {
+        _rc = RC_CANNOTRECEIVE;
+        break;
+    }
+    }
+    //***************************开接受中断********************************
+#if J1939_POLL_ECAN == J1939_FALSE
+    Port_RXinterruptEnable();
+#endif
+
+    return _rc;
+}
+/**
+ * @param[in] MsgPtr              存储读取消息的缓存
+ * @param[in] _Can_Node           读取消息的CAN硬件编号(从哪一路CAN读取数据)
+ * @return    RC_SUCCESS          读取消息成功,
+ * @return    RC_QUEUEEMPTY       读取消息不成功,没有消息。
+ * @note      从接受队列中读取一个信息到*MsgPtr。
+ */
+j1939_uint8_t J1939_Read_Message(J1939_MESSAGE *MsgPtr, CAN_NODE _Can_Node)
+{
+    return J1939_DequeueMessage(MsgPtr, _Can_Node);
+}
+/**
+* @param[in]  MsgPtr     用户要入队的消息
+* @param[in]  _Can_Node  要入队的CAN硬件编号(要选择的使用的CAN硬件编号)
+* @return     RC_SUCCESS          消息入队成功
+* @return     RC_QUEUEFULL        发送列队满,消息入队失败
+* @return     RC_CANNOTTRANSMIT   系统目前不能发送消息
+* @note     这段程序,将*MsgPtr放入发送消息列队中\n
+            如果信息不能入队或者发送,将有一个相应的返回提示,\n
+            如果发送中断被设置(可用),当消息列队后,发送中断被使能
+*/
+j1939_uint8_t J1939_EnqueueMessage(J1939_MESSAGE *MsgPtr, CAN_NODE _Can_Node)
+{
+    j1939_uint8_t _rc = RC_SUCCESS;
+
+#if J1939_POLL_ECAN == J1939_FALSE
+    Port_TXinterruptDisable();
+#endif
+
+    if (0)
+        _rc = RC_CANNOTTRANSMIT;
+    else
+    {
+        switch (_Can_Node)
+        {
+        case Select_CAN_NODE_1:
+        {
+            if ((J1939_OVERWRITE_TX_QUEUE == J1939_TRUE) ||
+                (TXQueueCount_1 < J1939_TX_QUEUE_SIZE))
+            {
+                if (TXQueueCount_1 < J1939_TX_QUEUE_SIZE)
+                {
+                    TXQueueCount_1++;
+                    TXTail_1++;
+                    if (TXTail_1 >= J1939_TX_QUEUE_SIZE)
+                        TXTail_1 = 0;
+                }
+                else
+                {
+                    J1939_Flags.TransmitMessagesdCover = 1; // 发送数据被覆盖,上一帧数据被覆盖
+                }
+                TXQueue_1[TXTail_1] = *MsgPtr;
+            }
+            else
+                _rc = RC_QUEUEFULL;
+            break;
+        }
+        case Select_CAN_NODE_2:
+        {
+            if ((J1939_OVERWRITE_TX_QUEUE == J1939_TRUE) ||
+                (TXQueueCount_2 < J1939_TX_QUEUE_SIZE))
+            {
+                if (TXQueueCount_2 < J1939_TX_QUEUE_SIZE)
+                {
+                    TXQueueCount_2++;
+                    TXTail_2++;
+                    if (TXTail_2 >= J1939_TX_QUEUE_SIZE)
+                        TXTail_2 = 0;
+                }
+                else
+                {
+                    J1939_Flags.TransmitMessagesdCover = 1; // 发送数据被覆盖,上一帧数据被覆盖
+                }
+                TXQueue_2[TXTail_2] = *MsgPtr;
+            }
+            else
+                _rc = RC_QUEUEFULL;
+            break;
+        }
+        case Select_CAN_NODE_3:
+        {
+            if ((J1939_OVERWRITE_TX_QUEUE == J1939_TRUE) ||
+                (TXQueueCount_3 < J1939_TX_QUEUE_SIZE))
+            {
+                if (TXQueueCount_3 < J1939_TX_QUEUE_SIZE)
+                {
+                    TXQueueCount_3++;
+                    TXTail_3++;
+                    if (TXTail_3 >= J1939_TX_QUEUE_SIZE)
+                        TXTail_3 = 0;
+                }
+                else
+                {
+                    J1939_Flags.TransmitMessagesdCover = 1; // 发送数据被覆盖,上一帧数据被覆盖
+                }
+                TXQueue_3[TXTail_3] = *MsgPtr;
+            }
+            else
+                _rc = RC_QUEUEFULL;
+            break;
+        }
+        case Select_CAN_NODE_4:
+        {
+            if ((J1939_OVERWRITE_TX_QUEUE == J1939_TRUE) ||
+                (TXQueueCount_4 < J1939_TX_QUEUE_SIZE))
+            {
+                if (TXQueueCount_4 < J1939_TX_QUEUE_SIZE)
+                {
+                    TXQueueCount_4++;
+                    TXTail_4++;
+                    if (TXTail_4 >= J1939_TX_QUEUE_SIZE)
+                        TXTail_4 = 0;
+                }
+                else
+                {
+                    J1939_Flags.TransmitMessagesdCover = 1; // 发送数据被覆盖,上一帧数据被覆盖
+                }
+                TXQueue_4[TXTail_4] = *MsgPtr;
+            }
+            else
+                _rc = RC_QUEUEFULL;
+            break;
+        }
+        default:
+        {
+            break;
+        }
+        }
+    }
+
+#if J1939_POLL_ECAN == J1939_FALSE
+    Port_TXinterruptEnable();
+    // 触发发送中断
+    Port_TXinterruptOk();
+#endif
+    return _rc;
+}
+/**
+ * @param[in]  MsgPtr              存储发送消息的缓存
+ * @param[in]  _Can_Node           发送消息的CAN硬件编号(从哪一路CAN发送数据)
+ * @return     RC_SUCCESS          发送消息成功
+ * @return     RC_QUEUEFULL        发送消息不成功,发送列队满,消息入队失败
+ * @return     RC_CANNOTTRANSMIT   发送消息不成功,系统目前不能发送消息
+ * @note       如果信息不能入队或者发送,将有一个相应的返回提示,\n
+ */
+j1939_uint8_t J1939_Send_Message(J1939_MESSAGE *MsgPtr, CAN_NODE _Can_Node)
+{
+    return J1939_EnqueueMessage(MsgPtr, _Can_Node);
+}
+
+void j1939_msg_push_queue(p_pdu_tag rec_msg)
+{
+    J1939_MESSAGE _msg;
+
+    _msg.Mxe.DataPage      = rec_msg->id.b.dp;
+    _msg.Mxe.Priority      = rec_msg->id.b.p;
+    _msg.Mxe.PDUFormat     = rec_msg->id.b.pf;
+    _msg.Mxe.PDUSpecific   = rec_msg->id.b.ps;
+    _msg.Mxe.SourceAddress = rec_msg->id.b.sa;
+    _msg.Mxe.DataLength    = rec_msg->reg.dlc;
+    _msg.Mxe.PGN           = 0;
+
+    for (uint8_t index = 0; index < rec_msg->reg.dlc; index++)
+    {
+        _msg.Mxe.Data[index] = rec_msg->data.u8_buf[index];
+    }
+    // en_queue(&j1939_rx_queue, _msg);
+}
+
+/**
+*
+* @note 这段代码在系统初始化中被调用,(放在CAN设备初始化之后)\n
+        初始化J1939全局变量\n
+*/
+void J1939_Initialization()
+{
+    /*初始化全局变量*/
+    J1939_Flags.FlagVal = 0; // 没有声明地址,其他的标识位将被设置为0(复位)
+
+    /*初始化接受和发送列队*/
+    TXHead_1       = 0;
+    TXHead_2       = 0;
+    TXHead_3       = 0;
+    TXHead_4       = 0;
+    TXTail_1       = 0xFF;
+    TXTail_2       = 0xFF;
+    TXTail_3       = 0xFF;
+    TXTail_4       = 0xFF;
+    RXHead_1       = 0;
+    RXHead_2       = 0;
+    RXHead_3       = 0;
+    RXHead_4       = 0;
+    RXTail_1       = 0xFF;
+    RXTail_2       = 0xFF;
+    RXTail_3       = 0xFF;
+    RXTail_4       = 0xFF;
+    TXQueueCount_1 = 0;
+    TXQueueCount_2 = 0;
+    TXQueueCount_3 = 0;
+    TXQueueCount_4 = 0;
+    RXQueueCount_1 = 0;
+    RXQueueCount_2 = 0;
+    RXQueueCount_3 = 0;
+    RXQueueCount_4 = 0;
+    /*初始化节点地址*/
+    NodeAddress_1 = J1939_STARTING_ADDRESS_1;
+    NodeAddress_2 = J1939_STARTING_ADDRESS_2;
+    NodeAddress_3 = J1939_STARTING_ADDRESS_3;
+    NodeAddress_4 = J1939_STARTING_ADDRESS_4;
+    /*初始化CAN节点的选择*/
+    Can_Node = Select_CAN_NODE_1;
+    /*初始化请求链表*/
+    REQUEST_LIST.PGN      = 0;
+    REQUEST_LIST.data     = J1939_NULL;
+    REQUEST_LIST.update   = J1939_NULL;
+    REQUEST_LIST.lenght   = 0;
+    REQUEST_LIST.Can_Node = Select_CAN_NODE_Null;
+    REQUEST_LIST.next     = J1939_NULL;
+    /*将TP协议置为空闲*/
+#if J1939_TP_RX_TX
+    J1939_TP_Flags_t.state          = J1939_TP_NULL;
+    J1939_TP_Flags_t.TP_RX_CAN_NODE = Select_CAN_NODE_Null;
+    J1939_TP_Flags_t.TP_TX_CAN_NODE = Select_CAN_NODE_Null;
+
+    TP_TX_MSG.packets_request_num = 0;
+    TP_TX_MSG.packets_total       = 0;
+    TP_TX_MSG.packet_offset_p     = 0;
+    TP_TX_MSG.time                = 0;
+    TP_TX_MSG.state               = J1939_TP_TX_WAIT;
+
+    TP_RX_MSG.packets_ok_num = 0;
+    TP_RX_MSG.packets_total  = 0;
+    TP_RX_MSG.time           = 0;
+    TP_RX_MSG.state          = J1939_TP_RX_WAIT;
+#endif
+}
+
+/**
+* @note 这个函数被调用,当设备产生CAN中断(可能是接受中断,也可能是发送中断)\n
+        首先我们要清除中断标识位\n
+        然后调用接受或者发送函数。
+*/
+#if J1939_POLL_ECAN == J1939_FALSE
+void J1939_ISR(void)
+{
+    // 判断相关标识位,是接受还是发送
+    // 清除标识位
+    Port_CAN_identifier_clc();
+    // 调用相关的处理函数
+    J1939_ReceiveMessages();
+    J1939_TransmitMessages();
+#if J1939_TP_RX_TX
+    J1939_TP_Poll();
+#endif // J1939_TP_RX_TX
+    // 可能存在因为错误产生中断,直接清除相关的标识位
+}
+#endif
+
+/**
+* @param[in]  ElapsedTime   一个大概的毫秒数,通常设置 5 或 3
+* @note 如果我们采用轮询的方式获取信息,这个函数每几个毫秒将被调用一次。\n
+        不断的接受消息和发送消息从消息队列中\n
+        此外,如果我们正在等待一个地址竞争反应。\n
+        如果超时,我们只接收特定的消息(目标地址 = J1939_Address)\n
+
+        如果设备使用中断,此函数被调用,在调用J1939_Initialization()函数后,因为\n
+        J1939_Initialization()可能初始化WaitingForAddressClaimContention标识位为1.\n
+
+        如果接受到命令地址消息,这个函数也必须被调用,以防万一总线要求我们改变地址\n
+
+        如果使用中断模式,本程序将不会处理接受和发送消息,只处理地址竞争超时。\n
+*/
+// 声明TP轮询函数
+void J1939_TP_Poll();
+void J1939_Poll()
+{
+    // 我们必须调用J1939_ReceiveMessages接受函数,在时间被重置为0之前。
+#if J1939_POLL_ECAN == J1939_TRUE
+    Can_Node      = Select_CAN_NODE_1;
+    J1939_Address = NodeAddress_1;
+    J1939_ReceiveMessages();
+    J1939_TransmitMessages();
+    Can_Node      = Select_CAN_NODE_2;
+    J1939_Address = NodeAddress_2;
+    J1939_ReceiveMessages();
+    J1939_TransmitMessages();
+    Can_Node      = Select_CAN_NODE_3;
+    J1939_Address = NodeAddress_3;
+    J1939_ReceiveMessages();
+    J1939_TransmitMessages();
+    Can_Node      = Select_CAN_NODE_4;
+    J1939_Address = NodeAddress_4;
+    J1939_ReceiveMessages();
+    J1939_TransmitMessages();
+#if J1939_TP_RX_TX
+    J1939_TP_Poll();
+#endif // J1939_TP_RX_TX
+#endif // J1939_POLL_ECAN == J1939_TRUE
+}
+void J1939_Response(const j1939_uint32_t PGN);
+
+#if J1939SoftwareFilterEn == J1939_TRUE
+
+/**
+* @return    RC_SUCCESS         消息是可以接受
+* @return    RC_CANNOTTRANSMIT  消息是不可以接受
+* @note 软件滤波器\n
+* @note 基于SAE J1939协议,我们需要CAN控制器提供至少3个滤波器给J1939协议代码。三个滤波器分别配置如下:
+        1. 设置滤波器0,只接受广播信息(PF = 240 -255)。
+        2. 设置设置滤波器1,2只接受全局地址(J1939_GLOBAL_ADDRESS)
+        3. 随着程序的运行,将改变滤波器2,来适应程序逻辑。
+*/
+j1939_uint8_t J1939_Messages_Filter(J1939_MESSAGE *MsgPtr)
+{
+    /*滤波器0*/
+    if ((MsgPtr->Mxe.PDUFormat) >= 240)
+    {
+        return RC_SUCCESS;
+    }
+    /*滤波器1*/
+    if (((MsgPtr->Mxe.PDUFormat) < 240) && (MsgPtr->Mxe.PDUSpecific == J1939_GLOBAL_ADDRESS))
+    {
+        return RC_SUCCESS;
+    }
+    /*滤波器2*/
+    switch (Can_Node)
+    {
+    case Select_CAN_NODE_1:
+    {
+        if (((MsgPtr->Mxe.PDUFormat) < 240) && (MsgPtr->Mxe.PDUSpecific == NodeAddress_1))
+        {
+            return RC_SUCCESS;
+        }
+        break;
+    }
+    case Select_CAN_NODE_2:
+    {
+        if (((MsgPtr->Mxe.PDUFormat) < 240) && (MsgPtr->Mxe.PDUSpecific == NodeAddress_2))
+        {
+            return RC_SUCCESS;
+        }
+        break;
+    }
+    case Select_CAN_NODE_3:
+    {
+        if (((MsgPtr->Mxe.PDUFormat) < 240) && (MsgPtr->Mxe.PDUSpecific == NodeAddress_3))
+        {
+            return RC_SUCCESS;
+        }
+        break;
+    }
+    case Select_CAN_NODE_4:
+    {
+        if (((MsgPtr->Mxe.PDUFormat) < 240) && (MsgPtr->Mxe.PDUSpecific == NodeAddress_4))
+        {
+            return RC_SUCCESS;
+        }
+        break;
+    }
+    default:
+    {
+        break;
+    }
+    }
+    return RC_CANNOTTRANSMIT;
+}
+
+#endif // J1939SoftwareFilterEn
+
+/**
+* @note 这段程序被调用,当CAN收发器接受数据(中断 或者 轮询)。\n
+        如果一个信息被接受, 它将被调用\n
+        如果信息是一个网络管理信息或长帧传输(TP),接受的信息将被加工处理,在这个函数中。\n
+        否则, 信息将放置在用户的接收队列。\n
+        注意:在这段程序运行期间中断是失能的。\n
+*/
+void J1939_ReceiveMessages(void)
+{
+#if J1939_TP_RX_TX
+    j1939_uint32_t _pgn = 0;
+#endif // J1939_TP_RX_TX
+    /*从接收缓存中读取信息到OneMessage中,OneMessage是一个全局变量*/
+    /*Port_CAN_Receive函数读取到数据返回1,没有数据则返回0*/
+    if (Port_CAN_Receive(&OneMessage))
+    {
+#if J1939SoftwareFilterEn == J1939_TRUE
+        if (J1939_Messages_Filter(&OneMessage) != RC_SUCCESS)
+        {
+            return;
+        }
+#endif // J1939SoftwareFilterEn
+        switch (OneMessage.Mxe.PDUFormat)
+        {
+#if J1939_TP_RX_TX
+        case J1939_PF_TP_CM: // 参考J1939-21 TP多帧传输协议
+            _pgn = (j1939_uint32_t)((OneMessage.Mxe.Data[7] << 16) & 0xFF0000) + (j1939_uint32_t)((OneMessage.Mxe.Data[6] << 8) & 0xFF00) + (j1939_uint32_t)((OneMessage.Mxe.Data[5]) & 0xFF);
+            if ((J1939_TP_Flags_t.state == J1939_TP_NULL) && (TP_RX_MSG.state == J1939_TP_RX_WAIT))
+            {
+                if (OneMessage.Mxe.Data[0] == 16)
+                {
+                    J1939_TP_Flags_t.state          = J1939_TP_RX;
+                    J1939_TP_Flags_t.TP_RX_CAN_NODE = Can_Node;
+
+                    TP_RX_MSG.tp_rx_msg.SA  = OneMessage.Mxe.SourceAddress;
+                    TP_RX_MSG.tp_rx_msg.PGN = (j1939_uint32_t)((OneMessage.Mxe.Data[7] << 16) & 0xFF0000) + (j1939_uint32_t)((OneMessage.Mxe.Data[6] << 8) & 0xFF00) + (j1939_uint32_t)((OneMessage.Mxe.Data[5]) & 0xFF);
+                    /*如果系统繁忙*/
+                    if (TP_RX_MSG.osbusy)
+                    {
+                        TP_RX_MSG.state = J1939_TP_RX_ERROR;
+                        break;
+                    }
+                    /*判断是否有足够的内存接收数据,如果没有直接,断开连接*/
+                    if (((j1939_uint32_t)((OneMessage.Mxe.Data[2] << 8) & 0xFF00) + (j1939_uint32_t)((OneMessage.Mxe.Data[1]) & 0xFF)) > J1939_TP_MAX_MESSAGE_LENGTH)
+                    {
+                        TP_RX_MSG.state = J1939_TP_RX_ERROR;
+                        break;
+                    }
+                    TP_RX_MSG.tp_rx_msg.byte_count = ((j1939_uint32_t)((OneMessage.Mxe.Data[2] << 8) & 0xFF00) + (j1939_uint32_t)((OneMessage.Mxe.Data[1]) & 0xFF));
+                    TP_RX_MSG.packets_total        = OneMessage.Mxe.Data[3];
+                    TP_RX_MSG.time                 = J1939_TP_T2;
+                    TP_RX_MSG.state                = J1939_TP_RX_READ_DATA;
+                    break;
+                }
+                goto PutInReceiveQueue;
+                break;
+            }
+            if (J1939_TP_Flags_t.state == J1939_TP_TX)
+            {
+                /*校验PGN*/
+                if (_pgn == TP_TX_MSG.tp_tx_msg.PGN)
+                {
+                    switch (OneMessage.Mxe.Data[0])
+                    {
+                    case J1939_RTS_CONTROL_BYTE:
+                        /* 程序运行到这里,说明已经与网络中设备1建立虚拟链接(作为发送端),但是收到设备2的链接请求,并且同一个PGN消息请求*/
+                        /* 根据J1939-21数据链路层的规定,我们要保持原有的链接,不做任何事,设备2会应为超时自动放弃链接*/
+                        break;
+                    case J1939_CTS_CONTROL_BYTE:
+                        if ((J1939_TP_TX_CM_WAIT == TP_TX_MSG.state) || (J1939_TP_WAIT_ACK == TP_TX_MSG.state))
+                        {
+                            /* 发送等待保持 */
+                            if (0x00u == OneMessage.Mxe.Data[1])
+                            {
+                                /* 刷新等待计数器 */
+                                TP_TX_MSG.time = J1939_TP_T4;
+                            }
+                            else
+                            {
+                                if ((OneMessage.Mxe.Data[2] + OneMessage.Mxe.Data[1]) > (TP_TX_MSG.packets_total + 1))
+                                {
+                                    /*请求超出数据包范围*/
+                                    TP_TX_MSG.state = J1939_TP_TX_ERROR;
+                                }
+                                else
+                                { /* response parameter OK */
+                                    TP_TX_MSG.packets_request_num = OneMessage.Mxe.Data[1];
+                                    TP_TX_MSG.packet_offset_p     = (j1939_uint8_t)(OneMessage.Mxe.Data[2] - 1);
+                                    TP_TX_MSG.state               = J1939_TP_TX_DT;
+                                }
+                            }
+                        }
+                        break;
+                    case J1939_EOMACK_CONTROL_BYTE:
+                        if (J1939_TP_WAIT_ACK == TP_TX_MSG.state)
+                        {
+                            TP_TX_MSG.state = J1939_TX_DONE;
+                        }
+                        // 这里可以增加一个对数据的校验
+                        break;
+                    case J1939_CONNABORT_CONTROL_BYTE:
+                        // 收到一个放弃连接,什么都不做,协议会在一段延时时间后主动放弃链接
+                        break;
+                    default:
+                        break;
+                    }
+                }
+            }
+            goto PutInReceiveQueue;
+            break;
+#endif // J1939_TP_RX_TX
+
+#if J1939_TP_RX_TX
+        case J1939_PF_DT:
+            if ((TP_RX_MSG.state == J1939_TP_RX_DATA_WAIT) && (TP_RX_MSG.tp_rx_msg.SA == OneMessage.Mxe.SourceAddress))
+            {
+                TP_RX_MSG.tp_rx_msg.data[(OneMessage.Mxe.Data[0] - 1) * 7u]     = OneMessage.Mxe.Data[1];
+                TP_RX_MSG.tp_rx_msg.data[(OneMessage.Mxe.Data[0] - 1) * 7u + 1] = OneMessage.Mxe.Data[2];
+                TP_RX_MSG.tp_rx_msg.data[(OneMessage.Mxe.Data[0] - 1) * 7u + 2] = OneMessage.Mxe.Data[3];
+                TP_RX_MSG.tp_rx_msg.data[(OneMessage.Mxe.Data[0] - 1) * 7u + 3] = OneMessage.Mxe.Data[4];
+                TP_RX_MSG.tp_rx_msg.data[(OneMessage.Mxe.Data[0] - 1) * 7u + 4] = OneMessage.Mxe.Data[5];
+                TP_RX_MSG.tp_rx_msg.data[(OneMessage.Mxe.Data[0] - 1) * 7u + 5] = OneMessage.Mxe.Data[6];
+                TP_RX_MSG.tp_rx_msg.data[(OneMessage.Mxe.Data[0] - 1) * 7u + 6] = OneMessage.Mxe.Data[7];
+                /*特殊处理重新接受已接受过的数据包*/
+                if ((OneMessage.Mxe.Data[0]) > TP_RX_MSG.packets_ok_num)
+                {
+                    TP_RX_MSG.packets_ok_num++;
+                }
+                TP_RX_MSG.time = J1939_TP_T1;
+                /*判断是否收到偶数个数据包或者读取到最后一个数据包*/
+                if ((TP_RX_MSG.packets_ok_num % 2 == 0) || (TP_RX_MSG.packets_ok_num == TP_RX_MSG.packets_total))
+                {
+                    TP_RX_MSG.state = J1939_TP_RX_READ_DATA;
+                    break;
+                }
+                break;
+            }
+            // 程序不可能运行到这,但是我们不能放弃接受的数据包
+            goto PutInReceiveQueue;
+#endif // J1939_TP_RX_TX
+        case J1939_PF_REQUEST:
+            /*用OneMessage.Mxe.PGN 来存下被请求的PGN*/
+            if (OneMessage.Mxe.Data[1] < 240)
+            {
+                OneMessage.Mxe.PGN = (j1939_uint32_t)((OneMessage.Mxe.Data[2] << 16) & 0x030000) + (j1939_uint32_t)((OneMessage.Mxe.Data[1] << 8) & 0xFF00) + 0x00;
+            }
+            else
+            {
+                OneMessage.Mxe.PGN = (j1939_uint32_t)((OneMessage.Mxe.Data[2] << 16) & 0x030000) + (j1939_uint32_t)((OneMessage.Mxe.Data[1] << 8) & 0xFF00) + (j1939_uint32_t)((OneMessage.Mxe.Data[0]) & 0xFF);
+            }
+            J1939_Response(OneMessage.Mxe.PGN);
+            break;
+        default:
+PutInReceiveQueue:
+{
+    /*
+    if(OneMessage.Mxe.PDUFormat < 240){
+        OneMessage.Mxe.PGN = (j1939_uint32_t)((OneMessage.Array[0]<<16)&0x030000)
+                            +(j1939_uint32_t)((OneMessage.Array[1]<<8)&0xFF00)
+                            +0x00;
+    }else{
+        OneMessage.Mxe.PGN = (j1939_uint32_t)((OneMessage.Array[0]<<16)&0x030000)
+                            +(j1939_uint32_t)((OneMessage.Array[1]<<8)&0xFF00)
+                            +(j1939_uint32_t)((OneMessage.Array[2])&0xFF);
+    }
+    */
+    if (OneMessage.Mxe.PDUFormat < 240)
+    {
+        OneMessage.Mxe.PGN = (OneMessage.Mxe.Res << 17) + (OneMessage.Mxe.DataPage << 16) + (OneMessage.Mxe.PDUFormat << 8);
+    }
+    else
+    {
+        OneMessage.Mxe.PGN = (OneMessage.Mxe.Res << 17) + (OneMessage.Mxe.DataPage << 16) + (OneMessage.Mxe.PDUFormat << 8) + OneMessage.Mxe.PDUSpecific;
+    }
+
+    switch (Can_Node)
+    {
+    case Select_CAN_NODE_1:
+    {
+        if ((J1939_OVERWRITE_RX_QUEUE == J1939_TRUE) ||
+            (RXQueueCount_1 < J1939_RX_QUEUE_SIZE))
+        {
+            if (RXQueueCount_1 < J1939_RX_QUEUE_SIZE)
+            {
+                RXQueueCount_1++;
+                RXTail_1++;
+                if (RXTail_1 >= J1939_RX_QUEUE_SIZE)
+                    RXTail_1 = 0;
+            }
+            else
+            {
+                J1939_Flags.ReceivedMessagesdCover              = 1; // 产生数据覆盖
+                J1939_Flags.ReceivedMessagesdCoverOrDroppedNode = Select_CAN_NODE_1;
+            }
+            RXQueue_1[RXTail_1] = OneMessage;
+        }
+        else
+            J1939_Flags.ReceivedMessagesDropped = 1; // 产生数据溢出
+        break;
+    }
+    case Select_CAN_NODE_2:
+    {
+        if ((J1939_OVERWRITE_RX_QUEUE == J1939_TRUE) ||
+            (RXQueueCount_2 < J1939_RX_QUEUE_SIZE))
+        {
+            if (RXQueueCount_2 < J1939_RX_QUEUE_SIZE)
+            {
+                RXQueueCount_2++;
+                RXTail_2++;
+                if (RXTail_2 >= J1939_RX_QUEUE_SIZE)
+                    RXTail_2 = 0;
+            }
+            else
+            {
+                J1939_Flags.ReceivedMessagesdCover              = 1; // 产生数据覆盖
+                J1939_Flags.ReceivedMessagesdCoverOrDroppedNode = Select_CAN_NODE_2;
+            }
+            RXQueue_2[RXTail_2] = OneMessage;
+        }
+        else
+            J1939_Flags.ReceivedMessagesDropped = 1;
+        break;
+    }
+    case Select_CAN_NODE_3:
+    {
+        if ((J1939_OVERWRITE_RX_QUEUE == J1939_TRUE) ||
+            (RXQueueCount_3 < J1939_RX_QUEUE_SIZE))
+        {
+            if (RXQueueCount_3 < J1939_RX_QUEUE_SIZE)
+            {
+                RXQueueCount_3++;
+                RXTail_3++;
+                if (RXTail_3 >= J1939_RX_QUEUE_SIZE)
+                    RXTail_3 = 0;
+            }
+            else
+            {
+                J1939_Flags.ReceivedMessagesdCover              = 1; // 产生数据覆盖
+                J1939_Flags.ReceivedMessagesdCoverOrDroppedNode = Select_CAN_NODE_3;
+            }
+            RXQueue_3[RXTail_3] = OneMessage;
+        }
+        else
+            J1939_Flags.ReceivedMessagesDropped = 1;
+        break;
+    }
+    case Select_CAN_NODE_4:
+    {
+        if ((J1939_OVERWRITE_RX_QUEUE == J1939_TRUE) ||
+            (RXQueueCount_4 < J1939_RX_QUEUE_SIZE))
+        {
+            if (RXQueueCount_4 < J1939_RX_QUEUE_SIZE)
+            {
+                RXQueueCount_4++;
+                RXTail_4++;
+                if (RXTail_4 >= J1939_RX_QUEUE_SIZE)
+                    RXTail_4 = 0;
+            }
+            else
+            {
+                J1939_Flags.ReceivedMessagesdCover              = 1; // 产生数据覆盖
+                J1939_Flags.ReceivedMessagesdCoverOrDroppedNode = Select_CAN_NODE_4;
+            }
+            RXQueue_4[RXTail_4] = OneMessage;
+        }
+        else
+            J1939_Flags.ReceivedMessagesDropped = 1;
+        break;
+    }
+    default:
+    {
+        break;
+    }
+    }
+}
+        }
+    }
+}
+
+/**
+* @return    RC_SUCCESS          信息发送成功
+* @return    RC_CANNOTTRANSMIT   系统没有发送消息,没有要发送的消息,或错误的CAN设备
+* @note      调用这个函数后,如果发送消息列队中有消息就位,则会发送消息 ,如果不能发送消息,相关的错误代码将返回。\n
+             程序运行期间,中断是被失能的。
+*/
+static j1939_uint8_t J1939_TransmitMessages()
+{
+    switch (Can_Node)
+    {
+    case Select_CAN_NODE_1:
+    {
+        if (TXQueueCount_1 == 0)
+        {
+            // 如果没有要发送的消息从发送消息列队中,恢复中断(清空发送标识位)
+#if J1939_POLL_ECAN == J1939_FALSE
+            Port_TXinterruptEnable();
+#endif
+            return RC_CANNOTTRANSMIT;
+        }
+        else
+        {
+            while (TXQueueCount_1 > 0)
+            {
+                /*确保上次数据发送成功*/
+                /**************可增加一个判断函数**************************/
+
+                TXQueue_1[TXHead_1].Mxe.SourceAddress = NodeAddress_1;
+
+                SendOneMessage((J1939_MESSAGE *)&(TXQueue_1[TXHead_1]));
+                TXHead_1++;
+                if (TXHead_1 >= J1939_TX_QUEUE_SIZE)
+                    TXHead_1 = 0;
+                TXQueueCount_1--;
+            }
+
+            /*配置了一些标识位,使能中断*/
+#if J1939_POLL_ECAN == J1939_FALSE
+            Port_TXinterruptEnable();
+#endif
+        }
+        break;
+    }
+    case Select_CAN_NODE_2:
+    {
+        if (TXQueueCount_2 == 0)
+        {
+            // 如果没有要发送的消息从发送消息列队中,恢复中断(清空发送标识位)
+#if J1939_POLL_ECAN == J1939_FALSE
+            Port_TXinterruptEnable();
+#endif
+            return RC_CANNOTTRANSMIT;
+        }
+        else
+        {
+
+            while (TXQueueCount_2 > 0)
+            {
+                /*确保上次数据发送成功*/
+                /**************可增加一个判断函数**************************/
+
+                TXQueue_2[TXHead_2].Mxe.SourceAddress = NodeAddress_2;
+
+                SendOneMessage((J1939_MESSAGE *)&(TXQueue_2[TXHead_2]));
+                TXHead_2++;
+                if (TXHead_2 >= J1939_TX_QUEUE_SIZE)
+                    TXHead_2 = 0;
+                TXQueueCount_2--;
+            }
+
+            /*配置了一些标识位,使能中断*/
+#if J1939_POLL_ECAN == J1939_FALSE
+            Port_TXinterruptEnable();
+#endif
+        }
+        break;
+    }
+    case Select_CAN_NODE_3:
+    {
+        if (TXQueueCount_3 == 0)
+        {
+            // 如果没有要发送的消息从发送消息列队中,恢复中断(清空发送标识位)
+#if J1939_POLL_ECAN == J1939_FALSE
+            Port_TXinterruptEnable();
+#endif
+            return RC_CANNOTTRANSMIT;
+        }
+        else
+        {
+            while (TXQueueCount_3 > 0)
+            {
+                /*确保上次数据发送成功*/
+                /**************可增加一个判断函数**************************/
+
+                TXQueue_3[TXHead_3].Mxe.SourceAddress = NodeAddress_3;
+
+                SendOneMessage((J1939_MESSAGE *)&(TXQueue_3[TXHead_3]));
+                TXHead_3++;
+                if (TXHead_3 >= J1939_TX_QUEUE_SIZE)
+                    TXHead_3 = 0;
+                TXQueueCount_3--;
+            }
+
+            /*配置了一些标识位,使能中断*/
+#if J1939_POLL_ECAN == J1939_FALSE
+            Port_TXinterruptEnable();
+#endif
+        }
+        break;
+    }
+    case Select_CAN_NODE_4:
+    {
+        if (TXQueueCount_4 == 0)
+        {
+            // 如果没有要发送的消息从发送消息列队中,恢复中断(清空发送标识位)
+#if J1939_POLL_ECAN == J1939_FALSE
+            Port_TXinterruptEnable();
+#endif
+            return RC_CANNOTTRANSMIT;
+        }
+        else
+        {
+
+            while (TXQueueCount_4 > 0)
+            {
+                /*确保上次数据发送成功*/
+                /**************可增加一个判断函数**************************/
+
+                TXQueue_4[TXHead_4].Mxe.SourceAddress = NodeAddress_4;
+
+                SendOneMessage((J1939_MESSAGE *)&(TXQueue_4[TXHead_4]));
+                TXHead_4++;
+                if (TXHead_4 >= J1939_TX_QUEUE_SIZE)
+                    TXHead_4 = 0;
+                TXQueueCount_4--;
+            }
+
+            /*配置了一些标识位,使能中断*/
+#if J1939_POLL_ECAN == J1939_FALSE
+            Port_TXinterruptEnable();
+#endif
+        }
+        break;
+    }
+    default:
+    {
+        return RC_CANNOTTRANSMIT;
+        break;
+    }
+    }
+
+    return RC_SUCCESS;
+}
+#if J1939_TP_RX_TX
+/**
+ * @note 发送TP.DT,参考J1939-21
+ */
+void J1939_TP_DT_Packet_send(void)
+{
+    J1939_MESSAGE  _msg;
+    j1939_uint16_t _packet_offset_p;
+    j1939_int32_t  _i           = 0;
+    _msg.Mxe.Priority           = J1939_TP_DT_PRIORITY;
+    _msg.Mxe.DataPage           = 0;
+    _msg.Mxe.PDUFormat          = J1939_PF_DT;
+    _msg.Mxe.DestinationAddress = TP_TX_MSG.tp_tx_msg.SA;
+    _msg.Mxe.DataLength         = 8;
+
+    /*获取请求发送的数据包数量*/
+    if (TP_TX_MSG.packets_request_num > 0)
+    {
+        TP_TX_MSG.packets_request_num--;
+        /*获取数据偏移指针*/
+        _packet_offset_p = (j1939_uint16_t)(TP_TX_MSG.packet_offset_p * 7u);
+        /*加载数据包编号*/
+        _msg.Mxe.Data[0] = (j1939_uint8_t)(1u + TP_TX_MSG.packet_offset_p);
+
+        for (_i = 0; _i < 7; _i++)
+        {
+            _msg.Mxe.Data[_i + 1] = TP_TX_MSG.tp_tx_msg.data[_packet_offset_p + _i];
+        }
+        /*是否是最后一包数据消息*/
+        if (TP_TX_MSG.packet_offset_p == (TP_TX_MSG.packets_total - 1u))
+        {
+            /*参数群是否能被填满,是否需要填充,*/
+            if (_packet_offset_p > TP_TX_MSG.tp_tx_msg.byte_count - 7)
+            {
+                /*计算需要填充的数据数*/
+                _i = TP_TX_MSG.tp_tx_msg.byte_count - _packet_offset_p - 7;
+
+                for (; _i < 0; _i++)
+                {
+                    /*我们默认J1939的参数群大小为8*/
+                    _msg.Mxe.Data[_i + 8] = J1939_RESERVED_BYTE;
+                }
+            }
+
+            TP_TX_MSG.packets_request_num = 0;
+            TP_TX_MSG.packet_offset_p     = 0;
+            TP_TX_MSG.time                = J1939_TP_T3;
+            /* 跳转步骤,等待结束确认或则重新发送数据请求*/
+            TP_TX_MSG.state = J1939_TP_WAIT_ACK;
+        }
+        else
+        {
+            /*为下一个数据发送做准备*/
+            TP_TX_MSG.packet_offset_p++;
+            TP_TX_MSG.state = J1939_TP_TX_DT;
+        }
+
+        /*可能队列已满,发不出去,但是这里不能靠返回值进行无限的死等*/
+        J1939_EnqueueMessage(&_msg, Can_Node);
+    }
+    else
+    {
+
+        TP_TX_MSG.packets_request_num = 0;
+        TP_TX_MSG.packet_offset_p     = 0;
+        TP_TX_MSG.time                = J1939_TP_T3;
+        TP_TX_MSG.state               = J1939_TP_WAIT_ACK;
+    }
+}
+/**
+ * @note 发送TP。CM-RTS,16,23,4,255,PGN消息,参考J1939-21,
+ */
+void J1939_CM_Start(void)
+{
+    j1939_uint32_t pgn_num;
+    J1939_MESSAGE  _msg;
+
+    pgn_num = TP_TX_MSG.tp_tx_msg.PGN;
+
+    _msg.Mxe.Priority           = J1939_TP_CM_PRIORITY;
+    _msg.Mxe.DataPage           = 0;
+    _msg.Mxe.PDUFormat          = J1939_PF_TP_CM;
+    _msg.Mxe.DestinationAddress = TP_TX_MSG.tp_tx_msg.SA;
+    _msg.Mxe.DataLength         = 8;
+    _msg.Mxe.Data[0]            = J1939_RTS_CONTROL_BYTE;
+    _msg.Mxe.Data[1]            = (j1939_uint8_t)TP_TX_MSG.tp_tx_msg.byte_count;
+    _msg.Mxe.Data[2]            = (j1939_uint8_t)((TP_TX_MSG.tp_tx_msg.byte_count) >> 8);
+    _msg.Mxe.Data[3]            = TP_TX_MSG.packets_total;
+    _msg.Mxe.Data[4]            = J1939_RESERVED_BYTE;
+    _msg.Mxe.Data[7]            = (j1939_uint8_t)((pgn_num >> 16) & 0xff);
+    _msg.Mxe.Data[6]            = (j1939_uint8_t)(pgn_num >> 8 & 0xff);
+    _msg.Mxe.Data[5]            = (j1939_uint8_t)(pgn_num & 0xff);
+
+    /*可能队列已满,发不出去,但是这里不能靠返回值进行无限的死等*/
+    J1939_EnqueueMessage(&_msg, Can_Node);
+
+    /*刷新等待时间,触发下一个步骤()*/
+    TP_TX_MSG.time  = J1939_TP_T3;
+    TP_TX_MSG.state = J1939_TP_TX_CM_WAIT;
+}
+/**
+ * @note 中断TP链接
+ */
+void J1939_TP_TX_Abort(void)
+{
+    J1939_MESSAGE  _msg;
+    j1939_uint32_t pgn_num;
+
+    pgn_num = TP_TX_MSG.tp_tx_msg.PGN;
+
+    _msg.Mxe.Priority           = J1939_TP_CM_PRIORITY;
+    _msg.Mxe.DataPage           = 0;
+    _msg.Mxe.PDUFormat          = J1939_PF_TP_CM;
+    _msg.Mxe.DestinationAddress = TP_TX_MSG.tp_tx_msg.SA;
+    _msg.Mxe.DataLength         = 8;
+    _msg.Mxe.Data[0]            = J1939_CONNABORT_CONTROL_BYTE;
+    _msg.Mxe.Data[1]            = J1939_RESERVED_BYTE;
+    _msg.Mxe.Data[2]            = J1939_RESERVED_BYTE;
+    _msg.Mxe.Data[3]            = J1939_RESERVED_BYTE;
+    _msg.Mxe.Data[4]            = J1939_RESERVED_BYTE;
+    _msg.Mxe.Data[7]            = (j1939_uint8_t)((pgn_num >> 16) & 0xff);
+    _msg.Mxe.Data[6]            = (j1939_uint8_t)(pgn_num >> 8 & 0xff);
+    _msg.Mxe.Data[5]            = (j1939_uint8_t)(pgn_num & 0xff);
+
+    /*可能队列已满,发不出去,但是这里不能靠返回值进行无限的死等*/
+    J1939_EnqueueMessage(&_msg, Can_Node);
+    /*结束发送*/
+    TP_TX_MSG.state = J1939_TX_DONE;
+}
+/**
+ * @note 中断TP链接
+ */
+void J1939_TP_RX_Abort(void)
+{
+    J1939_MESSAGE  _msg;
+    j1939_uint32_t pgn_num;
+
+    pgn_num = TP_RX_MSG.tp_rx_msg.PGN;
+
+    _msg.Mxe.Priority           = J1939_TP_CM_PRIORITY;
+    _msg.Mxe.DataPage           = 0;
+    _msg.Mxe.PDUFormat          = J1939_PF_TP_CM;
+    _msg.Mxe.DestinationAddress = TP_RX_MSG.tp_rx_msg.SA;
+    _msg.Mxe.DataLength         = 8;
+    _msg.Mxe.Data[0]            = J1939_CONNABORT_CONTROL_BYTE;
+    _msg.Mxe.Data[1]            = J1939_RESERVED_BYTE;
+    _msg.Mxe.Data[2]            = J1939_RESERVED_BYTE;
+    _msg.Mxe.Data[3]            = J1939_RESERVED_BYTE;
+    _msg.Mxe.Data[4]            = J1939_RESERVED_BYTE;
+    _msg.Mxe.Data[7]            = (j1939_uint8_t)((pgn_num >> 16) & 0xff);
+    _msg.Mxe.Data[6]            = (j1939_uint8_t)(pgn_num >> 8 & 0xff);
+    _msg.Mxe.Data[5]            = (j1939_uint8_t)(pgn_num & 0xff);
+
+    /*可能队列已满,发不出去,但是这里不能靠返回值进行无限的死等*/
+    J1939_EnqueueMessage(&_msg, Can_Node);
+    /*结束发送*/
+    TP_RX_MSG.state = J1939_RX_DONE;
+}
+/**
+ * @note TP的计时器
+ */
+j1939_uint8_t J1939_TP_TX_RefreshCMTimer(j1939_uint16_t dt_ms)
+{
+    if ((J1939_TP_TX_CM_WAIT == TP_TX_MSG.state) || (J1939_TP_WAIT_ACK == TP_TX_MSG.state))
+    {
+        if (TP_TX_MSG.time > dt_ms)
+        {
+            TP_TX_MSG.time = TP_TX_MSG.time - dt_ms;
+            return J1939_TP_TIMEOUT_NORMAL;
+        }
+        else
+        {
+            /*超时 */
+            TP_TX_MSG.time = 0u;
+            return J1939_TP_TIMEOUT_ABNORMAL;
+        }
+    }
+    else
+    {
+        return J1939_TP_TIMEOUT_NORMAL;
+    }
+}
+/**
+ * @note TP的计时器
+ */
+j1939_uint8_t J1939_TP_RX_RefreshCMTimer(j1939_uint16_t dt_ms)
+{
+    if ((J1939_TP_RX_DATA_WAIT == TP_RX_MSG.state))
+    {
+        if (TP_RX_MSG.time > dt_ms)
+        {
+            TP_RX_MSG.time = TP_RX_MSG.time - dt_ms;
+            return J1939_TP_TIMEOUT_NORMAL;
+        }
+        else
+        {
+            /*超时 */
+            TP_RX_MSG.time = 0u;
+            return J1939_TP_TIMEOUT_ABNORMAL;
+        }
+    }
+    else
+    {
+        return J1939_TP_TIMEOUT_NORMAL;
+    }
+}
+/**
+ * @note 发送读取数据 TP.CM_CTS 和 EndofMsgAck消息。
+ */
+void J1939_read_DT_Packet()
+{
+    J1939_MESSAGE  _msg;
+    j1939_uint32_t pgn_num;
+    pgn_num = TP_RX_MSG.tp_rx_msg.PGN;
+
+    _msg.Mxe.Priority           = J1939_TP_CM_PRIORITY;
+    _msg.Mxe.DataPage           = 0;
+    _msg.Mxe.PDUFormat          = J1939_PF_TP_CM;
+    _msg.Mxe.DestinationAddress = TP_RX_MSG.tp_rx_msg.SA;
+    _msg.Mxe.DataLength         = 8;
+
+    /*如果系统繁忙,保持链接但是不传送消息*/
+    if (TP_RX_MSG.osbusy)
+    {
+        _msg.Mxe.Data[0] = J1939_CTS_CONTROL_BYTE;
+        _msg.Mxe.Data[1] = 0;
+        _msg.Mxe.Data[2] = J1939_RESERVED_BYTE;
+        _msg.Mxe.Data[3] = J1939_RESERVED_BYTE;
+        _msg.Mxe.Data[4] = J1939_RESERVED_BYTE;
+        _msg.Mxe.Data[7] = (j1939_uint8_t)((pgn_num >> 16) & 0xff);
+        _msg.Mxe.Data[6] = (j1939_uint8_t)(pgn_num >> 8 & 0xff);
+        _msg.Mxe.Data[5] = (j1939_uint8_t)(pgn_num & 0xff);
+        /*可能队列已满,发不出去,但是这里不能靠返回值进行无限的死等*/
+        J1939_EnqueueMessage(&_msg, Can_Node);
+        return;
+    }
+    if (TP_RX_MSG.packets_total > TP_RX_MSG.packets_ok_num)
+    {
+        /*最后一次响应,如果不足2包数据*/
+        if ((TP_RX_MSG.packets_total - TP_RX_MSG.packets_ok_num) == 1)
+        {
+            _msg.Mxe.Data[0] = J1939_CTS_CONTROL_BYTE;
+            _msg.Mxe.Data[1] = 1;
+            _msg.Mxe.Data[2] = TP_RX_MSG.packets_total;
+            _msg.Mxe.Data[3] = J1939_RESERVED_BYTE;
+            _msg.Mxe.Data[4] = J1939_RESERVED_BYTE;
+            _msg.Mxe.Data[7] = (j1939_uint8_t)((pgn_num >> 16) & 0xff);
+            _msg.Mxe.Data[6] = (j1939_uint8_t)(pgn_num >> 8 & 0xff);
+            _msg.Mxe.Data[5] = (j1939_uint8_t)(pgn_num & 0xff);
+            /*可能队列已满,发不出去,但是这里不能靠返回值进行无限的死等*/
+            J1939_EnqueueMessage(&_msg, Can_Node);
+            TP_RX_MSG.state = J1939_TP_RX_DATA_WAIT;
+            return;
+        }
+        _msg.Mxe.Data[0] = J1939_CTS_CONTROL_BYTE;
+        _msg.Mxe.Data[1] = 2;
+        _msg.Mxe.Data[2] = (TP_RX_MSG.packets_ok_num + 1);
+        _msg.Mxe.Data[3] = J1939_RESERVED_BYTE;
+        _msg.Mxe.Data[4] = J1939_RESERVED_BYTE;
+        _msg.Mxe.Data[7] = (j1939_uint8_t)((pgn_num >> 16) & 0xff);
+        _msg.Mxe.Data[6] = (j1939_uint8_t)(pgn_num >> 8 & 0xff);
+        _msg.Mxe.Data[5] = (j1939_uint8_t)(pgn_num & 0xff);
+
+        /*可能队列已满,发不出去,但是这里不能靠返回值进行无限的死等*/
+        J1939_EnqueueMessage(&_msg, Can_Node);
+        TP_RX_MSG.state = J1939_TP_RX_DATA_WAIT;
+        return;
+    }
+    else
+    {
+        /*发送传输正常结束消息,EndofMsgAck*/
+        _msg.Mxe.Data[0] = J1939_EOMACK_CONTROL_BYTE;
+        _msg.Mxe.Data[1] = (TP_RX_MSG.tp_rx_msg.byte_count & 0x00ff);
+        _msg.Mxe.Data[2] = ((TP_RX_MSG.tp_rx_msg.byte_count >> 8) & 0x00ff);
+        _msg.Mxe.Data[3] = TP_RX_MSG.packets_total;
+        _msg.Mxe.Data[4] = J1939_RESERVED_BYTE;
+        _msg.Mxe.Data[7] = (j1939_uint8_t)((pgn_num >> 16) & 0xff);
+        _msg.Mxe.Data[6] = (j1939_uint8_t)(pgn_num >> 8 & 0xff);
+        _msg.Mxe.Data[5] = (j1939_uint8_t)(pgn_num & 0xff);
+        /*可能队列已满,发不出去,但是这里不能靠返回值进行无限的死等*/
+        J1939_EnqueueMessage(&_msg, Can_Node);
+        TP_RX_MSG.state = J1939_RX_DONE;
+        return;
+    }
+}
+/**
+* @note TP协议的心跳,为了满足在总线的计时准确,10ms轮询一次   J1939_TP_TX_RefreshCMTimer(10)\n
+        如果想要更高的分辨率,1ms轮询一次,但是要改下面计时函数  J1939_TP_TX_RefreshCMTimer(1)
+*/
+void J1939_TP_Poll()
+{
+    if (J1939_TP_Flags_t.state == J1939_TP_NULL || J1939_TP_Flags_t.state == J1939_TP_OSBUSY)
+    {
+        return;
+    }
+    if (J1939_TP_Flags_t.state == J1939_TP_RX)
+    {
+        Can_Node = J1939_TP_Flags_t.TP_RX_CAN_NODE;
+        switch (TP_RX_MSG.state)
+        {
+        case J1939_TP_RX_WAIT:;
+            break;
+        case J1939_TP_RX_READ_DATA:
+            /*发送读取数据 TP.CM_CTS 和 EndofMsgAck消息*/
+            J1939_read_DT_Packet();
+            break;
+        case J1939_TP_RX_DATA_WAIT:
+            /*等待TP.DT帧传输的消息*/
+            if (J1939_TP_TIMEOUT_ABNORMAL == J1939_TP_RX_RefreshCMTimer(10))
+            {
+                /* 等待超时,发生连接异常,跳转到异常步骤 */
+                TP_RX_MSG.state = J1939_TP_RX_ERROR;
+            }
+            break;
+        case J1939_TP_RX_ERROR:
+            J1939_TP_RX_Abort();
+            J1939_TP_Flags_t.TP_RX_CAN_NODE = Select_CAN_NODE_Null;
+            break;
+        case J1939_RX_DONE:
+            TP_RX_MSG.packets_ok_num = 0;
+            TP_RX_MSG.packets_total  = 0;
+            TP_RX_MSG.time           = J1939_TP_T3;
+            TP_RX_MSG.state          = J1939_TP_RX_WAIT;
+            J1939_TP_Flags_t.state   = J1939_TP_NULL;
+            break;
+        default:
+            break;
+        }
+        return;
+    }
+    if (J1939_TP_Flags_t.state == J1939_TP_TX)
+    {
+        Can_Node = J1939_TP_Flags_t.TP_TX_CAN_NODE;
+        switch (TP_TX_MSG.state)
+        {
+        case J1939_TP_TX_WAIT:
+            /*没有要发送的数据*/
+            break;
+        case J1939_TP_TX_CM_START:
+            /*发送TP.CM_RTS帧传输的消息(参考j1939-21)*/
+            J1939_CM_Start();
+            break;
+        case J1939_TP_TX_CM_WAIT:
+            /*等待TP.CM_CTS帧传输的消息*/
+            if (J1939_TP_TIMEOUT_ABNORMAL == J1939_TP_TX_RefreshCMTimer(10))
+            {
+                /* 等待超时,发生连接异常,跳转到异常步骤 */
+                TP_TX_MSG.state = J1939_TP_TX_ERROR;
+            }
+            break;
+        case J1939_TP_TX_DT:
+            J1939_TP_DT_Packet_send();
+            break;
+        case J1939_TP_WAIT_ACK:
+            /*等待TP.EndofMsgACK帧传输的消息*/
+            if (J1939_TP_TIMEOUT_ABNORMAL == J1939_TP_TX_RefreshCMTimer(10))
+            {
+                /* 等待超时,发生连接异常,跳转到异常步骤 */
+                TP_TX_MSG.state = J1939_TP_TX_ERROR;
+            }
+            break;
+        case J1939_TP_TX_ERROR:
+            J1939_TP_TX_Abort();
+
+            break;
+        case J1939_TX_DONE:
+            TP_TX_MSG.packets_request_num = 0;
+            TP_TX_MSG.packet_offset_p     = 0;
+            TP_TX_MSG.time                = J1939_TP_T3;
+            TP_TX_MSG.state               = J1939_TP_TX_WAIT;
+            J1939_TP_Flags_t.state        = J1939_TP_NULL;
+            break;
+        default:
+            // 程序不会运行到这里来,可以增加一个调试输出
+            break;
+        }
+        return;
+    }
+}
+
+/**这是一个非阻塞io接口
+ *
+ * @param[in] PGN	TP会话的参数群编号
+ * @param[in] SA		TP会话的目标地址
+ * @param[in] *data	TP会话的数据缓存地址
+ * @param[in] data_num TP会话的数据大小
+ * @param[in]  _Can_Node  要入队的CAN硬件编号(要选择的使用的CAN硬件编号)
+ * @return    RC_SUCCESS        成功打开TP链接,开始进入发送流程
+ * @return    RC_CANNOTTRANSMIT 不能发送,因为TP协议已经建立虚拟链接,并且未断开
+ * @note      TP协议的发送函数
+ */
+j1939_int8_t J1939_TP_TX_Message(j1939_uint32_t PGN, j1939_uint8_t DA, j1939_uint8_t *data, j1939_uint16_t data_num, CAN_NODE _Can_Node)
+{
+    j1939_uint16_t _byte_count = 0;
+    /*取得发送权限*/
+    if (J1939_TP_Flags_t.state == J1939_TP_NULL)
+    {
+        J1939_TP_Flags_t.state          = J1939_TP_TX;
+        J1939_TP_Flags_t.TP_TX_CAN_NODE = _Can_Node;
+    }
+    else
+    {
+        return RC_CANNOTTRANSMIT; // 不能发送,因为TP协议已经建立虚拟链接,并且未断开
+    }
+
+    TP_TX_MSG.tp_tx_msg.PGN        = PGN;
+    TP_TX_MSG.tp_tx_msg.SA         = DA;
+    TP_TX_MSG.tp_tx_msg.byte_count = data_num;
+    for (_byte_count = 0; _byte_count < data_num; _byte_count++)
+    {
+        TP_TX_MSG.tp_tx_msg.data[_byte_count] = data[_byte_count];
+    }
+    TP_TX_MSG.packet_offset_p     = 0;
+    TP_TX_MSG.packets_request_num = 0;
+    TP_TX_MSG.packets_total       = data_num / 7;
+    if ((data_num % 7) != 0)
+    {
+        TP_TX_MSG.packets_total++;
+    }
+    TP_TX_MSG.time = J1939_TP_T3;
+    // 触发开始CM_START
+    TP_TX_MSG.state = J1939_TP_TX_CM_START;
+
+    return RC_SUCCESS;
+}
+
+/**
+* @param[in]  msg.data	     读取数据的缓存
+* @param[in]  msg.data_num   读取数据的缓存大小
+* @param[in]  _Can_Node      要入队的CAN硬件编号(要选择的使用的CAN硬件编号)
+* @param[out] msg.SA         数据源地址
+* @param[out] msg.byte_count 数据大小
+* @param[out] msg.PGN        数据参数群编号
+* @return  RC_CANNOTRECEIVE 不能接受,TP协议正在接受数据中
+* @return  RC_SUCCESS		读取数据成功
+* @note TP的接受函数 , 接受缓存的大小必须大于接受数据的大小,建议初始化缓存大小用  J1939_TP_MAX_MESSAGE_LENGTH\n
+        请正确带入 缓存区的大小,参数错误程序运行有风险
+*/
+j1939_int8_t J1939_TP_RX_Message(TP_RX_MESSAGE *msg, CAN_NODE _Can_Node)
+{
+    j1939_uint16_t _a = 0;
+    /*判断是否能读取数据*/
+    if (J1939_TP_Flags_t.state == J1939_TP_NULL && TP_RX_MSG.tp_rx_msg.PGN != 0)
+    {
+        J1939_TP_Flags_t.state = J1939_TP_OSBUSY;
+    }
+    else
+    {
+        return RC_CANNOTRECEIVE; // 不能接受,TP协议正在接受数据中,或没有数据
+    }
+    // 判断是不是要读取那一路CAN数据
+    if (_Can_Node != J1939_TP_Flags_t.TP_RX_CAN_NODE)
+    {
+        /*释放TP接管权限*/
+        if (J1939_TP_Flags_t.state == J1939_TP_OSBUSY)
+        {
+            J1939_TP_Flags_t.state = J1939_TP_NULL;
+        }
+        return RC_CANNOTRECEIVE;
+    }
+    // 判断数据缓存够不够
+    if ((msg->data_num) < TP_RX_MSG.tp_rx_msg.byte_count)
+    {
+        return RC_CANNOTRECEIVE; // 不能接受,缓存区太小
+    }
+
+    /*获取数据*/
+    for (_a = 0; _a < msg->data_num; _a++)
+    {
+        msg->data[_a] = TP_RX_MSG.tp_rx_msg.data[_a];
+    }
+    /*获取数据 源地址*/
+    msg->SA = TP_RX_MSG.tp_rx_msg.SA;
+    /*获取数据的大小*/
+    msg->byte_count = TP_RX_MSG.tp_rx_msg.byte_count;
+    /*获取数据PGN*/
+    msg->PGN = TP_RX_MSG.tp_rx_msg.PGN;
+
+    /*丢弃读取过的数据*/
+    TP_RX_MSG.tp_rx_msg.byte_count = 0u;
+    TP_RX_MSG.tp_rx_msg.PGN        = 0;
+
+    /*释放TP接管权限*/
+    if (J1939_TP_Flags_t.state == J1939_TP_OSBUSY)
+    {
+        J1939_TP_Flags_t.state = J1939_TP_NULL;
+    }
+
+    return RC_SUCCESS;
+}
+/**
+ * @param[in] pgn  被请求的参数群
+ * @param[in] DA   目标地址(DestinationAddress) 当DA = 0xff表示是全局请求
+ * @param[in] _Can_Node  要入队的CAN硬件编号(要选择的使用的CAN硬件编号)
+ * @note      请求(从全局范围或则特定目的地的)参数群,请求规则J1939-21的16-17页,有明确的说明
+ */
+void J1939_Request_PGN(j1939_uint32_t pgn, j1939_uint8_t DA, CAN_NODE _Can_Node)
+{
+    J1939_MESSAGE _msg;
+
+    _msg.Mxe.DataPage           = 0;
+    _msg.Mxe.Priority           = J1939_REQUEST_PRIORITY;
+    _msg.Mxe.DestinationAddress = DA;
+    _msg.Mxe.DataLength         = 3;
+    _msg.Mxe.PDUFormat          = J1939_PF_REQUEST;
+    _msg.Mxe.Data[0]            = (j1939_uint8_t)(pgn & 0x000000FF);
+    _msg.Mxe.Data[1]            = (j1939_uint8_t)((pgn & 0x0000FF00) >> 8);
+    _msg.Mxe.Data[2]            = (j1939_uint8_t)((pgn & 0x00FF0000) >> 16);
+
+    while (J1939_EnqueueMessage(&_msg, _Can_Node) != RC_SUCCESS)
+        ;
+}
+/**
+ * @param[in]  data	      需要发送数据的缓存
+ * @param[in]  dataLenght  发送数据的缓存大小
+ * @param[in]  PGN         需要发送数据的PGN(参数群编号)
+ * @param[in]  void (*dataUPFun)()  用于更新缓存data 的函数地址指针
+ * @param[in]  _Can_Node      要入队的CAN硬件编号(要选择的使用的CAN硬件编号)
+ * @note 创建一个PGN 的 请求 对应的 响应\n 如果收到改请求则先运行 REQUEST_LIST.dataUPFun(),在将数据REQUEST_LIST.data发送出去
+ * @warning  本函数只能被串行调用,(多线程)并行调用请在函数外加互斥操作
+ */
+void J1939_Create_Response(j1939_uint8_t data[], j1939_uint16_t dataLenght, j1939_uint32_t PGN, void (*dataUPFun)(), CAN_NODE _Can_Node)
+{
+    /*查找可用的链表项*/
+    struct Request_List *_requestList = &REQUEST_LIST;
+    while (J1939_NULL != _requestList->next)
+    {
+        _requestList = _requestList->next;
+    }
+    _requestList->next = (struct Request_List *)malloc(sizeof(struct Request_List));
+    _requestList       = _requestList->next;
+
+    /*对新的链表项赋值*/
+    _requestList->data     = data;
+    _requestList->lenght   = dataLenght;
+    _requestList->PGN      = PGN;
+    _requestList->update   = dataUPFun;
+    _requestList->Can_Node = _Can_Node;
+    _requestList->next     = J1939_NULL;
+}
+/**
+* @note 当收到一个PGN请求后,如果有REQUEST_LIST中有相应的PGN,则会自动发送REQUEST_LIST中的PGN。\n
+  如果没有则会发送一个NACK; 本函数的响应逻辑,参考J1939-21 17页表4
+*/
+void J1939_Response(const j1939_uint32_t PGN)
+{
+    J1939_MESSAGE _msg;
+
+    /*查找可用的链表项*/
+    struct Request_List *_requestList = &REQUEST_LIST;
+    while ((PGN != _requestList->PGN) || (Can_Node != _requestList->Can_Node))
+    {
+        if (_requestList->next == J1939_NULL)
+        {
+            /*原文档规定 全局请求不被支持时不能响应 NACK*/
+            if (OneMessage.Mxe.PDUSpecific == J1939_GLOBAL_ADDRESS)
+            {
+                return;
+            }
+            if ((PGN & 0xFF00) >= 0xF000)
+            {
+                return;
+            }
+
+            /*没有相应的PGN响应被创建,向总线发送一个NACK*/
+            _msg.Mxe.Priority           = J1939_ACK_PRIORITY;
+            _msg.Mxe.DataPage           = 0;
+            _msg.Mxe.PDUFormat          = J1939_PF_ACKNOWLEDGMENT;
+            _msg.Mxe.DestinationAddress = OneMessage.Mxe.SourceAddress;
+            _msg.Mxe.DataLength         = 8;
+            _msg.Mxe.SourceAddress      = J1939_Address;
+            _msg.Mxe.Data[0]            = J1939_NACK_CONTROL_BYTE;
+            _msg.Mxe.Data[1]            = 0xFF;
+            _msg.Mxe.Data[2]            = 0xFF;
+            _msg.Mxe.Data[3]            = 0xFF;
+            _msg.Mxe.Data[4]            = 0xFF;
+            _msg.Mxe.Data[5]            = (PGN & 0x0000FF);
+            _msg.Mxe.Data[6]            = ((PGN >> 8) & 0x0000FF);
+            _msg.Mxe.Data[7]            = ((PGN >> 16) & 0x0000FF);
+
+            SendOneMessage((J1939_MESSAGE *)&_msg);
+            return;
+        }
+        else
+        {
+            _requestList = _requestList->next;
+        }
+    }
+
+    /*调用dataUPFun()函数,主要用于参数群数据更新*/
+    if (J1939_NULL != _requestList->update)
+    {
+        _requestList->update();
+    }
+
+    /*响应请求*/
+    if (_requestList->lenght > 8)
+    {
+        /*回一个确认响应多帧(非广播多帧)*/
+        if (RC_SUCCESS != J1939_TP_TX_Message(_requestList->PGN, OneMessage.Mxe.SourceAddress, _requestList->data, _requestList->lenght, Can_Node))
+        {
+            /*原文档规定 全局请求不被支持时不能响应 NACK*/
+            if (OneMessage.Mxe.PDUSpecific == J1939_GLOBAL_ADDRESS)
+            {
+                return;
+            }
+
+            /*如果长帧发送不成功*/
+            _msg.Mxe.Priority           = J1939_ACK_PRIORITY;
+            _msg.Mxe.DataPage           = 0;
+            _msg.Mxe.PDUFormat          = J1939_PF_ACKNOWLEDGMENT;
+            _msg.Mxe.DestinationAddress = OneMessage.Mxe.SourceAddress;
+            _msg.Mxe.DataLength         = 8;
+            _msg.Mxe.SourceAddress      = J1939_Address;
+            _msg.Mxe.Data[0]            = J1939_ACCESS_DENIED_CONTROL_BYTE;
+            _msg.Mxe.Data[1]            = 0xFF;
+            _msg.Mxe.Data[2]            = 0xFF;
+            _msg.Mxe.Data[3]            = 0xFF;
+            _msg.Mxe.Data[4]            = 0xFF;
+            _msg.Mxe.Data[5]            = (PGN & 0x0000FF);
+            _msg.Mxe.Data[6]            = ((PGN >> 8) & 0x0000FF);
+            _msg.Mxe.Data[7]            = ((PGN >> 16) & 0x0000FF);
+
+            SendOneMessage((J1939_MESSAGE *)&_msg);
+            return;
+        }
+
+        /*回一个确认响应*/
+        _msg.Mxe.Priority  = J1939_ACK_PRIORITY;
+        _msg.Mxe.DataPage  = 0;
+        _msg.Mxe.PDUFormat = J1939_PF_ACKNOWLEDGMENT;
+        /*原文档规定 全局请求响应到全局*/
+        if (OneMessage.Mxe.PDUSpecific == J1939_GLOBAL_ADDRESS)
+        {
+            _msg.Mxe.DestinationAddress = 0XFF;
+        }
+        else
+        {
+            _msg.Mxe.DestinationAddress = OneMessage.Mxe.SourceAddress;
+        }
+        _msg.Mxe.DataLength    = 8;
+        _msg.Mxe.SourceAddress = J1939_Address;
+        _msg.Mxe.Data[0]       = J1939_ACK_CONTROL_BYTE;
+        _msg.Mxe.Data[1]       = 0xFF;
+        _msg.Mxe.Data[2]       = 0xFF;
+        _msg.Mxe.Data[3]       = 0xFF;
+        _msg.Mxe.Data[4]       = 0xFF;
+        _msg.Mxe.Data[5]       = (PGN & 0x0000FF);
+        _msg.Mxe.Data[6]       = ((PGN >> 8) & 0x0000FF);
+        _msg.Mxe.Data[7]       = ((PGN >> 16) & 0x0000FF);
+        SendOneMessage((J1939_MESSAGE *)&_msg);
+    }
+    else
+    {
+
+        /*回一个确认响应*/
+        _msg.Mxe.Priority      = J1939_ACK_PRIORITY;
+        _msg.Mxe.DataPage      = 0;
+        _msg.Mxe.PDUFormat     = J1939_PF_ACKNOWLEDGMENT;
+        _msg.Mxe.SourceAddress = J1939_Address;
+        /*原文档规定 全局请求响应到全局*/
+        if ((OneMessage.Mxe.PDUSpecific == J1939_GLOBAL_ADDRESS) || ((PGN & 0xFF00) >= 0xF000))
+        {
+            _msg.Mxe.DestinationAddress = 0XFF;
+        }
+        else
+        {
+            _msg.Mxe.DestinationAddress = OneMessage.Mxe.SourceAddress;
+        }
+        _msg.Mxe.DataLength    = 8;
+        _msg.Mxe.SourceAddress = J1939_Address;
+        _msg.Mxe.Data[0]       = J1939_ACK_CONTROL_BYTE;
+        _msg.Mxe.Data[1]       = 0xFF;
+        _msg.Mxe.Data[2]       = 0xFF;
+        _msg.Mxe.Data[3]       = 0xFF;
+        _msg.Mxe.Data[4]       = 0xFF;
+        _msg.Mxe.Data[5]       = (PGN & 0x0000FF);
+        _msg.Mxe.Data[6]       = ((PGN >> 8) & 0x0000FF);
+        _msg.Mxe.Data[7]       = ((PGN >> 16) & 0x0000FF);
+        SendOneMessage((J1939_MESSAGE *)&_msg);
+
+        /*回一个确认响应单帧*/
+        _msg.Mxe.Priority      = J1939_ACK_PRIORITY;
+        _msg.Mxe.DataPage      = (((_requestList->PGN) >> 16) & 0x1);
+        _msg.Mxe.PDUFormat     = ((_requestList->PGN) >> 8) & 0xFF;
+        _msg.Mxe.SourceAddress = J1939_Address;
+        /*原文档规定 全局请求响应到全局*/
+        if (OneMessage.Mxe.PDUSpecific == J1939_GLOBAL_ADDRESS)
+        {
+            _msg.Mxe.DestinationAddress = 0XFF;
+        }
+        else
+        {
+            _msg.Mxe.DestinationAddress = OneMessage.Mxe.SourceAddress;
+        }
+        _msg.Mxe.DataLength = _requestList->lenght;
+        {
+            j1939_uint8_t _i = 0;
+            for (_i = 0; _i < (_requestList->lenght); _i++)
+            {
+                _msg.Mxe.Data[_i] = _requestList->data[_i];
+            }
+            for (; _i < 8; _i++)
+            {
+                _msg.Mxe.Data[_i] = 0xFF;
+            }
+        }
+        SendOneMessage((J1939_MESSAGE *)&_msg);
+    }
+}
+#endif

+ 332 - 0
packages/j1939/source/J1939_Config.H

@@ -0,0 +1,332 @@
+/*********************************************************************
+ *
+ *            J1939 Main Source Code
+ *
+ *********************************************************************
+ *
+ *	本程序是由XieTongXueFlyMe对现有的J1939协议文档分析,和对前辈的贡献总结,
+ * 写出的一套开源的J1939驱动。
+ *	本协议特点:
+ *		1.易移植(不针对特定的CAN硬件,只要满足CAN2.0B即可)
+ *		2.轻量级(可适应低端的MCU)
+ *		3.支持多任务调用接口(可用于嵌入式系统)
+ *		4.双模式(轮询或者中断,逻辑更加简单明了)
+ *		5.不掉帧(数据采用收发列队缓存)
+ *
+ *  源代码下载:
+ *		https://github.com/XeiTongXueFlyMe/J1939
+ *  源代码临时手册Web站点:
+ *		https://xeitongxueflyme.github.io/j1939doc.github.io/
+ *
+ * Version     Date        Description
+ * -------------------------------------------------------------------
+ * v1.0.0     2017/06/04    首个版本 Version 1 测试版发布
+ * v1.0.1     2017/08/04    完善功能
+ * v1.1.0     2017/11/22    Version 1 稳定发布版
+ * v2.0.1     2017/11/24    Version 2 测试版发布
+ * v2.0.2     2018/01/03    解决V2.0.1 遗留问题
+ * v2.1.0     2018/01/20    Version 2 稳定发布版
+ * Author               Date         changes
+ *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *XeiTongXueFlyMe       7/06/04      首个版本
+ *XeiTongXueFlyMe       7/08/04      增加对TP的支持
+ *XeiTongXueFlyMe       7/11/24      增加对多路CAN硬件的收发,和报文处理
+ *XeiTongXueFlyMe       7/11/29      增加请求和响应API
+ *XeiTongXueFlyMe       7/12/07      重做TP接受API函数
+ *XeiTongXueFlyMe       7/12/08      增加软件滤波器
+ *XeiTongXueFlyMe       8/01/03      重做接受发送API,简化协议栈初始化调用逻辑
+ **********************************************************************/
+
+#ifndef __J1939_Config_H
+#define __J1939_Config_H
+
+#include "J1939.H"
+#include "queue.h"
+#include <string.h>
+
+extern uint8_t  push_can_message_to_queue(uint32_t id, uint8_t len, uint8_t *p_data);
+extern CAN_NODE Can_Node; // CAN硬件选择
+
+/***************************J1939 地址配置*****************************/
+// 设备默认的地址(地址命名是有规定的,参考J1939的附录B 地址和标识符的分配)
+#define J1939_STARTING_ADDRESS_1 0x01
+#define J1939_STARTING_ADDRESS_2 244
+#define J1939_STARTING_ADDRESS_3 247
+#define J1939_STARTING_ADDRESS_4 0
+
+/******************************J1939功能配置***************************/
+#define J1939_RX_QUEUE_SIZE 3
+// 当mcu来不及处理消息,接收消息列队是否允许被新的消息覆盖
+#define J1939_OVERWRITE_RX_QUEUE J1939_FALSE
+#define J1939_TX_QUEUE_SIZE      3
+// 当mcu来不及处理消息,发送消息列队是否允许被新的消息覆盖
+#define J1939_OVERWRITE_TX_QUEUE J1939_FALSE
+// 是否使用轮询模式(否则使用中断模式)
+#define J1939_POLL_ECAN J1939_TRUE
+// 是否启用软件滤波器
+#define J1939SoftwareFilterEn J1939_TRUE
+/******************************J1939移植配置函数************************/
+
+#define Port_CAN_Transmit(MsgPtr)      J1939_CAN_Transmit(MsgPtr)
+#define Port_CAN_Receive(MsgPtr)       J1939_CAN_Receive(MsgPtr)
+#define Port_SetAddressFilter(Address) J1939_SetAddressFilter(Address)
+/*不使用中断模式,不对下面的函数进行移植*/
+#if J1939_POLL_ECAN == J1939_FALSE
+#define Port_RXinterruptEnable()  J1939_RXinterruptEnable()
+#define Port_RXinterruptDisable() J1939_RXinterruptDisable()
+#define Port_TXinterruptEnable()  J1939_TXinterruptEnable()
+#define Port_TXinterruptDisable() J1939_TXinterruptDisable()
+#define Port_TXinterruptOk()      J1939_TXinterruptOk()
+#define Port_CAN_identifier_clc() CAN_identifier_clc()
+#endif
+
+/***************************************************************************************/
+
+/*
+*输入:
+*输出:
+*说明:基于SAE J1939协议,我们需要CAN控制器提供至少3个滤波器给J1939协议代码。三个滤波器分别配置如下:
+        1. 设置滤波器0,只接受广播信息(PF = 240 -255)。
+        2. 设置设置滤波器1,2只接受全局地址(J1939_GLOBAL_ADDRESS)
+        3. 随着程序的运行,将改变滤波器2,来适应程序逻辑。
+    J1939_SetAddressFilter() 是用来设置滤波器2的, 函数主要设置PS位(目标地址),其目的是,让控制器
+    只接受发送给本设备的消息。
+*警告: 滤波器0,1是在CAN驱动里配置,如果对硬件滤波配置不是很熟练,可以使能软件滤波器,#define J1939SoftwareFilterEn
+*则可跳过本函数的移植和CAN硬件滤波器的配置,为了J1939协议栈性能最优化,建议只是用硬件滤波。
+*/
+void J1939_SetAddressFilter(unsigned char Ps_Address)
+{
+    switch (Can_Node)
+    {
+    case Select_CAN_NODE_1:
+    {
+        break;
+    }
+    case Select_CAN_NODE_2:
+    {
+        break;
+    }
+    case Select_CAN_NODE_3:
+    {
+        break;
+    }
+    case Select_CAN_NODE_4:
+    {
+        break;
+    }
+    default:
+    {
+        break;
+    }
+    }
+}
+
+/*
+*输入:  *MsgPtr ,协议要发送的消息,
+*输出:
+*说明:      将数据 从MsgPtr结构体赋值到CAN驱动自带的结构体中
+        先将传入函数的MsgPtr中的数据写到CAN的结构体,再调用CAN驱动的发送函数
+        默认支持4路CAN硬件的收发。如少于4路,只需配置相应的Can_Node开关代码区,
+        其他(Select_CAN_NODE)保持不变。就直接返回(break)。
+*/
+void J1939_CAN_Transmit(J1939_MESSAGE *MsgPtr)
+{
+    pdu_tag j1939_tx_data;
+
+    switch (Can_Node)
+    {
+    case Select_CAN_NODE_1:
+    {
+        j1939_tx_data.id.b.sa = MsgPtr->Mxe.SourceAddress;
+        j1939_tx_data.id.b.ps = MsgPtr->Mxe.PDUSpecific;
+        j1939_tx_data.id.b.pf = MsgPtr->Mxe.PDUFormat;
+        j1939_tx_data.id.b.dp = 0; // MsgPtr->Mxe.DataPage;
+
+        j1939_tx_data.id.b.r = 0; // MsgPtr->Mxe.Res;
+        j1939_tx_data.id.b.p = MsgPtr->Mxe.Priority;
+
+        j1939_tx_data.reg.dlc = MsgPtr->Mxe.DataLength;
+        memcpy(j1939_tx_data.data.u8_buf, MsgPtr->Mxe.Data, MsgPtr->Mxe.DataLength);
+
+        push_can_message_to_queue(j1939_tx_data.id.r, j1939_tx_data.reg.dlc, j1939_tx_data.data.u8_buf);
+
+        break;
+    }
+    case Select_CAN_NODE_2:
+    {
+
+        /*加载第二路CAN硬件的29位ID*/
+
+        /*CAN硬件加载数据长度*/
+
+        /*CAN硬件加载数据*/
+
+        /*CAN硬件加载RTR*/
+
+        // CAN硬件开始发送数据
+        break;
+    }
+    case Select_CAN_NODE_3:
+    {
+
+        /*加载第三路CAN硬件的29位ID*/
+
+        /*CAN硬件加载数据长度*/
+
+        /*CAN硬件加载数据*/
+
+        /*CAN硬件加载RTR*/
+
+        // CAN硬件开始发送数据
+        break;
+    }
+    case Select_CAN_NODE_4:
+    {
+        /*加载第四路CAN硬件的29位ID*/
+
+        /*CAN硬件加载数据长度*/
+
+        /*CAN硬件加载数据*/
+
+        /*CAN硬件加载RTR*/
+
+        // CAN硬件开始发送数据
+        break;
+    }
+    default:
+    {
+        break;
+    }
+    }
+}
+/*
+*输入:     *MsgPtr 数据要存入的内存的指针
+*输出:      1 | 0
+*说明:      读取CAN驱动的数据,如果没有数据,返回0
+        将CAN中的数据取出,存入J1939_MESSAGE结构体中
+        默认支持4路CAN硬件的收发。如少于4路,只需配置相应的Can_Node开关代码区,
+        其他(Select_CAN_NODE)保持不变。就直接返回(return 0)
+*/
+
+int J1939_CAN_Receive(J1939_MESSAGE *MsgPtr)
+{
+
+    j1939_uint8_t rec = RC_SUCCESS;
+    pdu_tag       j1939_tx_data;
+
+    switch (Can_Node)
+    {
+    case Select_CAN_NODE_1:
+    {
+        j1939_tx_data.id.b.sa = MsgPtr->Mxe.SourceAddress;
+        j1939_tx_data.id.b.ps = MsgPtr->Mxe.PDUSpecific;
+        j1939_tx_data.id.b.pf = MsgPtr->Mxe.PDUFormat;
+        j1939_tx_data.id.b.dp = 0; // MsgPtr->Mxe.DataPage;
+
+        j1939_tx_data.id.b.r = 0; // MsgPtr->Mxe.Res;
+        j1939_tx_data.id.b.p = MsgPtr->Mxe.Priority;
+
+        j1939_tx_data.reg.dlc = MsgPtr->Mxe.DataLength;
+        return 0;
+        break;
+    }
+    case Select_CAN_NODE_2:
+    {
+        if ("你的代码") // 判断CAN硬件2是否有数据到来
+        {
+            // 你的代码,从CAN硬件2 中将数据读取后,存入 MsgPtr
+            return 1;
+        }
+        return 0;
+        break;
+    }
+    case Select_CAN_NODE_3:
+    {
+        if ("你的代码") // 判断CAN硬件3是否有数据到来
+        {
+            // 你的代码,从CAN硬件3 中将数据读取后,存入 MsgPtr
+            return 1;
+        }
+        return 0;
+        break;
+    }
+    case Select_CAN_NODE_4:
+    {
+        if ("你的代码") // 判断CAN硬件4是否有数据到来
+        {
+            // 你的代码,从CAN硬件4 中将数据读取后,存入 MsgPtr
+            return 1;
+        }
+        return 0;
+        break;
+    }
+    default:
+    {
+        return 0; // 没有消息
+        break;
+    }
+    }
+    return 0; // 没有消息
+}
+
+/*不使用中断模式,不对下面的函数进行移植*/
+#if J1939_POLL_ECAN == J1939_FALSE
+/*
+ *输入:
+ *输出:
+ *说明:使能接受中断
+ */
+void J1939_RXinterruptEnable()
+{
+    ;
+}
+/*
+ *输入:
+ *输出:
+ *说明:失能接受中断
+ */
+void J1939_RXinterruptDisable()
+{
+    ;
+}
+/*
+ *输入:
+ *输出:
+ *说明:使能发送中断
+ */
+void J1939_TXinterruptEnable()
+{
+    ;
+}
+/*
+ *输入:
+ *输出:
+ *说明:失能发送中断
+ */
+void J1939_TXinterruptDisable()
+{
+    ;
+}
+/*
+*输入:
+*输出:
+*说明:触发发送中断标致位,当协议栈在中断模式下,要发送消息,将调用此函数
+    CAN驱动函数,就将直接把消息发送出去,不需要协议在调用任何can驱动函数
+*/
+void J1939_TXinterruptOk()
+{
+    ;
+}
+/*
+*输入:
+*输出:
+*说明:清除CAN驱动相关的中断产生标识位,包括(发送中断标志位,接受中断标
+    志位,can总线错误标识位)
+*/
+void CAN_identifier_clc()
+{
+    ;
+}
+#endif
+
+#endif