Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: модификатор const. Как правильно использовать в Си
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
Страницы: 1, 2, 3
inventor
где компилятор должен расположить "переменные"
такого вида:

CODE
// Описано глобально
const u8 x_pos[][8] = {
{50, 60},
{55, 62, 69, 76, 83, 90, 97, 104},
{76},
{76},
};


то же самое, описано внутри функции


и то же самое внутри функции
CODE

static const u8 x_pos[][8] = {
{50, 60},
{55, 62, 69, 76, 83, 90, 97, 104},
{76},
{76},
};



у меня есть неизменяемый массив большого размера
и при входе в функцию
этот констатный масив создается в стеке.
если его не определить как static
правильно ли это поведение или нет?


в первом варианте в глобальной константе
этот массив помещен в память Flash. Правильное поведение.

Во втором варианте в стек - неправильное
в третьем варианте во Flash память.





Kabdim
rtfm, очень нужно почитать умную книжку по языку на котором разрабатываете.

Модификатор const = сообщение компилятору что бы он проследил что бы код в котором определена эта переменная не пытался менять эти данные. Никаких других гарантий просто const не даёт. А еще бывают такие случаи как например volatile const или const register или const - аргумент функции или преобразования типов при которых cv-модификаторы меняются.
Вместе с тем конкретные компиляторы и линкеры для ембеда размещают глобальные константы во флеше. Как они станут глобальными через объявление на верхнем уровне или через спецификатор static - не важно.

Всё увиденное - верное поведение.
inventor
Цитата(Kabdim @ Dec 22 2017, 19:01) *
Вместе с тем конкретные компиляторы и линкеры для ембеда размещают глобальные константы во флеше. Как они станут глобальными через объявление на верхнем уровне или через спецификатор static - не важно.

Всё увиденное - верное поведение.



может ли компилятор поместить static const не во flash а в памяти данных?
demiurg_spb
Цитата(inventor @ Dec 22 2017, 19:21) *
может ли компилятор поместить static const не во flash а в памяти данных?

Легко. Причём это поведение описано в стандарте.
Если у флэша и ОЗУ разные адресные пространства именно так и будет.
Например, для AVR специально придуман квалификатор __flash, который укажет компилятору, что данные нужно поместить во флэш, а не в основную память (коей считается ОЗУ).
Для ARM, где единое адресное пространство, можно с уверенностью сказать, что static const данные лягут во флэш (кроме случая когда компилятор решит соптимизировать) .

Умная книга, которую ТС советовали читать - это стандарт языка Си...
Raven
А разве не должен компилятор помещать глобальные и static const объекты в .rodata секцию? (которая естественным образом ассоциируется с FLASH)
demiurg_spb
Цитата(Raven @ Dec 22 2017, 19:53) *
Нет не должен т.к. .rodata не всегда ассоциируется с FLASH.
Более того в avr-gcc нет секции .rodata

http://www.nongnu.org/avr-libc/user-manual/mem_sections.html
http://www.nongnu.org/avr-libc/user-manual/malloc.html
Kabdim
Цитата(inventor @ Dec 22 2017, 19:21) *
может ли компилятор поместить static const не во flash а в памяти данных?

Теоретически может, но делать этого не будет, т.к. поведение задано настройками.
Если говорить за gcc, то где-то в недрах проекта у вас должен быть файл с расширением *.ld в котором записано что и куда класть. Вы можете его редактировать что бы получить результат отличный от того того что по умолчанию.
Цитата(Raven @ Dec 22 2017, 19:53) *
А разве не должен компилятор помещать глобальные и static const объекты в .rodata секцию? (которая естественным образом ассоциируется с FLASH)

А линкер может в соответствии со своим скриптом секцию запихнуть туда куда записано в скрипте.
demiurg_spb
Цитата(Kabdim @ Dec 22 2017, 20:00) *

Согласно стандарту языка Си константные данные обязаны лечь в основное адресное пространство - всё.
А куда они лягут - об этом более нет ни слова.
Кстати, задумайтесь над тем что будет если константные данные всегда будут лежать во флэш и чем это чревато для архитектуры AVR и не только...

Совершенно легальный код станет невозможен:
Код
char str1[] = "xxx";
const char str2[] = "yyyy";

extern void print_str(const char* str);

print_str(str1);  // норм
print_str(str2);  // попа

Или так будет делать бессмысленно:
Код
volatite const int uptime;

Это я к чему - крутить параметры в скриптах линкера надо не с шашой наголо, а очень и очень вдумчиво...
k155la3
Цитата(Raven @ Dec 22 2017, 19:53) *
А разве не должен компилятор помещать глобальные и static const объекты в .rodata секцию? (которая естественным образом ассоциируется с FLASH)

Я сразу себя приучил, что компилятор мне ничего не "должен" sm.gif
Особенно в части, если включена оптимизация. И даже если не включена.
Есть много платформо-зависимых ньюансов.
Разобраться, опятьже, помогает RTFM + работа в отладчике с memory-->View.
inventor
то есть для того что бы константные данные
легли во flash память необходимо
сделать typedef для такого типа:


CODE
typedef const unsigned char cu8;
#define scu8 static cu8
Kabdim
Цитата(demiurg_spb @ Dec 22 2017, 20:07) *
Согласно стандарту языка Си константные данные обязаны лечь в основное адресное пространство - всё.

Верно, но пост был про поведение компилятора, а раздел для новичков, так что ответ по дефолту шел про армы о чем свидетельствуют некоторые ответы ТСа. Об особенностях авров честно говоря задумываться не хочу, в 2017 труп уже пора закопать.
DASM
Цитата(Kabdim @ Dec 23 2017, 22:41) *
Верно, но пост был про поведение компилятора, а раздел для новичков, так что ответ по дефолту шел про армы о чем свидетельствуют некоторые ответы ТСа. Об особенностях авров честно говоря задумываться не хочу, в 2017 труп уже пора закопать.

ну да, stm8 дешевле.
juvf
Цитата(demiurg_spb @ Dec 22 2017, 22:07) *
Согласно стандарту языка Си константные данные обязаны лечь в основное адресное пространство - всё.
Что такое "основное адресное пространство"? В Си нет такого. В Си нет адресных пространств одно адресное пространство.

ps и в вашем авр нет основного адр. простр. В авр гарвардская архитектура, там есть адресное пространство памяти программ и адресное пространство памяти данных. Но к стандарту Си это отношения не имеет, т.к. Си абстрагирован от архитектуры.

Куда разместит - зависит от компилятора. А вообще мне тоже не понятно почему во 2-м случае в ОЗУ. Получается что эти данный размещены дважды - и в озу и в пзу. Если это авр - то это понятно, для авр все случаи должны быть в озу. Если арм - то вроде как все константы должны быть в флеше. Зачем их дублировать в ОЗУ?
DASM
Цитата(juvf @ Dec 24 2017, 20:36) *
Что такое "основное адресное пространство"? В Си нет такого. В Си нет адресных пространств одно адресное пространство.

ps и в вашем авр нет основного адр. простр. В авр гарвардская архитектура, там есть адресное пространство памяти программ и адресное пространство памяти данных. Но к стандарту Си это отношения не имеет, т.к. Си абстрагирован от архитектуры.

Куда разместит - зависит от компилятора. А вообще мне тоже не понятно почему во 2-м случае в ОЗУ. Получается что эти данный размещены дважды - и в озу и в пзу. Если это авр - то это понятно, для авр все случаи должны быть в озу. Если арм - то вроде как все константы должны быть в флеше. Зачем их дублировать в ОЗУ?

хотя бы потому, что ICode и Dcode шины разные, мультплексируются. При выборке из флеша медленого к тому же prefetch работает, размещая константы во флеше он сбросится, итого двойной тормоз выйдет.
const нужен только чтобы уберечь программиста от самого себя, а никак не указание компилятору что и как размещать.
razrab83
Цитата(DASM @ Dec 24 2017, 20:04) *
const нужен только чтобы уберечь программиста от самого себя, а никак не указание компилятору что и как размещать.
А почему глобальный конст во флеше, локальный в озу?
juvf
Цитата(DASM @ Dec 25 2017, 00:04) *
const нужен только чтобы уберечь программиста от самого себя, а никак не указание компилятору что и как размещать.
Да, согласен, но тоже не понятно почему тогда во всех случаях по разному.

Более того, static - это всего лишь указание компилятору, что данные статические, а никак не указание компилятору что и как размещать. Почему со статиком размещаются данные в др месте?
DASM
еще как указание. статик в теле фции размещается не на стеке, а в общей куче (не путать с кучей malloc). ну и плюс ограничение видимости одной единицей трансляции, если не в теле функции

Цитата(razrab83 @ Dec 25 2017, 06:10) *
А почему глобальный конст во флеше, локальный в озу?

? это самодеятельность компилера на его страх и риск.

собственно если точнее static тоже не говорит где размещать, но определяет время жизни. А уж размещение статик не на стеке - прросто вытекает из этого
juvf
Цитата(DASM @ Dec 25 2017, 12:28) *
еще как указание. статик в теле фции размещается не на стеке, а в общей куче (не путать с кучей malloc).

пф.... утверждение осталось, только дополню...

Более того, static - это всего лишь указание компилятору, что данные статические, а никак не указание компилятору что и как размещать, я имел в виду, указание не про кучу и стек, а указание про озу/флешь/еепром/внешнюю память и т.п.

Цитата
это самодеятельность компилера на его страх и риск.
Согласен. В Си/С++ нет ни каких указаний на этот счет. Поэтому разработчики компиляторов на своё усмотрение делают реализацию. И поэтому, если важна область размещения, нужно компиллер контролировать и давать явные указания для размещения данных в нужную память.

Цитата(DASM @ Dec 25 2017, 12:31) *
А уж размещение статик не на стеке - прросто вытекает из этого
Ни чего не вытекает. Статик можно разместить в ОЗУ, а можно разместить в флеше. Конст можно разместить в озу, а можно в флеше. Компилятор волен сам - где и что размещать (в озу или во флешь), и его размещения не поддаются логике.
Kabdim
Цитата(juvf @ Dec 25 2017, 10:57) *
его размещения не поддаются логике.

Вполне поддаются и даже описаны в документации.
DASM
Цитата(juvf @ Dec 25 2017, 10:57) *
пф.... утверждение осталось, только дополню...

Более того, static - это всего лишь указание компилятору, что данные статические, а никак не указание компилятору что и как размещать, я имел в виду, указание не про кучу и стек, а указание про озу/флешь/еепром/внешнюю память и т.п.

Согласен. В Си/С++ нет ни каких указаний на этот счет. Поэтому разработчики компиляторов на своё усмотрение делают реализацию. И поэтому, если важна область размещения, нужно компиллер контролировать и давать явные указания для размещения данных в нужную память.

Ни чего не вытекает. Статик можно разместить в ОЗУ, а можно разместить в флеше. Конст можно разместить в озу, а можно в флеше. Компилятор волен сам - где и что размещать (в озу или во флешь), и его размещения не поддаются логике.

вытекает что не на стеке
juvf
Цитата(DASM @ Dec 25 2017, 13:15) *
вытекает что не на стеке

Причем тут стек? вопрос ТС не про стек, а про флешь vs озу.
inventor
наверное в следующих стандартах Си это
можно было бы учесть. с const ИМЕю ввиду..
что бы я еще сделал: ввел бы модификатор переменных global
для чего это: предположим в заголовочном файле
мы перечисляем все переменные, которые использует программа
в сегодняшних компиляторах для этого нужно писать в заголовке перменнные с словом extern
и определять сами эти переменные в *.c файле
если в заголовке описать переменные static - то все файлы, которые этот
заголовок включают будут плодить копии этих переменных, что совсем неправильно.
слово global помогло бы этого избежать
ViKo
Все, что описал топикстартер в начале темы, верно. Нужно понять (и простить). Не хотите, чтобы const переменная переписывалась из ПЗУ в ОЗУ - сделайте ее глобальной. Не нравятся глобальные переменные - сделайте ее статической внутри функции.
demiurg_spb
Цитата(juvf @ Dec 24 2017, 20:36) *
Что такое "основное адресное пространство"? В Си нет такого. В Си нет адресных пространств одно адресное пространство.

ps и в вашем авр нет основного адр. простр. В авр гарвардская архитектура, там есть адресное пространство памяти программ и адресное пространство памяти данных. Но к стандарту Си это отношения не имеет, т.к. Си абстрагирован от архитектуры.
Если Вы не в теме, то это не означает, что этого нет.
https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gc...-Address-Spaces

В настоящий момент в GCC именно на этой почве случился ступор.
Разработчики avr-gcc не могут сделать так, чтобы по возможности константные данные автоматом ложились во флэш именно из-за того, что стандарт в настоящее время этого не разрешает.

Если интересно - скачайте стандарт c11.
Сергей Борщ
Вообще-то в GCC в режиме С (без плюсов) уже года два как поддерживаются разные адресные пространства, в том числе и __flash. А вот в стандарте плюсов их нет, поэтому нет их и в плюсах AVG-GCC, поэтому там ступор, да. А еще - бывают контроллеры вообще без набортного флеша, там и код и константы - все в ОЗУ живет. И к чему все эти споры?
demiurg_spb
Цитата(Сергей Борщ @ Dec 25 2017, 17:48) *

Я не про плюсы и говорю. И ступор не в плюсах.
Код
const char __flash* const __flash names[] =
{
    "aaa",
    "bbb",
    "ccc"
};

не работает, а по всей здравой логике должно.
но народ упёрся и говорит, что нарушать стандарт не будем.
inventor
Цитата(Сергей Борщ @ Dec 25 2017, 17:48) *
А еще - бывают контроллеры вообще без набортного флеша, там и код и константы - все в ОЗУ живет. И к чему все эти споры?


cc3200
но там все равно подрузамевается память только для чтения:
CODE
45 190 bytes of readonly code memory
6 072 bytes of readonly data memory
138 267 bytes of readwrite data memory

juvf
Цитата
Согласно стандарту языка Си константные данные обязаны лечь в основное адресное пространство - всё.

Цитата(demiurg_spb @ Dec 25 2017, 19:08) *
Если Вы не в теме, то это не означает, что этого нет.
https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gc...-Address-Spaces

В настоящий момент в GCC именно на этой почве случился ступор.
Разработчики avr-gcc не могут сделать так, чтобы по возможности константные данные автоматом ложились во флэш именно из-за того, что стандарт в настоящее время этого не разрешает.

Если интересно - скачайте стандарт c11.
И? Где в стандарте си основное адресное пространство?
Да даже в по вашей ссылке нет ни каких основных адресных пространств.

ps Это вы не в теме. При чем тут на какойт-о AVR Named Address Spaces? Вопрос не о авр, и даже не о gcc, а о Си.

pps
Цитата
константные данные автоматом ложились во флэш именно из-за того, что стандарт в настоящее время этого не разрешает.

Навыдумывали. В стандарте Си нет даже слова flash. Если интересно - скачайте стандарт c11.
demiurg_spb
С вами бесполезно разговаривать - это Вы к AVR и flash привязались, не удосужившись прочесть представленные ссылки.
Всё о чём я написал напрямую относится к GCC в общем который, если Вы не в курсе, раньше всех коммерческих продуктов реализует новые возможности языка.
Мы используем в своих разработках GCC для множества архитектур, и по мере возможности делаем его и libc лучше. И мне очень странно слушать Ваши непонятные высказывания.
На этом с Вами разговор считаю законченным, пребывайте в осознании своего всезнания и далее.
Цитата
As an extension, GNU C supports named address spaces as defined in the N1275 draft of ISO/IEC DTR 18037. Support for named address spaces in GCC will evolve as the draft technical report changes. Calling conventions for any target might also change. At present, only the AVR, SPU, M32C, RL78, and x86 targets support address spaces other than the generic address space.

Address space identifiers may be used exactly like any other C type qualifier (e.g., const or volatile). See the N1275 document for more details.

http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1275.pdf
http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1005.pdf

Вдогонку: OpenCL основан на С99 и тоже использует схожие принципы что и Си для ембеда в части адресных пространств.
https://software.intel.com/en-us/articles/t...ce-in-opencl-20
juvf
Цитата(demiurg_spb @ Dec 26 2017, 17:03) *
написал всё что думаю о вас.... много букв.... удалил....

Вы видите/замечаете/понимаете разницу между "общий" и "основной", между "generic" и "general", между "Programming languages - C" и "Programming languages - C - Extensions to support embedded processors", между "gcc" и "си".


Цитата
принципы что и Си для ембеда
Ого!!! Уже не "Си", а "Си для ембеда". Исправляетесь, значит есть смысл от общения. wink.gif
demiurg_spb
Цитата(juvf @ Dec 27 2017, 05:57) *
Пусть generic - общий. Что от это изменилось? Си он и в африке Си и теперь в нём есть часть (читай глава) затрагивающая ембед.
А на gcc я ссылаюсь от того что это чуть-ли не единственный (ну может быть clang ещё) доступный, открытый и ОЧЕНЬ распространнённый компилятор для огромного количества архитектур.
Люди, разрабатывающие его являются членами комитета, утверждающего и разрабатывающего стандарт Си. Чем не автортет? Не согласны - приведите свои доводы.
Не нравится как я излагаю - читайте прикреплённые мной ссылки на оригиналы статей. Ради этого я их и прилагаю.
juvf
Цитата(demiurg_spb @ Dec 27 2017, 15:12) *
Пусть generic - общий. Что от это изменилось?

Изменилось то, что вы думает об одном, а горите другое.
demiurg_spb
Цитата(juvf @ Dec 27 2017, 13:49) *
Изменилось то, что вы думает об одном, а говорите другое.

Согласен. Бываю грешен.
Kabdim
Демиург, вы переоцниваете значимость техникал репортов. Переводя на русский это законопроект, который отнюдь не обязательно станет законом. Собственно в итоге не включают в станадарт большинство техникал репортов. Даже тех которые заметно более полезные чем выше перечисленные.
demiurg_spb
Время покажет. Факт есть факт - в gcc уже реализовано и мало помалу обкатывается.
inventor
мдя
задал простой вопрос
и как всегда разгорелся срач на ровном месте
pnp_mechanic
Вставлю и я свои 5 коп.
Inventor, всегда можно посмотреть адрес конкретной переменной.
Или константы . Средства Си это отлично могут делать.
aiwa
Цитата(inventor @ Dec 25 2017, 10:36) *
....в сегодняшних компиляторах для этого нужно писать в заголовке перменнные с словом extern

слово global помогло бы этого избежать


По количеству нажатий global ничем не лучше extern.
Зачем плодить синонимы?

Quasar
Цитата(razrab83 @ Dec 25 2017, 06:10) *
А почему глобальный конст во флеше, локальный в озу?



Локальная const переменная может инициализироваться в момент вызова функции и на стадии сборки неизвестна. Нечего класть во флеш. А вот static const и глобальная const переменная известны уже на стадии сборки.

PS: у меня однажды с одним коллегой драма случилась, он мне долго доказывал, что const ложится всегда исключительно в ro секцию (типа константа ЖЕ) и меняться в процессе исполнения не может (так как либо это флеш, либо область защищенная MMU). Если общение было в тот момент не по переписке, думаю и до мордобития дошло бы дело smile3009.gif
sigmaN
Про применение volatile const для read only регистров переферии уже упоминалось?
Кажется это довольно яркая демонстрация того, что const гарантирует в первую очередь ошибку компилятора при попытке что-то записать в такую переменную, а всё остальное это уже побочные эффекты, оптимизации и здравый смысл разработчиков компилятора.
Quasar
Цитата(sigmaN @ Jan 1 2018, 21:44) *
Про применение volatile const для read only регистров переферии уже упоминалось?
Кажется это довольно яркая демонстрация того, что const гарантирует в первую очередь ошибку компилятора при попытке что-то записать в такую переменную, а всё остальное это уже побочные эффекты, оптимизации и здравый смысл разработчиков компилятора.


Я в свое время добавил вопрос о const в список вопросов для соискателей на собеседовании. Удивительно было то, что порой люди с опытом 5 лет и более, ничего кроме "const это константа неизменяемая" сказать не могут. А случай когда регистр периферии volatile const они обычно называют каким-то искусственным и притянутым за уши.

razrab83
Цитата(Quasar @ Dec 30 2017, 09:04) *
Локальная const переменная может инициализироваться в момент вызова функции и на стадии сборки неизвестна. Нечего класть во флеш. А вот static const и глобальная const переменная известны уже на стадии сборки.
Локальная const переменная на стадии сборки известна.
sigmaN
Код
int f(int a )
{
const int c = 5;
return a + c;
}
Цитата
Локальная const переменная на стадии сборки известна.

Сделали такой вывод потому, что можете видеть = 5 своими глазами? wink.gif

Выразимся точнее
Переменная c при любой настройке компилятора не ляжет во флеш потому, что у нее не static storage duration.
Переменная c вообще не займет никакой памяти(даже на стеке) при включении оптимизации.
Ознакомьтесь с
https://en.wikipedia.org/wiki/Constant_folding
razrab83
Цитата
Переменная c вообще не займет никакой памяти(даже на стеке)
Как раз таки переменная c займет память программ.

int f(int a )
{//при входе а копируем в аккумулятор
const int c = 5;//этой строки в коде вообще может не быть.
return a + c;//здесь будет выполнен может быть выполнен код типа такого add acc,#5, где #5 - это и есть наша const int c, и эта пятерка лежит во флешь.
}
sigmaN
Ну так мы же про размещение данных говорим вроде как.
Цитата
return a + c;//здесь будет выполнен может быть выполнен код типа такого add acc,#5, где #5 - это и есть наша const int c, и эта пятерка лежит во флешь.
Кстати говоря эта пятерка уже не переменная. Она станет частью инструкции в общем случае называемой Add Immediate. Т.е. не пятерка займет флеш, а инструкция у котой нужные биты будут равны пятерке.
Так что не будем путать тёплое с мягким. Во флеше пятерки нет - есть инструкция, куда она входит.

А если в вышеуказанном примере сделать const int с = 1 то вообще интересно может получится - вместо этого будет сгенерирована какая-нибудь инструкция
Код
inc acc
которая инкрементирует аккумулятор.
Тоже скажете, что константа во флеше?
Quasar
Цитата(razrab83 @ Jan 3 2018, 13:26) *
Локальная const переменная на стадии сборки известна.



Тогда подумайте и попробуйте собрать этот код:

Код
#include <inttypes.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>

void foo ( uint32_t in ) {
    const uint32_t test = in;
    const uint32_t *pTest = &test;

    printf ( "%d, %p\n", test, pTest );

}

int main ( void ) {
    time_t t;
    
    srand((unsigned) time(&t));

    foo ( 55 );
    foo ( 77 );

    foo ( rand() % 100 );

    return 0;
}
razrab83
Цитата(sigmaN @ Jan 3 2018, 18:26) *
Тоже скажете, что константа во флеше?
Да. С точки зрения Си константа есть, а как там её компилятор реализовал - это уже дело компилятора.

2Quasar
Код
const uint32_t test = in;
убедили. такая константа инитится во время выполнения. Но "const uint32_t test = 5;" инитится известна при компиляции.
Quasar
Цитата(razrab83 @ Jan 4 2018, 11:50) *
2Quasar
Код
const uint32_t test = in;
убедили. такая константа инитится во время выполнения. Но "const uint32_t test = 5;" инитится известна при компиляции.


Конкретно ваша "const uint32_t test = 5" соптимизируется непонятно во что. Но компилятор действует "в общем". А "в общем", модификатор const - гарант того, что конструкция "a = 5" вне блока инициализации невалидна. Остальное - следствие здравого смысла. Если можно const переменную убрать в rodata (FLASH или ro ОЗУ), её туда уберут, если нельзя - то нет, не уберут.
inventor
читаю pdf на IAR
такой забавный пример с константами:
Цитата
String literals and other constants can be avoided by using initialized variables. For
example, the following lines:

CODE

__ramfunc void test()
{
/* myc: initializer in ROM */
const int myc[] = { 10, 20 };
/* string literal in ROM */
msg("Hello");
}

Цитата
can be rewritten to:

CODE

__ramfunc void test()
{
/* myc: initialized by cstartup */
static int myc[] = { 10, 20 };
/* hello: initialized by cstartup */
static char hello[] = "Hello";
msg(hello);
}
sigmaN
Правильно, потому что это __ramfunc и никто не хочет чтоб "Hello" занимало оперативку
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.