{"id":179,"date":"2019-03-05T17:27:25","date_gmt":"2019-03-05T17:27:25","guid":{"rendered":"https:\/\/oshablue.com\/bsides\/?p=179"},"modified":"2020-06-01T20:03:52","modified_gmt":"2020-06-01T20:03:52","slug":"if2c-command-set-api-code-examples","status":"publish","type":"post","link":"https:\/\/oshablue.com\/doc\/if2c-command-set-api-code-examples\/","title":{"rendered":"IF2C: Command Set, API, Code Examples"},"content":{"rendered":"<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_68 counter-hierarchy ez-toc-counter ez-toc-light-blue ez-toc-container-direction\">\n<p class=\"ez-toc-title\">Table of Contents<\/p>\n<label for=\"ez-toc-cssicon-toggle-item-69ea6edd35ff3\" class=\"ez-toc-cssicon-toggle-label\"><span class=\"\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #999;color:#999\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #999;color:#999\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span><\/label><input type=\"checkbox\"  id=\"ez-toc-cssicon-toggle-item-69ea6edd35ff3\"  aria-label=\"Toggle\" \/><nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-4'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/oshablue.com\/doc\/if2c-command-set-api-code-examples\/#HOST-IF2C_Interface\" title=\"HOST-IF2C Interface\">HOST-IF2C Interface<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-4'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/oshablue.com\/doc\/if2c-command-set-api-code-examples\/#Command_Set_for_the_DL-Host_IF2C_API\" title=\"Command Set for the DL-Host IF2C API\">Command Set for the DL-Host IF2C API<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-4'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/oshablue.com\/doc\/if2c-command-set-api-code-examples\/#Example_HOST-IF2C_Interface_Header\" title=\"Example HOST-IF2C Interface Header\">Example HOST-IF2C Interface Header<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-4'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/oshablue.com\/doc\/if2c-command-set-api-code-examples\/#Example_HOST-IF2C_Interface_Source\" title=\"Example HOST-IF2C Interface Source\">Example HOST-IF2C Interface Source<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-4'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/oshablue.com\/doc\/if2c-command-set-api-code-examples\/#Example_HOST-IF2C_Command_Calls_to_the_Interface_Code\" title=\"Example HOST-IF2C Command Calls to the Interface Code\">Example HOST-IF2C Command Calls to the Interface Code<\/a><\/li><\/ul><\/nav><\/div>\n\n<p>There are two (2) APIs of interest here: <\/p>\n\n\n\n<ol class=\"wp-block-list\"><li>API for the DL-Host that talks to the IF2C, for example the DL0102GXN as a host, as provided in sample firmware.  This is covered here.<\/li><li>API for the IF2C accessory itself.<\/li><\/ol>\n\n\n\n<p><a href=\"https:\/\/oshablue.com\/bsides\/2019\/02\/28\/if2c-example-data-acquisition-sequence\/\">A simple communications example is here.<\/a><\/p>\n\n\n\n<!--more-->\n\n\n\n<h4 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"HOST-IF2C_Interface\"><\/span>HOST-IF2C Interface<span class=\"ez-toc-section-end\"><\/span><\/h4>\n\n\n\n<p>The HOST talks to the IF2C accessory by SPI with a !SS (slave select) signal.  On the current DLITE\/(H)DL Family with the GPIO interface for stacking accessories, PORTB4 is a good candidate the for the !SS signal to the IF2C.  The IF2C MCU runs at a slower speed (because it can and ought to for this application) so the DL-Host needs to use a slower SPI speed when talking to the IF2C.  A different SPI mode is also used.  A separate initialization function for the IF2C is probably warranted, as well as a way to track what SPI device the DL-Host is talking to, so that the SPI port is correctly initialized depending on the currently selected slave device.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Command_Set_for_the_DL-Host_IF2C_API\"><\/span>Command Set for the DL-Host IF2C API<span class=\"ez-toc-section-end\"><\/span><\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\">\/\/ Add to file(s) (for example):<br>\/\/ dlite_commands.c\/h<br>\/\/ This addition is present starting in firmware revision:<br>\/\/ FW E2019.00016<br><br>#define DCMD_DO_IF2C                              0xDB<br><br>extern const char c_do_if2c[DLITE_STD_CMD_LEN] = <br>    {DLITE_CMD_PREFIX, DCMD_DO_EEPROM, 0x00, 0x00, DLITE_CMD_SUFFIX}; <br>extern const char c_tx_do_if2c_ok[17] = \"IF2C COMMAND OK\\r\\0\";<br>extern const char c_tx_do_if2c_err[20] = \"IF2C COMMAND ERROR\\r\\0\";<br><br>\/\/ ARG 1: Command and options<br>#define DCMD_DO_IF2C_SET_TXCHAN_ON              0x01<br>#define DCMD_DO_IF2C_SET_TXCHAN_OFF             0x03 \/\/ Specific channel off<br>#define DCMD_DO_IF2C_SET_TXCHAN_ALLOFF          0x05 \/\/ All channels off<br>#define DCMD_DO_IF2C_SET_RXCHAN_ON              0x10 \/\/ Only one channel ever on at a time for Rx<br>#define DCMD_DO_IF2C_SET_RXCHAN_ALLOFF          0x20<br><br>\/\/ ARG 2: param is channel, if implemented<br>\/\/ 0x00 means all off<br>\/\/ For commands to turn all off, ARG 2 is unimplemented<br>\/\/ 0x01 - 0x08 = Channel number (Base 1))<br><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Example_HOST-IF2C_Interface_Header\"><\/span>Example HOST-IF2C Interface Header<span class=\"ez-toc-section-end\"><\/span><\/h4>\n\n\n\n<p>This code handles the interface from the HOST to the IF2C to &#8220;convert&#8221; commands coming in to the (H)DL to the IF2C implementation.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">\/* <br> File:   hdl0108if2c-dl0102.h<br> Interface for the DL0102G(XN), DLITE0100A1, (H)DL Family to the<br> accessory board: HDL-0108-IF2C<br> *\/ <br>#include &lt;stdbool.h&gt;<br>#ifndef HDL0108IF2C_DL0102_H<br>#define    HDL0108IF2C_DL0102_H<br>#ifdef    __cplusplus<br> extern \"C\" {<br>#endif<br><br>#define INIT_SYSTEM_WITH_IF2C 1<br><br>\/\/ Functions adapted from MCC Pin Manager auto-generated code<br>#define IF2C_nSS_TRIS                 TRISBbits.TRISB4<br>#define IF2C_nSS_LAT                  LATBbits.LATB4<br>#define IF2C_nSS_PORT                 PORTBbits.RB4<br>#define IF2C_nSS_WPU                  WPUBbits.WPUB4<br>#define IF2C_nSS_OD                   ODCONBbits.ODCB4<br>#define IF2C_nSS_ANS                  ANSELBbits.ANSB4<br>#define IF2C_nSS_SetHigh()            do { LATBbits.LATB4 = 1; } while(0)<br>#define IF2C_nSS_SetLow()             do { LATBbits.LATB4 = 0; } while(0)<br>#define IF2C_nSS_Toggle()             do { LATBbits.LATB4 = ~LATBbits.LATB4; } while(0)<br>#define IF2C_nSS_GetValue()           PORTBbits.RB4<br>#define IF2C_nSS_SetDigitalInput()    do { TRISBbits.TRISB4 = 1; } while(0)<br>#define IF2C_nSS_SetDigitalOutput()   do { TRISBbits.TRISB4 = 0; } while(0)<br>#define IF2C_nSS_SetPullup()          do { WPUBbits.WPUB4 = 1; } while(0)<br>#define IF2C_nSS_ResetPullup()        do { WPUBbits.WPUB4 = 0; } while(0)<br>#define IF2C_nSS_SetPushPull()        do { ODCONBbits.ODCB4 = 0; } while(0)<br>#define IF2C_nSS_SetOpenDrain()       do { ODCONBbits.ODCB4 = 1; } while(0)<br>#define IF2C_nSS_SetAnalogMode()      do { ANSELBbits.ANSB4 = 1; } while(0)<br>#define IF2C_nSS_SetDigitalMode()     do { ANSELBbits.ANSB4 = 0; } while(0)<br>#define IF2C_SELECT()                 IF2C_nSS_SetLow()<br>#define IF2C_DESELECT()               IF2C_nSS_SetHigh()<br><br>#define POST_SELECT_DELAY_NS          1000000<br>#define POST_COMM_DELAY_US            100000<br><br>#define IF2C_CMD_SETRXCHANON          0b10100000<br>#define IF2C_CMD_SETRXCHANALLOFF      0b10100000<br>#define IF2C_CMD_SETTXCHANON          0b11000010 <br>#define IF2C_CMD_SETTXCHANOFF         0b11000011<br>#define IF2C_CMD_ARGSETALLTXCHANOFF 0x0F<br><br> \/\/ SPI Setup<br> \/\/ IF2C SPI MODE IS 1 (not 3: (1,1) CPOL=1, CPHA=1)<br> \/\/ However other (H)DL peripherals are different<br> \/\/ Idle should be high (active low) =&gt; CPOL = 1<br> \/\/ But data changes on idle=&gt;active (high=&gt;low) which is CKE = 0<br> \/\/ so that it can be sampled in the middle from low=&gt;high (active=&gt;idle) clock<br> #define IF2C_SCLK_POL       0   \/\/ Mode 1: pol:0, pha:1, in theory<br> #define IF2C_SCLK_PHA       1<br> #define IF2C_SPI_MODE8      0   \/\/ 8-bit, not 16-bit word<br> \/\/ FSCK = FP \/ (Primary Prescaler x Secondary Prescaler)<br> \/\/ 1 MHz     = 70 MHz \/ (p x s)<br> \/\/ ( p x s ) = 70 \/ 1 = 70<br> \/\/ Available primary values:<br> \/\/ 11       1:1<br> \/\/ 10       4:1<br> \/\/ 01       16:1<br> \/\/ 00       64:1<br> \/\/<br> \/\/ Available secondary values:<br> \/\/ 111      1:1<br> \/\/ 110      2:1<br> \/\/ 101      3:1<br> \/\/ 100      4:1<br> \/\/ 011      5:1<br> \/\/ 010      6:1<br> \/\/ 001      7:1<br> \/\/ 000      8:1<br> \/\/<br> \/\/ 70\/80 = 70 \/ (16 x 5) = 875 kHz<br> \/\/ Secondary: SPRE: 000 = 8:1 while 111=1:1<br> \/\/ Primary: PPRE: 00 = 64:1, 01=16:1, 10=4:1, 11=1:1<br> \/\/ Don't set both to 1:1<br> #define IF2C_SPI_SPRE_521KHZ   0b000<br> #define IF2C_SPI_SPRE_1042KHZ  0b100<br> #define IF2C_SPI_SPRE_695KHZ   0b010<br> #define IF2C_SPI_PPRE          0b01<br> #define IF2C_SPI_SPRE          0b000<br> \/\/ Measured values<br> \/\/ PPRE 0b01 and SPRE 0b000 gives measured clock at 521 kHz<br> \/\/ on a typical HOST (H)DL device<br> \/\/ IF2C was previously tested at reliable max of only 50-100kHz<br> \/\/ Using PPRE 0b00 is 4x slower 64:1<br> \/\/ Using SPRE 0b000 is already the slowest divisor<br> \/\/ So this is about 130kHz<br><br> \/\/ Function prototypes<br> unsigned char If2cHandler(unsigned char arg1, unsigned char arg2);<br> void InitIf2c(void);<br> unsigned int SetIf2cTxChan(unsigned char chan, bool on_not_off, bool full_off);<br> unsigned int SetIf2cRxChan(unsigned char chan);<br> void If2cSelect(void);<br> void If2cDeselect(void);<br><br>#ifdef    __cplusplus<br> }<br>#endif<br>#endif    \/* HDL0108IF2C_DL0102_H *\/<br><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Example_HOST-IF2C_Interface_Source\"><\/span>Example HOST-IF2C Interface Source<span class=\"ez-toc-section-end\"><\/span><\/h4>\n\n\n\n<p>Formatting adapted and code modified, please verify matching source to header conventions and naming.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"hdl0108if2c-dl0102.h\"<br>#include \"user.h\"<br>#include \"dlite_commands.h\"<br>#include &lt;xc.h&gt;<br><br>\/*<br> * TODO<br> * Probably good to add channel range sanity checking<br> * (0=off,  1-8=chans allowed)<br> *\/ <br><br>void InitIf2c() {<br>     IF2C_nSS_SetDigitalMode();<br>     IF2C_nSS_SetDigitalOutput();<br>     IF2C_DESELECT(); \/\/ Should pull high<br>}<br><br>unsigned char If2cHandler(unsigned char arg1, unsigned char arg2) {<br><br><code>unsigned char rBuf[2]; unsigned char err = 0; <\/code><br><code>unsigned char * pBuf = rBuf; <\/code><br><code>unsigned int len = 2; <\/code><br><code>unsigned int res = 0x0000; <\/code><br><br><code>\/\/ Such that we can set the SPI to what is needed here and indicate to the <\/code><br><code>\/\/ main code that SPI configuration is no longer suited to the usual  <\/code><br><code>\/\/ accessories for which it might have previously been initialized ClearActiveSpiDevice();  <\/code><br><code>\/\/ Initialize SPI for the IF2C <\/code><br><code>\/\/ This is not done in the basic SPI setup because the main code  <\/code><br><code>\/\/ probably wants to set up for other accessories - and\/or we are  <\/code><br><code>\/\/ preserving this behavior for backwards compatibility <\/code><br><br><code>SetupSpi(         <\/code><br><code> IF2C_SCLK_POL,          <\/code><br><code> IF2C_SCLK_PHA,          <\/code><br><code> IF2C_SPI_MODE8,          <\/code><br><code> IF2C_SPI_PPRE,         <\/code><br><code> IF2C_SPI_SPRE); <\/code><br><br><code>switch (arg1) {     <\/code><br><code>    case DCMD_DO_IF2C_SET_TXCHAN_ON:         <\/code><br><code>        res = SetIf2cTxChan(arg2, true, false);    <\/code><br><code>        break;     <\/code><br><code>    case DCMD_DO_IF2C_SET_TXCHAN_OFF:         <\/code><br><code>        res = SetIf2cTxChan(arg2, false, false);          <\/code><br><code>        break;     <\/code><br><code>    case DCMD_DO_IF2C_SET_TXCHAN_OFF_WSHUNT:         <\/code><br><code>        res = SetIf2cTxChan(arg2, false, true);         <\/code><br><code>        break;     <\/code><br><code>    case DCMD_DO_IF2C_SET_TXCHAN_ALLOFF:         <\/code><br><code>        res = SetIf2cTxChan(IF2C_CMD_ARGSETALLTXCHANOFF, false, false);         <\/code><br><code>        break;     <\/code><br><code>    case DCMD_DO_IF2C_SET_TXCHAN_ALLOFF_WSHUNT:         <\/code><br><code>        res = SetIf2cTxChan(IF2C_CMD_ARGSETALLTXCHANOFF, false, true);         <\/code><br><code>        break;     <\/code><br><code>    case DCMD_DO_IF2C_SET_RXCHAN_ON:     <\/code><br><code>    case DCMD_DO_IF2C_SET_RXCHAN_ALLOFF:         <\/code><br><code>        res = SetIf2cRxChan(arg2);         <\/code><br><code>        break;     <\/code><br><code>    default:         <\/code><br><code>        err = 0x01; <\/code><br><code>} <\/code><br><br><code>rBuf[0] = (res&amp;0xff00)&gt;&gt;8;  \/\/ first byte is in the MSB place of the int result <\/code><br><code>rBuf[1] = (res&amp;0xff);       \/\/ 2nd byte from the transaction is in the LSB <\/code><br><br><code>if (!err) <\/code><br><code>    _ProcessTx((char *)pBuf, len); \/\/ Raw data bytes <\/code><br><code>else     <\/code><br><code>    ProcessTxString((char *)c_tx_do_if2c_err); return err;<\/code><br> }<br> void If2cSelect(void) {<br>     IF2C_SELECT();<br> }<br> void If2cDeselect(void) {<br>     IF2C_DESELECT();<br> }<br><br> unsigned int SetIf2cTxChan(<br>         unsigned char chan, bool on_not_off, bool full_off) {<br>     unsigned char cmd = 0x00;<br>     unsigned char cmdIfOff = 0x00;<br>     cmdIfOff = full_off ? IF2C_CMD_SETTXCHANOFFWSHUNT : IF2C_CMD_SETTXCHANOFF;<br>     cmd = on_not_off ? IF2C_CMD_SETTXCHANON : cmdIfOff;<br>     return _SPITxRxWord2(<br>             &amp;If2cDeselect, &amp;If2cSelect, <br>             POST_SELECT_DELAY_NS, POST_COMM_DELAY_US, <br>             cmd, chan);<br> }<br> <br>unsigned int SetIf2cRxChan(unsigned char chan) {<br>     \/\/ chan is arg2 from the dl command packet<br>     unsigned char cmd = 0x00;<br>     switch (chan) {<br>         case 0x00:<br>             cmd = IF2C_CMD_SETRXCHANALLOFF;<br>             break;<br>         default:<br>             cmd = IF2C_CMD_SETRXCHANON|(chan);<br>     }<br>     \/\/ The SPI function pushes the bytes into a 16-bit word for Tx<br>     \/\/ For our Rx chan control cmd example, 2nd byte is not used<br>     return _SPITxRxWord2(<br>         &amp;If2cDeselect, &amp;If2cSelect, <br>         POST_SELECT_DELAY_NS, POST_COMM_DELAY_US, <br>         cmd, 0xff);<br> } <br><\/pre>\n\n\n\n<p><\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Example_HOST-IF2C_Command_Calls_to_the_Interface_Code\"><\/span>Example HOST-IF2C Command Calls to the Interface Code<span class=\"ez-toc-section-end\"><\/span><\/h4>\n\n\n\n<p>Something like this could go into the host receive command loop for the switch on the command type:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">case DCMD_DO_IF2C:<br>    if (If2cHandler(arg1, arg2) == (uchar)0x00)<br>        ProcessTxString((char *)c_tx_do_if2c_ok);<br>    break;<br><\/pre>\n\n\n\n<p>And don&#8217;t forget about initializing the SPI and\/or managing the SPI configurations on the host:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">#ifdef INIT_SYSTEM_WITH_IF2C<br> #if INIT_SYSTEM_WITH_IF2C<br> <code> InitIf2c();<\/code><br> #endif<br>#endif<\/pre>\n\n\n\n<p>And example of the SetupSpi code, with plenty of comments and tested\/commented lines for illustration, left over dev notes:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">void SetupSpi( unsigned char polarity, unsigned char phase, unsigned char word_not_byte, <br>         unsigned char primary_prescaler_bits, <br>         unsigned char secondary_prescaler_bits) {<br><br><code>SPI2STAT = 0x0; \/\/ Disable SPI2 module first <\/code><br><code>SPI2CON1 = 0x01e1; <\/code><br><code>\/\/ Double-check - below taken from CE436 <\/code><br><code>\/\/ FRAMEN = 0, SPIFSD = 0,     DISSDO = 0, MODE16 = 0 <\/code><br><code>\/\/ SMP = 0,    CKP = 1,        CKE = 1,    SSEN = 0 <\/code><br><code>\/\/ MSTEN = 1,  SPRE = 0b000    PPRE = 0b01 <\/code><br><br><code>SPI2CON1bits.MSTEN = 1; \/\/ Master mode <\/code><br><code>SPI2CON1bits.SMP = 1; \/\/ 1 = sample at end of output, set only after master bit set SPI2CON1bits.SSEN = 0; \/\/ In master, GPIO is used for !SS <\/code><br><code>SPI2CON1bits.MODE16 = word_not_byte; \/\/ ADIS uses word mode <\/code><br><br><code>\/\/ Clock rate: SPI1,3,4 max rate master half-duplex 15 MHz, same SPI2 <\/code><br><code>\/\/SPI2CON1bits.SPRE = ADIS_SPI2_SPRE_521KHZ;         \/\/ Secondary - safest, slowest \/\/SPI2CON1bits.SPRE = ADIS_SPI2_SPRE_1042KHZ;        \/\/ Easily clearing 1kHz for manual capture on adis, but concern <\/code><br><br><code>SPI2CON1bits.SPRE = secondary_prescaler_bits; \/\/ Compromise, easily clears 1kHz, room for longer delay if needed <\/code><br><code>SPI2CON1bits.PPRE = primary_prescaler_bits; \/\/ Primary <\/code><br><br><code>SPI2CON1bits.CKE = phase; \/\/ Clock edge <\/code><br><code>SPI2CON1bits.CKP = polarity; \/\/ Clock polarity <\/code><br><br><code>SPI2STATbits.SPIEN = 1; \/\/ Enable SPI2<\/code><br>}<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>There are two (2) APIs of interest here: API for the DL-Host that talks to the IF2C, for example the DL0102GXN as a host, as provided in sample firmware. This is covered here. API for the IF2C accessory itself. A simple communications example is here.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[18,15,22,21,9,16,17,13,14,12],"tags":[],"class_list":["post-179","post","type-post","status-publish","format-standard","hentry","category-hdlite-accessories","category-hdlite-family","category-dl0102","category-dl0102gxn","category-hardware","category-hdl-0108-if2c-r01-a1","category-if2c","category-ndt","category-new-prototypes","category-ultrasonics","entry"],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/oshablue.com\/doc\/wp-json\/wp\/v2\/posts\/179","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/oshablue.com\/doc\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/oshablue.com\/doc\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/oshablue.com\/doc\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/oshablue.com\/doc\/wp-json\/wp\/v2\/comments?post=179"}],"version-history":[{"count":5,"href":"https:\/\/oshablue.com\/doc\/wp-json\/wp\/v2\/posts\/179\/revisions"}],"predecessor-version":[{"id":496,"href":"https:\/\/oshablue.com\/doc\/wp-json\/wp\/v2\/posts\/179\/revisions\/496"}],"wp:attachment":[{"href":"https:\/\/oshablue.com\/doc\/wp-json\/wp\/v2\/media?parent=179"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/oshablue.com\/doc\/wp-json\/wp\/v2\/categories?post=179"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/oshablue.com\/doc\/wp-json\/wp\/v2\/tags?post=179"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}