source: trunk/fw_g473rct/SES/src/main.c @ 25

Last change on this file since 25 was 25, checked in by f.jahn, 7 weeks ago

RTC implementiert

File size: 17.5 KB
Line 
1/* USER CODE BEGIN Header */
2/**
3  ******************************************************************************
4  * @file           : main.c
5  * @brief          : Main program body
6  ******************************************************************************
7  * @attention
8  *
9  * Copyright (c) 2025 STMicroelectronics.
10  * All rights reserved.
11  *
12  * This software is licensed under terms that can be found in the LICENSE file
13  * in the root directory of this software component.
14  * If no LICENSE file comes with this software, it is provided AS-IS.
15  *
16  ******************************************************************************
17  */
18/* USER CODE END Header */
19/* Includes ------------------------------------------------------------------*/
20#include "main.h"
21#include "adc.h"
22#include "dma.h"
23#include "fdcan.h"
24#include "i2c.h"
25#include "spi.h"
26#include "usart.h"
27#include "usb.h"
28#include "gpio.h"
29
30/* Private includes ----------------------------------------------------------*/
31/* USER CODE BEGIN Includes */
32#include <stdio.h>
33#include "sysdata.h"
34#include "wh_counter.h"
35#include "ah_counter.h"
36#include "eeprom.h"
37#include "modbus.h"
38#include "chip_temperature.h"
39#include "battery_voltage.h"
40#include "ads1260.h"
41#include "shunt_voltage.h"
42#include "fast_current.h"
43#include "int_bat_voltage.h"
44#include "chip_temperature.h"
45#include "shunt_temperature.h"
46#include "esr.h"
47#include "ads1260.h"
48#include "outputs.h"
49#include "crc.h"
50/* USER CODE END Includes */
51
52/* Private typedef -----------------------------------------------------------*/
53/* USER CODE BEGIN PTD */
54
55/* USER CODE END PTD */
56
57/* Private define ------------------------------------------------------------*/
58/* USER CODE BEGIN PD */
59
60/* USER CODE END PD */
61
62/* Private macro -------------------------------------------------------------*/
63/* USER CODE BEGIN PM */
64
65/* USER CODE END PM */
66
67/* Private variables ---------------------------------------------------------*/
68
69/* USER CODE BEGIN PV */
70modbus_t modbusData __attribute__((section(".RAM1")));
71
72__IO uint16_t adc12Data[100][2] __attribute__((section(".RAM1")));
73__IO uint32_t adc1Data[1] __attribute__((section(".RAM1")));
74__IO uint32_t adc2Data[1] __attribute__((section(".RAM1")));
75__IO uint32_t adc3Data[3] __attribute__((section(".RAM1")));
76__IO uint32_t adc4Data[1] __attribute__((section(".RAM1")));
77__IO uint32_t adc5Data[4] __attribute__((section(".RAM1")));
78int silentmode =0;
79static volatile uint32_t newADC12Data = 0;
80static volatile uint32_t newADC3Data = 0;
81static volatile uint32_t newADC4Data = 0;
82static volatile uint32_t newADC5Data = 0;
83/* USER CODE END PV */
84
85/* Private function prototypes -----------------------------------------------*/
86void SystemClock_Config(void);
87/* USER CODE BEGIN PFP */
88bool SetFlashReadProtection(bool state);
89uint8_t printprotectionstate(void);
90bool SetBootFromFlashAndReadOutProtection(void);
91/* USER CODE END PFP */
92
93/* Private user code ---------------------------------------------------------*/
94/* USER CODE BEGIN 0 */
95
96/* USER CODE END 0 */
97
98/**
99  * @brief  The application entry point.
100  * @retval int
101  */
102int main(void)
103{
104
105  /* USER CODE BEGIN 1 */
106    uint8_t firstStartCatcher;
107        int mode_button_disable_time=0;
108        uint32_t adc12_time;
109        uint32_t adc12_lasttime;
110  /* USER CODE END 1 */
111
112  /* MCU Configuration--------------------------------------------------------*/
113
114  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
115  HAL_Init();
116
117  /* USER CODE BEGIN Init */
118
119  /* USER CODE END Init */
120
121  /* Configure the system clock */
122  SystemClock_Config();
123
124  /* USER CODE BEGIN SysInit */
125
126  /* USER CODE END SysInit */
127
128  /* Initialize all configured peripherals */
129  MX_GPIO_Init();
130  MX_DMA_Init();
131  MX_ADC1_Init();
132  MX_ADC2_Init();
133  MX_ADC3_Init();
134  MX_ADC4_Init();
135  MX_ADC5_Init();
136  MX_FDCAN2_Init();
137  MX_FDCAN3_Init();
138  MX_I2C3_Init();
139  MX_I2C4_Init();
140  MX_SPI3_Init();
141  MX_USART1_UART_Init();
142  MX_USART2_UART_Init();
143  MX_USB_PCD_Init();
144  /* USER CODE BEGIN 2 */
145  MX_CRC_Init(); //Cube is not generating this call ?!
146  printf("Test debug io\r\n");
147  SYS_DATA_Init();
148  WH_COUNTER_Init();
149  AH_COUNTER_Init();
150
151
152  startType_t startType = EEPROM_isFirstStart();
153
154  switch(startType)
155  {
156          case FIRST_START_AFTER_ERASE:                                 EEPROM_fullRestore(&sys_data);            break;
157          case FIRST_START_AFTER_COMPARTIBLE_UPDATE:    EEPROM_readConfig(&sys_data);             break;
158          case FIRST_START_AFTER_INCOMPARTIBLE_UPDATE:  EEPROM_factoryRestore(&sys_data, 0);  break;  // Preserving calibration and settings
159          case FIRST_START_ERROR:                                               EEPROM_fullRestore(&sys_data);            break;
160  }
161
162  if(HAL_GPIO_ReadPin(GPIO_INPUT_BTN_MODE_GPIO_Port, GPIO_INPUT_BTN_MODE_Pin) == GPIO_PIN_RESET)
163  {
164    HAL_Delay(50);
165    if(HAL_GPIO_ReadPin(GPIO_INPUT_BTN_MODE_GPIO_Port, GPIO_INPUT_BTN_MODE_Pin) == GPIO_PIN_RESET)
166    {
167      printf("factory restore...\n");
168      EEPROM_factoryRestore(&sys_data, 1);
169    }
170  }
171
172    // Modbus Initialisierung
173  mbInit(&modbusData, sys_data.s.parameter.baudrate, sys_data.s.parameter.parityMode, sys_data.s.parameter.stopBit, &huart2);
174
175    // STM32G0 Chiptemperatur Kalibrierung
176  CHIP_TEMPERATURE_Calibration();
177
178  HAL_ADCEx_Calibration_Start(&hadc1, ADC_DIFFERENTIAL_ENDED);
179  HAL_ADCEx_Calibration_Start(&hadc2, ADC_DIFFERENTIAL_ENDED);
180  HAL_ADCEx_Calibration_Start(&hadc3, ADC_SINGLE_ENDED);
181  HAL_ADCEx_Calibration_Start(&hadc4, ADC_DIFFERENTIAL_ENDED);
182  HAL_ADCEx_Calibration_Start(&hadc5, ADC_SINGLE_ENDED);
183
184
185  //SET_BIT(hadc2.Instance->CFGR, ADC_CFGR_DMAEN); //Enable DMA transfer for ADC slave (ADC12_CCR.MDMA = 0b00 -> MDMA mode disabled)
186  //HAL_DMA_Start(hadc2.DMA_Handle,(uint32_t)&hadc2.Instance->DR, (uint32_t)adc2Data,1); //Start ADC slave DMA
187  //SET_BIT(hadc1.Instance->CFGR, ADC_CFGR_DMAEN); //Enable DMA transfer for ADC master (ADC12_CCR.MDMA = 0b00 -> MDMA mode disabled)
188 
189    //HAL_ADC_Start_DMA(&hadc2, (uint32_t*)adc2Data, 1);
190  if (HAL_ADCEx_MultiModeStart_DMA(&hadc1,(uint32_t *)adc12Data,100))  //Start ADC interleaved mode
191  {
192     /* Start Error */
193     Error_Handler();
194  }
195
196  if (HAL_ADC_Start_DMA(&hadc3, (uint32_t *) adc3Data , 3))
197  {
198     /* Start Error */
199     Error_Handler();
200  }
201
202  if (HAL_ADC_Start_DMA(&hadc4, (uint32_t *) adc4Data , 1))
203  {
204     /* Start Error */
205     Error_Handler();
206  }
207
208
209  if (HAL_ADC_Start_DMA(&hadc5, (uint32_t *) adc5Data , 4))
210  {
211     /* Start Error */
212     Error_Handler();
213  }
214
215
216  // ADS1260 Initialierung
217  ADS1260_init();
218  printf("ADS1260 Init\n");
219  OUTPUTS_Init();
220
221  /* USER CODE END 2 */
222
223  /* Infinite loop */
224  /* USER CODE BEGIN WHILE */
225  while (1)
226  {
227    /* USER CODE END WHILE */
228
229    /* USER CODE BEGIN 3 */
230        if (newADC12Data == 1)
231    {
232          //Mit ADC_DIV2,Sample time 12,5Cycklen, ADC Clock 50Mhz, Oversampling 256
233          //Tconv = 6400 Takte = 0,128ms Pro Konvertierung. Also für 100 messwerte 12,8mS
234          BATTERY_VOLTAGE_Exec( adc12Data[0][1]);
235          FAST_CURRENT_Exec(adc12Data[0][0]); 
236          newADC12Data = 0;
237          adc12_time = HAL_GetTick() - adc12_lasttime;
238          adc12_lasttime = HAL_GetTick();
239
240        }
241
242
243        if (newADC3Data == 1)
244    {
245          SHUNT_TEMPERATURE_Exec(adc3Data[0]);
246        }
247
248
249        if (newADC4Data == 1)
250    {
251          SHUNT_VOLTAGE_Exec( adc4Data[0]);
252        }
253
254
255        if (newADC5Data == 1)
256    {
257          CHIP_TEMPERATURE_Exec(adc5Data[0]);
258          INT_BAT_VOLTAGE_Exec( adc5Data[1]);
259          sys_data.s.values.ovp_sense =  (adc5Data[2] * VREF * 21 ) / 65536.0;
260      sys_data.s.values.lvp_sense =  (adc5Data[3] * VREF * 21 ) / 65536.0;
261        }
262
263
264        if (newCurrentValue == 1)
265    {
266      ADS1260_ConversionFinished(); 
267      ESR_Exec();
268
269      newCurrentValue = 0;
270
271    }
272
273        if(sys_data.s.parameter.command != 0)
274    {
275      if  (modbusData.current_query ==  MB_QUERY_NOTHING)
276      {
277        //printf("CMD = %d\n", sys_data.s.parameter.command);
278        switch (sys_data.s.parameter.command )
279        {
280          case COMMAND_STORE_CONFIG:                          EEPROM_storeConfig(&sys_data,0);                                                                                    break;
281          case COMMAND_FULL_RESTORE:                          EEPROM_fullRestore(&sys_data);                                                                                      break;
282          case COMMAND_FACTORY_RESTORE:                       EEPROM_factoryRestore(&sys_data, 1);                                                                                break;
283          case COMMAND_RESTORE_LAST_SAVED_VALUES:             EEPROM_readConfig(&sys_data);                                                                                               break;
284          case COMMAND_STORE_WITH_SERIAL_NUMBER:              EEPROM_storeConfig(&sys_data,1);                                                                                    break;        // Seriennummer schreiben
285          case COMMAND_RESTART:                               NVIC_SystemReset();                                                                                                                 break;
286          case COMMAND_BATTERY_CURRENT_OFFSET_CAL:            ADS_1260_BatteryCurrentOffsetCalibrationStart(&sys_data);                                   break;
287          case COMMAND_BATTERY_CURRENT_OFFSET_COMMONMODE_CAL: ADS_1260_BatteryCurrentOffsetCommonModeErrorComepensationStart(&sys_data);  break;
288          case COMMAND_BATTERY_CURRENT_OFFSET_TEMP_CAL:       ADS_1260_BatteryCurrentOffsetTemperatureErrorComepensationStart();                  break;
289          case COMMAND_BATTERY_CURRENT_GAIN_CAL:              ADS_1260_BatteryCurrentGainCalibrationStart(&sys_data);                                     break;
290          case COMMAND_BATTERY_CURRENT_GAIN_TEMP_SHUNT_CAL:   ADS_1260_BatteryCurrentGainTemperatureCalibrationShuntStart();                      break;
291//        case COMMAND_BATTERY_CURRENT_GAIN_TEMP_CHIP_CAL:    ADS_1260_BatteryCurrentGainTemperatureCalibrationChipStart(); break;
292          case COMMAND_SET_RDP_LEVEL0:                        SetFlashReadProtection(false);                                                                                      break;
293          case COMMAND_SET_RDP_LEVEL1:                        SetFlashReadProtection(true);                                                                                               break;
294          case COMMAND_SET_RDP_LEVEL1_AND_BOOTSEL:            SetBootFromFlashAndReadOutProtection();                                                                     break;
295          default:                                            printf("UNKNOWN COMMAND\n");
296        }
297        sys_data.s.parameter.command = 0;
298      }
299      else
300      {
301        //printf("wait with execution till modbus communnikation finished\n");
302      }
303    }
304
305    if((HAL_GPIO_ReadPin(GPIO_INPUT_BTN_MODE_GPIO_Port, GPIO_INPUT_BTN_MODE_Pin) == GPIO_PIN_RESET) && (mode_button_disable_time == 0))
306    {
307      HAL_Delay(10);
308      //Taste weiterhin gedrckt?
309      if(HAL_GPIO_ReadPin(GPIO_INPUT_BTN_MODE_GPIO_Port, GPIO_INPUT_BTN_MODE_Pin) == GPIO_PIN_RESET)
310      {
311        //Ja, dann Silent Mode umschalten
312        mode_button_disable_time=500;
313        if (silentmode == 0)
314        {
315          silentmode = 1;
316          HAL_GPIO_WritePin(LED_FUNC_GPIO_Port, LED_FUNC_Pin,GPIO_PIN_SET);
317        }
318        else
319        {
320          silentmode = 0;
321        }
322       }
323    }
324
325        // Modbus Kommunikation
326
327//      printf("data12d1=%d,data12d2=%d,data5=%d\r\n", adc12Data[0], adc12Data[1] , adc5Data[2]);
328    if (mbGetFrameComplete(&modbusData) == true)
329    {
330      if (mbSlaveCheckModbusRtuQuery(&modbusData) == RESPOND_TO_QUERY)
331      {
332          if (silentmode == 0)
333          {
334            mbSlaveProcessRtuQuery(&modbusData);
335          }
336      }
337      else
338      {
339        huart1.RxState = HAL_UART_STATE_BUSY_RX;
340      }
341    }
342
343  }
344  /* USER CODE END 3 */
345}
346
347/**
348  * @brief System Clock Configuration
349  * @retval None
350  */
351void SystemClock_Config(void)
352{
353  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
354  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
355
356  /** Configure the main internal regulator output voltage
357  */
358  HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);
359
360  /** Initializes the RCC Oscillators according to the specified parameters
361  * in the RCC_OscInitTypeDef structure.
362  */
363  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI48|RCC_OSCILLATORTYPE_HSE;
364  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
365  RCC_OscInitStruct.HSI48State = RCC_HSI48_ON;
366  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
367  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
368  RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV2;
369  RCC_OscInitStruct.PLL.PLLN = 16;
370  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
371  RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
372  RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
373  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
374  {
375    Error_Handler();
376  }
377
378  /** Initializes the CPU, AHB and APB buses clocks
379  */
380  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
381                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
382  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
383  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
384  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
385  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
386
387  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3) != HAL_OK)
388  {
389    Error_Handler();
390  }
391}
392
393/* USER CODE BEGIN 4 */
394 void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
395 {
396    if (hadc->Instance==ADC1)
397        {
398          newADC12Data=1;
399        }
400
401        if (hadc->Instance==ADC3)
402        {
403          newADC3Data=1;
404        }
405
406
407        if (hadc->Instance==ADC4)
408        {
409          newADC4Data=1;
410        }
411
412        if (hadc->Instance==ADC5)
413        {
414          newADC5Data=1;
415        }
416 }
417
418
419 
420/**
421
422  * @brief  Set flash read protection.
423
424  * @param  [in] state: Flash read protection state, true: enable protection, false: disable protection.
425
426  * @retval true:  Successful operation.
427
428  * @retval false: Operation failed.
429
430  */
431
432bool SetFlashReadProtection(bool state)
433{
434
435  FLASH_OBProgramInitTypeDef OptionsBytesStruct = {0};
436  HAL_FLASHEx_OBGetConfig(&OptionsBytesStruct);
437
438  if(state == true)
439  {
440    printf("Start enable readout protection\n");
441    if(OptionsBytesStruct.RDPLevel == OB_RDP_LEVEL_0)
442    {
443      OptionsBytesStruct.OptionType = OPTIONBYTE_RDP;
444      OptionsBytesStruct.RDPLevel   = OB_RDP_LEVEL_1;
445      if (HAL_FLASH_Unlock() != HAL_OK)
446      {
447        printf("Flash unlock error\n");
448      }
449      if (HAL_FLASH_OB_Unlock() != HAL_OK)
450      {
451        printf("Flash ob unlock error\n");
452      }
453
454      printf("...Flash unlock\n");
455      if(HAL_FLASHEx_OBProgram(&OptionsBytesStruct) != HAL_OK)
456      {
457        printf("...Enable lock error\n");
458        HAL_FLASH_OB_Lock();
459        return false;
460      }
461      HAL_FLASH_OB_Lock();
462      printf("Flash Optionbyte locked\n");
463      HAL_FLASH_Lock();
464      printf("Flash  locked\n");
465      printf("...Enable lock process finished\n");
466    }
467    else
468    {
469      printf("...Flash lock already active\n");
470    }
471  }
472  else
473  {
474    if(OptionsBytesStruct.RDPLevel == OB_RDP_LEVEL_1)
475    {
476      OptionsBytesStruct.OptionType = OPTIONBYTE_RDP;
477      OptionsBytesStruct.RDPLevel   = OB_RDP_LEVEL_0;
478
479      if (HAL_FLASH_Unlock() != HAL_OK)
480      {
481        printf("Flash unlock error\n");
482        return false;
483      }
484      printf("...Flash unlocked\n");
485
486      if (HAL_FLASH_OB_Unlock() != HAL_OK)
487      {
488        printf("Flash ob unlock error\n");
489        return false;
490      }
491      printf("...Flash ob unlocked\n");
492
493      if(HAL_FLASHEx_OBProgram(&OptionsBytesStruct) != HAL_OK)
494      {
495        HAL_FLASH_OB_Lock();
496        printf("Flash Optionbyte programm failed\n");
497        return false;
498      }
499
500      printf("Flash Optionbyte programmed\n");
501      HAL_FLASH_OB_Lock();
502      printf("Flash Optionbyte locked\n");
503      HAL_FLASH_Lock();
504      printf("Flash  locked\n");
505      printf("...Disable lock process finished\n");
506
507;
508    }
509  }
510  return true;
511}
512
513bool SetBootFromFlashAndReadOutProtection(void)
514{
515
516  FLASH_OBProgramInitTypeDef OptionsBytesStruct = {0};
517  HAL_FLASHEx_OBGetConfig(&OptionsBytesStruct);
518
519  //Konfiguriere RDP fr Readoutprotection and USER OPTION BYTE FR Boot from Flash
520  OptionsBytesStruct.OptionType = OPTIONBYTE_USER | OPTIONBYTE_RDP;
521
522  //Set Readout Protection Level 1
523  OptionsBytesStruct.OptionType = OPTIONBYTE_USER|OPTIONBYTE_RDP;
524  OptionsBytesStruct.RDPLevel   = OB_RDP_LEVEL_1;
525
526  //Selecting Boot from Main Flash Memory
527  OptionsBytesStruct.USERType =    OB_USER_nBOOT0 | OB_USER_nSWBOOT0 | OB_USER_nBOOT1 ;
528  OptionsBytesStruct.USERConfig  = OB_USER_nBOOT0 | OB_USER_nSWBOOT0;
529
530  if (HAL_FLASH_Unlock() != HAL_OK)
531  {
532    printf("Flash unlock error\n");
533  }
534  if (HAL_FLASH_OB_Unlock() != HAL_OK)
535  {
536    printf("Flash ob unlock error\n");
537  }
538
539  printf("...Flash unlock\n");
540  if(HAL_FLASHEx_OBProgram(&OptionsBytesStruct) != HAL_OK)
541  {
542    printf("...Enable lock error\n");
543    HAL_FLASH_OB_Lock();
544    return false;
545  }
546  HAL_FLASH_OB_Lock();
547  printf("Flash Optionbyte locked\n");
548  HAL_FLASH_Lock();
549  printf("Flash  locked\n");
550  printf("...Enable lock process finished\n");
551
552  return true;
553}
554uint8_t printprotectionstate(void)
555{
556  FLASH_OBProgramInitTypeDef OptionsBytesStruct = {0};
557  HAL_FLASHEx_OBGetConfig(&OptionsBytesStruct);
558  uint8_t result = 0;
559
560  if(OptionsBytesStruct.RDPLevel == OB_RDP_LEVEL_0)
561  {
562    //OptionsBytesStruct.OptionType = OPTIONBYTE_RDP;
563    //OptionsBytesStruct.RDPLevel   = OB_RDP_LEVEL_1;
564    printf("PROTECTION: OB_RDP_LEVEL_0\n");
565    result = 0;
566  }
567  else if(OptionsBytesStruct.RDPLevel == OB_RDP_LEVEL_1)
568  {
569    printf("PROTECTION: OB_RDP_LEVEL_1\n");
570    result = 1;
571  }
572  else if(OptionsBytesStruct.RDPLevel == OB_RDP_LEVEL_2)
573  {
574    printf("PROTECTION: OB_RDP_LEVEL_2\n");
575    result = 2;
576  }
577  return  result;
578}
579
580/* USER CODE END 4 */
581
582/**
583  * @brief  This function is executed in case of error occurrence.
584  * @retval None
585  */
586void Error_Handler(void)
587{
588  /* USER CODE BEGIN Error_Handler_Debug */
589  /* User can add his own implementation to report the HAL error return state */
590  __disable_irq();
591  printf("error handler!\r\n");
592  while (1)
593  {
594  }
595  /* USER CODE END Error_Handler_Debug */
596}
597#ifdef USE_FULL_ASSERT
598/**
599  * @brief  Reports the name of the source file and the source line number
600  *         where the assert_param error has occurred.
601  * @param  file: pointer to the source file name
602  * @param  line: assert_param error line source number
603  * @retval None
604  */
605void assert_failed(uint8_t *file, uint32_t line)
606{
607  /* USER CODE BEGIN 6 */
608  /* User can add his own implementation to report the file name and line number,
609     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
610         printf("Wrong parameters value: file %s on line %d\r\n", file, line);
611  /* USER CODE END 6 */
612}
613#endif /* USE_FULL_ASSERT */
Note: See TracBrowser for help on using the repository browser.