You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							286 lines
						
					
					
						
							7.7 KiB
						
					
					
				
			
		
		
	
	
							286 lines
						
					
					
						
							7.7 KiB
						
					
					
				| #define GMLAN_TICKS_PER_SECOND 33300 //1sec @ 33.3kbps
 | |
| #define GMLAN_TICKS_PER_TIMEOUT_TICKLE 500 //15ms @ 33.3kbps
 | |
| #define GMLAN_HIGH 0 //0 is high on bus (dominant)
 | |
| #define GMLAN_LOW 1 //1 is low on bus
 | |
| 
 | |
| #define DISABLED -1
 | |
| #define BITBANG 0
 | |
| #define GPIO_SWITCH 1
 | |
| 
 | |
| #define MAX_BITS_CAN_PACKET (200)
 | |
| 
 | |
| int gmlan_alt_mode = DISABLED;
 | |
| 
 | |
| // returns out_len
 | |
| int do_bitstuff(char *out, char *in, int in_len) {
 | |
|   int last_bit = -1;
 | |
|   int bit_cnt = 0;
 | |
|   int j = 0;
 | |
|   for (int i = 0; i < in_len; i++) {
 | |
|     char bit = in[i];
 | |
|     out[j] = bit;
 | |
|     j++;
 | |
| 
 | |
|     // do the stuffing
 | |
|     if (bit == last_bit) {
 | |
|       bit_cnt++;
 | |
|       if (bit_cnt == 5) {
 | |
|         // 5 in a row the same, do stuff
 | |
|         last_bit = !bit;
 | |
|         out[j] = last_bit;
 | |
|         j++;
 | |
|         bit_cnt = 1;
 | |
|       }
 | |
|     } else {
 | |
|       // this is a new bit
 | |
|       last_bit = bit;
 | |
|       bit_cnt = 1;
 | |
|     }
 | |
|   }
 | |
|   return j;
 | |
| }
 | |
| 
 | |
| int append_crc(char *in, int in_len) {
 | |
|   unsigned int crc = 0;
 | |
|   for (int i = 0; i < in_len; i++) {
 | |
|     crc <<= 1;
 | |
|     if (((unsigned int)(in[i]) ^ ((crc >> 15) & 1U)) != 0U) {
 | |
|       crc = crc ^ 0x4599U;
 | |
|     }
 | |
|     crc &= 0x7fffU;
 | |
|   }
 | |
|   int in_len_copy = in_len;
 | |
|   for (int i = 14; i >= 0; i--) {
 | |
|     in[in_len_copy] = (crc >> (unsigned int)(i)) & 1U;
 | |
|     in_len_copy++;
 | |
|   }
 | |
|   return in_len_copy;
 | |
| }
 | |
| 
 | |
| int append_bits(char *in, int in_len, char *app, int app_len) {
 | |
|   int in_len_copy = in_len;
 | |
|   for (int i = 0; i < app_len; i++) {
 | |
|     in[in_len_copy] = app[i];
 | |
|     in_len_copy++;
 | |
|   }
 | |
|   return in_len_copy;
 | |
| }
 | |
| 
 | |
| int append_int(char *in, int in_len, int val, int val_len) {
 | |
|   int in_len_copy = in_len;
 | |
|   for (int i = val_len - 1; i >= 0; i--) {
 | |
|     in[in_len_copy] = ((unsigned int)(val) & (1U << (unsigned int)(i))) != 0U;
 | |
|     in_len_copy++;
 | |
|   }
 | |
|   return in_len_copy;
 | |
| }
 | |
| 
 | |
| int get_bit_message(char *out, CAN_FIFOMailBox_TypeDef *to_bang) {
 | |
|   char pkt[MAX_BITS_CAN_PACKET];
 | |
|   char footer[] = {
 | |
|     1,  // CRC delimiter
 | |
|     1,  // ACK
 | |
|     1,  // ACK delimiter
 | |
|     1,1,1,1,1,1,1, // EOF
 | |
|     1,1,1, // IFS
 | |
|   };
 | |
| 
 | |
|   int len = 0;
 | |
| 
 | |
|   // test packet
 | |
|   int dlc_len = to_bang->RDTR & 0xF;
 | |
|   len = append_int(pkt, len, 0, 1);    // Start-of-frame
 | |
| 
 | |
|   if ((to_bang->RIR & 4) != 0) {
 | |
|     // extended identifier
 | |
|     len = append_int(pkt, len, to_bang->RIR >> 21, 11);  // Identifier
 | |
|     len = append_int(pkt, len, 3, 2);    // SRR+IDE
 | |
|     len = append_int(pkt, len, (to_bang->RIR >> 3) & ((1U << 18) - 1U), 18);  // Identifier
 | |
|     len = append_int(pkt, len, 0, 3);    // RTR+r1+r0
 | |
|   } else {
 | |
|     // standard identifier
 | |
|     len = append_int(pkt, len, to_bang->RIR >> 21, 11);  // Identifier
 | |
|     len = append_int(pkt, len, 0, 3);    // RTR+IDE+reserved
 | |
|   }
 | |
| 
 | |
|   len = append_int(pkt, len, dlc_len, 4);    // Data length code
 | |
| 
 | |
|   // append data
 | |
|   for (int i = 0; i < dlc_len; i++) {
 | |
|     unsigned char dat = ((unsigned char *)(&(to_bang->RDLR)))[i];
 | |
|     len = append_int(pkt, len, dat, 8);
 | |
|   }
 | |
| 
 | |
|   // append crc
 | |
|   len = append_crc(pkt, len);
 | |
| 
 | |
|   // do bitstuffing
 | |
|   len = do_bitstuff(out, pkt, len);
 | |
| 
 | |
|   // append footer
 | |
|   len = append_bits(out, len, footer, sizeof(footer));
 | |
|   return len;
 | |
| }
 | |
| 
 | |
| void setup_timer4(void) {
 | |
|   // setup
 | |
|   TIM4->PSC = 48-1;          // tick on 1 us
 | |
|   TIM4->CR1 = TIM_CR1_CEN;   // enable
 | |
|   TIM4->ARR = 30-1;          // 33.3 kbps
 | |
| 
 | |
|   // in case it's disabled
 | |
|   NVIC_EnableIRQ(TIM4_IRQn);
 | |
| 
 | |
|   // run the interrupt
 | |
|   TIM4->DIER = TIM_DIER_UIE; // update interrupt
 | |
|   TIM4->SR = 0;
 | |
| }
 | |
| 
 | |
| int gmlan_timeout_counter = GMLAN_TICKS_PER_TIMEOUT_TICKLE; //GMLAN transceiver times out every 17ms held high; tickle every 15ms
 | |
| int can_timeout_counter = GMLAN_TICKS_PER_SECOND; //1 second
 | |
| 
 | |
| int inverted_bit_to_send = GMLAN_HIGH;
 | |
| int gmlan_switch_below_timeout = -1;
 | |
| int gmlan_switch_timeout_enable = 0;
 | |
| 
 | |
| void gmlan_switch_init(int timeout_enable) {
 | |
|   gmlan_switch_timeout_enable = timeout_enable;
 | |
|   gmlan_alt_mode = GPIO_SWITCH;
 | |
|   gmlan_switch_below_timeout = 1;
 | |
|   set_gpio_mode(GPIOB, 13, MODE_OUTPUT);
 | |
| 
 | |
|   setup_timer4();
 | |
| 
 | |
|   inverted_bit_to_send = GMLAN_LOW; //We got initialized, set the output low
 | |
| }
 | |
| 
 | |
| void set_gmlan_digital_output(int to_set) {
 | |
|   inverted_bit_to_send = to_set;
 | |
|   /*
 | |
|   puts("Writing ");
 | |
|   puth(inverted_bit_to_send);
 | |
|   puts("\n");
 | |
|   */
 | |
| }
 | |
| 
 | |
| void reset_gmlan_switch_timeout(void) {
 | |
|   can_timeout_counter = GMLAN_TICKS_PER_SECOND;
 | |
|   gmlan_switch_below_timeout = 1;
 | |
|   gmlan_alt_mode = GPIO_SWITCH;
 | |
| }
 | |
| 
 | |
| void set_bitbanged_gmlan(int val) {
 | |
|   if (val != 0) {
 | |
|     GPIOB->ODR |= (1U << 13);
 | |
|   } else {
 | |
|     GPIOB->ODR &= ~(1U << 13);
 | |
|   }
 | |
| }
 | |
| 
 | |
| char pkt_stuffed[MAX_BITS_CAN_PACKET];
 | |
| int gmlan_sending = -1;
 | |
| int gmlan_sendmax = -1;
 | |
| bool gmlan_send_ok = true;
 | |
| 
 | |
| int gmlan_silent_count = 0;
 | |
| int gmlan_fail_count = 0;
 | |
| #define REQUIRED_SILENT_TIME 10
 | |
| #define MAX_FAIL_COUNT 10
 | |
| 
 | |
| void TIM4_IRQHandler(void) {
 | |
|   if (gmlan_alt_mode == BITBANG) {
 | |
|     if ((TIM4->SR & TIM_SR_UIF) && (gmlan_sendmax != -1)) {
 | |
|       int read = get_gpio_input(GPIOB, 12);
 | |
|       if (gmlan_silent_count < REQUIRED_SILENT_TIME) {
 | |
|         if (read == 0) {
 | |
|           gmlan_silent_count = 0;
 | |
|         } else {
 | |
|           gmlan_silent_count++;
 | |
|         }
 | |
|       } else {
 | |
|         bool retry = 0;
 | |
|         // in send loop
 | |
|         if ((gmlan_sending > 0) &&  // not first bit
 | |
|            ((read == 0) && (pkt_stuffed[gmlan_sending-1] == 1)) &&  // bus wrongly dominant
 | |
|            (gmlan_sending != (gmlan_sendmax - 11))) {    //not ack bit
 | |
|           puts("GMLAN ERR: bus driven at ");
 | |
|           puth(gmlan_sending);
 | |
|           puts("\n");
 | |
|           retry = 1;
 | |
|         } else if ((read == 1) && (gmlan_sending == (gmlan_sendmax - 11))) {    // recessive during ACK
 | |
|           puts("GMLAN ERR: didn't recv ACK\n");
 | |
|           retry = 1;
 | |
|         } else {
 | |
|           // do not retry
 | |
|         }
 | |
|         if (retry) {
 | |
|           // reset sender (retry after 7 silent)
 | |
|           set_bitbanged_gmlan(1); // recessive
 | |
|           gmlan_silent_count = 0;
 | |
|           gmlan_sending = 0;
 | |
|           gmlan_fail_count++;
 | |
|           if (gmlan_fail_count == MAX_FAIL_COUNT) {
 | |
|             puts("GMLAN ERR: giving up send\n");
 | |
|             gmlan_send_ok = false;
 | |
|           }
 | |
|         } else {
 | |
|           set_bitbanged_gmlan(pkt_stuffed[gmlan_sending]);
 | |
|           gmlan_sending++;
 | |
|         }
 | |
|       }
 | |
|       if ((gmlan_sending == gmlan_sendmax) || (gmlan_fail_count == MAX_FAIL_COUNT)) {
 | |
|         set_bitbanged_gmlan(1); // recessive
 | |
|         set_gpio_mode(GPIOB, 13, MODE_INPUT);
 | |
|         TIM4->DIER = 0;  // no update interrupt
 | |
|         TIM4->CR1 = 0;   // disable timer
 | |
|         gmlan_sendmax = -1;   // exit
 | |
|       }
 | |
|     }
 | |
|     TIM4->SR = 0;
 | |
|   } else if (gmlan_alt_mode == GPIO_SWITCH) {
 | |
|     if ((TIM4->SR & TIM_SR_UIF) && (gmlan_switch_below_timeout != -1)) {
 | |
|       if ((can_timeout_counter == 0) && gmlan_switch_timeout_enable) {
 | |
|         //it has been more than 1 second since timeout was reset; disable timer and restore the GMLAN output
 | |
|         set_gpio_output(GPIOB, 13, GMLAN_LOW);
 | |
|         gmlan_switch_below_timeout = -1;
 | |
|         gmlan_timeout_counter = GMLAN_TICKS_PER_TIMEOUT_TICKLE;
 | |
|         gmlan_alt_mode = DISABLED;
 | |
|       }
 | |
|       else {
 | |
|         can_timeout_counter--;
 | |
|         if (gmlan_timeout_counter == 0) {
 | |
|           //Send a 1 (bus low) every 15ms to reset the GMLAN transceivers timeout
 | |
|           gmlan_timeout_counter = GMLAN_TICKS_PER_TIMEOUT_TICKLE;
 | |
|           set_gpio_output(GPIOB, 13, GMLAN_LOW);
 | |
|         }
 | |
|         else {
 | |
|           set_gpio_output(GPIOB, 13, inverted_bit_to_send);
 | |
|           gmlan_timeout_counter--;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     TIM4->SR = 0;
 | |
|   } else {
 | |
|     puts("invalid gmlan_alt_mode\n");
 | |
|   }
 | |
| }
 | |
| 
 | |
| bool bitbang_gmlan(CAN_FIFOMailBox_TypeDef *to_bang) {
 | |
|   gmlan_send_ok = true;
 | |
|   gmlan_alt_mode = BITBANG;
 | |
| 
 | |
|   if (gmlan_sendmax == -1) {
 | |
|     int len = get_bit_message(pkt_stuffed, to_bang);
 | |
|     gmlan_fail_count = 0;
 | |
|     gmlan_silent_count = 0;
 | |
|     gmlan_sending = 0;
 | |
|     gmlan_sendmax = len;
 | |
|     // setup for bitbang loop
 | |
|     set_bitbanged_gmlan(1); // recessive
 | |
|     set_gpio_mode(GPIOB, 13, MODE_OUTPUT);
 | |
| 
 | |
|     setup_timer4();
 | |
|   }
 | |
|   return gmlan_send_ok;
 | |
| }
 | |
| 
 | |
| 
 |