restructuring

This commit is contained in:
2022-03-10 11:04:14 +03:00
parent 29560b7c0c
commit 733dbd75d2
1758 changed files with 14 additions and 26855 deletions

View File

@@ -0,0 +1,147 @@
BINARY = sockfans
BOOTPORT ?= /dev/ttyUSB0
BOOTSPEED ?= 57600
# MCU FAMILY
FAMILY = F0
# MCU code
MCU = F072xB
# hardware definitions
#DEFS += -DEBUG
# change this linking script depending on particular MCU model,
# for example, if you have STM32F103VBT6, you should write:
LDSCRIPT = stm32f0728.ld
INDEPENDENT_HEADERS=
FP_FLAGS ?= -msoft-float
ASM_FLAGS = -mthumb -mcpu=cortex-m0 -march=armv6-m -mtune=cortex-m0
ARCH_FLAGS = $(ASM_FLAGS) $(FP_FLAGS)
###############################################################################
# Executables
OPREFIX ?= /opt/bin/arm-none-eabi
#PREFIX ?= /usr/x86_64-pc-linux-gnu/arm-none-eabi/gcc-bin/7.3.0/arm-none-eabi
PREFIX ?= $(OPREFIX)
RM := rm -f
RMDIR := rmdir
CC := $(PREFIX)-gcc
LD := $(PREFIX)-gcc
AR := $(PREFIX)-ar
AS := $(PREFIX)-as
OBJCOPY := $(OPREFIX)-objcopy
OBJDUMP := $(OPREFIX)-objdump
GDB := $(OPREFIX)-gdb
STFLASH := $(shell which st-flash)
STBOOT := $(shell which stm32flash)
DFUUTIL := $(shell which dfu-util)
###############################################################################
# Source files
OBJDIR = mk
LDSCRIPT ?= $(BINARY).ld
SRC := $(wildcard *.c)
OBJS := $(addprefix $(OBJDIR)/, $(SRC:%.c=%.o))
STARTUP = $(OBJDIR)/startup.o
OBJS += $(STARTUP)
DEPS := $(OBJS:.o=.d)
INC_DIR ?= ../inc
INCLUDE := -I$(INC_DIR)/Fx -I$(INC_DIR)/cm
LIB_DIR := $(INC_DIR)/ld
###############################################################################
# C flags
CFLAGS += -O2 -g -MD -D__thumb2__=1
CFLAGS += -Wall -Werror -Wextra -Wshadow -Wimplicit-function-declaration
CFLAGS += -Wredundant-decls $(INCLUDE)
# -Wmissing-prototypes -Wstrict-prototypes
CFLAGS += -fno-common -ffunction-sections -fdata-sections
###############################################################################
# Linker flags
LDFLAGS += --static -nostartfiles
#--specs=nano.specs
LDFLAGS += -L$(LIB_DIR)
LDFLAGS += -T$(LDSCRIPT)
LDFLAGS += -Wl,-Map=$(OBJDIR)/$(BINARY).map
LDFLAGS += -Wl,--gc-sections
###############################################################################
# Used libraries
LDLIBS += -Wl,--start-group -lc -lgcc -Wl,--end-group
LDLIBS += $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
DEFS += -DSTM32$(FAMILY) -DSTM32$(MCU)
#.SUFFIXES: .elf .bin .hex .srec .list .map .images
#.SECONDEXPANSION:
#.SECONDARY:
ELF := $(OBJDIR)/$(BINARY).elf
LIST := $(OBJDIR)/$(BINARY).list
BIN := $(BINARY).bin
HEX := $(BINARY).hex
all: bin list
elf: $(ELF)
bin: $(BIN)
hex: $(HEX)
list: $(LIST)
ifneq ($(MAKECMDGOALS),clean)
-include $(DEPS)
endif
$(OBJDIR):
mkdir $(OBJDIR)
$(STARTUP): $(INC_DIR)/startup/vector.c
$(CC) $(CFLAGS) $(DEFS) $(INCLUDE) $(ARCH_FLAGS) -o $@ -c $<
$(OBJDIR)/%.o: %.c
@echo " CC $<"
$(CC) $(CFLAGS) $(DEFS) $(INCLUDE) $(ARCH_FLAGS) -o $@ -c $<
#$(OBJDIR)/%.d: %.c $(OBJDIR)
# $(CC) -MM -MG $< | sed -e 's,^\([^:]*\)\.o[ ]*:,$(@D)/\1.o $(@D)/\1.d:,' >$@
$(BIN): $(ELF)
@echo " OBJCOPY $(BIN)"
$(OBJCOPY) -Obinary $(ELF) $(BIN)
$(HEX): $(ELF)
@echo " OBJCOPY $(HEX)"
$(OBJCOPY) -Oihex $(ELF) $(HEX)
$(LIST): $(ELF)
@echo " OBJDUMP $(LIST)"
$(OBJDUMP) -S $(ELF) > $(LIST)
$(ELF): $(OBJDIR) $(OBJS)
@echo " LD $(ELF)"
$(LD) $(LDFLAGS) $(ARCH_FLAGS) $(OBJS) $(LDLIBS) -o $(ELF)
clean:
@echo " CLEAN"
$(RM) $(OBJS) $(DEPS) $(ELF) $(HEX) $(LIST) $(OBJDIR)/*.map *.d
@rmdir $(OBJDIR) 2>/dev/null || true
dfuboot: $(BIN)
@echo " LOAD $(BIN) THROUGH DFU"
$(DFUUTIL) -a0 -D $(BIN) -s 0x08000000
flash: $(BIN)
@echo " FLASH $(BIN)"
$(STFLASH) write $(BIN) 0x8000000
boot: $(BIN)
@echo " LOAD $(BIN) through bootloader"
$(STBOOT) -b$(BOOTSPEED) $(BOOTPORT) -w $(BIN)
gentags:
CFLAGS="$(CFLAGS) $(DEFS)" geany -g $(BINARY).c.tags *[hc] 2>/dev/null
.PHONY: clean flash boot gentags

View File

@@ -0,0 +1,164 @@
Контроллер питания и охлаждения.
===============================
-- Четыре канала измерения температуры с точностью +-1degrC (три канала управляют активностью кулеров, четвертый - для общего отключения питания в случае достижения критической температуры).
-- Два канала управления четырехпроводными кулерами с контролем их активности.
-- Две кнопки управления (включить/экстренно выключить нагрузку).
-- Внешний сигнал (пищалка 12В): короткий сигнал раз в 10 секунд - один из кулеров не вращается (а должен), непрерывные сигналы - критическая ситуация, питание скоро будет отключено, (сигналы в течение 4с с паузой в 6с - резерв).
-- Режим ручного управления (без контроля температур с соответствующими действиями) или мониторинга (в этом режиме нельзя вручную задавать параметры кулера или внешнего сигнала).
== help ==
```
'0x' - turn cooler0 on/off (x=1/0) or get status (x - any other)
'1x' - turn cooler1 on/off (x=1/0) or get status (x - any other)
'Ax' - get ADC raw value (x=0..7)
'B' - buttons' state
'bx' - buzzer: x==0 - off, x==1 - on, x==l - long beeps, x==s - short beeps
'Cx' - get cooler x (0/1) RPS
'D' - activate DFU mode
'E' - show current state
'Gx' - get cooler x (0..3) PWM settings
'M' - get MCU temperature
'm' - toggle monitoring
'R' - software reset
'rx' - relay on/off (x=1/0) or get status
'Sx y' - set coolerx PWM to y
's' - show settings
'T' - get time from start (ms)
'tx' - get temperature x (0..3)
'V' - get voltage
'Z' - reinit ADC
'!' - switch between manual and automatic modes
```
=== 0x,1x ===
x=='0' - выключить питание кулера; x=='1' - включить питание; любое другое значение - проверить состояние.
=== Ax ===
x=={0..7} - получить "сырое значение" x-го канала АЦП (в ADU).
Каналы: 0..3 - термометры, 4 - измерение 12В, 5 - измерение 5В, 6 - температура МК, 7 - уровень 3.3В.
=== B ===
Состояние обеих кнопок, например:
```
BUTTON0=0
BUTTON1=0
```
Нажатие кнопок проверяется один раз в секунду. Кнопка BUTTON0 переводит систему в автоматический режим и включает реле. Кнопка BUTTON1 отключает реле, отключает все кулеры и сигнал и переводит систему в ручной режим.
=== bx ===
Изменить состояние внешнего сигнала. 0 - выключить, 1 - включить серию непрерывных сигналов, l - включить серию коротких сигналов в течение 4 секунд с паузой в 6 секунд, s - включить короткий сигнал (0.5с) с паузой 9.5с.
=== Cx ===
Получить значения скорости вращения четырехпроводного кулера (обороты в секунду). Например:
```
C0
RPM0=78
C1
RPM1=0
```
=== D ===
Активировать режим DFU для перепрошивки. После прошивки нужно перезапустить МК, закоротив контакты "reset" или кратковременно отключив от питания.
=== E ===
Отобразить текущее состояние системы, например:
```
TIME=1229247
T0=293
T1=264
T2=262
T3=254
BUZZER=OFF
BUTTON0=0
BUTTON1=0
RPS0=82
RPS1=107
PWM0=30
PWM1=40
PWM2=33
COOLER0=1
COOLER1=1
RELAY=1
```
Где
TIME - время с момента включения (мс, приблизительно);
Tx - температуры (x10) соответствующих каналов в градусах Цельсия;
BUZZER - состояние сигнала;
BUTTONx - состояние кнопок (1 - нажата, 0 - отпущена);
RPSx - скорость вращения кулера x (оборотов в секунду);
PWMx - установленное значение ШИМ (в процентах, 0..100) канала x;
COOLERx - включено ли питание кулера x (0..1), из-за неправильной схемотехники не рекомендуется отключать питание четырехпроводных кулеров (+12В поступает в этом случае на измерительный вход);
RELAY - состояние реле (1 - включено, 0 - выключено).
=== Gx ===
Отобразить значения настройки ШИМ кулера x.
=== M ===
Отобразить температуру МК (приближенная температура, x10 градусов Цельсия).
=== m ===
Переключить (вкл/выкл) режим мониторинга, когда каждые 5 секунд отображается состояние системы.
=== R ===
Программный перезапуск системы.
=== rx ===
x==0 - выключить реле, x==1 - включить реле, любое другое значение - получить состояние реле.
=== Sx y ===
Установить значение заполнения ШИМ кулера x (0..2) в y (0..100). Согласно опыту, четырехпроводные кулеры не стартуют при значении PWM<15, а двухпроводные не стартуют при PWM<35, поэтому для получения малых оборотов необходимо стартовать на большей скорости, а затем уже установить нужное значение заполнения ШИМ.
=== s ===
Отобразить "вшитые" в код настройки, например:
```
Thysteresis=30
Tmin={400, 350, 350}
Tmax={900, 800, 600}
T3max=850
```
В данном случае гистерезис температуры установлен в 3 градуса, область допустимых значений температур - 40..90 градусов для канала 0, 35..80 градусов для канала 1 и 35..60 градусов для канала 2. Критическая температура канала 3 установлена в 85 градусов. Если в течение 20 секунд превышено значение одной из критических температур (для T0..2 они равны Tmax+Thysteresis), то реле отключается, система остается в автоматическом режиме.
=== T ===
Отобразить время (условное) в миллисекундах со старта.
=== tx ===
Получить значение температуры x-го канала (0..3). Температура умножена на 10. Например:
```
t0
T0=294
t1
T1=265
t2
T2=264
t3
T3=256
```
Соответственно, температуры равны: t0=29.4, t1=26.5, t2=26.4 и t3=25.6.
Учитывая то, что величина вычисляется кусочно-линейной аппроксимацией с погрешностью до 0.1 градуса, а сами NTC дают разброс не лучше +-0.5 градуса, не стоит надеяться на то, что температуры будут достаточно точными.
=== V ===
Получить значения напряжения (x100) в каналах, например:
```
V3_3=330
V5=428
V12=1055
```
Означает, что питание МК =3.3В, на входе 5В присутствует 4.28В, а на входе 12В присутствует 10.55В.
=== Z ===
Реинициализация АЦП (ХЗ, зачем я это добавил).
=== ! ===
Переключение между автоматическим и ручным режимами управления.

View File

@@ -0,0 +1,138 @@
/*
* This file is part of the Chiller project.
* Copyright 2018 Edward V. Emelianov <edward.emelianoff@gmail.com>.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include "adc.h"
/**
* @brief ADC_array - array for ADC channels with median filtering:
* 0..3 - external NTC
* 4 - ext 12V
* 5 - ext 5V
* 6 - internal Tsens
* 7 - Vref
*/
uint16_t ADC_array[NUMBER_OF_ADC_CHANNELS*9];
/**
* @brief getADCval - calculate median value for `nch` channel
* @param nch - number of channel
* @return
*/
uint16_t getADCval(int nch){
int i, addr = nch;
register uint16_t temp;
#define PIX_SORT(a,b) { if ((a)>(b)) PIX_SWAP((a),(b)); }
#define PIX_SWAP(a,b) { temp=(a);(a)=(b);(b)=temp; }
uint16_t p[9];
for(i = 0; i < 9; ++i, addr += NUMBER_OF_ADC_CHANNELS) // first we should prepare array for optmed
p[i] = ADC_array[addr];
PIX_SORT(p[1], p[2]) ; PIX_SORT(p[4], p[5]) ; PIX_SORT(p[7], p[8]) ;
PIX_SORT(p[0], p[1]) ; PIX_SORT(p[3], p[4]) ; PIX_SORT(p[6], p[7]) ;
PIX_SORT(p[1], p[2]) ; PIX_SORT(p[4], p[5]) ; PIX_SORT(p[7], p[8]) ;
PIX_SORT(p[0], p[3]) ; PIX_SORT(p[5], p[8]) ; PIX_SORT(p[4], p[7]) ;
PIX_SORT(p[3], p[6]) ; PIX_SORT(p[1], p[4]) ; PIX_SORT(p[2], p[5]) ;
PIX_SORT(p[4], p[7]) ; PIX_SORT(p[4], p[2]) ; PIX_SORT(p[6], p[4]) ;
PIX_SORT(p[4], p[2]) ;
return p[4];
#undef PIX_SORT
#undef PIX_SWAP
}
// return MCU temperature (degrees of celsius * 10)
int32_t getMCUtemp(){
// getVdd();
// make correction on Vdd value
// int32_t temperature = (int32_t)ADC_array[4] * VddValue / 330;
int32_t ADval = getADCval(6);
int32_t temperature = (int32_t) *TEMP30_CAL_ADDR - ADval;
temperature *= (int32_t)(1100 - 300);
temperature /= (int32_t)(*TEMP30_CAL_ADDR - *TEMP110_CAL_ADDR);
temperature += 300;
return(temperature);
}
// return Vdd * 100 (V)
uint32_t getVdd(){
uint32_t vdd = ((uint32_t) *VREFINT_CAL_ADDR) * (uint32_t)330; // 3.3V
vdd /= getADCval(7);
return vdd;
}
// convert ADU into Volts (*100)
static inline uint32_t Ufromadu(uint8_t nch){
uint32_t ADU = getADCval(nch);
ADU *= getVdd();
ADU >>= 12; // /4096
return ADU;
}
// get 12V (*100)
uint32_t getU12(){
uint32_t V = Ufromadu(4) * 493;
return V / 100;
}
// get 5V (*100)
uint32_t getU5(){
return Ufromadu(5) * 2;
}
/**
* @brief getNTC - return temperature of NTC (*10 degrC)
* @param nch - NTC channel number (0..3)
* @return
*/
int16_t getNTC(int nch){
#define NKNOTS (14)
const int16_t ADU[NKNOTS] = {732, 945, 1197, 2035, 2309, 2542, 2739, 2859, 2969, 3068, 3154, 3228, 3293, 3347};
const int16_t T[NKNOTS] = {100, 160, 227, 438, 508, 571, 628, 666, 702, 738, 772, 805, 837, 869};
/*
* coefficients: 0.028261 0.026536 0.025136 0.025738 0.027044 0.028922 0.031038 0.033255 0.036056 0.039606 0.044173 0.050296 0.058920 0.071729
* use
* [N D] = rat(K*10); printf("N="); printf("%d, ", N); printf("\nD="); printf("%d, ", D);printf("\n");
*/
const int16_t N[NKNOTS] = {13, 95, 185, 96, 43, 153, 347, 141, 128, 261, 235, 85, 393, 307};
const int16_t D[NKNOTS] = {46, 358, 736, 373, 159, 529, 1118, 424, 355, 659, 532, 169, 667, 428};
if(nch < 0 || nch > 3) return -30000;
uint16_t val = getADCval(nch);
// find interval
int idx = (NKNOTS)/2, left = 0, right = NKNOTS-1; // left, right, middle
while(idx > left && idx < right){
int16_t midval = ADU[idx];
if(val < midval){
if(idx == 0) break;
if(val > ADU[idx-1]){ // found
--idx;
break;
}
right = idx - 1;
idx = (left + right)/2;
}else{
if(val < ADU[idx+1]) break; // found
left = idx + 1;
idx = (left + right)/2;
}
}
if(idx < 0) idx = 0;
else if(idx > NKNOTS-1) idx = NKNOTS - 1;
// T = Y0(idx) + K(idx) * (ADU - X0(idx));
int16_t valT = T[idx] + (N[idx]*(val - ADU[idx]))/D[idx];
#undef NKNOTS
return valT;
}

View File

@@ -0,0 +1,33 @@
/*
* This file is part of the Chiller project.
* Copyright 2018 Edward V. Emelianov <edward.emelianoff@gmail.com>.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef ADC_H
#define ADC_H
#include "stm32f0.h"
// 6 channels + vref + Tmcu
#define NUMBER_OF_ADC_CHANNELS (8)
extern uint16_t ADC_array[];
int32_t getMCUtemp();
uint32_t getVdd();
uint16_t getADCval(int nch);
int16_t getNTC(int nch);
uint32_t getU12();
uint32_t getU5();
#endif // ADC_H

View File

@@ -0,0 +1,196 @@
/*
* This file is part of the SockFans project.
* Copyright 2020 Edward V. Emelianov <edward.emelianoff@gmail.com>.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include <stm32f0.h>
#include "adc.h"
#include "flash.h"
#include "proto.h" // printout
#include <string.h> // memcpy
// max amount of Config records stored (will be recalculate in flashstorage_init()
static uint32_t maxCnum = FLASH_BLOCK_SIZE / sizeof(user_conf);
#define USERCONF_INITIALIZER { \
.userconf_sz = sizeof(user_conf) \
,.Tturnoff = 20000 \
,.Thyst = 30 \
,.Tmin = {400, 400, 400} \
,.Tmax = {900, 800, 800, 800} \
}
static int erase_flash(const void*, const void*);
static int write2flash(const void*, const void*, uint32_t);
// don't write `static` here, or get error:
// 'memcpy' forming offset 8 is out of the bounds [0, 4] of object '__varsstart' with type 'uint32_t'
const user_conf *Flash_Data = (const user_conf *)(&__varsstart);
user_conf the_conf = USERCONF_INITIALIZER;
static int currentconfidx = -1; // index of current configuration
/**
* @brief binarySearch - binary search in flash for last non-empty cell
* any struct searched should have its sizeof() @ the first field!!!
* @param l - left index
* @param r - right index (should be @1 less than last index!)
* @param start - starting address
* @param stor_size - size of structure to search
* @return index of non-empty cell or -1
*/
static int binarySearch(int r, const uint8_t *start, int stor_size){
int l = 0;
while(r >= l){
int mid = l + (r - l) / 2;
const uint8_t *s = start + mid * stor_size;
if(*((const uint16_t*)s) == stor_size){
if(*((const uint16_t*)(s + stor_size)) == 0xffff){
return mid;
}else{ // element is to the right
l = mid + 1;
}
}else{ // element is to the left
r = mid - 1;
}
}
return -1; // not found
}
/**
* @brief flashstorage_init - initialization of user conf storage
* run in once @ start
*/
void flashstorage_init(){
if(FLASH_SIZE > 0 && FLASH_SIZE < 20000){
uint32_t flsz = FLASH_SIZE * 1024; // size in bytes
flsz -= (uint32_t)(&__varsstart) - FLASH_BASE;
maxCnum = flsz / sizeof(user_conf);
//SEND("flsz="); printu(flsz);
//SEND("\nmaxCnum="); printu(maxCnum); newline(); sendbuf();
}
// -1 if there's no data at all & flash is clear; maxnum-1 if flash is full
currentconfidx = binarySearch((int)maxCnum-2, (const uint8_t*)Flash_Data, sizeof(user_conf));
if(currentconfidx > -1){
memcpy(&the_conf, &Flash_Data[currentconfidx], sizeof(user_conf));
}
}
// store new configuration
// @return 0 if all OK
int store_userconf(){
// maxnum - 3 means that there always should be at least one empty record after last data
// for binarySearch() checking that there's nothing more after it!
if(currentconfidx > (int)maxCnum - 3){ // there's no more place
currentconfidx = 0;
if(erase_flash(Flash_Data, (&__varsstart))) return 1;
}else ++currentconfidx; // take next data position (0 - within first run after firmware flashing)
return write2flash((const void*)&Flash_Data[currentconfidx], &the_conf, sizeof(the_conf));
}
static int write2flash(const void *start, const void *wrdata, uint32_t stor_size){
int ret = 0;
if (FLASH->CR & FLASH_CR_LOCK){ // unloch flash
FLASH->KEYR = FLASH_KEY1;
FLASH->KEYR = FLASH_KEY2;
}
while (FLASH->SR & FLASH_SR_BSY);
if(FLASH->SR & FLASH_SR_WRPRTERR){
MSG("Can't remove write protection\n");
return 1; // write protection
}
FLASH->SR = FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPRTERR; // clear all flags
FLASH->CR |= FLASH_CR_PG;
const uint16_t *data = (const uint16_t*) wrdata;
volatile uint16_t *address = (volatile uint16_t*) start;
uint32_t i, count = (stor_size + 1) / 2;
for (i = 0; i < count; ++i){
IWDG->KR = IWDG_REFRESH;
*(volatile uint16_t*)(address + i) = data[i];
while (FLASH->SR & FLASH_SR_BSY);
if(FLASH->SR & FLASH_SR_PGERR){
ret = 1; // program error - meet not 0xffff
MSG("FLASH_SR_PGERR\n");
break;
}else while (!(FLASH->SR & FLASH_SR_EOP));
FLASH->SR = FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPRTERR;
}
FLASH->CR |= FLASH_CR_LOCK; // lock it back
FLASH->CR &= ~(FLASH_CR_PG);
MSG("Flash stored\n");
return ret;
}
/**
* @brief erase_flash - erase N pages of flash memory
* @param start - first address
* @param end - last address (or NULL if need to erase all flash remaining)
* @return 0 if succeed
*/
static int erase_flash(const void *start, const void *end){
int ret = 0;
uint32_t nblocks = 1, flsz = 0;
if(!end){ // erase all remaining
if(FLASH_SIZE > 0 && FLASH_SIZE < 20000){
flsz = FLASH_SIZE * 1024; // size in bytes
flsz -= (uint32_t)start - FLASH_BASE;
}
}else{ // erase a part
flsz = (uint32_t)end - (uint32_t)start;
}
nblocks = flsz / FLASH_BLOCK_SIZE;
if(nblocks == 0 || nblocks >= FLASH_SIZE) return 1;
for(uint32_t i = 0; i < nblocks; ++i){
#ifdef EBUG
SEND("Try to erase page #"); printu(i); newline(); sendbuf();
#endif
IWDG->KR = IWDG_REFRESH;
/* (1) Wait till no operation is on going */
/* (2) Clear error & EOP bits */
/* (3) Check that the Flash is unlocked */
/* (4) Perform unlock sequence */
while ((FLASH->SR & FLASH_SR_BSY) != 0){} /* (1) */
FLASH->SR = FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPRTERR; /* (2) */
/* if (FLASH->SR & FLASH_SR_EOP){
FLASH->SR |= FLASH_SR_EOP;
}*/
if ((FLASH->CR & FLASH_CR_LOCK) != 0){ /* (3) */
FLASH->KEYR = FLASH_KEY1; /* (4) */
FLASH->KEYR = FLASH_KEY2;
}
/* (1) Set the PER bit in the FLASH_CR register to enable page erasing */
/* (2) Program the FLASH_AR register to select a page to erase */
/* (3) Set the STRT bit in the FLASH_CR register to start the erasing */
/* (4) Wait until the EOP flag in the FLASH_SR register set */
/* (5) Clear EOP flag by software by writing EOP at 1 */
/* (6) Reset the PER Bit to disable the page erase */
FLASH->CR |= FLASH_CR_PER; /* (1) */
FLASH->AR = (uint32_t)Flash_Data + i*FLASH_BLOCK_SIZE; /* (2) */
FLASH->CR |= FLASH_CR_STRT; /* (3) */
while(!(FLASH->SR & FLASH_SR_EOP));
FLASH->SR |= FLASH_SR_EOP; /* (5)*/
if(FLASH->SR & FLASH_SR_WRPRTERR){ /* Check Write protection error */
ret = 1;
MSG("Write protection error!\n");
FLASH->SR |= FLASH_SR_WRPRTERR; /* Clear the flag by software by writing it at 1*/
break;
}
FLASH->CR &= ~FLASH_CR_PER; /* (6) */
}
return ret;
}

View File

@@ -0,0 +1,51 @@
/*
* This file is part of the SockFans project.
* Copyright 2020 Edward V. Emelianov <edward.emelianoff@gmail.com>.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#ifndef FLASH_H__
#define FLASH_H__
#include "hardware.h"
#define FLASH_BLOCK_SIZE (1024)
#define FLASH_SIZE_REG ((uint32_t)0x1FFFF7CC)
#define FLASH_SIZE *((uint16_t*)FLASH_SIZE_REG)
#define TMINNO (3)
#define TMAXNO (4)
/*
* struct to save user configurations
*/
typedef struct __attribute__((packed, aligned(4))){
uint16_t userconf_sz; // "magick number"
uint32_t Tturnoff; // wait for Tturnoff ms before turning power off
uint32_t Thyst; // Thysteresis
int16_t Tmin[TMINNO]; // minT
int16_t Tmax[TMAXNO]; // maxT
} user_conf;
extern user_conf the_conf; // global user config (read from FLASH to RAM)
// data from ld-file: start address of storage
extern const uint32_t __varsstart;
void flashstorage_init();
int store_userconf();
void dump_userconf();
#endif // FLASH_H__

View File

@@ -0,0 +1,246 @@
/*
* geany_encoding=koi8-r
* hardware.c - hardware-dependent macros & functions
*
* Copyright 2018 Edward V. Emelianov <eddy@sao.ru, edward.emelianoff@gmail.com>
*
* 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.
*
*/
#include "adc.h"
#include "hardware.h"
#include "proto.h"
volatile uint32_t Cooler1RPM; // Cooler1 RPM counter by EXTI @PA7
buzzer_state buzzer = BUZZER_OFF; // buzzer state
void adc_setup(){
uint16_t ctr = 0; // 0xfff0 - more than 1.3ms
ADC1->CR &= ~ADC_CR_ADEN;
DMA1_Channel1->CCR &= ~DMA_CCR_EN;
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN; // Enable the peripheral clock of the ADC
RCC->CR2 |= RCC_CR2_HSI14ON; // Start HSI14 RC oscillator
while ((RCC->CR2 & RCC_CR2_HSI14RDY) == 0 && ++ctr < 0xfff0){}; // Wait HSI14 is ready
// calibration
if(ADC1->CR & ADC_CR_ADEN){ // Ensure that ADEN = 0
ADC1->CR &= (uint32_t)(~ADC_CR_ADEN); // Clear ADEN
}
ADC1->CR |= ADC_CR_ADCAL; // Launch the calibration by setting ADCAL
ctr = 0; // ADC calibration time is 5.9us
while(ADC1->CR & ADC_CR_ADCAL && ++ctr < 0xfff0); // Wait until ADCAL=0
// enable ADC
ctr = 0;
do{
ADC1->CR |= ADC_CR_ADEN;
}while((ADC1->ISR & ADC_ISR_ADRDY) == 0 && ++ctr < 0xfff0);
// configure ADC
ADC1->CFGR1 |= ADC_CFGR1_CONT; // Select the continuous mode
ADC1->CHSELR = ADC_CHSELR_CHSEL0 | ADC_CHSELR_CHSEL1 | ADC_CHSELR_CHSEL2 |
ADC_CHSELR_CHSEL3 | ADC_CHSELR_CHSEL4 | ADC_CHSELR_CHSEL5 |
ADC_CHSELR_CHSEL16 | ADC_CHSELR_CHSEL17; // Select CHSEL0..5 - ADC inputs, 16,17 - t. sensor and vref
ADC1->SMPR |= ADC_SMPR_SMP; // Select a sampling mode of 111 i.e. 239.5 ADC clk to be greater than 17.1us
ADC->CCR |= ADC_CCR_TSEN | ADC_CCR_VREFEN; // Wake-up the VREFINT and Temperature sensor
// configure DMA for ADC
RCC->AHBENR |= RCC_AHBENR_DMA1EN; // Enable the peripheral clock on DMA
ADC1->CFGR1 |= ADC_CFGR1_DMAEN | ADC_CFGR1_DMACFG; // Enable DMA transfer on ADC and circular mode
DMA1_Channel1->CPAR = (uint32_t) (&(ADC1->DR)); // Configure the peripheral data register address
DMA1_Channel1->CMAR = (uint32_t)(ADC_array); // Configure the memory address
DMA1_Channel1->CNDTR = NUMBER_OF_ADC_CHANNELS * 9; // Configure the number of DMA tranfer to be performs on DMA channel 1
DMA1_Channel1->CCR |= DMA_CCR_MINC | DMA_CCR_MSIZE_0 | DMA_CCR_PSIZE_0 | DMA_CCR_CIRC; // Configure increment, size, interrupts and circular mode
DMA1_Channel1->CCR |= DMA_CCR_EN; // Enable DMA Channel 1
ADC1->CR |= ADC_CR_ADSTART; // start the ADC conversions
}
static inline void gpio_setup(void){
RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN | RCC_AHBENR_GPIOCEN;
OFF(BUZZER); OFF(RELAY); OFF(COOLER0); OFF(COOLER1);
// All outputs are pullups
// PA0..5 - ADC, PA6, PA8..10 - timers (PA6, PA7 - pullup, PA7 - exti), PA14 - buzzer
GPIOA->MODER = GPIO_MODER_MODER0_AI | GPIO_MODER_MODER1_AI |
GPIO_MODER_MODER2_AI | GPIO_MODER_MODER3_AI |
GPIO_MODER_MODER4_AI | GPIO_MODER_MODER5_AI |
GPIO_MODER_MODER6_AF | GPIO_MODER_MODER8_AF |
GPIO_MODER_MODER9_AF | GPIO_MODER_MODER10_AF|
GPIO_MODER_MODER14_O;
GPIOA->PUPDR = GPIO_PUPDR6_PU | GPIO_PUPDR7_PU;
// EXTI @ PA7
SYSCFG->EXTICR[1] = SYSCFG_EXTICR2_EXTI7_PA; // PORTA for EXTI
EXTI->IMR = EXTI_IMR_MR7; // select pin 7
EXTI->RTSR = EXTI_RTSR_TR7; // rising edge @ pin 7
NVIC_EnableIRQ(EXTI4_15_IRQn); // enable interrupt
NVIC_SetPriority(EXTI4_15_IRQn, 4); // set low priority
// PB4/5 - cooler, PB14/15 - buttons (pullup)
GPIOB->MODER = GPIO_MODER_MODER4_O | GPIO_MODER_MODER5_O;
GPIOB->PUPDR = GPIO_PUPDR14_PU | GPIO_PUPDR15_PU;
// PC13 - relay
GPIOC->MODER = GPIO_MODER_MODER13_O;
/* Alternate functions:
* PA6 - TIM3_CH1 AF1
* PA8 - TIM1_CH1 AF2
* PA9 - TIM1_CH2 AF2
* PA10 - TIM1_CH3 AF2
*/
GPIOA->AFR[0] = (1 << (6*4));
GPIOA->AFR[1] = (2 << (0*4)) | (2 << (1*4)) | (2 << (2*4));
}
static inline void timers_setup(){
// TIM1 channels 1..3 - PWM output
RCC->APB2ENR |= RCC_APB2ENR_TIM1EN; // enable clocking
TIM1->PSC = 19; // F=48/20 = 2.4MHz
TIM1->ARR = 100; // PWM frequency = 2.4/101 = 23.76kHz
// PWM mode 1 (OCxM = 110), preload enable
TIM1->CCMR1 = TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1PE |
TIM_CCMR1_OC2M_2 | TIM_CCMR1_OC2M_1 | TIM_CCMR1_OC2PE;
TIM1->CCMR2 = TIM_CCMR2_OC3M_2 | TIM_CCMR2_OC3M_1 | TIM_CCMR2_OC3PE;
TIM1->CCER = TIM_CCER_CC1E | TIM_CCER_CC2E | TIM_CCER_CC3E; // active high (CC1P=0), enable outputs
TIM1->BDTR |= TIM_BDTR_MOE; // enable main output
TIM1->CR1 |= TIM_CR1_CEN; // enable timer
TIM1->EGR |= TIM_EGR_UG; // force update generation
// TIM3 channel 1 - external counter on channel1
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
TIM3->SMCR = TIM_SMCR_TS_2 | TIM_SMCR_TS_0 | TIM_SMCR_SMS; // TS=101, SMS=111 - external trigger on input1
TIM3->CCMR1 = TIM_CCMR1_CC1S_0; // CC1 is input mapped on channel TI1
TIM3->CR1 = TIM_CR1_CEN;
}
void HW_setup(){
gpio_setup();
adc_setup();
timers_setup();
}
void iwdg_setup(){
uint32_t tmout = 16000000;
/* Enable the peripheral clock RTC */
/* (1) Enable the LSI (40kHz) */
/* (2) Wait while it is not ready */
RCC->CSR |= RCC_CSR_LSION; /* (1) */
while((RCC->CSR & RCC_CSR_LSIRDY) != RCC_CSR_LSIRDY){if(--tmout == 0) break;} /* (2) */
/* Configure IWDG */
/* (1) Activate IWDG (not needed if done in option bytes) */
/* (2) Enable write access to IWDG registers */
/* (3) Set prescaler by 64 (1.6ms for each tick) */
/* (4) Set reload value to have a rollover each 2s */
/* (5) Check if flags are reset */
/* (6) Refresh counter */
IWDG->KR = IWDG_START; /* (1) */
IWDG->KR = IWDG_WRITE_ACCESS; /* (2) */
IWDG->PR = IWDG_PR_PR_1; /* (3) */
IWDG->RLR = 1250; /* (4) */
tmout = 16000000;
while(IWDG->SR){if(--tmout == 0) break;} /* (5) */
IWDG->KR = IWDG_REFRESH; /* (6) */
}
// pause in milliseconds for some purposes
void pause_ms(uint32_t pause){
uint32_t Tnxt = Tms + pause;
while(Tms < Tnxt) nop();
}
void Jump2Boot(){
void (*SysMemBootJump)(void);
volatile uint32_t addr = SystemMem;
// reset systick
SysTick->CTRL = 0;
// reset clocks
RCC->APB1RSTR = RCC_APB1RSTR_CECRST | RCC_APB1RSTR_DACRST | RCC_APB1RSTR_PWRRST | RCC_APB1RSTR_CRSRST |
RCC_APB1RSTR_CANRST | RCC_APB1RSTR_USBRST | RCC_APB1RSTR_I2C2RST | RCC_APB1RSTR_I2C1RST |
RCC_APB1RSTR_USART4RST | RCC_APB1RSTR_USART3RST | RCC_APB1RSTR_USART2RST | RCC_APB1RSTR_SPI2RST |
RCC_APB1RSTR_WWDGRST | RCC_APB1RSTR_TIM14RST |
#ifdef STM32F072xB
RCC_APB1RSTR_TIM7RST | RCC_APB1RSTR_TIM6RST |
#endif
RCC_APB1RSTR_TIM3RST | RCC_APB1RSTR_TIM2RST;
RCC->APB2RSTR = RCC_APB2RSTR_DBGMCURST | RCC_APB2RSTR_TIM17RST | RCC_APB2RSTR_TIM16RST |
#ifdef STM32F072xB
RCC_APB2RSTR_TIM15RST |
#endif
RCC_APB2RSTR_USART1RST | RCC_APB2RSTR_SPI1RST | RCC_APB2RSTR_TIM1RST | RCC_APB2RSTR_ADCRST | RCC_APB2RSTR_SYSCFGRST;
RCC->AHBRSTR = 0;
RCC->APB1RSTR = 0;
RCC->APB2RSTR = 0;
/* // reset GPIO - DON'T WORK! ???
GPIOA->MODER = 0; GPIOA->PUPDR = 0; GPIOA->ODR = 0;
GPIOB->MODER = 0; GPIOB->PUPDR = 0; GPIOB->ODR = 0;
GPIOC->MODER = 0; GPIOC->PUPDR = 0; GPIOC->ODR = 0;
#ifdef STM32F072xB
GPIOD->MODER = 0; GPIOD->PUPDR = 0; GPIOD->ODR = 0;
GPIOE->MODER = 0; GPIOE->PUPDR = 0; GPIOE->ODR = 0;
#endif
GPIOF->MODER = 0; GPIOF->PUPDR = 0; GPIOF->ODR = 0; */
// remap memory to 0 (only for STM32F0)
SYSCFG->CFGR1 = 0x01; __DSB(); __ISB();
SysMemBootJump = (void (*)(void)) (*((uint32_t *)(addr + 4)));
// set main stack pointer
__set_MSP(*((uint32_t *)addr));
// jump to bootloader
SysMemBootJump();
}
void buzzer_chk(){ // check buzzer state
static uint32_t lastTms = 0;
static buzzer_state oldstate = BUZZER_OFF;
uint32_t B, S; // length of beep and silence
if(buzzer == oldstate){ // keep current state
if(lastTms > Tms) return;
switch(buzzer){ // beep on/off
case BUZZER_LONG:
B = LONG_BUZZER_PERIOD;
S = LONG_BUZZER_PAUSE;
break;
case BUZZER_SHORT:
B = SHORT_BUZZER_PERIOD;
S = SHORT_BUZZER_PAUSE;
break;
default:
return;
}
if(CHK(BUZZER)){ // is ON
OFF(BUZZER);
lastTms = Tms + S;
}else{ // is OFF
ON(BUZZER);
lastTms = Tms + B;
}
return;
}
switch(buzzer){ // change buzzer state
case BUZZER_ON:
ON(BUZZER);
break;
case BUZZER_OFF:
OFF(BUZZER);
break;
case BUZZER_LONG:
ON(BUZZER);
lastTms = Tms + LONG_BUZZER_PERIOD;
break;
case BUZZER_SHORT:
ON(BUZZER);
lastTms = Tms + SHORT_BUZZER_PERIOD;
break;
}
oldstate = buzzer;
}
void exti4_15_isr(){
EXTI->PR |= EXTI_PR_PR7; // clear pending bit
++Cooler1RPM;
}

View File

@@ -0,0 +1,89 @@
/*
* geany_encoding=koi8-r
* hardware.h
*
* Copyright 2018 Edward V. Emelianov <eddy@sao.ru, edward.emelianoff@gmail.com>
*
* 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.
*
*/
#pragma once
#ifndef __HARDWARE_H__
#define __HARDWARE_H__
#include <stm32f0.h>
#define SYSMEM03x 0x1FFFEC00
#define SYSMEM04x 0x1FFFC400
#define SYSMEM05x 0x1FFFEC00
#define SYSMEM07x 0x1FFFC800
#define SYSMEM09x 0x1FFFD800
#define SystemMem SYSMEM07x
#define CONCAT(a,b) a ## b
#define STR_HELPER(s) #s
#define STR(s) STR_HELPER(s)
// Buzzer: PA14
#define BUZZER_port GPIOA
#define BUZZER_pin (1<<14)
// Cooler0/1 power on/off: PB4, PB5
#define COOLER0_port GPIOB
#define COOLER0_pin (1<<4)
#define COOLER1_port GPIOB
#define COOLER1_pin (1<<5)
// Relay: PC13
#define RELAY_port GPIOC
#define RELAY_pin (1<<13)
// Buttons: PB14/15
#define BUTTON0_port GPIOB
#define BUTTON0_pin (1<<14)
#define BUTTON1_port GPIOB
#define BUTTON1_pin (1<<15)
// common macro for getting status
#define CHK(x) ((x ## _port->IDR & (x ## _pin)) ? 1 : 0)
#define ON(x) do{pin_set(x ## _port, x ## _pin);}while(0)
#define OFF(x) do{pin_clear(x ## _port, x ## _pin);}while(0)
typedef enum{
BUZZER_OFF, // buzzer is off
BUZZER_ON, // continuous beeep
BUZZER_SHORT, // short beeps with longer pause
BUZZER_LONG // long beeps with shorter pause
} buzzer_state;
// Length of long and short time periods (ms)
#define LONG_BUZZER_PERIOD (4000)
#define LONG_BUZZER_PAUSE (6000)
#define SHORT_BUZZER_PERIOD (500)
#define SHORT_BUZZER_PAUSE (9500)
extern volatile uint32_t Tms;
extern volatile uint32_t Coolerspeed[2];
extern volatile uint32_t Cooler1RPM;
extern buzzer_state buzzer;
void HW_setup(void);
void adc_setup();
void iwdg_setup();
void pause_ms(uint32_t pause);
void Jump2Boot();
void buzzer_chk();
#endif // __HARDWARE_H__

View File

@@ -0,0 +1,22 @@
EESchema-LIBRARY Version 2.3 Date: Sun 04 May 2014 09:27:50 PM MSK
#encoding utf-8
#
# ACS712
#
DEF ACS712 U 0 40 Y Y 1 F N
F0 "U" 0 300 60 H V C CNN
F1 "ACS712" 0 -350 60 H V C CNN
DRAW
S -450 250 450 -300 0 1 0 N
X IP+ 1 -550 150 300 R 50 50 1 1 I
X IP+ 2 -550 50 300 R 50 50 1 1 I
X IP- 3 -550 -100 300 R 50 50 1 1 I
X IP- 4 -550 -200 300 R 50 50 1 1 I
X GND 5 550 -200 300 L 50 50 1 1 I
X FILTER 6 550 -100 300 L 50 50 1 1 I
X VIOUT 7 550 50 300 L 50 50 1 1 I
X Vcc 8 550 150 300 L 50 50 1 1 I
ENDDRAW
ENDDEF
#
#End Library

View File

@@ -0,0 +1,190 @@
EESchema-LIBRARY Version 2.3
#encoding utf-8
#
# 74HC4051
#
DEF 74HC4051 U 0 10 Y Y 1 F N
F0 "U" 0 0 50 H V C CNN
F1 "74HC4051" 0 -150 50 H V C CNN
F2 "" 0 0 50 H V C CNN
F3 "" 0 0 50 H V C CNN
$FPLIST
SO16
TSSOP16
SSOP16
DHVQFN16
$ENDFPLIST
DRAW
S -400 450 400 -450 0 1 0 N
X Y4 1 700 -50 300 L 50 50 1 1 B
X Y6 2 700 -250 300 L 50 50 1 1 B
X Z 3 0 -750 300 U 50 50 1 1 B
X Y7 4 700 -350 300 L 50 50 1 1 B
X Y5 5 700 -150 300 L 50 50 1 1 B
X ~E 6 -700 -350 300 R 50 50 1 1 I I
X VEE 7 -700 0 300 R 50 50 1 1 W
X GND 8 -700 -200 300 R 50 50 1 1 W
X S2 9 -700 150 300 R 50 50 1 1 I
X S1 10 -700 250 300 R 50 50 1 1 I
X S0 11 -700 350 300 R 50 50 1 1 I
X Y3 12 700 50 300 L 50 50 1 1 B
X Y0 13 700 350 300 L 50 50 1 1 B
X Y1 14 700 250 300 L 50 50 1 1 B
X Y2 15 700 150 300 L 50 50 1 1 B
X VCC 16 -700 -100 300 R 50 50 1 1 W
ENDDRAW
ENDDEF
#
# D_Schottky_x2_ACom_AKK
#
DEF D_Schottky_x2_ACom_AKK D 0 30 Y N 1 F N
F0 "D" 50 -100 50 H V C CNN
F1 "D_Schottky_x2_ACom_AKK" 0 100 50 H V C CNN
F2 "" 0 0 50 H V C CNN
F3 "" 0 0 50 H V C CNN
DRAW
P 2 0 1 0 -140 0 150 0 N
P 2 0 1 0 0 0 0 -100 N
P 3 0 1 8 -150 50 -150 -50 -150 -50 N
P 3 0 1 8 150 50 150 -50 150 -50 N
P 4 0 1 8 -150 50 -170 50 -170 40 -170 40 N
P 4 0 1 8 150 -50 170 -50 170 -40 170 -40 N
P 4 0 1 8 150 50 130 50 130 40 130 40 N
P 5 0 1 8 -130 -40 -130 -50 -150 -50 -150 -50 -150 -50 N
P 6 0 1 8 -50 -50 -150 0 -50 50 -50 -50 -50 -50 -50 -50 N
P 6 0 1 8 50 50 150 0 50 -50 50 50 50 50 50 50 N
X A 1 0 -200 100 U 50 50 0 1 P
X K 2 -300 0 150 R 50 50 0 1 P
X K 3 300 0 150 L 50 50 0 1 P
ENDDRAW
ENDDEF
#
# LM1117-ADJ
#
DEF LM1117-ADJ U 0 30 Y Y 1 F N
F0 "U" 100 -250 50 H V C CNN
F1 "LM1117-ADJ" 0 250 50 H V C CNN
F2 "" 0 0 50 H V C CNN
F3 "" 0 0 50 H V C CNN
ALIAS LM1117-1.8 LM1117-2.5 LM1117-3.3 LM1117-5.0
$FPLIST
SOT-223*
TO-263*
TO-252*
$ENDFPLIST
DRAW
S -200 -200 200 200 0 1 10 f
X GND/ADJ 1 0 -300 100 U 50 50 1 1 W
X VO 2 300 0 100 L 50 50 1 1 w
X VI 3 -300 0 100 R 50 50 1 1 W
ENDDRAW
ENDDEF
#
# PESD1CAN
#
DEF PESD1CAN D 0 30 Y N 1 F N
F0 "D" 0 -350 50 H V C CNN
F1 "PESD1CAN" 50 150 50 H V C CNN
F2 "" 0 0 50 H V C CNN
F3 "" 0 0 50 H V C CNN
$FPLIST
SOT23
$ENDFPLIST
DRAW
S -200 100 300 -300 0 1 0 N
P 2 0 1 0 -140 -200 150 -200 N
P 2 0 1 0 -140 0 150 0 N
P 3 0 1 8 -150 -150 -150 -250 -150 -250 N
P 3 0 1 8 -150 50 -150 -50 -150 -50 N
P 3 0 1 8 150 -150 150 -250 150 -250 N
P 3 0 1 8 150 50 150 -50 150 -50 N
P 4 0 1 8 -150 -150 -170 -150 -170 -160 -170 -160 N
P 4 0 1 8 -150 50 -170 50 -170 40 -170 40 N
P 4 0 1 8 150 -250 170 -250 170 -240 170 -240 N
P 4 0 1 8 150 -150 130 -150 130 -160 130 -160 N
P 4 0 1 8 150 -50 170 -50 170 -40 170 -40 N
P 4 0 1 0 150 0 250 0 250 -200 150 -200 N
P 4 0 1 8 150 50 130 50 130 40 130 40 N
P 5 0 1 8 -130 -240 -130 -250 -150 -250 -150 -250 -150 -250 N
P 5 0 1 8 -130 -40 -130 -50 -150 -50 -150 -50 -150 -50 N
P 6 0 1 8 -50 -250 -150 -200 -50 -150 -50 -250 -50 -250 -50 -250 N
P 6 0 1 8 -50 -50 -150 0 -50 50 -50 -50 -50 -50 -50 -50 N
P 6 0 1 8 50 -150 150 -200 50 -250 50 -150 50 -150 50 -150 N
P 6 0 1 8 50 50 150 0 50 -50 50 50 50 50 50 50 N
X K 1 -300 0 150 R 50 50 0 1 P
X K 2 -300 -200 150 R 50 50 0 1 P
X O 3 400 -100 150 L 50 50 0 1 P
ENDDRAW
ENDDEF
#
# TPS2051
#
DEF TPS2051 U 0 40 Y Y 1 F N
F0 "U" 0 -300 60 H V C CNN
F1 "TPS2051" 0 300 60 H V C CNN
F2 "" 0 0 60 H I C CNN
F3 "" 0 0 60 H I C CNN
DRAW
S -250 250 250 -250 0 1 0 N
X GND 1 -450 150 200 R 50 50 1 1 W
X IN 2 -450 50 200 R 50 50 1 1 W
X IN 3 -450 -50 200 R 50 50 1 1 P
X EN 4 -450 -150 200 R 50 50 1 1 I
X ~OC 5 450 -150 200 L 50 50 1 1 O
X OUT 6 450 -50 200 L 50 50 1 1 P
X OUT 7 450 50 200 L 50 50 1 1 P
X OUT 8 450 150 200 L 50 50 1 1 w
ENDDRAW
ENDDEF
#
# USB6B1
#
DEF USB6B1 D 0 30 Y N 1 F N
F0 "D" 0 -450 50 H V C CNN
F1 "USB6B1" 0 400 50 H V C CNN
F2 "" 200 -100 50 V V C CNN
F3 "" 200 -100 50 V V C CNN
$FPLIST
SO8
$ENDFPLIST
DRAW
C -150 -300 7 0 1 0 N
C -150 100 7 0 1 0 N
C -150 300 7 0 1 0 N
C 0 -300 7 0 1 0 N
C 0 -100 7 0 1 0 N
C 0 300 7 0 1 0 N
C 200 -300 7 0 1 0 N
C 200 300 7 0 1 0 N
S -300 -100 300 -100 0 1 0 N
S -300 300 300 300 0 1 0 N
S -200 -150 -100 -150 0 1 0 N
S -200 250 -100 250 0 1 0 N
S -150 300 -150 -300 0 1 0 N
S -50 -150 50 -150 0 1 0 N
S -50 250 50 250 0 1 0 N
S 0 300 0 -300 0 1 0 N
S 200 300 200 -300 0 1 0 N
S 300 -300 -300 -300 0 1 0 N
S 300 100 -300 100 0 1 0 N
P 3 0 1 8 150 50 250 50 250 50 N
P 4 0 1 8 150 50 150 30 160 30 160 30 N
P 4 0 1 8 250 50 250 70 240 70 240 70 N
P 5 0 1 0 -250 350 300 350 300 -350 -250 -350 -250 350 N
P 6 0 1 8 -200 -250 -150 -150 -100 -250 -200 -250 -200 -250 -200 -250 N
P 6 0 1 8 -200 150 -150 250 -100 150 -200 150 -200 150 -200 150 N
P 6 0 1 8 -50 -250 0 -150 50 -250 -50 -250 -50 -250 -50 -250 N
P 6 0 1 8 -50 150 0 250 50 150 -50 150 -50 150 -50 150 N
P 6 0 1 8 150 -50 200 50 250 -50 150 -50 150 -50 150 -50 N
X VCC 1 -500 300 200 R 50 50 1 1 P
X I/O1 2 -500 100 200 R 50 50 1 1 P
X I/O2 3 -500 -100 200 R 50 50 1 1 P
X GND 4 -500 -300 200 R 50 50 1 1 P
X GND 5 500 -300 200 L 50 50 1 1 P
X I/O2 6 500 -100 200 L 50 50 1 1 P
X I/O1 7 500 100 200 L 50 50 1 1 P
X VCC 8 500 300 200 L 50 50 1 1 P
ENDDRAW
ENDDEF
#
#End Library

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,6 @@
(fp_lib_table
(lib (name TestPoint)(type KiCad)(uri ${KISYSMOD}/TestPoint.pretty)(options "")(descr ""))
(lib (name Fuse)(type KiCad)(uri ${KISYSMOD}/Fuse.pretty)(options "")(descr ""))
(lib (name MyFootprints)(type KiCad)(uri /home/eddy/Docs/SAO/ELECTRONICS/STM32/F0-srcs/CANbus_stepper/my_footprints.pretty)(options "")(descr ""))
(lib (name Connector_Dsub)(type KiCad)(uri /usr/share/kicad/kicad-footprints/Connector_Dsub.pretty)(options "")(descr ""))
)

View File

@@ -0,0 +1,9 @@
(module Hole_3mm (layer F.Cu) (tedit 5913F6E4)
(fp_text reference REF** (at 0 3.81) (layer F.SilkS) hide
(effects (font (size 1 1) (thickness 0.15)))
)
(fp_text value Hole_3mm (at 0 -7.62) (layer F.Fab) hide
(effects (font (size 1 1) (thickness 0.15)))
)
(pad 1 thru_hole circle (at 0 0) (size 5 5) (drill 3) (layers *.Cu *.Mask))
)

View File

@@ -0,0 +1,10 @@
(module TH_via (layer F.Cu) (tedit 5A5E619A)
(fp_text reference REF** (at 0 0.5) (layer F.SilkS) hide
(effects (font (size 1 1) (thickness 0.15)))
)
(fp_text value TH_via (at 0 -0.5) (layer F.Fab) hide
(effects (font (size 1 1) (thickness 0.15)))
)
(pad 1 thru_hole circle (at 0 0) (size 1.5 1.5) (drill 0.8) (layers *.Cu *.Mask)
(zone_connect 1))
)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,169 @@
G04 #@! TF.GenerationSoftware,KiCad,Pcbnew,5.1.6*
G04 #@! TF.CreationDate,2020-10-24T20:22:56+03:00*
G04 #@! TF.ProjectId,stm32,73746d33-322e-46b6-9963-61645f706362,rev?*
G04 #@! TF.SameCoordinates,Original*
G04 #@! TF.FileFunction,Soldermask,Bot*
G04 #@! TF.FilePolarity,Negative*
%FSLAX46Y46*%
G04 Gerber Fmt 4.6, Leading zero omitted, Abs format (unit mm)*
G04 Created by KiCad (PCBNEW 5.1.6) date 2020-10-24 20:22:56*
%MOMM*%
%LPD*%
G01*
G04 APERTURE LIST*
G04 #@! TA.AperFunction,Profile*
%ADD10C,0.150000*%
G04 #@! TD*
%ADD11R,2.130000X2.430000*%
%ADD12O,2.130000X2.430000*%
%ADD13R,3.000000X3.000000*%
%ADD14C,3.000000*%
%ADD15R,2.100000X2.100000*%
%ADD16O,2.100000X2.100000*%
%ADD17O,2.100000X2.400000*%
%ADD18C,3.400000*%
%ADD19C,2.900000*%
%ADD20C,2.100000*%
%ADD21C,3.900000*%
%ADD22C,3.600000*%
%ADD23R,2.400000X2.305000*%
%ADD24O,2.400000X2.305000*%
%ADD25R,2.000000X2.000000*%
%ADD26C,2.000000*%
G04 APERTURE END LIST*
D10*
X38000000Y-104500000D02*
X38000000Y-52000000D01*
X113500000Y-104500000D02*
X38000000Y-104500000D01*
X113500000Y-52000000D02*
X113500000Y-104500000D01*
X38000000Y-52000000D02*
X113500000Y-52000000D01*
D11*
X94500000Y-56000000D03*
D12*
X97040000Y-56000000D03*
X99580000Y-56000000D03*
X102120000Y-56000000D03*
X86620000Y-56000000D03*
X84080000Y-56000000D03*
X81540000Y-56000000D03*
D11*
X79000000Y-56000000D03*
D13*
X52000000Y-98500000D03*
D14*
X57000000Y-98500000D03*
D15*
X74602000Y-98255500D03*
D16*
X74602000Y-100795500D03*
X72062000Y-98255500D03*
X72062000Y-100795500D03*
X69522000Y-98255500D03*
X69522000Y-100795500D03*
X66982000Y-98255500D03*
X66982000Y-100795500D03*
D17*
X109000000Y-68500000D03*
G36*
G01*
X105450000Y-69391177D02*
X105450000Y-67608823D01*
G75*
G02*
X105758823Y-67300000I308823J0D01*
G01*
X107241177Y-67300000D01*
G75*
G02*
X107550000Y-67608823I0J-308823D01*
G01*
X107550000Y-69391177D01*
G75*
G02*
X107241177Y-69700000I-308823J0D01*
G01*
X105758823Y-69700000D01*
G75*
G02*
X105450000Y-69391177I0J308823D01*
G01*
G37*
G36*
G01*
X65950000Y-55891177D02*
X65950000Y-54108823D01*
G75*
G02*
X66258823Y-53800000I308823J0D01*
G01*
X67741177Y-53800000D01*
G75*
G02*
X68050000Y-54108823I0J-308823D01*
G01*
X68050000Y-55891177D01*
G75*
G02*
X67741177Y-56200000I-308823J0D01*
G01*
X66258823Y-56200000D01*
G75*
G02*
X65950000Y-55891177I0J308823D01*
G01*
G37*
X69500000Y-55000000D03*
D13*
X56885500Y-58000000D03*
D14*
X51885500Y-58000000D03*
D18*
X57025200Y-74107720D03*
D19*
X55075200Y-68157720D03*
D18*
X42825200Y-68107720D03*
X42875200Y-80157720D03*
D19*
X55075200Y-80157720D03*
D15*
X105463000Y-82063000D03*
D20*
X105463000Y-79563000D03*
X107463000Y-79563000D03*
X107463000Y-82063000D03*
D21*
X110173000Y-86833000D03*
X110173000Y-74793000D03*
D22*
X44500000Y-100500000D03*
X107500000Y-61000000D03*
X44500000Y-61000000D03*
X107500000Y-100500000D03*
D16*
X89588000Y-94001000D03*
D15*
X89588000Y-96541000D03*
X93334500Y-96541000D03*
D16*
X93334500Y-94001000D03*
D23*
X42153500Y-88349500D03*
D24*
X42153500Y-90889500D03*
X42153500Y-93429500D03*
D15*
X79682000Y-70950500D03*
D16*
X82222000Y-70950500D03*
X71460000Y-77872000D03*
D15*
X74000000Y-77872000D03*
D25*
X63844500Y-82734000D03*
D26*
X63844500Y-86234000D03*
M02*

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,498 @@
%FSLAX45Y45*%
G04 Gerber Fmt 4.5, Leading zero omitted, Abs format (unit mm)*
G04 Created by KiCad (PCBNEW 5.1.6) date 2020-10-24 20:22:54*
%MOMM*%
%LPD*%
G01*
G04 APERTURE LIST*
%TA.AperFunction,Profile*%
%ADD10C,0.150000*%
%TD*%
%ADD11C,0.200000*%
%ADD12C,0.300000*%
G04 APERTURE END LIST*
D10*
X3800000Y-10450000D02*
X3800000Y-5200000D01*
X11350000Y-10450000D02*
X3800000Y-10450000D01*
X11350000Y-5200000D02*
X11350000Y-10450000D01*
X3800000Y-5200000D02*
X11350000Y-5200000D01*
D11*
X10590000Y-9890000D02*
X10910000Y-10210000D01*
X10910000Y-9890000D02*
X10590000Y-10210000D01*
X4290000Y-5940000D02*
X4610000Y-6260000D01*
X4610000Y-5940000D02*
X4290000Y-6260000D01*
X10590000Y-5940000D02*
X10910000Y-6260000D01*
X10910000Y-5940000D02*
X10590000Y-6260000D01*
X4290000Y-9890000D02*
X4610000Y-10210000D01*
X4610000Y-9890000D02*
X4290000Y-10210000D01*
D12*
X4078928Y-10923214D02*
X4078928Y-10623214D01*
X4150357Y-10623214D01*
X4193214Y-10637500D01*
X4221786Y-10666072D01*
X4236071Y-10694643D01*
X4250357Y-10751786D01*
X4250357Y-10794643D01*
X4236071Y-10851786D01*
X4221786Y-10880357D01*
X4193214Y-10908929D01*
X4150357Y-10923214D01*
X4078928Y-10923214D01*
X4378928Y-10923214D02*
X4378928Y-10723214D01*
X4378928Y-10780357D02*
X4393214Y-10751786D01*
X4407500Y-10737500D01*
X4436071Y-10723214D01*
X4464643Y-10723214D01*
X4564643Y-10923214D02*
X4564643Y-10723214D01*
X4564643Y-10623214D02*
X4550357Y-10637500D01*
X4564643Y-10651786D01*
X4578928Y-10637500D01*
X4564643Y-10623214D01*
X4564643Y-10651786D01*
X4750357Y-10923214D02*
X4721786Y-10908929D01*
X4707500Y-10880357D01*
X4707500Y-10623214D01*
X4907500Y-10923214D02*
X4878928Y-10908929D01*
X4864643Y-10880357D01*
X4864643Y-10623214D01*
X5250357Y-10923214D02*
X5250357Y-10623214D01*
X5350357Y-10837500D01*
X5450357Y-10623214D01*
X5450357Y-10923214D01*
X5721786Y-10923214D02*
X5721786Y-10766072D01*
X5707500Y-10737500D01*
X5678928Y-10723214D01*
X5621786Y-10723214D01*
X5593214Y-10737500D01*
X5721786Y-10908929D02*
X5693214Y-10923214D01*
X5621786Y-10923214D01*
X5593214Y-10908929D01*
X5578928Y-10880357D01*
X5578928Y-10851786D01*
X5593214Y-10823214D01*
X5621786Y-10808929D01*
X5693214Y-10808929D01*
X5721786Y-10794643D01*
X5864643Y-10723214D02*
X5864643Y-11023214D01*
X5864643Y-10737500D02*
X5893214Y-10723214D01*
X5950357Y-10723214D01*
X5978928Y-10737500D01*
X5993214Y-10751786D01*
X6007500Y-10780357D01*
X6007500Y-10866072D01*
X5993214Y-10894643D01*
X5978928Y-10908929D01*
X5950357Y-10923214D01*
X5893214Y-10923214D01*
X5864643Y-10908929D01*
X6136071Y-10894643D02*
X6150357Y-10908929D01*
X6136071Y-10923214D01*
X6121786Y-10908929D01*
X6136071Y-10894643D01*
X6136071Y-10923214D01*
X6136071Y-10737500D02*
X6150357Y-10751786D01*
X6136071Y-10766072D01*
X6121786Y-10751786D01*
X6136071Y-10737500D01*
X6136071Y-10766072D01*
X3472500Y-11257500D02*
X3792500Y-11577500D01*
X3792500Y-11257500D02*
X3472500Y-11577500D01*
X4050357Y-11253214D02*
X4236071Y-11253214D01*
X4136071Y-11367500D01*
X4178928Y-11367500D01*
X4207500Y-11381786D01*
X4221786Y-11396071D01*
X4236071Y-11424643D01*
X4236071Y-11496071D01*
X4221786Y-11524643D01*
X4207500Y-11538929D01*
X4178928Y-11553214D01*
X4093214Y-11553214D01*
X4064643Y-11538929D01*
X4050357Y-11524643D01*
X4364643Y-11524643D02*
X4378928Y-11538929D01*
X4364643Y-11553214D01*
X4350357Y-11538929D01*
X4364643Y-11524643D01*
X4364643Y-11553214D01*
X4493214Y-11281786D02*
X4507500Y-11267500D01*
X4536071Y-11253214D01*
X4607500Y-11253214D01*
X4636071Y-11267500D01*
X4650357Y-11281786D01*
X4664643Y-11310357D01*
X4664643Y-11338929D01*
X4650357Y-11381786D01*
X4478928Y-11553214D01*
X4664643Y-11553214D01*
X4850357Y-11253214D02*
X4878928Y-11253214D01*
X4907500Y-11267500D01*
X4921786Y-11281786D01*
X4936071Y-11310357D01*
X4950357Y-11367500D01*
X4950357Y-11438929D01*
X4936071Y-11496071D01*
X4921786Y-11524643D01*
X4907500Y-11538929D01*
X4878928Y-11553214D01*
X4850357Y-11553214D01*
X4821786Y-11538929D01*
X4807500Y-11524643D01*
X4793214Y-11496071D01*
X4778928Y-11438929D01*
X4778928Y-11367500D01*
X4793214Y-11310357D01*
X4807500Y-11281786D01*
X4821786Y-11267500D01*
X4850357Y-11253214D01*
X5078928Y-11553214D02*
X5078928Y-11353214D01*
X5078928Y-11381786D02*
X5093214Y-11367500D01*
X5121786Y-11353214D01*
X5164643Y-11353214D01*
X5193214Y-11367500D01*
X5207500Y-11396071D01*
X5207500Y-11553214D01*
X5207500Y-11396071D02*
X5221786Y-11367500D01*
X5250357Y-11353214D01*
X5293214Y-11353214D01*
X5321786Y-11367500D01*
X5336071Y-11396071D01*
X5336071Y-11553214D01*
X5478928Y-11553214D02*
X5478928Y-11353214D01*
X5478928Y-11381786D02*
X5493214Y-11367500D01*
X5521786Y-11353214D01*
X5564643Y-11353214D01*
X5593214Y-11367500D01*
X5607500Y-11396071D01*
X5607500Y-11553214D01*
X5607500Y-11396071D02*
X5621786Y-11367500D01*
X5650357Y-11353214D01*
X5693214Y-11353214D01*
X5721786Y-11367500D01*
X5736071Y-11396071D01*
X5736071Y-11553214D01*
X6321786Y-11238929D02*
X6064643Y-11624643D01*
X6707500Y-11253214D02*
X6736071Y-11253214D01*
X6764643Y-11267500D01*
X6778928Y-11281786D01*
X6793214Y-11310357D01*
X6807500Y-11367500D01*
X6807500Y-11438929D01*
X6793214Y-11496071D01*
X6778928Y-11524643D01*
X6764643Y-11538929D01*
X6736071Y-11553214D01*
X6707500Y-11553214D01*
X6678928Y-11538929D01*
X6664643Y-11524643D01*
X6650357Y-11496071D01*
X6636071Y-11438929D01*
X6636071Y-11367500D01*
X6650357Y-11310357D01*
X6664643Y-11281786D01*
X6678928Y-11267500D01*
X6707500Y-11253214D01*
X6936071Y-11524643D02*
X6950357Y-11538929D01*
X6936071Y-11553214D01*
X6921786Y-11538929D01*
X6936071Y-11524643D01*
X6936071Y-11553214D01*
X7236071Y-11553214D02*
X7064643Y-11553214D01*
X7150357Y-11553214D02*
X7150357Y-11253214D01*
X7121786Y-11296071D01*
X7093214Y-11324643D01*
X7064643Y-11338929D01*
X7350357Y-11281786D02*
X7364643Y-11267500D01*
X7393214Y-11253214D01*
X7464643Y-11253214D01*
X7493214Y-11267500D01*
X7507500Y-11281786D01*
X7521786Y-11310357D01*
X7521786Y-11338929D01*
X7507500Y-11381786D01*
X7336071Y-11553214D01*
X7521786Y-11553214D01*
X7778928Y-11253214D02*
X7721786Y-11253214D01*
X7693214Y-11267500D01*
X7678928Y-11281786D01*
X7650357Y-11324643D01*
X7636071Y-11381786D01*
X7636071Y-11496071D01*
X7650357Y-11524643D01*
X7664643Y-11538929D01*
X7693214Y-11553214D01*
X7750357Y-11553214D01*
X7778928Y-11538929D01*
X7793214Y-11524643D01*
X7807500Y-11496071D01*
X7807500Y-11424643D01*
X7793214Y-11396071D01*
X7778928Y-11381786D01*
X7750357Y-11367500D01*
X7693214Y-11367500D01*
X7664643Y-11381786D01*
X7650357Y-11396071D01*
X7636071Y-11424643D01*
X7921786Y-11253214D02*
X7921786Y-11310357D01*
X8036071Y-11253214D02*
X8036071Y-11310357D01*
X8478928Y-11667500D02*
X8464643Y-11653214D01*
X8436071Y-11610357D01*
X8421786Y-11581786D01*
X8407500Y-11538929D01*
X8393214Y-11467500D01*
X8393214Y-11410357D01*
X8407500Y-11338929D01*
X8421786Y-11296071D01*
X8436071Y-11267500D01*
X8464643Y-11224643D01*
X8478928Y-11210357D01*
X8721786Y-11353214D02*
X8721786Y-11553214D01*
X8650357Y-11238929D02*
X8578928Y-11453214D01*
X8764643Y-11453214D01*
X9107500Y-11553214D02*
X9107500Y-11253214D01*
X9236071Y-11553214D02*
X9236071Y-11396071D01*
X9221786Y-11367500D01*
X9193214Y-11353214D01*
X9150357Y-11353214D01*
X9121786Y-11367500D01*
X9107500Y-11381786D01*
X9421786Y-11553214D02*
X9393214Y-11538929D01*
X9378928Y-11524643D01*
X9364643Y-11496071D01*
X9364643Y-11410357D01*
X9378928Y-11381786D01*
X9393214Y-11367500D01*
X9421786Y-11353214D01*
X9464643Y-11353214D01*
X9493214Y-11367500D01*
X9507500Y-11381786D01*
X9521786Y-11410357D01*
X9521786Y-11496071D01*
X9507500Y-11524643D01*
X9493214Y-11538929D01*
X9464643Y-11553214D01*
X9421786Y-11553214D01*
X9693214Y-11553214D02*
X9664643Y-11538929D01*
X9650357Y-11510357D01*
X9650357Y-11253214D01*
X9921786Y-11538929D02*
X9893214Y-11553214D01*
X9836071Y-11553214D01*
X9807500Y-11538929D01*
X9793214Y-11510357D01*
X9793214Y-11396071D01*
X9807500Y-11367500D01*
X9836071Y-11353214D01*
X9893214Y-11353214D01*
X9921786Y-11367500D01*
X9936071Y-11396071D01*
X9936071Y-11424643D01*
X9793214Y-11453214D01*
X10050357Y-11538929D02*
X10078928Y-11553214D01*
X10136071Y-11553214D01*
X10164643Y-11538929D01*
X10178928Y-11510357D01*
X10178928Y-11496071D01*
X10164643Y-11467500D01*
X10136071Y-11453214D01*
X10093214Y-11453214D01*
X10064643Y-11438929D01*
X10050357Y-11410357D01*
X10050357Y-11396071D01*
X10064643Y-11367500D01*
X10093214Y-11353214D01*
X10136071Y-11353214D01*
X10164643Y-11367500D01*
X10278928Y-11667500D02*
X10293214Y-11653214D01*
X10321786Y-11610357D01*
X10336071Y-11581786D01*
X10350357Y-11538929D01*
X10364643Y-11467500D01*
X10364643Y-11410357D01*
X10350357Y-11338929D01*
X10336071Y-11296071D01*
X10321786Y-11267500D01*
X10293214Y-11224643D01*
X10278928Y-11210357D01*
X10821786Y-11667500D02*
X10807500Y-11653214D01*
X10778928Y-11610357D01*
X10764643Y-11581786D01*
X10750357Y-11538929D01*
X10736071Y-11467500D01*
X10736071Y-11410357D01*
X10750357Y-11338929D01*
X10764643Y-11296071D01*
X10778928Y-11267500D01*
X10807500Y-11224643D01*
X10821786Y-11210357D01*
X10936071Y-11353214D02*
X10936071Y-11553214D01*
X10936071Y-11381786D02*
X10950357Y-11367500D01*
X10978928Y-11353214D01*
X11021786Y-11353214D01*
X11050357Y-11367500D01*
X11064643Y-11396071D01*
X11064643Y-11553214D01*
X11250357Y-11553214D02*
X11221786Y-11538929D01*
X11207500Y-11524643D01*
X11193214Y-11496071D01*
X11193214Y-11410357D01*
X11207500Y-11381786D01*
X11221786Y-11367500D01*
X11250357Y-11353214D01*
X11293214Y-11353214D01*
X11321786Y-11367500D01*
X11336071Y-11381786D01*
X11350357Y-11410357D01*
X11350357Y-11496071D01*
X11336071Y-11524643D01*
X11321786Y-11538929D01*
X11293214Y-11553214D01*
X11250357Y-11553214D01*
X11436071Y-11353214D02*
X11550357Y-11353214D01*
X11478928Y-11253214D02*
X11478928Y-11510357D01*
X11493214Y-11538929D01*
X11521786Y-11553214D01*
X11550357Y-11553214D01*
X11878928Y-11353214D02*
X11878928Y-11653214D01*
X11878928Y-11367500D02*
X11907500Y-11353214D01*
X11964643Y-11353214D01*
X11993214Y-11367500D01*
X12007500Y-11381786D01*
X12021786Y-11410357D01*
X12021786Y-11496071D01*
X12007500Y-11524643D01*
X11993214Y-11538929D01*
X11964643Y-11553214D01*
X11907500Y-11553214D01*
X11878928Y-11538929D01*
X12193214Y-11553214D02*
X12164643Y-11538929D01*
X12150357Y-11510357D01*
X12150357Y-11253214D01*
X12436071Y-11553214D02*
X12436071Y-11396071D01*
X12421786Y-11367500D01*
X12393214Y-11353214D01*
X12336071Y-11353214D01*
X12307500Y-11367500D01*
X12436071Y-11538929D02*
X12407500Y-11553214D01*
X12336071Y-11553214D01*
X12307500Y-11538929D01*
X12293214Y-11510357D01*
X12293214Y-11481786D01*
X12307500Y-11453214D01*
X12336071Y-11438929D01*
X12407500Y-11438929D01*
X12436071Y-11424643D01*
X12536071Y-11353214D02*
X12650357Y-11353214D01*
X12578928Y-11253214D02*
X12578928Y-11510357D01*
X12593214Y-11538929D01*
X12621786Y-11553214D01*
X12650357Y-11553214D01*
X12864643Y-11538929D02*
X12836071Y-11553214D01*
X12778928Y-11553214D01*
X12750357Y-11538929D01*
X12736071Y-11510357D01*
X12736071Y-11396071D01*
X12750357Y-11367500D01*
X12778928Y-11353214D01*
X12836071Y-11353214D01*
X12864643Y-11367500D01*
X12878928Y-11396071D01*
X12878928Y-11424643D01*
X12736071Y-11453214D01*
X13136071Y-11553214D02*
X13136071Y-11253214D01*
X13136071Y-11538929D02*
X13107500Y-11553214D01*
X13050357Y-11553214D01*
X13021786Y-11538929D01*
X13007500Y-11524643D01*
X12993214Y-11496071D01*
X12993214Y-11410357D01*
X13007500Y-11381786D01*
X13021786Y-11367500D01*
X13050357Y-11353214D01*
X13107500Y-11353214D01*
X13136071Y-11367500D01*
X13250357Y-11667500D02*
X13264643Y-11653214D01*
X13293214Y-11610357D01*
X13307500Y-11581786D01*
X13321786Y-11538929D01*
X13336071Y-11467500D01*
X13336071Y-11410357D01*
X13321786Y-11338929D01*
X13307500Y-11296071D01*
X13293214Y-11267500D01*
X13264643Y-11224643D01*
X13250357Y-11210357D01*
M02*

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,40 @@
"Source:","/home/eddy/Yandex.Disk/Projects/stm32samples/F0-nolib/Socket_fans/kicad/stm32.sch"
"Date:","ðÎ 02 ÎÏÑ 2020 23:57:22"
"Tool:","Eeschema 5.1.6"
"Generator:","/usr/share/kicad/plugins/bom_csv_grouped_by_value_with_fp.py"
"Component Count:","89"
"Ref","Qnty","Value","Cmp name","Footprint","Description","Vendor"
"C1, C2, C3, C4, C5, C6, C8, C13, C14, C15, C16, C17, C18, C19, C20, ","15","0.1","C","Capacitor_SMD:C_0603_1608Metric_Pad1.05x0.95mm_HandSolder","Unpolarized capacitor",""
"C7, ","1","47uF, 10V","CP","Capacitor_Tantalum_SMD:CP_EIA-6032-28_Kemet-C_Pad2.25x2.35mm_HandSolder","Polarized capacitor",""
"C9, ","1","10uF, 10V","C","Capacitor_SMD:C_1206_3216Metric_Pad1.42x1.75mm_HandSolder","Unpolarized capacitor",""
"C10, ","1","47u, 25V","CP","Capacitor_THT:CP_Radial_D8.0mm_P3.50mm","Polarized capacitor",""
"D1, D2, D4, D5, D6, D9, ","6","1N5819","D_Schottky","Diode_SMD:D_SOD-323_HandSoldering","Schottky diode",""
"D3, ","1","MM3Z7V5","D_Zener","Diode_SMD:D_0805_2012Metric_Pad1.15x1.40mm_HandSolder","Zener diode",""
"D7, ","1","MM3Z4V3","D_Zener","Diode_SMD:D_0805_2012Metric_Pad1.15x1.40mm_HandSolder","Zener diode",""
"D8, D10, ","2","MM3Z3V6","D_Zener","Diode_SMD:D_0805_2012Metric_Pad1.15x1.40mm_HandSolder","Zener diode",""
"J1, ","1","12VIN","Conn_01x02-Chiller_control-rescue","TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-1,5-2_1x02_P5.00mm_Horizontal","",""
"J2, ","1","thermal","Conn_02x04_Odd_Even","Connector_PinSocket_2.54mm:PinSocket_2x04_P2.54mm_Vertical","Generic connector, double row, 02x04, odd/even pin numbering scheme (row 1 odd numbers, row 2 even numbers), script generated (kicad-library-utils/schlib/autogen/connector/)",""
"J3, ","1","Buzzer","Conn_01x02_Male","Connector_JST:JST_EH_B2B-EH-A_1x02_P2.50mm_Vertical","Generic connector, single row, 01x02, script generated (kicad-library-utils/schlib/autogen/connector/)",""
"J4, ","1","cooler3","Conn_01x02_Male","Connector_JST:JST_EH_B2B-EH-A_1x02_P2.50mm_Vertical","Generic connector, single row, 01x02, script generated (kicad-library-utils/schlib/autogen/connector/)",""
"J5, J6, ","2","FAN","Conn_01x04_Male","Connector:FanPinHeader_1x04_P2.54mm_Vertical","Generic connector, single row, 01x04, script generated (kicad-library-utils/schlib/autogen/connector/)",""
"J7, J10, ","2","Conn_01x02_Female","Conn_01x02_Female","Connector_PinSocket_2.54mm:PinSocket_1x02_P2.54mm_Vertical","Generic connector, single row, 01x02, script generated (kicad-library-utils/schlib/autogen/connector/)",""
"J8, ","1","MKDS","Conn_01x02_Female","TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-1,5-2_1x02_P5.00mm_Horizontal","Generic connector, single row, 01x02, script generated (kicad-library-utils/schlib/autogen/connector/)",""
"K1, ","1","SRD-12VDC","G5LE-1-socket-rescue","Relay_THT:Relay_SPDT_SANYOU_SRD_Series_Form_C","",""
"L1, ","1","BMBA 0.1mH","L-Chiller_control-rescue","Inductor_SMD:L_0805_2012Metric_Pad1.15x1.40mm_HandSolder","",""
"P1, ","1","USB_A","USB_B","Connector_USB:USB_B_OST_USB-B1HSxx_Horizontal","USB Type B connector",""
"P2, P3, P4, P5, ","4","Hole","Conn_01x01","MountingHole:MountingHole_3.2mm_M3","Generic connector, single row, 01x01, script generated (kicad-library-utils/schlib/autogen/connector/)",""
"Q1, ","1","AO3401","Q_PMOS_GSD","Package_TO_SOT_SMD:SOT-23_Handsoldering","P-MOSFET transistor, gate/source/drain",""
"Q2, Q3, Q4, Q5, Q6, ","5","IRLML2502","Q_NMOS_GSD-socket-rescue","Package_TO_SOT_SMD:SOT-23_Handsoldering","",""
"R1, R2, R4, R6, R8, R13, R14, R16, R17, R34, ","10","10k","R-socket-rescue","Resistor_SMD:R_0603_1608Metric_Pad1.05x0.95mm_HandSolder","",""
"R3, R5, R7, R9, ","4","4k7, 1%","R-Chiller_control-rescue","Resistor_SMD:R_0805_2012Metric_Pad1.15x1.40mm_HandSolder","",""
"R10, R11, R12, R15, R18, R19, R20, R21, R24, R25, R32, ","11","510","R-socket-rescue","Resistor_SMD:R_0603_1608Metric_Pad1.05x0.95mm_HandSolder","",""
"R22, ","1","47k","R","Resistor_SMD:R_0603_1608Metric_Pad1.05x0.95mm_HandSolder","Resistor",""
"R23, R30, R31, ","3","22","R","Resistor_SMD:R_0603_1608Metric_Pad1.05x0.95mm_HandSolder","Resistor",""
"R26, ","1","3.3k","R","Resistor_SMD:R_0603_1608Metric_Pad1.05x0.95mm_HandSolder","Resistor",""
"R27, ","1","1k","R","Resistor_SMD:R_0603_1608Metric_Pad1.05x0.95mm_HandSolder","Resistor",""
"R28, R29, ","2","4.7k","R","Resistor_SMD:R_0603_1608Metric_Pad1.05x0.95mm_HandSolder","Resistor",""
"SW1, SW2, ","2","SW_Push","SW_Push","Connector_PinSocket_2.54mm:PinSocket_1x02_P2.54mm_Vertical","Push button switch, generic, two pins",""
"U1, ","1","LM1117-3.3","LM1117-3.3","Package_TO_SOT_SMD:SOT-223-3_TabPin2","800mA Low-Dropout Linear Regulator, 3.3V fixed output, TO-220/TO-252/TO-263/SOT-223",""
"U2, ","1","L7805","L7805","Package_TO_SOT_THT:TO-220-3_Vertical","Positive 1.5A 35V Linear Regulator, Fixed Output 5V, TO-220/TO-263/TO-252",""
"U3, ","1","STM32F072CBTx","STM32F072CBTx","Package_QFP:LQFP-48_7x7mm_P0.5mm","ARM Cortex-M0 MCU, 128KB flash, 16KB RAM, 48MHz, 2-3.6V, 37 GPIO, LQFP-48",""
"U4, ","1","USBLC6-2SC6","USBLC6-2SC6","Package_TO_SOT_SMD:SOT-23-6","Bidirectional ESD Protection Diode, SOT-23-6",""

View File

@@ -0,0 +1,307 @@
EESchema-LIBRARY Version 2.4
#encoding utf-8
#
# +12V-Chiller_control-rescue
#
DEF +12V-Chiller_control-rescue #PWR 0 0 Y Y 1 F P
F0 "#PWR" 0 -150 50 H I C CNN
F1 "+12V-Chiller_control-rescue" 0 140 50 H V C CNN
F2 "" 0 0 50 H I C CNN
F3 "" 0 0 50 H I C CNN
DRAW
P 2 0 1 0 -30 50 0 100 N
P 2 0 1 0 0 0 0 100 N
P 2 0 1 0 0 100 30 50 N
X +12V 1 0 0 0 U 50 50 1 1 W N
ENDDRAW
ENDDEF
#
# +3.3V-Chiller_control-rescue
#
DEF +3.3V-Chiller_control-rescue #PWR 0 0 Y Y 1 F P
F0 "#PWR" 0 -150 50 H I C CNN
F1 "+3.3V-Chiller_control-rescue" 0 140 50 H V C CNN
F2 "" 0 0 50 H I C CNN
F3 "" 0 0 50 H I C CNN
DRAW
P 2 0 1 0 -30 50 0 100 N
P 2 0 1 0 0 0 0 100 N
P 2 0 1 0 0 100 30 50 N
X +3V3 1 0 0 0 U 50 50 1 1 W N
ENDDRAW
ENDDEF
#
# C-Chiller_control-rescue
#
DEF C-Chiller_control-rescue C 0 10 N Y 1 F N
F0 "C" 25 100 50 H V L CNN
F1 "C-Chiller_control-rescue" 25 -100 50 H V L CNN
F2 "" 38 -150 50 H I C CNN
F3 "" 0 0 50 H I C CNN
$FPLIST
C_*
$ENDFPLIST
DRAW
P 2 0 1 20 -80 -30 80 -30 N
P 2 0 1 20 -80 30 80 30 N
X ~ 1 0 150 110 D 50 50 1 1 P
X ~ 2 0 -150 110 U 50 50 1 1 P
ENDDRAW
ENDDEF
#
# CP-Chiller_control-rescue
#
DEF CP-Chiller_control-rescue C 0 10 N Y 1 F N
F0 "C" 25 100 50 H V L CNN
F1 "CP-Chiller_control-rescue" 25 -100 50 H V L CNN
F2 "" 38 -150 50 H I C CNN
F3 "" 0 0 50 H I C CNN
$FPLIST
CP_*
$ENDFPLIST
DRAW
S -90 20 -90 40 0 1 0 N
S -90 20 90 20 0 1 0 N
S 90 -20 -90 -40 0 1 0 F
S 90 40 -90 40 0 1 0 N
S 90 40 90 20 0 1 0 N
P 2 0 1 0 -70 90 -30 90 N
P 2 0 1 0 -50 110 -50 70 N
X ~ 1 0 150 110 D 50 50 1 1 P
X ~ 2 0 -150 110 U 50 50 1 1 P
ENDDRAW
ENDDEF
#
# Conn_01x02-Chiller_control-rescue
#
DEF Conn_01x02-Chiller_control-rescue J 0 40 Y N 1 F N
F0 "J" 0 100 50 H V C CNN
F1 "Conn_01x02-Chiller_control-rescue" 0 -200 50 H V C CNN
F2 "" 0 0 50 H I C CNN
F3 "" 0 0 50 H I C CNN
$FPLIST
Connector*:*_??x*mm*
Connector*:*1x??x*mm*
Pin?Header?Straight?1X*
Pin?Header?Angled?1X*
Socket?Strip?Straight?1X*
Socket?Strip?Angled?1X*
$ENDFPLIST
DRAW
S -50 -95 0 -105 1 1 6 N
S -50 5 0 -5 1 1 6 N
S -50 50 50 -150 1 1 10 f
X Pin_1 1 -200 0 150 R 50 50 1 1 P
X Pin_2 2 -200 -100 150 R 50 50 1 1 P
ENDDRAW
ENDDEF
#
# D-Chiller_control-rescue
#
DEF D-Chiller_control-rescue D 0 40 N N 1 F N
F0 "D" 0 100 50 H V C CNN
F1 "D-Chiller_control-rescue" 0 -100 50 H V C CNN
F2 "" 0 0 50 H I C CNN
F3 "" 0 0 50 H I C CNN
$FPLIST
TO-???*
*SingleDiode
*_Diode_*
*SingleDiode*
D_*
$ENDFPLIST
DRAW
P 2 0 1 8 -50 50 -50 -50 N
P 2 0 1 0 50 0 -50 0 N
P 4 0 1 8 50 50 50 -50 -50 0 50 50 N
X K 1 -150 0 100 R 50 50 1 1 P
X A 2 150 0 100 L 50 50 1 1 P
ENDDRAW
ENDDEF
#
# G5LE-1-socket-rescue
#
DEF G5LE-1-socket-rescue K 0 40 Y Y 1 F N
F0 "K" 450 150 50 H V L CNN
F1 "G5LE-1-socket-rescue" 450 50 50 H V L CNN
F2 "Relay_THT:Relay_SPDT_OMRON-G5LE-1" 450 -50 50 H I L CNN
F3 "" 0 -400 50 H I C CNN
$FPLIST
Relay*SPDT*Omron*G5LE?1*
$ENDFPLIST
DRAW
S -400 200 400 -200 0 1 10 f
S -325 75 -75 -75 0 1 10 N
P 2 0 0 0 100 150 100 200 N
P 2 0 0 0 300 150 300 200 N
P 4 0 0 0 300 150 300 100 275 125 300 150 N
P 2 0 1 10 -300 -75 -100 75 N
P 2 0 1 0 -200 -200 -200 -75 N
P 2 0 1 0 -200 200 -200 75 N
P 2 0 1 10 -75 0 -50 0 N
P 2 0 1 10 -25 0 0 0 N
P 2 0 1 10 25 0 50 0 N
P 2 0 1 10 25 0 50 0 N
P 2 0 1 10 75 0 100 0 N
P 2 0 1 10 125 0 150 0 N
P 2 0 1 20 200 -100 125 150 N
P 2 0 1 0 200 -100 200 -200 N
P 3 0 1 0 100 100 125 125 100 150 F
X ~ 1 200 -300 100 U 50 50 1 1 P
X ~ 2 -200 -300 100 U 50 50 1 1 P
X ~ 3 300 300 100 D 50 50 1 1 P
X ~ 4 100 300 100 D 50 50 1 1 P
X ~ 5 -200 300 100 D 50 50 1 1 P
ENDDRAW
ENDDEF
#
# GND-Chiller_control-rescue
#
DEF GND-Chiller_control-rescue #PWR 0 0 Y Y 1 F P
F0 "#PWR" 0 -250 50 H I C CNN
F1 "GND-Chiller_control-rescue" 0 -150 50 H V C CNN
F2 "" 0 0 50 H I C CNN
F3 "" 0 0 50 H I C CNN
DRAW
P 6 0 1 0 0 0 0 -50 50 -50 0 -100 -50 -50 0 -50 N
X GND 1 0 0 0 D 50 50 1 1 W N
ENDDRAW
ENDDEF
#
# GND-socket-rescue
#
DEF GND-socket-rescue #PWR 0 0 Y Y 1 F P
F0 "#PWR" 0 -250 50 H I C CNN
F1 "GND-socket-rescue" 0 -150 50 H V C CNN
F2 "" 0 0 50 H I C CNN
F3 "" 0 0 50 H I C CNN
DRAW
P 6 0 1 0 0 0 0 -50 50 -50 0 -100 -50 -50 0 -50 N
X GND 1 0 0 0 D 50 50 1 1 W N
ENDDRAW
ENDDEF
#
# L-Chiller_control-rescue
#
DEF L-Chiller_control-rescue L 0 40 N N 1 F N
F0 "L" -50 0 50 V V C CNN
F1 "L-Chiller_control-rescue" 75 0 50 V V C CNN
F2 "" 0 0 50 H I C CNN
F3 "" 0 0 50 H I C CNN
$FPLIST
Choke_*
*Coil*
Inductor_*
L_*
$ENDFPLIST
DRAW
A 0 -75 25 -899 899 0 1 0 N 0 -100 0 -50
A 0 -25 25 -899 899 0 1 0 N 0 -50 0 0
A 0 25 25 -899 899 0 1 0 N 0 0 0 50
A 0 75 25 -899 899 0 1 0 N 0 50 0 100
X 1 1 0 150 50 D 50 50 1 1 P
X 2 2 0 -150 50 U 50 50 1 1 P
ENDDRAW
ENDDEF
#
# Q_NMOS_GSD-Chiller_control-rescue
#
DEF Q_NMOS_GSD-Chiller_control-rescue Q 0 0 Y N 1 F N
F0 "Q" 200 50 50 H V L CNN
F1 "Q_NMOS_GSD-Chiller_control-rescue" 200 -50 50 H V L CNN
F2 "" 200 100 50 H I C CNN
F3 "" 0 0 50 H I C CNN
DRAW
C 65 0 111 0 1 10 N
C 100 -70 11 0 1 0 F
C 100 70 11 0 1 0 F
P 2 0 1 0 2 0 10 0 N
P 2 0 1 0 30 -70 100 -70 N
P 2 0 1 10 30 -50 30 -90 N
P 2 0 1 0 30 0 100 0 N
P 2 0 1 10 30 20 30 -20 N
P 2 0 1 0 30 70 100 70 N
P 2 0 1 10 30 90 30 50 N
P 2 0 1 0 100 -70 100 -100 N
P 2 0 1 0 100 -70 100 0 N
P 2 0 1 0 100 100 100 70 N
P 3 0 1 10 10 75 10 -75 10 -75 N
P 4 0 1 0 40 0 80 15 80 -15 40 0 F
P 4 0 1 0 100 -70 130 -70 130 70 100 70 N
P 4 0 1 0 110 20 115 15 145 15 150 10 N
P 4 0 1 0 130 15 115 -10 145 -10 130 15 N
X G 1 -200 0 200 R 50 50 1 1 I
X S 2 100 -200 100 U 50 50 1 1 P
X D 3 100 200 100 D 50 50 1 1 P
ENDDRAW
ENDDEF
#
# Q_NMOS_GSD-socket-rescue
#
DEF Q_NMOS_GSD-socket-rescue Q 0 0 Y N 1 F N
F0 "Q" 200 50 50 H V L CNN
F1 "Q_NMOS_GSD-socket-rescue" 200 -50 50 H V L CNN
F2 "" 200 100 50 H I C CNN
F3 "" 0 0 50 H I C CNN
DRAW
C 65 0 111 0 1 10 N
C 100 -70 11 0 1 0 F
C 100 70 11 0 1 0 F
P 2 0 1 0 2 0 10 0 N
P 2 0 1 0 30 -70 100 -70 N
P 2 0 1 10 30 -50 30 -90 N
P 2 0 1 0 30 0 100 0 N
P 2 0 1 10 30 20 30 -20 N
P 2 0 1 0 30 70 100 70 N
P 2 0 1 10 30 90 30 50 N
P 2 0 1 0 100 -70 100 -100 N
P 2 0 1 0 100 -70 100 0 N
P 2 0 1 0 100 100 100 70 N
P 3 0 1 10 10 75 10 -75 10 -75 N
P 4 0 1 0 40 0 80 15 80 -15 40 0 F
P 4 0 1 0 100 -70 130 -70 130 70 100 70 N
P 4 0 1 0 110 20 115 15 145 15 150 10 N
P 4 0 1 0 130 15 115 -10 145 -10 130 15 N
X G 1 -200 0 200 R 50 50 1 1 I
X S 2 100 -200 100 U 50 50 1 1 P
X D 3 100 200 100 D 50 50 1 1 P
ENDDRAW
ENDDEF
#
# R-Chiller_control-rescue
#
DEF R-Chiller_control-rescue R 0 0 N Y 1 F N
F0 "R" 80 0 50 V V C CNN
F1 "R-Chiller_control-rescue" 0 0 50 V V C CNN
F2 "" -70 0 50 V I C CNN
F3 "" 0 0 50 H I C CNN
$FPLIST
R_*
R_*
$ENDFPLIST
DRAW
S -40 -100 40 100 0 1 10 N
X ~ 1 0 150 50 D 50 50 1 1 P
X ~ 2 0 -150 50 U 50 50 1 1 P
ENDDRAW
ENDDEF
#
# R-socket-rescue
#
DEF R-socket-rescue R 0 0 N Y 1 F N
F0 "R" 80 0 50 V V C CNN
F1 "R-socket-rescue" 0 0 50 V V C CNN
F2 "" -70 0 50 V I C CNN
F3 "" 0 0 50 H I C CNN
$FPLIST
R_*
R_*
$ENDFPLIST
DRAW
S -40 -100 40 100 0 1 10 N
X ~ 1 0 150 50 D 50 50 1 1 P
X ~ 2 0 -150 50 U 50 50 1 1 P
ENDDRAW
ENDDEF
#
#End Library

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,276 @@
update=Пн 03 фев 2020 17:18:45
version=1
last_client=kicad
[cvpcb]
version=1
NetIExt=net
[general]
version=1
[eeschema]
version=1
LibDir=
[schematic_editor]
version=1
PageLayoutDescrFile=
PlotDirectoryName=
SubpartIdSeparator=46
SubpartFirstId=49
NetFmtName=Pcbnew
SpiceAjustPassiveValues=0
LabSize=50
ERC_TestSimilarLabels=1
[pcbnew]
version=1
PageLayoutDescrFile=
LastNetListRead=stm32.net
CopperLayerCount=2
BoardThickness=2.5
AllowMicroVias=0
AllowBlindVias=0
RequireCourtyardDefinitions=0
ProhibitOverlappingCourtyards=1
MinTrackWidth=0.2
MinViaDiameter=0.7999999999999999
MinViaDrill=0.5
MinMicroViaDiameter=0.2
MinMicroViaDrill=0.09999999999999999
MinHoleToHole=0.25
TrackWidth1=0.2
TrackWidth2=0.2
TrackWidth3=0.3
TrackWidth4=0.5
TrackWidth5=1
TrackWidth6=2
ViaDiameter1=1
ViaDrill1=0.6
ViaDiameter2=1
ViaDrill2=0.6
ViaDiameter3=1.5
ViaDrill3=0.8
dPairWidth1=0.2
dPairGap1=0.25
dPairViaGap1=0.25
SilkLineWidth=0.15
SilkTextSizeV=1
SilkTextSizeH=1
SilkTextSizeThickness=0.15
SilkTextItalic=0
SilkTextUpright=1
CopperLineWidth=0.2
CopperTextSizeV=1.5
CopperTextSizeH=1.5
CopperTextThickness=0.3
CopperTextItalic=0
CopperTextUpright=1
EdgeCutLineWidth=0.15
CourtyardLineWidth=0.05
OthersLineWidth=0.15
OthersTextSizeV=1
OthersTextSizeH=1
OthersTextSizeThickness=0.15
OthersTextItalic=0
OthersTextUpright=1
SolderMaskClearance=0.2
SolderMaskMinWidth=0
SolderPasteClearance=0
SolderPasteRatio=-0
[pcbnew/Layer.F.Cu]
Name=F.Cu
Type=0
Enabled=1
[pcbnew/Layer.In1.Cu]
Name=In1.Cu
Type=0
Enabled=0
[pcbnew/Layer.In2.Cu]
Name=In2.Cu
Type=0
Enabled=0
[pcbnew/Layer.In3.Cu]
Name=In3.Cu
Type=0
Enabled=0
[pcbnew/Layer.In4.Cu]
Name=In4.Cu
Type=0
Enabled=0
[pcbnew/Layer.In5.Cu]
Name=In5.Cu
Type=0
Enabled=0
[pcbnew/Layer.In6.Cu]
Name=In6.Cu
Type=0
Enabled=0
[pcbnew/Layer.In7.Cu]
Name=In7.Cu
Type=0
Enabled=0
[pcbnew/Layer.In8.Cu]
Name=In8.Cu
Type=0
Enabled=0
[pcbnew/Layer.In9.Cu]
Name=In9.Cu
Type=0
Enabled=0
[pcbnew/Layer.In10.Cu]
Name=In10.Cu
Type=0
Enabled=0
[pcbnew/Layer.In11.Cu]
Name=In11.Cu
Type=0
Enabled=0
[pcbnew/Layer.In12.Cu]
Name=In12.Cu
Type=0
Enabled=0
[pcbnew/Layer.In13.Cu]
Name=In13.Cu
Type=0
Enabled=0
[pcbnew/Layer.In14.Cu]
Name=In14.Cu
Type=0
Enabled=0
[pcbnew/Layer.In15.Cu]
Name=In15.Cu
Type=0
Enabled=0
[pcbnew/Layer.In16.Cu]
Name=In16.Cu
Type=0
Enabled=0
[pcbnew/Layer.In17.Cu]
Name=In17.Cu
Type=0
Enabled=0
[pcbnew/Layer.In18.Cu]
Name=In18.Cu
Type=0
Enabled=0
[pcbnew/Layer.In19.Cu]
Name=In19.Cu
Type=0
Enabled=0
[pcbnew/Layer.In20.Cu]
Name=In20.Cu
Type=0
Enabled=0
[pcbnew/Layer.In21.Cu]
Name=In21.Cu
Type=0
Enabled=0
[pcbnew/Layer.In22.Cu]
Name=In22.Cu
Type=0
Enabled=0
[pcbnew/Layer.In23.Cu]
Name=In23.Cu
Type=0
Enabled=0
[pcbnew/Layer.In24.Cu]
Name=In24.Cu
Type=0
Enabled=0
[pcbnew/Layer.In25.Cu]
Name=In25.Cu
Type=0
Enabled=0
[pcbnew/Layer.In26.Cu]
Name=In26.Cu
Type=0
Enabled=0
[pcbnew/Layer.In27.Cu]
Name=In27.Cu
Type=0
Enabled=0
[pcbnew/Layer.In28.Cu]
Name=In28.Cu
Type=0
Enabled=0
[pcbnew/Layer.In29.Cu]
Name=In29.Cu
Type=0
Enabled=0
[pcbnew/Layer.In30.Cu]
Name=In30.Cu
Type=0
Enabled=0
[pcbnew/Layer.B.Cu]
Name=B.Cu
Type=0
Enabled=1
[pcbnew/Layer.B.Adhes]
Enabled=1
[pcbnew/Layer.F.Adhes]
Enabled=1
[pcbnew/Layer.B.Paste]
Enabled=1
[pcbnew/Layer.F.Paste]
Enabled=1
[pcbnew/Layer.B.SilkS]
Enabled=1
[pcbnew/Layer.F.SilkS]
Enabled=1
[pcbnew/Layer.B.Mask]
Enabled=1
[pcbnew/Layer.F.Mask]
Enabled=1
[pcbnew/Layer.Dwgs.User]
Enabled=1
[pcbnew/Layer.Cmts.User]
Enabled=1
[pcbnew/Layer.Eco1.User]
Enabled=1
[pcbnew/Layer.Eco2.User]
Enabled=1
[pcbnew/Layer.Edge.Cuts]
Enabled=1
[pcbnew/Layer.Margin]
Enabled=1
[pcbnew/Layer.B.CrtYd]
Enabled=1
[pcbnew/Layer.F.CrtYd]
Enabled=1
[pcbnew/Layer.B.Fab]
Enabled=1
[pcbnew/Layer.F.Fab]
Enabled=1
[pcbnew/Layer.Rescue]
Enabled=0
[pcbnew/Netclasses]
[pcbnew/Netclasses/Default]
Name=Default
Clearance=0.2
TrackWidth=0.2
ViaDiameter=1
ViaDrill=0.6
uViaDiameter=0.3
uViaDrill=0.1
dPairWidth=0.2
dPairGap=0.25
dPairViaGap=0.25
[pcbnew/Netclasses/1]
Name=0.5
Clearance=0.3
TrackWidth=0.5
ViaDiameter=1
ViaDrill=0.6
uViaDiameter=0.3
uViaDrill=0.1
dPairWidth=0.2
dPairGap=0.25
dPairViaGap=0.25
[pcbnew/Netclasses/2]
Name=1
Clearance=0.5
TrackWidth=1
ViaDiameter=1.5
ViaDrill=0.8
uViaDiameter=0.3
uViaDrill=0.1
dPairWidth=0.2
dPairGap=0.25
dPairViaGap=0.25

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,4 @@
(sym_lib_table
(lib (name elements)(type Legacy)(uri ${KIPRJMOD}/elements.lib)(options "")(descr ""))
(lib (name stm32-rescue)(type Legacy)(uri ${KIPRJMOD}/stm32-rescue.lib)(options "")(descr ""))
)

View File

@@ -0,0 +1,13 @@
function [X0 Y0 K] = buildk(X, Y, dYmax)
%
% [X0 Y0 K] = buildk(X, Y, dYmax) - build arrays of knots (X0, Y0) and linear koefficients K
% for piecewise-linear approximation of Y(X) with max deviation `dYmax`
%
X0 = []; Y0 = []; K = [];
knots = [1 getknots(X, Y, dYmax) max(size(X))];
for i = 1:max(size(knots))-1
idx = knots(i):knots(i+1);
[x y k] = linearapprox(X(idx), Y(idx));
X0 = [X0 x]; Y0 = [Y0 y]; K = [K k];
endfor
endfunction

View File

@@ -0,0 +1,29 @@
function T = calcT(ADU)
%
% T = calcT(ADU) - piecewise calculation prototype
%
X0 = [732.44 944.75 1197.23 2034.68 2308.60 2541.55 2738.63 2859.45 2969.21 3067.67 3153.52 3228.22 3292.84 3347.15];
Y0 = [10.000 16.000 22.700 43.750 50.800 57.100 62.800 66.550 70.200 73.750 77.150 80.450 83.700 86.900];
K = [0.028261 0.026536 0.025136 0.025738 0.027044 0.028922 0.031038 0.033255 0.036056 0.039606 0.044173 0.050296 0.058920 0.071729];
imax = max(size(X0)); idx = int32((imax+1)/2);
T = [];
% find index
while(idx > 0 && idx <= imax)
x = X0(idx);
half = int32(idx/2);
if(ADU < x)
%printf("%g < %g\n", ADU, x);
if(idx == 1) break; endif; % less than first index
if(ADU > X0(idx-1)) idx -= 1; break; endif; % found
idx = half; % another half
else
%printf("%g > %g\n", ADU, x);
if(idx == imax) break; endif; % more than last index
if(ADU < X0(idx+1)) break; endif; % found
idx += half;
endif
endwhile
if(idx < 1) printf("too low (<%g)!\n", X0(1)); idx = 1; endif
if(idx > imax) idx = imax; endif;
T = Y0(idx) + K(idx) * (ADU - X0(idx));
endfunction

View File

@@ -0,0 +1,13 @@
function idx = getknots(X, Y, dYmax)
%
% idx = getknots(X, Y, dYmax) - calculate piecewise-linear approximation knots for Y(X)
% dYmax - maximal deviation
%
idx = [];
I = getnewpt(X, Y, dYmax);
if(I > 0)
L = getknots(X(1:I), Y(1:I), dYmax);
R = I-1 + getknots(X(I:end), Y(I:end), dYmax);
idx = [L I R];
endif
endfunction

View File

@@ -0,0 +1,17 @@
function idx = getnewpt(X, Y, delt)
%
% idx = getnewpt(X, Y, delt)
% find point where Y-`linear approx` is maximal
% return index of max deviation or -1 if it is less than `delt`
%
% make approximation
[x0 y0 k] = linearapprox(X,Y);
% find new knot
adiff = abs(Y - (y0 + k*(X-x0)));
maxadiff = max(adiff);
if(maxadiff < delt)
idx = -1;
else
idx = find(adiff == max(adiff));
endif
endfunction

View File

@@ -0,0 +1,8 @@
function [x0 y0 k] = linearapprox(X,Y)
%
% [a b] = linearapprox(X,Y) - find linear approximation of function Y(X) through first and last points
% y = y0 + k*(X-x0)
%
x0 = X(1); y0 = Y(1);
k = (Y(end) - y0) / (X(end) - x0);
endfunction

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,8 @@
<html><head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<script type="text/javascript" src="a_data/a.js" async="false"></script>
</head>
<body>
</body></html>

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,5 @@
/* >>> file start: js/crossStorageServ.js */
var _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e};!function(){function e(e){var t="LJ.CrossStorage"===e.data.source;if(!t)return null;var n=e.data;if("object"===("undefined"==typeof n?"undefined":_typeof(n))&&n.fn&&("getItem"===n.fn&&o.parent.postMessage({crossStorageServResponse:localStorage.getItem(n.args[0]),requestID:n.requestID},"*"),"setItem"===n.fn)){var r=n.args[1],f="";"string"==typeof r?f=r:"object"===("undefined"==typeof r?"undefined":_typeof(r))&&(f=JSON.stringify(r)),localStorage.setItem(n.args[0],f)}}function t(){try{return window.self!==window.top}catch(e){return!0}}if(!t())return null;var o=window;"object"===("undefined"==typeof LJMocks?"undefined":_typeof(LJMocks))&&LJMocks.window&&(o=LJMocks.window),o.addEventListener("message",e)}();
/* <<< file end: js/crossStorageServ.js */
//# map link was there [crossStorageServ.js.map]

Binary file not shown.

After

Width:  |  Height:  |  Size: 655 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 632 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 612 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 664 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 820 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 613 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 628 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 640 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 607 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 355 B

View File

@@ -0,0 +1,101 @@
(function(){var f,h=h||{},k=this;function n(a){return void 0!==a}function p(){}function aa(a){a.B=function(){return a.vb?a.vb:a.vb=new a}}
function ba(a){var b=typeof a;if("object"==b)if(a){if(a instanceof Array)return"array";if(a instanceof Object)return b;var c=Object.prototype.toString.call(a);if("[object Window]"==c)return"object";if("[object Array]"==c||"number"==typeof a.length&&"undefined"!=typeof a.splice&&"undefined"!=typeof a.propertyIsEnumerable&&!a.propertyIsEnumerable("splice"))return"array";if("[object Function]"==c||"undefined"!=typeof a.call&&"undefined"!=typeof a.propertyIsEnumerable&&!a.propertyIsEnumerable("call"))return"function"}else return"null";
else if("function"==b&&"undefined"==typeof a.call)return"object";return b}function q(a){return"array"==ba(a)}function ca(a){var b=ba(a);return"array"==b||"object"==b&&"number"==typeof a.length}function t(a){return"string"==typeof a}function u(a){return"function"==ba(a)}var da="closure_uid_"+(1E9*Math.random()>>>0),ea=0;function fa(a,b,c){return a.call.apply(a.bind,arguments)}
function ga(a,b,c){if(!a)throw Error();if(2<arguments.length){var d=Array.prototype.slice.call(arguments,2);return function(){var c=Array.prototype.slice.call(arguments);Array.prototype.unshift.apply(c,d);return a.apply(b,c)}}return function(){return a.apply(b,arguments)}}function v(a,b,c){v=Function.prototype.bind&&-1!=Function.prototype.bind.toString().indexOf("native code")?fa:ga;return v.apply(null,arguments)}var w=Date.now||function(){return+new Date};
function x(a,b){function c(){}c.prototype=b.prototype;a.yc=b.prototype;a.prototype=new c;a.prototype.constructor=a;a.Lc=function(a,c,g){for(var l=Array(arguments.length-2),m=2;m<arguments.length;m++)l[m-2]=arguments[m];return b.prototype[c].apply(a,l)}};var ha={};function ia(){}ia.prototype.send=function(a,b,c){k.navigator.sendBeacon(a,b)?c.eb():c.error()};function ja(){this.b=this.a=void 0}ja.prototype.send=function(a,b){this.a=new Image;this.a.onload=v(this.f,this,b.eb);this.a.onerror=v(this.c,this,b.error);this.a.onabort=v(this.c,this,b.error);this.a.src=a;this.b=k.setTimeout(v(this.c,this,b.error),ka)};function la(a){a.b&&(k.clearTimeout(a.b),a.b=null)}function ma(a){a.a.src="";a.a.onload=function(){};a.a.onabort=function(){};a.a.onerror=function(){}}ja.prototype.f=function(a){la(this);a()};ja.prototype.c=function(a){ma(this);la(this);a()};y.a={};y.a.Nc=/iPad|iPhone|iPod/.test(k.navigator.userAgent)&&!k.Ic;y.a.i={};y.a.i.Bb=!1;y.a.i.Jb="Silverlight Plug-In";y.a.i.qa="application/x-silverlight";y.a.i.Ib=[y.a.i.qa,y.a.i.qa+"-2",y.a.i.qa+"-2-b2",y.a.i.qa+"-2-b1"];y.a.i.Db="AgControl.AgControl";y.a.i.oa=!1;y.a.i.va="";
y.a.i.tc=function(){var a=k.navigator;if(a.plugins&&a.plugins.length){var b=a.plugins[y.a.i.Jb];b&&(y.a.i.oa=!0,b.description&&(y.a.i.va=y.a.i.Xa(b.description)))}else if(a.mimeTypes&&a.mimeTypes.length)for(var c=y.a.i.Ib,b=0;b<c.length;b++){var d=a.mimeTypes[c[b]];if(d&&d.enabledPlugin){y.a.i.oa=!!d.enabledPlugin;y.a.i.oa&&(y.a.i.va=y.a.i.Xa(d.enabledPlugin.description));break}}else{a=[0,0,0,0];try{c=new ActiveXObject(y.a.i.Db);y.a.i.oa=!0;for(b=0;b<a.length;b++){for(var e=0,g=1048575,l=0;e<g;)d=
a[b]=e+(g-e>>1),c.IsVersionSupported(a.join("."))?(l=d,e=d+1):g=d;a[b]=l}y.a.i.va=y.a.i.Xa(a.join("."))}catch(m){}}};y.a.i.Xa=function(a){return"1.0.30226.2"===a?"2.0.30226.2":a};y.a.i.Bb||y.a.i.tc();y.a.i.Cc=y.a.i.oa;y.a.i.VERSION=y.a.i.va;y.u={};
y.u.zc=function(a){var b=typeof a;if("object"===b)if(a){if(a instanceof Array)return"array";if(a instanceof Object)return b;var c=Object.prototype.toString.call(a);if("[object Window]"===c)return"object";if("[object Array]"===c||"number"===typeof a.length&&"undefined"!==typeof a.splice&&"undefined"!==typeof a.propertyIsEnumerable&&!a.propertyIsEnumerable("splice"))return"array";if("[object Function]"===c||"undefined"!==typeof a.call&&"undefined"!==typeof a.propertyIsEnumerable&&!a.propertyIsEnumerable("call"))return"function"}else return"null";else if("function"===
b&&"undefined"===typeof a.call)return"object";return b};y.u.uc=function(a){var b=typeof a;return"object"==b&&null!=a||"function"==b};y.u.isArray=function(a){return"array"===y.u.zc(a)};y.W={};y.W.wc=function(){console.warn("\u0412\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043c\u0435\u0442\u043e\u0434 syncUserId.\n\u041e\u0431 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 \u044d\u0442\u043e\u0433\u043e \u043c\u0435\u0442\u043e\u0434\u0430 \u043f\u043e\u0447\u0438\u0442\u0430\u0439\u0442\u0435 \u0432 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 http://top100.rambler.ru/doc/guide-rambler-top100.pdf")};
y.W.log=function(){if(k.console){var a=new Date;console.log([a.getHours(),a.getMinutes(),a.getSeconds(),a.getMilliseconds()].join(":")+"\t",Array.prototype.slice.call(arguments).join(" "))}};y.G={};y.G.Vb=function(a){if("function"===typeof k.CustomEvent)return new k.CustomEvent(a);var b=document.createEvent("CustomEvent");b.initCustomEvent(a,!0,!0,!0);return b};y.G.oc=function(a){try{var b=y.G.Vb(a);b&&document.dispatchEvent(b)}catch(c){console.error("Event initKraken unsupported!")}};var na=!1;function z(){var a=void 0;na?a={$:!0,vc:!0}:a=!0;return a}try{var qa=Object.defineProperty&&Object.defineProperty({},"passive",{get:function(){na=!0}});k.addEventListener&&k.addEventListener("testPassiveEvents",null,qa)}catch(a){console.error(a)};y.H={};y.H.fb=function(a,b){function c(){e=k.setTimeout(d,1E3);a.apply(null,l)}function d(){e=null;g&&(g=!1,c())}b&&(a=v(a,b));var e=null,g=!1,l=[];return function(a){l=arguments;e?g=!0:c()}};y.g={};y.g.Ba=function(){return Math.round(2147483647*Math.random())};y.g.trunc=function(a,b){var c=b||1;return(a/c>>0)*c};y.g.wb=function(a){return"number"==typeof a&&!k.isNaN(a)&&k.isFinite(a)};y.g.Aa=function(a){return y.g.wb(a)&&0<a};function ra(a,b){this.b=a;this.a=b}ra.prototype.toString=function(){return this.b+"x"+this.a};function sa(a,b){this.c=a;this.f=b||ta;this.b=!1;this.a=void 0}var ta=1E3;sa.prototype.start=function(){this.b=!0;this.a||ua(this)};sa.prototype.g=function(){this.b&&(this.a&&va(this),this.c(),this.b&&ua(this))};function ua(a){a.a=k.setTimeout(v(a.g,a),a.f)}function va(a){a.a&&(k.clearTimeout(a.a),a.a=null)};y.Gc={};function wa(a,b){this.a=a;this.I=b};function A(){this.c=this.b=0;this.a=[]}A.prototype.enqueue=function(a){return this.a[this.c++]=a};A.prototype.na=function(){return this.D()?null:this.a[this.b++]};A.prototype.M=function(){return this.a[this.b]};A.prototype.D=function(){return this.b>=this.c};y.c={};y.c.ta="top100_id";y.c.$b=864E5;y.c.I="";y.c.Oa=function(a){for(var b=1,c=0,d=0;d<a.length;d++)c=a.charCodeAt(d),b=(b<<7&4294967295)+(c<<16)+c,c=b&4278190080,0!==c&&(b=b^c>>24);return b};y.c.Xb=function(){return"."+k.document.location.hostname.split(".").reverse().splice(0,2).reverse().join(".")};y.c.Wb=function(a){var b=k.navigator.userAgent+h.cookie+h.referrer+h.innerWidth+h.innerHeight+Math.random().toString(36).substr(2,9);return["t1",a,y.c.Oa(b),+new Date].join(".")};
y.c.pb=function(a,b){var c=b||y.c.Wb(a);B.set(y.c.ta,c,y.c.$b,"/",y.c.Xb());y.c.I=c};y.c.ub=function(){return!!y.c.I};y.c.xa=function(a){var b=B.get(y.c.ta);b||y.c.ub()?b&&!y.c.ub()&&y.c.pb(a,b):y.c.pb(a);return y.c.I};y.j={};y.j.Lb=0;y.j.Ma="kraken_uid_property_"+y.g.Ba();y.j.sc=function(a){return!!a[y.j.Ma]};y.j.qc=function(a){y.j.sc(a)||(a[y.j.Ma]=++y.j.Lb);return a[y.j.Ma]};y.l={};y.l.xc=function(a){for(var b=[],c={},d=0;d<a.length;){var e=a[d++],g;g=e;var l=void 0;g=l=y.u.uc(g)?"o"+y.j.qc(g):(typeof g).charAt(0)+g;c[g]||(c[g]=!0,b.push(e))}return b};y.l.map=function(a,b,c){if(Array.prototype.map)return Array.prototype.map.call(a,b,c);for(var d=[],e=a.length,g=0;g<e;++g)d[g]=b.call(c,a[g],g,a);return d};y.l.includes=function(a,b,c){var d=a.length;for(c=c||0;c<d;++c)if(a[c]===b)return!0;return!1};y.h={};y.h.ta="_ym_uid";y.h.I="";y.h.mc=function(a){y.h.I=a};y.h.Yb=function(){return y.h.I};y.h.rc=function(){var a=B.get(y.h.ta);a&&y.h.mc(a);return y.h.Yb()};function xa(a,b,c){this.f=c;this.c=a;this.g=b;this.b=0;this.a=null}xa.prototype.get=function(){var a;0<this.b?(this.b--,a=this.a,this.a=a.next,a.next=null):a=this.c();return a};function ya(a,b){a.g(b);a.b<a.f&&(a.b++,b.next=a.a,a.a=b)};function C(a){if(Error.captureStackTrace)Error.captureStackTrace(this,C);else{var b=Error().stack;b&&(this.stack=b)}a&&(this.message=String(a))}x(C,Error);C.prototype.name="CustomError";function za(a,b,c,d,e){this.reset(a,b,c,d,e)}za.prototype.a=null;var Aa=0;za.prototype.reset=function(a,b,c,d,e){"number"==typeof e||Aa++;d||w();this.b=b;delete this.a};function Ba(){0!=Ca&&(this[da]||(this[da]=++ea));this.H=this.H;this.Ia=this.Ia}var Ca=0;Ba.prototype.H=!1;function Da(a,b){this.type=a;this.a=this.target=b}Da.prototype.c=function(){};var Ea="closure_listenable_"+(1E6*Math.random()|0),Fa=0;function Ga(a,b,c,d,e){this.listener=a;this.a=null;this.src=b;this.type=c;this.$=!!d;this.za=e;++Fa;this.da=this.ua=!1}function Ha(a){a.da=!0;a.listener=null;a.a=null;a.src=null;a.za=null};var Ia;function Ja(a){var b=[];Ka(new La,a,b);return b.join("")}function La(){}
function Ka(a,b,c){if(null==b)c.push("null");else{if("object"==typeof b){if(q(b)){var d=b;b=d.length;c.push("[");for(var e="",g=0;g<b;g++)c.push(e),Ka(a,d[g],c),e=",";c.push("]");return}if(b instanceof String||b instanceof Number||b instanceof Boolean)b=b.valueOf();else{c.push("{");e="";for(d in b)Object.prototype.hasOwnProperty.call(b,d)&&(g=b[d],"function"!=typeof g&&(c.push(e),Ma(d,c),c.push(":"),Ka(a,g,c),e=","));c.push("}");return}}switch(typeof b){case "string":Ma(b,c);break;case "number":c.push(isFinite(b)&&
!isNaN(b)?String(b):"null");break;case "boolean":c.push(String(b));break;case "function":c.push("null");break;default:throw Error("Unknown type: "+typeof b);}}}var Na={'"':'\\"',"\\":"\\\\","/":"\\/","\b":"\\b","\f":"\\f","\n":"\\n","\r":"\\r","\t":"\\t","\x0B":"\\u000b"},Oa=/\uffff/.test("\uffff")?/[\\\"\x00-\x1f\x7f-\uffff]/g:/[\\\"\x00-\x1f\x7f-\xff]/g;
function Ma(a,b){b.push('"',a.replace(Oa,function(a){var b=Na[a];b||(b="\\u"+(a.charCodeAt(0)|65536).toString(16).substr(1),Na[a]=b);return b}),'"')};function Pa(a,b){for(var c in a)b.call(void 0,a[c],c,a)}function Qa(a){var b=[],c=0,d;for(d in a)b[c++]=a[d];return b}function Ra(a){var b=[],c=0,d;for(d in a)b[c++]=d;return b}function Sa(a){return null!==a&&"withCredentials"in a}var Ta="constructor hasOwnProperty isPrototypeOf propertyIsEnumerable toLocaleString toString valueOf".split(" ");
function Ua(a,b){for(var c,d,e=1;e<arguments.length;e++){d=arguments[e];for(c in d)a[c]=d[c];for(var g=0;g<Ta.length;g++)c=Ta[g],Object.prototype.hasOwnProperty.call(d,c)&&(a[c]=d[c])}};function Va(a,b){this.b=a;this.a=b}f=Va.prototype;f.clone=function(){return new Va(this.b,this.a)};f.toString=function(){return"("+this.b+" x "+this.a+")"};f.nc=function(){return this.b*this.a};f.D=function(){return!this.nc()};f.ceil=function(){this.b=Math.ceil(this.b);this.a=Math.ceil(this.a);return this};f.floor=function(){this.b=Math.floor(this.b);this.a=Math.floor(this.a);return this};f.round=function(){this.b=Math.round(this.b);this.a=Math.round(this.a);return this};function Wa(a){a.prototype.then=a.prototype.then;a.prototype.$goog_Thenable=!0}function Xa(a){if(!a)return!1;try{return!!a.$goog_Thenable}catch(b){return!1}};function Ya(a){this.a=a}var Za=/\s*;\s*/;f=Ya.prototype;f.set=function(a,b,c,d,e,g){if(/[;=\s]/.test(a))throw Error('Invalid cookie name "'+a+'"');if(/[;\r\n]/.test(b))throw Error('Invalid cookie value "'+b+'"');n(c)||(c=-1);e=e?";domain="+e:"";d=d?";path="+d:"";g=g?";secure":"";c=0>c?"":0==c?";expires="+(new Date(1970,1,1)).toUTCString():";expires="+(new Date(w()+1E3*c)).toUTCString();this.a.cookie=a+"="+b+e+d+c+g};
f.get=function(a,b){for(var c=a+"=",d=(this.a.cookie||"").split(Za),e=0,g;g=d[e];e++){if(0==g.lastIndexOf(c,0))return g.substr(c.length);if(g==a)return""}return b};f.remove=function(a,b,c){var d=n(this.get(a));this.set(a,"",0,b,c);return d};f.R=function(){return $a(this).keys};f.S=function(){return $a(this).values};f.D=function(){return!this.a.cookie};f.clear=function(){for(var a=$a(this).keys,b=a.length-1;0<=b;b--)this.remove(a[b])};
function $a(a){a=(a.a.cookie||"").split(Za);for(var b=[],c=[],d,e,g=0;e=a[g];g++)d=e.indexOf("="),-1==d?(b.push(""),c.push(e)):(b.push(e.substring(0,d)),c.push(e.substring(d+1)));return{keys:b,values:c}}var B=new Ya(document);B.b=3950;function ab(){}ab.prototype.a=null;function bb(a){var b;(b=a.a)||(b={},cb(a)&&(b[0]=!0,b[1]=!0),b=a.a=b);return b};function db(a){db[" "](a);return a}db[" "]=p;function eb(a,b){for(var c=a.split("%s"),d="",e=Array.prototype.slice.call(arguments,1);e.length&&1<c.length;)d+=c.shift()+e.shift();return d+c.join("%s")}var fb=String.prototype.trim?function(a){return a.trim()}:function(a){return a.replace(/^[\s\xa0]+|[\s\xa0]+$/g,"")};function gb(a,b){return a<b?-1:a>b?1:0};function D(a){this.b=[];this.f=[];this.a={};this.h=this.c=0;this.g=a||!1}f=D.prototype;f.D=function(){return 0===this.c&&0===this.h};f.clone=function(){for(var a=new D(this.g),b=this.f.concat(),c=this.b.concat(),d=0,e=b.length;d<e;++d)a.K(b[d],this.a[b[d]]);d=0;for(e=c.length;d<e;++d)a.set(c[d],this.a[c[d]]);return a};f.get=function(a,b){a=hb(this,a);return Object.prototype.hasOwnProperty.call(this.a,a)?this.a[a]:b};
f.set=function(a,b){a=hb(this,a);Object.prototype.hasOwnProperty.call(this.a,a)||(this.c++,this.b.push(a));this.a[a]=b};f.remove=function(a){a=hb(this,a);if(Object.prototype.hasOwnProperty.call(this.a,a)){delete this.a[a];for(var b=[],c=0,d=this.b.length;c<d;++c)this.b[c]!==a&&b.push(this.b[c]);this.b=b;this.c=b.length}};f.K=function(a,b){a=hb(this,a);Object.prototype.hasOwnProperty.call(this.a,a)||(this.h++,this.f.push(a));this.a[a]=b};
f.toString=function(){if(this.D())return"";for(var a=[],b=this.f.concat().concat(this.b.concat()),c=void 0,d=void 0,c="",e=0,g=b.length;e<g;++e)c=b[e],d=this.get(c),c=encodeURIComponent(String(c)),""!==d&&(c+="="+encodeURIComponent(String(d))),a.push(c);return a.join("&")};function hb(a,b){var c=String(b);a.g&&(c=c.toLowerCase());return c}var E=D.prototype;E.set=E.set;E.get=E.get;E.setMeta=E.K;E.remove=E.remove;E.isEmpty=E.D;E.toString=E.toString;y.ia={};y.ia.Va=function(){var a=new D;a.K("et","uid");return a};y.ga={};y.ga.zb=function(a){var b=new D,c;for(c in a)a.hasOwnProperty(c)&&b.set(c,a[c]);return b};y.ha={};y.ha.Va=function(a){var b=new D;a=y.ga.zb(a);b.K("et","cv");b.set("cv",a.toString());return b};function ib(a,b){b.unshift(a);C.call(this,eb.apply(null,b));b.shift()}x(ib,C);ib.prototype.name="AssertionError";function jb(a,b){throw new ib("Failure"+(a?": "+a:""),Array.prototype.slice.call(arguments,1));};var F=Array.prototype.indexOf?function(a,b,c){return Array.prototype.indexOf.call(a,b,c)}:function(a,b,c){c=null==c?0:0>c?Math.max(0,a.length+c):c;if(t(a))return t(b)&&1==b.length?a.indexOf(b,c):-1;for(;c<a.length;c++)if(c in a&&a[c]===b)return c;return-1},kb=Array.prototype.forEach?function(a,b,c){Array.prototype.forEach.call(a,b,c)}:function(a,b,c){for(var d=a.length,e=t(a)?a.split(""):a,g=0;g<d;g++)g in e&&b.call(c,e[g],g,a)},lb=Array.prototype.filter?function(a,b,c){return Array.prototype.filter.call(a,
b,c)}:function(a,b,c){for(var d=a.length,e=[],g=0,l=t(a)?a.split(""):a,m=0;m<d;m++)if(m in l){var r=l[m];b.call(c,r,m,a)&&(e[g++]=r)}return e},mb=Array.prototype.some?function(a,b,c){return Array.prototype.some.call(a,b,c)}:function(a,b,c){for(var d=a.length,e=t(a)?a.split(""):a,g=0;g<d;g++)if(g in e&&b.call(c,e[g],g,a))return!0;return!1};
function nb(a,b){var c;a:{c=a.length;for(var d=t(a)?a.split(""):a,e=0;e<c;e++)if(e in d&&b.call(void 0,d[e],e,a)){c=e;break a}c=-1}return 0>c?null:t(a)?a.charAt(c):a[c]}function ob(a,b){var c=F(a,b),d;(d=0<=c)&&Array.prototype.splice.call(a,c,1);return d}function pb(a){return Array.prototype.concat.apply(Array.prototype,arguments)}function qb(a){for(var b=[],c=0;c<a;c++)b[c]=0;return b};function rb(){this.a=[]}rb.prototype.remove=function(){var a=this.a,b=a.length,c=a[0];if(0!==b){if(1===b){if(!q(a))for(b=a.length-1;0<=b;b--)delete a[b];a.length=0}else{a[0]=a.pop();for(var a=0,b=this.a,d=b.length,e=void 0,g=void 0,e=void 0,l=b[a];a<d>>1;){e=2*a+1;g=2*a+2;e=g<d&&b[g].a<b[e].a?g:e;if(b[e].a>l.a)break;b[a]=b[e];a=e}b[a]=l}return c.I}};rb.prototype.M=function(){return 0===this.a.length?void 0:this.a[0].I};rb.prototype.D=function(){return 0==this.a.length};function sb(){this.a=new rb}sb.prototype.enqueue=function(a,b){var c=this.a;c.a.push(new wa(a,b));for(var d=c.a.length-1,c=c.a,e=c[d],g=void 0;0<d;)if(g=d-1>>1,c[g].a>e.a)c[d]=c[g],d=g;else break;c[d]=e};sb.prototype.na=function(){return this.a.remove()};sb.prototype.M=function(){return this.a.M()};sb.prototype.D=function(){return this.a.D()};function tb(){this.b=this.a=null}var vb=new xa(function(){return new ub},function(a){a.reset()},100);tb.prototype.remove=function(){var a=null;this.a&&(a=this.a,this.a=this.a.next,this.a||(this.b=null),a.next=null);return a};function ub(){this.next=this.b=this.a=null}ub.prototype.set=function(a,b){this.a=a;this.b=b;this.next=null};ub.prototype.reset=function(){this.next=this.b=this.a=null};function wb(a){this.src=a;this.A={};this.a=0}function xb(a,b,c,d,e){var g=b.toString();b=a.A[g];b||(b=a.A[g]=[],a.a++);var l=yb(b,c,d,e);-1<l?(a=b[l],a.ua=!1):(a=new Ga(c,a.src,g,!!d,e),a.ua=!1,b.push(a));return a}wb.prototype.remove=function(a,b,c,d){a=a.toString();if(!(a in this.A))return!1;var e=this.A[a];b=yb(e,b,c,d);return-1<b?(Ha(e[b]),Array.prototype.splice.call(e,b,1),0==e.length&&(delete this.A[a],this.a--),!0):!1};
function zb(a,b){var c=b.type;c in a.A&&ob(a.A[c],b)&&(Ha(b),0==a.A[c].length&&(delete a.A[c],a.a--))}function yb(a,b,c,d){for(var e=0;e<a.length;++e){var g=a[e];if(!g.da&&g.listener==b&&g.$==!!c&&g.za==d)return e}return-1};function Ab(a,b){this.a=n(a)?a:0;this.J=n(b)?b:0}f=Ab.prototype;f.clone=function(){return new Ab(this.a,this.J)};f.toString=function(){return"("+this.a+", "+this.J+")"};f.ceil=function(){this.a=Math.ceil(this.a);this.J=Math.ceil(this.J);return this};f.floor=function(){this.a=Math.floor(this.a);this.J=Math.floor(this.J);return this};f.round=function(){this.a=Math.round(this.a);this.J=Math.round(this.J);return this};var Bb;function Cb(){}x(Cb,ab);function Db(a){return(a=cb(a))?new ActiveXObject(a):new XMLHttpRequest}function cb(a){if(!a.b&&"undefined"==typeof XMLHttpRequest&&"undefined"!=typeof ActiveXObject){for(var b=["MSXML2.XMLHTTP.6.0","MSXML2.XMLHTTP.3.0","MSXML2.XMLHTTP","Microsoft.XMLHTTP"],c=0;c<b.length;c++){var d=b[c];try{return new ActiveXObject(d),a.b=d}catch(e){}}throw Error("Could not create ActiveXObject. ActiveX might be disabled, or MSXML might not be installed");}return a.b}Bb=new Cb;function Eb(a,b){this.b={};this.a=[];this.c=0;var c=arguments.length;if(1<c){if(c%2)throw Error("Uneven number of arguments");for(var d=0;d<c;d+=2)this.set(arguments[d],arguments[d+1])}else if(a){a instanceof Eb?(c=a.R(),d=a.S()):(c=Ra(a),d=Qa(a));for(var e=0;e<c.length;e++)this.set(c[e],d[e])}}f=Eb.prototype;f.S=function(){Fb(this);for(var a=[],b=0;b<this.a.length;b++)a.push(this.b[this.a[b]]);return a};f.R=function(){Fb(this);return this.a.concat()};f.D=function(){return 0==this.c};
f.clear=function(){this.b={};this.c=this.a.length=0};f.remove=function(a){return Object.prototype.hasOwnProperty.call(this.b,a)?(delete this.b[a],this.c--,this.a.length>2*this.c&&Fb(this),!0):!1};function Fb(a){if(a.c!=a.a.length){for(var b=0,c=0;b<a.a.length;){var d=a.a[b];Object.prototype.hasOwnProperty.call(a.b,d)&&(a.a[c++]=d);b++}a.a.length=c}if(a.c!=a.a.length){for(var e={},c=b=0;b<a.a.length;)d=a.a[b],Object.prototype.hasOwnProperty.call(e,d)||(a.a[c++]=d,e[d]=1),b++;a.a.length=c}}
f.get=function(a,b){return Object.prototype.hasOwnProperty.call(this.b,a)?this.b[a]:b};f.set=function(a,b){Object.prototype.hasOwnProperty.call(this.b,a)||(this.c++,this.a.push(a));this.b[a]=b};f.forEach=function(a,b){for(var c=this.R(),d=0;d<c.length;d++){var e=c[d],g=this.get(e);a.call(b,g,e,this)}};f.clone=function(){return new Eb(this)};function Gb(a){if(a.S&&"function"==typeof a.S)return a.S();if(t(a))return a.split("");if(ca(a)){for(var b=[],c=a.length,d=0;d<c;d++)b.push(a[d]);return b}return Qa(a)}
function Hb(a,b){if(a.forEach&&"function"==typeof a.forEach)a.forEach(b,void 0);else if(ca(a)||t(a))kb(a,b,void 0);else{var c;if(a.R&&"function"==typeof a.R)c=a.R();else if(a.S&&"function"==typeof a.S)c=void 0;else if(ca(a)||t(a)){c=[];for(var d=a.length,e=0;e<d;e++)c.push(e)}else c=Ra(a);for(var d=Gb(a),e=d.length,g=0;g<e;g++)b.call(void 0,d[g],c&&c[g],a)}};var Ib=/^(?:([^:/?#.]+):)?(?:\/\/(?:([^/?#]*)@)?([^/#?]*?)(?::([0-9]+))?(?=[/#?]|$))?([^?#]+)?(?:\?([^#]*))?(?:#(.*))?$/;var Jb=!1,G="";function Kb(a){a=a.match(/[\d]+/g);if(!a)return"";a.length=3;return a.join(".")}
(function(){if(navigator.plugins&&navigator.plugins.length){var a=navigator.plugins["Shockwave Flash"];if(a&&(Jb=!0,a.description)){G=Kb(a.description);return}if(navigator.plugins["Shockwave Flash 2.0"]){Jb=!0;G="2.0.0.11";return}}if(navigator.mimeTypes&&navigator.mimeTypes.length&&(a=navigator.mimeTypes["application/x-shockwave-flash"],Jb=!!a&&a.enabledPlugin)){G=Kb(a.enabledPlugin.description);return}try{var b=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7");Jb=!0;G=Kb(b.GetVariable("$version"));
return}catch(c){}try{b=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6");Jb=!0;G="6.0.21";return}catch(c){}try{b=new ActiveXObject("ShockwaveFlash.ShockwaveFlash"),Jb=!0,G=Kb(b.GetVariable("$version"))}catch(c){}})();var Lb=G;var Mb;a:{var Nb=k.navigator;if(Nb){var Ob=Nb.userAgent;if(Ob){Mb=Ob;break a}}Mb=""}function H(a){return-1!=Mb.indexOf(a)};function Pb(a){k.setTimeout(function(){throw a;},0)}var Qb;
function Rb(){var a=k.MessageChannel;"undefined"===typeof a&&"undefined"!==typeof window&&window.postMessage&&window.addEventListener&&!H("Presto")&&(a=function(){var a=document.createElement("IFRAME");a.style.display="none";a.src="";document.documentElement.appendChild(a);var b=a.contentWindow,a=b.document;a.open();a.write("");a.close();var c="callImmediate"+Math.random(),d="file:"==b.location.protocol?"*":b.location.protocol+"//"+b.location.host,a=v(function(a){if(("*"==d||a.origin==d)&&a.data==
c)this.port1.onmessage()},this);b.addEventListener("message",a,!1);this.port1={};this.port2={postMessage:function(){b.postMessage(c,d)}}});if("undefined"!==typeof a&&!H("Trident")&&!H("MSIE")){var b=new a,c={},d=c;b.port1.onmessage=function(){if(n(c.next)){c=c.next;var a=c.qb;c.qb=null;a()}};return function(a){d.next={qb:a};d=d.next;b.port2.postMessage(0)}}return"undefined"!==typeof document&&"onreadystatechange"in document.createElement("SCRIPT")?function(a){var b=document.createElement("SCRIPT");
b.onreadystatechange=function(){b.onreadystatechange=null;b.parentNode.removeChild(b);b=null;a();a=null};document.documentElement.appendChild(b)}:function(a){k.setTimeout(a,0)}};function Sb(a,b){Tb||Ub();Vb||(Tb(),Vb=!0);var c=Wb,d=vb.get();d.set(a,b);c.b?c.b.next=d:c.a=d;c.b=d}var Tb;function Ub(){if(k.Promise&&k.Promise.resolve){var a=k.Promise.resolve(void 0);Tb=function(){a.then(Xb)}}else Tb=function(){var a=Xb;!u(k.setImmediate)||k.Window&&k.Window.prototype&&!H("Edge")&&k.Window.prototype.setImmediate==k.setImmediate?(Qb||(Qb=Rb()),Qb(a)):k.setImmediate(a)}}var Vb=!1,Wb=new tb;
function Xb(){for(var a=null;a=Wb.remove();){try{a.a.call(a.b)}catch(b){Pb(b)}ya(vb,a)}Vb=!1};function J(a,b){this.a=Yb;this.j=void 0;this.c=this.b=this.f=null;this.g=this.h=!1;if(a!=p)try{var c=this;a.call(b,function(a){Zb(c,$b,a)},function(a){try{if(a instanceof Error)throw a;throw Error("Promise rejected.");}catch(b){}Zb(c,K,a)})}catch(d){Zb(this,K,d)}}var Yb=0,$b=2,K=3;function ac(){this.next=this.context=this.b=this.c=this.a=null;this.f=!1}ac.prototype.reset=function(){this.context=this.b=this.c=this.a=null;this.f=!1};var bc=new xa(function(){return new ac},function(a){a.reset()},100);
function cc(a,b,c){var d=bc.get();d.c=a;d.b=b;d.context=c;return d}J.prototype.then=function(a,b,c){return dc(this,u(a)?a:null,u(b)?b:null,c)};Wa(J);function ec(a,b){a.b||a.a!=$b&&a.a!=K||fc(a);a.c?a.c.next=b:a.b=b;a.c=b}function dc(a,b,c,d){var e=cc(null,null,null);e.a=new J(function(a,l){e.c=b?function(c){try{var e=b.call(d,c);a(e)}catch(I){l(I)}}:a;e.b=c?function(b){try{var e=c.call(d,b);a(e)}catch(I){l(I)}}:l});e.a.f=a;ec(a,e);return e.a}J.prototype.u=function(a){this.a=Yb;Zb(this,$b,a)};
J.prototype.v=function(a){this.a=Yb;Zb(this,K,a)};function Zb(a,b,c){if(a.a==Yb){a==c&&(b=K,c=new TypeError("Promise cannot resolve to itself"));a.a=1;var d;a:{var e=c,g=a.u,l=a.v;if(e instanceof J)ec(e,cc(g||p,l||null,a)),d=!0;else if(Xa(e))e.then(g,l,a),d=!0;else{var m=typeof e;if("object"==m&&null!=e||"function"==m)try{var r=e.then;if(u(r)){gc(e,r,g,l,a);d=!0;break a}}catch(I){l.call(a,I);d=!0;break a}d=!1}}d||(a.j=c,a.a=b,a.f=null,fc(a),b!=K||hc(a,c))}}
function gc(a,b,c,d,e){function g(a){m||(m=!0,d.call(e,a))}function l(a){m||(m=!0,c.call(e,a))}var m=!1;try{b.call(a,l,g)}catch(r){g(r)}}function fc(a){a.h||(a.h=!0,Sb(a.l,a))}function ic(a){var b=null;a.b&&(b=a.b,a.b=b.next,b.next=null);a.b||(a.c=null);return b}
J.prototype.l=function(){for(var a=null;a=ic(this);){var b=this.a,c=this.j;if(b==K&&a.b&&!a.f)for(var d=void 0,d=this;d&&d.g;d=d.f)d.g=!1;if(a.a)a.a.f=null,jc(a,b,c);else try{a.f?a.c.call(a.context):jc(a,b,c)}catch(e){kc.call(null,e)}ya(bc,a)}this.h=!1};function jc(a,b,c){b==$b?a.c.call(a.context,c):a.b&&a.b.call(a.context,c)}function hc(a,b){a.g=!0;Sb(function(){a.g&&kc.call(null,b)})}var kc=Pb;function lc(a){Ba.call(this);this.h=1;this.f=[];this.c=0;this.a=[];this.b={};this.j=Boolean(a)}x(lc,Ba);function mc(a,b,c,d){if(b=a.b[b]){var e=a.a;if(b=nb(b,function(a){return e[a+1]==c&&e[a+2]==d}))return a.g(b)}return!1}lc.prototype.g=function(a){var b=this.a[a];if(b){var c=this.b[b];0!=this.c?(this.f.push(a),this.a[a+1]=p):(c&&ob(c,a),delete this.a[a],delete this.a[a+1],delete this.a[a+2])}return!!b};
lc.prototype.l=function(a,b){var c=this.b[a];if(c){for(var d=Array(arguments.length-1),e=1,g=arguments.length;e<g;e++)d[e-1]=arguments[e];if(this.j)for(e=0;e<c.length;e++){var l=c[e];nc(this.a[l+1],this.a[l+2],d)}else{this.c++;try{for(e=0,g=c.length;e<g;e++)l=c[e],this.a[l+1].apply(this.a[l+2],d)}finally{if(this.c--,0<this.f.length&&0==this.c)for(;c=this.f.pop();)this.g(c)}}return 0!=e}return!1};function nc(a,b,c){Sb(function(){a.apply(b,c)})}
lc.prototype.clear=function(a){if(a){var b=this.b[a];b&&(kb(b,this.g,this),delete this.b[a])}else this.a.length=0,this.b={}};var oc=H("Opera")||H("OPR"),L=H("Trident")||H("MSIE"),pc=H("Edge"),qc=H("Gecko")&&!(-1!=Mb.toLowerCase().indexOf("webkit")&&!H("Edge"))&&!(H("Trident")||H("MSIE"))&&!H("Edge"),rc=-1!=Mb.toLowerCase().indexOf("webkit")&&!H("Edge"),sc=rc&&H("Mobile");function tc(){var a=k.document;return a?a.documentMode:void 0}var uc;
a:{var vc="",wc=function(){var a=Mb;if(qc)return/rv\:([^\);]+)(\)|;)/.exec(a);if(pc)return/Edge\/([\d\.]+)/.exec(a);if(L)return/\b(?:MSIE|rv)[: ]([^\);]+)(\)|;)/.exec(a);if(rc)return/WebKit\/(\S+)/.exec(a);if(oc)return/(?:Version)[ \/]?(\S+)/.exec(a)}();wc&&(vc=wc?wc[1]:"");if(L){var xc=tc();if(null!=xc&&xc>parseFloat(vc)){uc=String(xc);break a}}uc=vc}var yc={};
function M(a){var b;if(!(b=yc[a])){b=0;for(var c=fb(String(uc)).split("."),d=fb(String(a)).split("."),e=Math.max(c.length,d.length),g=0;0==b&&g<e;g++){var l=c[g]||"",m=d[g]||"",r=RegExp("(\\d*)(\\D*)","g"),I=RegExp("(\\d*)(\\D*)","g");do{var oa=r.exec(l)||["","",""],pa=I.exec(m)||["","",""];if(0==oa[0].length&&0==pa[0].length)break;b=gb(0==oa[1].length?0:parseInt(oa[1],10),0==pa[1].length?0:parseInt(pa[1],10))||gb(0==oa[2].length,0==pa[2].length)||gb(oa[2],pa[2])}while(0==b)}b=yc[a]=0<=b}return b}
var zc=k.document,Ac=zc&&L?tc()||("CSS1Compat"==zc.compatMode?parseInt(uc,10):5):void 0;y.b={};y.b.Cb=!1;y.b.jb=!1;y.b.Nb=y.b.Cb||y.b.jb;y.b.Ga=!1;y.b.Kb={Ab:"a"};
y.b.ready=function(a){function b(){c||(c=!0,y.b.Ga=!0,a())}var c=!1;y.b.Ga&&a();if(document.addEventListener)document.addEventListener("DOMContentLoaded",function(){b()},!1);else if(document.attachEvent){if(document.documentElement.doScroll&&window==window.top){var d=function(){if(!c&&document.body)try{document.documentElement.doScroll("left"),b()}catch(a){setTimeout(d,0)}};d()}document.attachEvent("onreadystatechange",function(){"complete"===document.readyState&&b()})}window.addEventListener?window.addEventListener("load",
b,!1):window.attachEvent&&window.attachEvent("onload",b)};y.b.ready(function(){y.b.Ga=!0});y.b.P=function(a){return t(a)?document.getElementById(a):a};y.b.getElementsByTagName=function(a){a=a.toUpperCase();return k.document.getElementsByTagName(a)};y.b.Ua=function(){var a=k.document.body,b=k.document.documentElement,a=lb([a.scrollHeight,b.scrollHeight,a.offsetHeight,b.offsetHeight,a.clientHeight,b.clientHeight],function(a){return a?!0:!1});return Math.max.apply(null,a)};
y.b.tb=function(a){a=a||k;var b=a.document;if(rc&&!sc){n(a.innerHeight)||(a=k);var b=a.innerHeight,c=a.document.documentElement.scrollHeight;a==a.top&&c<b&&(b-=15);return new ra(a.innerWidth,b)}a=y.b.Zb(b)?b.documentElement:b.body;return new ra(a.clientWidth,a.clientHeight)};y.b.Zb=function(a){return y.b.Nb?y.b.jb:"CSS1Compat"==a.compatMode};function Bc(){this.a=[];k.setTimeout(v(function(){Cc(this)},this),0)}aa(Bc);function Cc(a){for(var b=y.b.getElementsByTagName(y.b.Kb.Ab),c=[],d=0,e=b.length;d<e;++d)c.push(b[d]);b=y.l.map(c,function(a){return a.href});a.a=y.l.xc(b)};function Dc(a){this.f=a;this.b=this.c=this.a=null}function Ec(a,b){this.name=a;this.value=b}Ec.prototype.toString=function(){return this.name};var Fc=new Ec("SEVERE",1E3),Gc=new Ec("CONFIG",700),Hc=new Ec("FINE",500);function Jc(a){if(a.c)return a.c;if(a.a)return Jc(a.a);jb("Root logger has no level set.");return null}
Dc.prototype.log=function(a,b,c){if(a.value>=Jc(this).value)for(u(b)&&(b=b()),a=new za(a,String(b),this.f),c&&(a.a=c),c="log:"+a.b,k.console&&(k.console.timeStamp?k.console.timeStamp(c):k.console.markTimeline&&k.console.markTimeline(c)),k.msWriteProfilerMark&&k.msWriteProfilerMark(c),c=this;c;)c=c.a};var Kc={},Lc=null;
function Mc(a){Lc||(Lc=new Dc(""),Kc[""]=Lc,Lc.c=Gc);var b;if(!(b=Kc[a])){b=new Dc(a);var c=a.lastIndexOf("."),d=a.substr(c+1),c=Mc(a.substr(0,c));c.b||(c.b={});c.b[d]=b;b.a=c;Kc[a]=b}return b};var Nc=!L||9<=Number(Ac),Oc=L&&!M("9");!rc||M("528");qc&&M("1.9b")||L&&M("8")||oc&&M("9.5")||rc&&M("528");qc&&!M("8")||L&&M("9");function Pc(a,b){Da.call(this,a?a.type:"");this.a=this.target=null;this.keyCode=this.button=this.screenY=this.screenX=0;this.metaKey=this.shiftKey=this.ctrlKey=!1;this.b=this.state=null;if(a){this.type=a.type;var c=a.changedTouches?a.changedTouches[0]:null;this.target=a.target||a.srcElement;this.a=b;var d=a.relatedTarget;if(d&&qc)try{db(d.nodeName)}catch(e){}null===c?(this.screenX=a.screenX||0,this.screenY=a.screenY||0):(this.screenX=c.screenX||0,this.screenY=c.screenY||0);this.button=a.button;this.keyCode=
a.keyCode||0;this.ctrlKey=a.ctrlKey;this.shiftKey=a.shiftKey;this.metaKey=a.metaKey;this.state=a.state;this.b=a;a.defaultPrevented&&this.c()}}x(Pc,Da);Pc.prototype.c=function(){Pc.yc.c.call(this);var a=this.b;if(a.preventDefault)a.preventDefault();else if(a.returnValue=!1,Oc)try{if(a.ctrlKey||112<=a.keyCode&&123>=a.keyCode)a.keyCode=-1}catch(b){}};Pc.prototype.O=function(){return this.b};var Qc="closure_lm_"+(1E6*Math.random()|0),Rc={},Sc=0;
function N(a,b,c,d,e){if(q(b))for(var g=0;g<b.length;g++)N(a,b[g],c,d,e);else if(c=Tc(c),a&&a[Ea])Uc(a,b,c,d,e);else{if(!b)throw Error("Invalid event type");var g=!!d,l=Vc(a);l||(a[Qc]=l=new wb(a));c=xb(l,b,c,d,e);if(!c.a){d=Wc();c.a=d;d.src=a;d.listener=c;if(a.addEventListener)a.addEventListener(b.toString(),d,g);else if(a.attachEvent)a.attachEvent(Xc(b.toString()),d);else throw Error("addEventListener and attachEvent are unavailable.");Sc++}}}
function Wc(){var a=Yc,b=Nc?function(c){return a.call(b.src,b.listener,c)}:function(c){c=a.call(b.src,b.listener,c);if(!c)return c};return b}function Zc(a,b,c,d,e){if(q(b))for(var g=0;g<b.length;g++)Zc(a,b[g],c,d,e);else(c=Tc(c),a&&a[Ea])?a.pa.remove(String(b),c,d,e):a&&(a=Vc(a))&&(b=a.A[b.toString()],a=-1,b&&(a=yb(b,c,!!d,e)),(c=-1<a?b[a]:null)&&$c(c))}
function $c(a){if("number"!=typeof a&&a&&!a.da){var b=a.src;if(b&&b[Ea])zb(b.pa,a);else{var c=a.type,d=a.a;b.removeEventListener?b.removeEventListener(c,d,a.$):b.detachEvent&&b.detachEvent(Xc(c),d);Sc--;(c=Vc(b))?(zb(c,a),0==c.a&&(c.src=null,b[Qc]=null)):Ha(a)}}}function Xc(a){return a in Rc?Rc[a]:Rc[a]="on"+a}function ad(a,b,c,d){var e=!0;if(a=Vc(a))if(b=a.A[b.toString()])for(b=b.concat(),a=0;a<b.length;a++){var g=b[a];g&&g.$==c&&!g.da&&(g=bd(g,d),e=e&&!1!==g)}return e}
function bd(a,b){var c=a.listener,d=a.za||a.src;a.ua&&$c(a);return c.call(d,b)}
function Yc(a,b){if(a.da)return!0;if(!Nc){var c;if(!(c=b))a:{c=["window","event"];for(var d=k,e;e=c.shift();)if(null!=d[e])d=d[e];else{c=null;break a}c=d}e=c;c=new Pc(e,this);d=!0;if(!(0>e.keyCode||void 0!=e.returnValue)){a:{var g=!1;if(0==e.keyCode)try{e.keyCode=-1;break a}catch(r){g=!0}if(g||void 0==e.returnValue)e.returnValue=!0}e=[];for(g=c.a;g;g=g.parentNode)e.push(g);for(var g=a.type,l=e.length-1;0<=l;l--){c.a=e[l];var m=ad(e[l],g,!0,c),d=d&&m}for(l=0;l<e.length;l++)c.a=e[l],m=ad(e[l],g,!1,
c),d=d&&m}return d}return bd(a,new Pc(b,this))}function Vc(a){a=a[Qc];return a instanceof wb?a:null}var cd="__closure_events_fn_"+(1E9*Math.random()>>>0);function Tc(a){if(u(a))return a;a[cd]||(a[cd]=function(b){return a.handleEvent(b)});return a[cd]};y.f={};y.f.Bc={Jc:"scroll"};y.f.s=0;y.f.Za=!1;y.f.sa=[];y.f.La=300;y.f.la=48;y.f.Kc=function(a){if(!k.addEventListener)return!1;0===y.f.sa.length&&y.f.Na();y.f.sa.push(a);return!0};
y.f.Na=function(){var a=void 0,b={},c={$:!0,vc:!0};k.document.addEventListener("touchstart",function(c){1===c.touches.length&&(a=w(),b=c.changedTouches.item(0))},y.f.Za?c:!0);k.document.addEventListener("touchend",function(c){if(1!==c.changedTouches.length)b={};else{var e=w(),g=c.changedTouches.item(0);if(g.identifier!==b.identifier)b={};else if(e-a>=y.f.La)b={};else{var e=b.radiusX||y.f.la,l=b.radiusY||y.f.la;if(Math.abs(g.pageX-b.pageX)>e||Math.abs(g.pageY-b.pageY)>l||Math.abs(g.screenX-b.screenX)>
e||Math.abs(g.screenY-b.screenY)>l)b={};else{g=0;for(e=y.f.sa.length;g<e;++g)y.f.sa[g](c,y.f.s++);b={}}}}},y.f.Za?c:!0)};try{qa=Object.defineProperty&&Object.defineProperty({},"passive",{get:function(){y.f.Za=!0}}),k.addEventListener&&k.addEventListener("testPassiveEvents",null,qa)}catch(a){console.error(a)};var O={m:{}};O.m.keydown=void 0;O.addListener=function(a,b){switch(a){case "keydown":O.Pb();break;default:return}O.m[a]=b};O.Pb=function(){N(k.document,"keydown",O.gc,z())};O.gc=function(a){O.m.keydown(a)};var P={m:{}};P.m.click=void 0;P.m.mousedown=void 0;P.m.tap=void 0;P.m.touchstart=void 0;P.m.touchend=void 0;P.X={};P.X.mousedown=new A;P.X.click=new A;P.X.tap=new A;P.La=300;P.la=48;P.addListener=function(a,b){switch(a){case "click":P.Ob();break;case "tap":P.Na();break;case "mousedown":P.Qb();break;case "touchstart":P.Tb();break;default:return}P.m[a]=b};P.Ob=function(){N(k.document,"click",P.bc,z())};P.Qb=function(){N(k.document,"mousedown",P.hc,z())};
P.Tb=function(){N(k.document,"touchstart",P.kc,z())};
P.Na=function(){if(!k.addEventListener)return!1;var a=void 0,b={};k.document.addEventListener("touchstart",function(c){1===c.touches.length&&(a=w(),b=c.changedTouches.item(0))},z());k.document.addEventListener("touchend",function(c){if(1!==c.changedTouches.length)b={};else{var d=w(),e=c.changedTouches.item(0);if(e.identifier!==b.identifier)b={};else if(d-a>=P.La)b={};else{var d=b.radiusX||P.la,g=b.radiusY||P.la;Math.abs(e.pageX-b.pageX)>d||Math.abs(e.pageY-b.pageY)>g||Math.abs(e.screenX-b.screenX)>
d||Math.abs(e.screenY-b.screenY)>g?b={}:(c.getBrowserEvent=c.O,P.Qa(c),b={})}}},z());return null};P.bc=function(a){a.getBrowserEvent=a.O;P.m.click(a)};P.hc=function(a){if(!P.ob("tap",a)){var b=P.X.mousedown;b.enqueue({target:a.target,yb:k.setTimeout(function(){b.na()},1E3)});a.getBrowserEvent=a.O;P.m.mousedown(a)}};P.kc=function(a){a.getBrowserEvent=a.O;P.m.touchstart(a)};
P.Qa=function(a){if(!P.ob("mousedown",a)){var b=P.X.tap;b.enqueue({target:a.target,yb:k.setTimeout(function(){b.na()},1E3)});a.Oc=!0;a.getBrowserEvent=a.O;P.m.tap(a)}};P.ob=function(a,b){var c=P.X[a];if(c.D()||c.M().target!==b.target)return!1;k.clearTimeout(c.M().yb);c.na();return!0};var Q={m:{}};Q.m.scroll=void 0;Q.addListener=function(a,b){switch(a){case "scroll":Q.Sb();break;default:return}Q.m[a]=b};Q.Sb=function(){N(k.document,"scroll",Q.jc,z())};Q.jc=function(a){Q.m.scroll(a)};var R={m:{}};R.m.beforeunload=void 0;R.m.resize=void 0;R.addListener=function(a,b){switch(a){case "beforeunload":R.Ub();break;case "resize":R.Rb();break;default:return}R.m[a]=b};R.Ub=function(){N(k,"beforeunload",R.Ra,z())};R.Rb=function(){N(k,"resize",R.Pa,z())};R.Ra=function(a){R.m.beforeunload(a)};R.Pa=function(a){R.m.resize(a)};function S(){this.c=new lc;this.f={}}aa(S);S.prototype.a=function(a,b,c){var d=this.c,e=d.b[a];e||(e=d.b[a]=[]);var g=d.h;d.a[g]=a;d.a[g+1]=b;d.a[g+2]=c;d.h=g+3;e.push(g);return g};S.prototype.g=function(a,b,c){return mc(this.c,a,b,c)};S.prototype.b=function(a,b){return this.c.l.apply(this.c,arguments)};S.prototype.addListener=function(a,b,c){a=y.u.isArray(a)?a:[a];for(var d=0,e=a.length;d<e;++d)dd(this,a[d]).A.push({Z:b,context:c})};
function dd(a,b){var c=a.f[b];c||(c=a.f[b]={A:[],Ya:void 0});c.Ya||(c.Ya=ed(b),c.Ya.addListener(b,fd(a,b)));return c}function ed(a){switch(a){case "click":case "mousedown":case "tap":case "touchstart":return P;case "beforeunload":case "resize":return R;case "keydown":return O;case "scroll":return Q;default:return null}}
function fd(a,b){return v(function(){for(var a=dd(this,b).A,d=Array(arguments.length),e=0,g=arguments.length;e<g;e++)d[e]=arguments[e];e=0;for(g=a.length;e<g;++e)a[e].Z.apply(a[e].context,d)},a)}var T=S.prototype;T.subscribe=T.a;T.unsubscribe=T.g;T.publish=T.b;T.addListener=T.addListener;function gd(){this.c=S.B();this.a=0;w();this.b=!0;k.setTimeout(v(this.f,this),hd(this));var a=y.H.fb(this.g,this);this.c.addListener(id,a,this)}var jd=[0,10,30,60,120,180,240,300,360,420,480,540,600,720,840,960,1080,1200],id=["click","mousedown","keydown","scroll"];gd.prototype.g=function(){this.b=!0};function hd(a){return++a.a>=jd.length?12E4:1E3*(jd[a.a]-jd[a.a-1])}gd.prototype.f=function(){this.b&&(this.c.b("ping"),this.b=!1);k.setTimeout(v(this.f,this),hd(this))};function kd(){this.c=this.a=void 0;this.b=this.f="";this.g=void 0;var a;a:if("visibilityState"in document)this.f="visibilitychange",this.b="hidden",a=!0;else{a=void 0;for(var b=0;b<ld;++b)if(a=ld[b],a+"VisibilityState"in document){this.f=a+"visibilitychange";this.b=a+"Hidden";a=!0;break a}a=!1}if(this.c=a)this.g=S.B(),this.a=!k.document[this.b],N(k.document,this.f,this.h,!1,this)}var ld=["webkit","moz","ms","o"];kd.prototype.h=function(){this.a=!k.document[this.b];this.g.b("visibility")};function md(){Ba.call(this);this.pa=new wb(this);this.ra=this}x(md,Ba);md.prototype[Ea]=!0;md.prototype.removeEventListener=function(a,b,c,d){Zc(this,a,b,c,d)};function U(a,b){var c=a.ra,d=b,e=d.type||d;if(t(d))d=new Da(d,c);else if(d instanceof Da)d.target=d.target||c;else{var g=d,d=new Da(e,c);Ua(d,g)}c=d.a=c;nd(c,e,!0,d);nd(c,e,!1,d)}function Uc(a,b,c,d,e){xb(a.pa,String(b),c,d,e)}
function nd(a,b,c,d){if(b=a.pa.A[String(b)]){b=b.concat();for(var e=!0,g=0;g<b.length;++g){var l=b[g];if(l&&!l.da&&l.$==c){var m=l.listener,r=l.za||l.src;l.ua&&zb(a.pa,l);e=!1!==m.call(r,d)&&e}}}};function od(){this.b=S.B();this.a=void 0;this.c=Bc.B();pd(this)}var qd=/^javascript\:/i,rd=/^_(self|parent|top)$/i;function pd(a){a.b.addListener("mousedown",function(a){var c=a.O().button;0!==c&&1!==c||sd(this,a)},a);a.b.addListener("keydown",function(a){13===a.O().keyCode&&sd(this,a)},a)}
function sd(a,b){var c;for(c=b.target;c&&(!n(c.tagName)||"a"!==c.tagName.toLowerCase()||!c.href);)c=c.parentNode;var d=new D;if(c&&c.href){a.a=c.href;var e=a.a;-1!==e.indexOf(k.location.host)||e.match(qd)||(c.target&&c.target.match(rd),d.K("et","extln"),d.set("extln",a.a),y.l.includes(a.c.a,a.a)&&d.set("um_log","cl"),a.b.b("extLink",d))}};!qc&&!L||L&&9<=Number(Ac)||qc&&M("1.9.1");L&&M("9");function td(a,b){Pa(b,function(b,d){"style"==d?a.style.cssText=b:"class"==d?a.className=b:"for"==d?a.htmlFor=b:ud.hasOwnProperty(d)?a.setAttribute(ud[d],b):0==d.lastIndexOf("aria-",0)||0==d.lastIndexOf("data-",0)?a.setAttribute(d,b):a[d]=b})}var ud={cellpadding:"cellPadding",cellspacing:"cellSpacing",colspan:"colSpan",frameborder:"frameBorder",height:"height",maxlength:"maxLength",nonce:"nonce",role:"role",rowspan:"rowSpan",type:"type",usemap:"useMap",valign:"vAlign",width:"width"};
function vd(a){a=a.document;a="CSS1Compat"==a.compatMode?a.documentElement:a.body;return new Va(a.clientWidth,a.clientHeight)}function wd(a){return a.parentWindow||a.defaultView}function xd(a){this.a=a||k.document||document}xd.prototype.P=function(a){return t(a)?this.a.getElementById(a):a};xd.prototype.tb=function(a){return vd(a||wd(this.a)||window)};
xd.prototype.Ua=function(){var a;a:{var b=wd(this.a),c=b.document;a=0;if(c){a=c.body;var d=c.documentElement;if(!d||!a){a=0;break a}b=vd(b).a;if("CSS1Compat"==c.compatMode&&d.scrollHeight)a=d.scrollHeight!=b?d.scrollHeight:d.offsetHeight;else{var c=d.scrollHeight,e=d.offsetHeight;d.clientHeight!=e&&(c=a.scrollHeight,e=a.offsetHeight);a=c>b?c>e?c:e:c<e?c:e}}}return a};
xd.prototype.contains=function(a,b){if(!a||!b)return!1;if(a.contains&&1==b.nodeType)return a==b||a.contains(b);if("undefined"!=typeof a.compareDocumentPosition)return a==b||Boolean(a.compareDocumentPosition(b)&16);for(;b&&a!=b;)b=b.parentNode;return b==a};function yd(){this.b=new D;this.a=void 0;var a=this.b;a.K("et","pv");a.set("bs",y.b.tb());a.set("ce",navigator.cookieEnabled?1:0);var b=k.document;b&&(a.set("rf",b.referrer||""),a.set("en",b.characterSet||b.charset||""),a.set("pt",b.title.substring(0,255)));if(b=k.screen)a.set("sr",b.width+"x"+b.height),a.set("cd",b.colorDepth+"-bit");if(b=k.navigator)a.set("la",b.language||b.browserLanguage||""),a.set("ja",b.javaEnabled()?1:0),a.set("acn",b.appCodeName),a.set("an",b.appName),a.set("pl",b.platform);
a.set("tz",(new Date).getTimezoneOffset());a.set("fv",zd());a.set("sv",y.a.i.VERSION);a.set("lv",Ad(this))}function Bd(a,b,c,d){var e=a.b.clone(),g=b.hb&&a.Oa();d=d||b.cb||k.location.href.split("#")[0];e.set("pt",document.title.substring(0,255));var l;if(l=b.C){var m;a:{l=b.C;for(m in l){m=!1;break a}m=!0}l=!m}l&&(m=y.ga.zb(b.C),e.set("cv",m.toString()));q(b.ma)&&b.ma.length&&(a=a.c(b.ma),e.set("ch",Ja(a)));g&&e.set("hash",g);(c||0==c)&&e.set("le",c);d&&e.set("url",d);return e}
function Ad(a){if(!a.a){a.a=B.get("last_visit");for(var b=["/",k.document.pathname],c=0,d=b.length;c<d;++c)B.remove("last_visit",b[c]);b=new Date;b=b.getTime()+6E4*b.getTimezoneOffset()+"::"+b.getTime();c="."+k.document.location.hostname.split("www.").pop();B.set("last_visit",b,864E5,"/",c)}return a.a||""}yd.prototype.c=function(a){for(var b=[],c=0,d=a.length;c<d;++c)b.push(a[c].substring(0,255));return b};
function zd(){var a=Lb.match(/[\d]+/g);if(!a||!a.length)return"";a.length=3;return a[0]+"."+a[1]+" r"+a[2]}yd.prototype.c=function(a){for(var b=[],c=0,d=a.length;c<d;++c)b.push(a[c].substring(0,255));return b};yd.prototype.Oa=function(){var a=k.location.hash.split("#")[1];return y.b.P(a)?null:a};function Cd(){this.a=this.c=this.b=void 0;this.g=!1;k.setTimeout(v(this.f,this),0)}Cd.prototype.f=function(){this.a=y.b.Ua();this.b=vd(window).a;this.c=this.a/10;var a=y.g.Aa(this.a),b=y.g.Aa(this.b);a&&b?(this.g=!0,S.B().addListener("resize",y.H.fb(this.Pa,this),this)):k.setTimeout(v(this.f,this),1E3)};Cd.prototype.Pa=function(){this.b=vd(window).a};function V(a,b){a&&a.log(Hc,b,void 0)};function Dd(a,b,c){if(u(a))c&&(a=v(a,c));else if(a&&"function"==typeof a.handleEvent)a=v(a.handleEvent,a);else throw Error("Invalid listener argument");return 2147483647<Number(b)?-1:k.setTimeout(a,b||0)};function Ed(a){md.call(this);this.Ha=new Eb;this.G=a||null;this.b=!1;this.v=this.a=null;this.g=this.ga=this.j="";this.f=this.W=this.h=this.V=!1;this.c=0;this.l=null;this.ia=Fd;this.u=this.ja=!1}x(Ed,md);var Fd="",Gd=Ed.prototype,Hd=Mc("goog.net.XhrIo");Gd.F=Hd;var Id=/^https?$/i,Jd=["POST","PUT"];
Ed.prototype.send=function(a,b,c,d){if(this.a)throw Error("[goog.net.XhrIo] Object is active with another request="+this.j+"; newUri="+a);b=b?b.toUpperCase():"GET";this.j=a;this.g="";this.ga=b;this.V=!1;this.b=!0;this.a=this.G?Db(this.G):Db(Bb);this.v=this.G?bb(this.G):bb(Bb);this.a.onreadystatechange=v(this.ha,this);try{V(this.F,W(this,"Opening Xhr")),this.W=!0,this.a.open(b,String(a),!0),this.W=!1}catch(g){V(this.F,W(this,"Error opening Xhr: "+g.message));Kd(this,g);return}a=c||"";var e=this.Ha.clone();
d&&Hb(d,function(a,b){e.set(b,a)});d=nb(e.R(),Ld);c=k.FormData&&a instanceof k.FormData;!(0<=F(Jd,b))||d||c||e.set("Content-Type","application/x-www-form-urlencoded;charset=utf-8");e.forEach(function(a,b){this.a.setRequestHeader(b,a)},this);this.ia&&(this.a.responseType=this.ia);Sa(this.a)&&(this.a.withCredentials=this.ja);try{Md(this),0<this.c&&(this.u=Nd(this.a),V(this.F,W(this,"Will abort after "+this.c+"ms if incomplete, xhr2 "+this.u)),this.u?(this.a.timeout=this.c,this.a.ontimeout=v(this.Da,
this)):this.l=Dd(this.Da,this.c,this)),V(this.F,W(this,"Sending request")),this.h=!0,this.a.send(a),this.h=!1}catch(g){V(this.F,W(this,"Send error: "+g.message)),Kd(this,g)}};function Nd(a){return L&&M(9)&&"number"==typeof a.timeout&&n(a.ontimeout)}function Ld(a){return"content-type"==a.toLowerCase()}
Ed.prototype.Da=function(){"undefined"!=typeof h&&this.a&&(this.g="Timed out after "+this.c+"ms, aborting",V(this.F,W(this,this.g)),U(this,"timeout"),this.a&&this.b&&(V(this.F,W(this,"Aborting")),this.b=!1,this.f=!0,this.a.abort(),this.f=!1,U(this,"complete"),U(this,"abort"),Od(this)))};function Kd(a,b){a.b=!1;a.a&&(a.f=!0,a.a.abort(),a.f=!1);a.g=b;Pd(a);Od(a)}function Pd(a){a.V||(a.V=!0,U(a,"complete"),U(a,"error"))}Ed.prototype.ha=function(){this.H||(this.W||this.h||this.f?Qd(this):this.Ja())};
Ed.prototype.Ja=function(){Qd(this)};
function Qd(a){if(a.b&&"undefined"!=typeof h)if(a.v[1]&&4==Rd(a)&&2==Sd(a))V(a.F,W(a,"Local request error detected and ignored"));else if(a.h&&4==Rd(a))Dd(a.ha,0,a);else if(U(a,"readystatechange"),4==Rd(a)){V(a.F,W(a,"Request complete"));a.b=!1;try{var b=Sd(a),c;a:switch(b){case 200:case 201:case 202:case 204:case 206:case 304:case 1223:c=!0;break a;default:c=!1}var d;if(!(d=c)){var e;if(e=0===b){var g=String(a.j).match(Ib)[1]||null;if(!g&&k.self&&k.self.location)var l=k.self.location.protocol,g=
l.substr(0,l.length-1);e=!Id.test(g?g.toLowerCase():"")}d=e}if(d)U(a,"complete"),U(a,"success");else{var m;try{m=2<Rd(a)?a.a.statusText:""}catch(r){V(a.F,"Can not get status: "+r.message),m=""}a.g=m+" ["+Sd(a)+"]";Pd(a)}}finally{Od(a)}}}function Od(a){if(a.a){Md(a);var b=a.a,c=a.v[0]?p:null;a.a=null;a.v=null;U(a,"ready");try{b.onreadystatechange=c}catch(d){(a=a.F)&&a.log(Fc,"Problem encountered resetting onreadystatechange: "+d.message,void 0)}}}
function Md(a){a.a&&a.u&&(a.a.ontimeout=null);"number"==typeof a.l&&(k.clearTimeout(a.l),a.l=null)}function Rd(a){return a.a?a.a.readyState:0}function Sd(a){try{return 2<Rd(a)?a.a.status:-1}catch(b){return-1}}function W(a,b){return b+" ["+a.ga+" "+a.j+" "+Sd(a)+"]"};function Td(){this.a=void 0}Td.prototype.send=function(a,b,c){Ud(this,c);this.a.send(a,"POST",b)};function Ud(a,b){a.a=new Ed;a.a.ja=!0;a.a.c=Math.max(0,ka);Uc(a.a,"success",function(){b.eb()});Uc(a.a,"error",function(){b.error()})};function Vd(){this.a=new ja;this.c=new Td;this.b=new ia}aa(Vd);var ka=1E3,Wd="withCredentials"in new XMLHttpRequest,Xd=!!k.navigator.sendBeacon;Vd.prototype.send=function(a,b,c,d,e){a=e||a.ya();c===Yd?this.b.send(a,b.toString(),d):c===Zd?this.c.send(a,b.toString(),d):c===$d&&(b.setMeta("rn",y.g.Ba()),a+="?"+b.toString(),this.a.send(a,d))};function ae(){this.a=new sb;this.u=new Vd;this.h=!1;this.b=0;this.c=!1;this.f=0}aa(ae);var Yd="beacon",Zd="xhr",$d="image";ae.prototype.g=function(){if(this.a.D())this.h=!1;else{var a=this.a.M(),b=a.url;this.u.send(a.data[0][0],a.data[0][1],a.type,{eb:v(this.l,this),error:v(this.j,this)},b)}};ae.prototype.l=function(){this.c=!1;this.b=this.f=0;var a=this.a.M();a.data.shift();0===a.data.length&&(a=this.a.na(),a.Z&&a.Z());this.g()};
ae.prototype.j=function(){if(5<=this.f++)this.c=!1,this.b=this.f=0;else{if(!this.c){this.c=!0;var a=this.a.M();a&&a.data&&a.data[0][1].set("retry",1)}this.b+=250;k.setTimeout(v(this.g,this),this.b)}};function be(){this.b=S.B();this.g=new kd;this.j=new Cd;this.h=new sa(v(this.v,this));this.f=!0;this.c=this.a=void 0;this.b.a("visibility",this.u,this);this.a={time:0,ea:qb(10)};Xd&&this.g.c?this.g.a&&this.h.start():new gd;var a=y.H.fb(this.l,this);this.b.addListener(ce,a,this);de(this)}var ce=["click","mousedown","keydown","scroll"];be.prototype.u=function(){var a=this.g.a;if(Xd){var b=this.h;a?b.start():(b.b=!1,va(b))}};
be.prototype.v=function(){if(this.f){var a=this.j,b,c;c=(k||window).document;b=(c?new xd(9==c.nodeType?c:c.ownerDocument||c.document):Ia||(Ia=new xd)).a;c=b.scrollingElement?b.scrollingElement:rc||"CSS1Compat"!=b.compatMode?b.body||b.documentElement:b.documentElement;b=wd(b);var d=(L&&M("10")&&b.pageYOffset!=c.scrollTop?new Ab(c.scrollLeft,c.scrollTop):new Ab(b.pageXOffset||c.scrollLeft,b.pageYOffset||c.scrollTop)).J;a.a=y.b.Ua();b=Math.floor(d/a.c+.3);c=Math.floor((d+a.b)/a.c+.7)-1;a.a<d+a.b&&(c=
y.g.trunc(c,10)-1);a=Math.ceil(a.a/a.c)-1;d=y.g.wb(b)&&y.g.Aa(c)&&y.g.Aa(a);if(this.j.g&&d)for(a+1>this.a.ea.length&&(this.a.ea=pb(this.a.ea,qb(a-this.a.ea.length+1))),a=b;a<=c;++a)this.a.ea[a]++;this.a.time++}};be.prototype.l=function(){this.f=!0;de(this)};function de(a){a.c&&k.clearTimeout(a.c);a.c=k.setTimeout(v(function(){this.f=!1},a),3E4)};
function ee(a,b){this.f=[];this.H=b||null;this.a=this.b=!1;this.c=void 0;this.u=this.v=this.h=!1;this.g=0;this.j=null;this.G=0}ee.prototype.l=function(a,b){this.h=!1;fe(this,a,b)};function fe(a,b,c){a.b=!0;a.c=c;a.a=!b;ge(a)}function he(a){if(a.b){if(!a.u)throw new ie;a.u=!1}}ee.prototype.Z=function(a){he(this);fe(this,!0,a)};function je(a,b,c){a.f.push([b,c,void 0]);a.b&&ge(a)}
ee.prototype.then=function(a,b,c){var d,e,g=new J(function(a,b){d=a;e=b});je(this,d,function(a){e(a)});return g.then(a,b,c)};Wa(ee);function ke(a){return mb(a.f,function(a){return u(a[1])})}
function ge(a){if(a.g&&a.b&&ke(a)){var b=a.g,c=le[b];c&&(k.clearTimeout(c.a),delete le[b]);a.g=0}a.j&&(a.j.G--,delete a.j);for(var b=a.c,d=c=!1;a.f.length&&!a.h;){var e=a.f.shift(),g=e[0],l=e[1],e=e[2];if(g=a.a?l:g)try{var m=g.call(e||a.H,b);n(m)&&(a.a=a.a&&(m==b||m instanceof Error),a.c=b=m);if(Xa(b)||"function"===typeof k.Promise&&b instanceof k.Promise)d=!0,a.h=!0}catch(r){b=r,a.a=!0,ke(a)||(c=!0)}}a.c=b;d&&(m=v(a.l,a,!0),d=v(a.l,a,!1),b instanceof ee?(je(b,m,d),b.v=!0):b.then(m,d));c&&(b=new me(b),
le[b.a]=b,a.g=b.a)}function ie(){C.call(this)}x(ie,C);ie.prototype.message="Deferred has already fired";ie.prototype.name="AlreadyCalledError";function me(a){this.a=k.setTimeout(v(this.c,this),0);this.b=a}me.prototype.c=function(){delete le[this.a];throw this.b;};var le={};function ne(a){var b={},c=b.document||document,d=document.createElement("SCRIPT"),e={Qc:d,Da:void 0},g=new ee(0,e),l=null,m=null!=b.timeout?b.timeout:5E3;0<m&&(l=window.setTimeout(function(){oe(d,!0);var b=new pe(qe,"Timeout reached for loading script "+a);he(g);fe(g,!1,b)},m),e.Da=l);d.onload=d.onreadystatechange=function(){d.readyState&&"loaded"!=d.readyState&&"complete"!=d.readyState||(oe(d,b.Mc||!1,l),g.Z(null))};d.onerror=function(){oe(d,!0,l);var b=new pe(re,"Error while loading script "+a);
he(g);fe(g,!1,b)};e=b.attributes||{};Ua(e,{type:"text/javascript",charset:"UTF-8",src:a});td(d,e);se(c).appendChild(d)}function se(a){var b=a.getElementsByTagName("HEAD");return b&&0!=b.length?b[0]:a.documentElement}function oe(a,b,c){null!=c&&k.clearTimeout(c);a.onload=p;a.onerror=p;a.onreadystatechange=p;b&&window.setTimeout(function(){a&&a.parentNode&&a.parentNode.removeChild(a)},0)}var re=0,qe=1;function pe(a,b){var c="Jsloader error (code #"+a+")";b&&(c+=": "+b);C.call(this,c)}x(pe,C);function te(){this.b={};this.a={};this.c=S.B();for(var a in ue)this.a[ue[a].name]=[];this.c.a("module_init",this.f,this)}aa(te);var ve="//st.top100.ru/top100/1.8.0/",ue={Mb:{name:"usability",path:"usability.js"},Eb:{name:"ecommerce",path:"ecommerce.js"}};function we(a,b,c){a.b[b.name]||(ne(ve+b.path),a.a[b.name].push(c))}te.prototype.f=function(a,b){for(this.b[a]=b;this.a[a].length;)this.a[a].shift()(b)};function xe(){this.j=this.h=this.b=this.g=void 0;this.v=ae.B();this.u=te.B();this.a=[];this.f=[];this.l=!1;this.c=S.B();this.g=new yd;new od;this.h=Bc.B();this.c.a("extLink",this.fc,this);this.c.a("click",this.cc,this);this.c.a("tap",this.Qa,this);this.c.a("ecommerce",this.dc,this);this.j=new be;this.c.a("activity",this.ac,this);this.c.a("ping",this.ic,this);this.c.addListener("beforeunload",this.Ra,this)}aa(xe);
function ye(a,b){var c=ze(a,b);if(!c.ca){for(var d=0,e=a.a.length;d<e;++d)a.a[d].id==c.id&&a.a.splice(d,1);c.w&&0<c.w.length&&we(a.u,ue.Mb,v(a.lc,a));c.L&&we(a.u,ue.Eb,v(a.ec,a));c.aa&&Ae(a,c.aa);a.a.push(c);c.ca||(c.element?(d=y.b.P(c.element))&&1===d.nodeType&&(d.innerHTML=a.ba(c.s,0)):a.U(c.s));c.s.o.Ea&&k.setTimeout(v(function(){var a=c.s,b;b=this.h;if(0===b.a.length)b=null;else{var d=new D;d.K("et","ll");d.set("ll",Ja(b.a));b=d}b&&(b=X(a,b),Y(this,[[a,b]],void 0,void 0,a.Wa()))},a),0)}}f=xe.prototype;
f.U=function(a,b,c){b=Bd(this.g,a.o,b,c);b=X(a,b);Y(this,[[a,b]]);if(b=Be(this,a)){c=0;for(var d=b.w.length;c<d;++c)b.Ca[b.w[c]]=[];!a.o.Fa&&Ce(this,b)}};f.ba=function(a,b,c){b=Bd(this.g,a.o,b,c);b=X(a,b);b.K("rn",y.g.Ba());c=a.o.T;return'<a href="https://top100.rambler.ru'+(c?"/home?id="+c:"")+'" target="_blank"><img src="'+(a.ya()+"?"+b.toString())+'" title="Rambler\'s Top100" alt="Rambler\'s Top100" border="0" /></a>'};
function Y(a,b,c,d,e){a=a.v;var g={};c=c||5;if(1===c)g.type=Yd;else{var l=b[0][1],m=void 0,r=l.get("et"),I=["bv","cl","ec","extln","ll"];0<=F(["extln","act"],r)&&Xd?m=Yd:0<=F(I,r)&&Wd?m=Zd:2E3>=l.toString().length?m=$d:Wd&&(m=Zd);g.type=m}g.type&&(g.data=b,g.Z=d,g.url=e,a.a.enqueue(c,g),a.h||(a.h=!0,a.g()))}f.cc=function(){for(var a=void 0,b=0,c=this.a.length;b<c;++b){var a=this.a[b],d=this.b.getClicks(a.w);d&&(d=X(a.s,d),Y(this,[[a.s,d]]))}this.b.eraseClicksData()};
f.Qa=function(){for(var a=void 0,b=0,c=this.a.length;b<c;++b){var a=this.a[b],d=this.b.getClicks(a.w);d&&(d.set("clt","tap"),d=X(a.s,d),Y(this,[[a.s,d]]))}this.b.eraseClicksData()};f.ic=function(){var a=new D;a.set("et","ping");for(var b=void 0,c=[],d=0,e=this.a.length;d<e;++d)this.a[d].s.o.ca||(b=X(this.a[d].s,a.clone())),c.push([this.a[d].s,b]);0!==c.length&&Y(this,c)};
f.dc=function(a){for(var b=[],c=0,d=this.a.length;c<d;++c)if(this.a[c].L){var e=X(this.a[c].s,a.clone());b.push([this.a[c].s,e])}0!==b.length&&Y(this,b)};f.fc=function(a,b){for(var c=[],d=0,e=this.a.length;d<e;++d)this.a[d].s.o.Ea||a.remove("um_log"),c.push([this.a[d].s,X(this.a[d].s,a.clone())]);0!==c.length&&Y(this,c,void 0,b)};f.ac=function(a,b){for(var c=[],d=b?1:5,e=0,g=this.a.length;e<g;++e)c.push([this.a[e].s,X(this.a[e].s,a.clone())]);0!==c.length&&Y(this,c,d)};
function ze(a,b){var c={},d=b.o;c.id=b.wa();c.s=b;c.element=d.P();c.w=d.Sa;c.L=d.L;c.ca=d.ca;c.Pc=!1;c.Ca={};c.aa=d.Ta;if(c.aa.length)for(var d=0,e=c.aa.length;d<e;++d)0<=F(c.w,c.aa[d])||c.w.push(c.aa[d]);if(a.f.length)for(d=0,e=a.f.length;d<e;++d)0<=F(c.w,a.f[d])||c.w.push(a.f[d]);d=0;for(e=c.w.length;d<e;++d)c.Ca[c.w[d]]=[];return c}function Be(a,b){for(var c=b.wa(),d=0,e=a.a.length;d<e;++d)if(a.a[d].id===c)return a.a[d];return null}
function Ae(a,b){for(var c=0,d=a.a.length;c<d;++c)for(var e=a.a[c],g=b,l=0,m=g.length;l<m;++l)0<=F(e.w,g[l])||(e.w.push(g[l]),e.Ca[g[l]]=[]);c=0;for(d=b.length;c<d;++c)0<=F(a.f,b[c])||a.f.push(b[c]);a.b&&a.b.addAttributes(b);a.Y()}function Ce(a,b){if(a.b){var c=a.b.getBlocks(b.w,b.Ca),d=void 0;if(c)for(var e=0,g=c.length;e<g;++e)d=c[e],d.isEmpty()||(d=X(b.s,d),Y(a,[[b.s,d]]))}}
f.lc=function(a){this.b=a();a=0;for(var b=this.a.length;a<b;++a)this.b.addAttributes(this.a[a].w);this.Y();k.setTimeout(v(this.Y,this),1E3);k.setTimeout(v(this.Y,this),2E3);k.setTimeout(v(this.Y,this),4E3);k.setTimeout(v(this.Y,this),8E3)};f.Y=function(){for(var a=0,b=this.a.length;a<b;++a)!this.a[a].s.o.Fa&&Ce(this,this.a[a])};f.ec=function(a){for(var b=void 0,c=0,d=this.a.length;c<d;++c)if(this.a[c].L){b=this.a[c].L;break}a(b)};
f.Ra=function(){if(!this.l){if(Xd){var a=this.j,b=new D,c=Ja({time:a.a.time,screens:a.a.ea});b.K("et","act");b.set("meta",c);a.b.b("activity",b,!0)}this.l=!0}};function De(a,b){this.a=this.b=void 0;Ee(this);this.version="1.8.0";if(a){if(this.T=a.project,this.Sa=a.attributes_dataset||[],this.Ta=a.common_attributes||[],this.fa=a.splits||[],this.ma=a.chapters||[],this.C=a.custom_vars||{},this.L=a.ecommerce||void 0,this.element=a.element||void 0,this.hb=a.trackHashes||!1,this.Ea=a.trackLinks||!1,this.cb=a.url||void 0,this.Fa=a.usabilityManualControl||!1,a.user_id||null===a.user_id?this.N=a.user_id:this.N=void 0,!0===a.useYmId&&(this.Ka=y.h.rc()),a.sync){var c=
a.sync;this.C=this.C||{};this.C.__uid=c}}else this.T=ha.Ac,this.Sa=[],this.Ta=[],this.fa=[],this.ma=[],this.N=this.element=this.L=this.C=void 0,this.Ea=this.hb=!1,this.cb=void 0,this.Fa=!1;var c=this.T||"-1",d=a&&a.protocol;if(d){var e=void 0,g;for(g in Fe)if(e=Fe[g],d.split(":")[0]===e){":"!==e[e.length-1]&&(e=e+":");this.ka=e;break}ve=this.ka+ve}else this.ka=void 0;g=a.top100Id;this.gb=y.c.xa(c);if("string"===typeof g||"number"===typeof g)this.rb=g;c=void 0;this.ka?c=this.ka:c="https:"===k.location.protocol?
"https:":"http:";this.b=c+"//kraken.rambler.ru/cnt/";this.a=c+"//kraken.rambler.ru/um_cnt/";this.ca=b||!1}var Fe={Dc:"http",Ec:"https"};f=De.prototype;f.version=void 0;f.gb="";f.Ka="";f.rb=void 0;f.T=void 0;f.$a=void 0;f.Sa=void 0;f.Ta=void 0;f.fa=void 0;f.ma=void 0;f.C=void 0;f.name=void 0;f.L=void 0;f.element=void 0;f.ka=void 0;f.ca=void 0;f.N=void 0;f.hb=void 0;f.Ea=void 0;f.cb=void 0;f.Fa=!1;f.ya=function(){return this.b};f.Wa=function(){return this.a};f.bb=function(a){this.name=a};f.P=function(){return this.element};
function Ee(a){a.$a=(new Date/1E3).toString()+"-"+y.g.Ba().toString()};function Ge(a,b){this.o=new De(a,b);this.a=xe.B();ye(this.a,this)}f=Ge.prototype;f.ya=function(){return this.o.ya()};f.Wa=function(){return this.o.Wa()};f.bb=function(a){this.o.bb(a)};f.wa=function(){return this.o.T};f.ab=function(a){this.o.T=a};f.U=function(a){Ee(this.o);this.a.U(this,1,a)};f.ib=function(a,b){var c=y.b.P(a);c&&1===c.nodeType?c.innerHTML=this.a.ba(this,0,b):this.a.U(this,0,b)};f.sb=function(a,b){var c=y.b.P(a);c&&1===c.nodeType&&(c.innerHTML=this.a.ba(this,2,b))};f.pc=function(){return this.o.$a};
f.ba=function(){return this.a.ba(this,0)};f.kb=function(){};f.nb=function(a){var b=this.o;a.splits&&(b.fa=a.splits);a.custom_vars&&(b.C=a.custom_vars)};f.mb=function(a,b){var c=this.o;c.C=c.C||{};c.C[a]=b};f.xb=function(a){this.b("__uid",a)};f.lb=function(a){var b=this.a;a=y.ha.Va(a);a=X(this,a);Y(b,[[this,a]])};f.Gb=function(){var a=this.a;Ce(a,Be(a,this))};f.Hb=function(a){var b=this.o;b.N||null===b.N?(this.o.N=a,a=this.a,b=y.ia.Va(),b=X(this,b),Y(a,[[this,b]])):y.W.wc()};
function X(a,b){var c=a.o;b.setMeta("pid",c.T);b.setMeta("rid",c.$a);b.setMeta("tid",c.rb||c.gb);b.setMeta("v",c.version);q(c.fa)&&c.fa.length&&b.set("sp",Ja(c.fa));a.o.N&&b.setMeta("uid",c.N);c.Ka&&b.setMeta("yid",c.Ka);return b}f.xa=function(){return this.o.gb};var Z=Ge.prototype;Z.setAccount=Z.ab;Z.getAccount=Z.wa;Z.trackPageview=Z.U;Z.trackPageView=Z.U;Z.trackPageviewByLogo=Z.ib;Z.trackPageViewByLogo=Z.ib;Z.drawLogoTo=Z.sb;Z.setCustomVar=Z.mb;Z.getCustomVar=Z.kb;Z.sendCustomVars=Z.lb;
Z.getWidgetHtml=Z.ba;Z.syncUserId=Z.Hb;Z.sync=Z.xb;Z.getRequestId=Z.pc;Z.sendBlocks=Z.Gb;Z.getTop100Id=Z.xa;Z.updateOptions=Z.nb;function y(a,b){a.checkInit&&k.setTimeout(function(){y.G.oc("initKraken"+a.project)},0);if(b)return new Ge(a,b);y.v[a.project]=new Ge(a,b);return y.v[a.project]}y.v={};y.Hc={};y.Ha=0;y.Ia=function(){return S.B()};y.Fc=function(){return S.B()};y.V=function(a,b){var c=void 0!==a?a:"~"+y.Ha++,d=new y({},!0);y.v[c]=d;d.bb(c);b&&d.ab(b);return d};y.Ja=function(a){return y.V(void 0,a)};y.ja=function(a){a=a||"";return y.v[a]||y.V(a)};y.loaded=!0;y.Fb=!0;
y.ra=function(a){var b=k[a];b&&b.isTop100Namespace||(k[a]=y)};y.ra("Kraken");y.ra("top100");function He(){}He.prototype.push=function(){for(var a=arguments,b=0;b<a.length;b++)try{if("function"===typeof a[b])a[b]();else{var c="",d=a[b][0],e=d.lastIndexOf(".");0<e&&(c=d.substring(0,e),d=d.substring(e+1));var g=y.ja(c);g[d].apply(g,a[b].slice(1))}}catch(l){console.error(l)}};
if(k._top100q&&q(k._top100q)){var Ie=new He;for(k._top100q=k._top100q.reverse();k._top100q.length;)Ie.push(k._top100q.pop());k._top100q=Ie}k._top100q||(k._top100q=new He);Z=Ge.prototype;Z.setAccount=Z.ab;Z.getAccount=Z.wa;Z.trackPageview=Z.U;Z.trackPageviewByLogo=Z.ib;Z.drawLogoTo=Z.sb;Z.setCustomVar=Z.mb;Z.getCustomVar=Z.kb;Z.sendCustomVars=Z.lb;Z.sync=Z.xb;Z.getTop100Id=Z.xa;Z.updateOptions=Z.nb;window._top100||(window._top100={},window._top100.createTracker=y.V,window._top100.getTrackerByName=y.ja,window._top100.getTracker=y.Ja,window._top100.getPubSub=y.Ia,window._top100.loaded=y.loaded,y.isTop100Namespace=y.Fb);})();

Binary file not shown.

After

Width:  |  Height:  |  Size: 579 B

View File

@@ -0,0 +1,113 @@
/*
* main.c
*
* Copyright 2017 Edward V. Emelianoff <eddy@sao.ru, edward.emelianoff@gmail.com>
*
* 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.
*/
#include "flash.h"
#include "hardware.h"
#include "monitor.h"
#include "proto.h"
#include "usb.h"
#include "usb_lib.h"
volatile uint32_t Tms = 0;
volatile uint32_t Coolerspeed[2]; // RPM of cooler0/1
/* Called when systick fires */
void sys_tick_handler(void){
static uint32_t actr = 0;
++Tms;
if(++actr == 1000){ // RPM counter
Coolerspeed[0] = TIM3->CNT/2;
TIM3->CNT = 0;
Coolerspeed[1] = Cooler1RPM/2;
Cooler1RPM = 0;
actr = 0;
}
}
#define USBBUF 63
// usb getline
static char *get_USB(){
static char tmpbuf[USBBUF+1], *curptr = tmpbuf;
static int rest = USBBUF;
uint8_t x = USB_receive((uint8_t*)curptr);
if(!x) return NULL;
curptr[x] = 0;
if(x == 1 && *curptr == 0x7f){ // backspace
if(curptr > tmpbuf){
--curptr;
USND("\b \b");
}
return NULL;
}
USB_sendstr(curptr); // echo
if(curptr[x-1] == '\n'){ // || curptr[x-1] == '\r'){
curptr = tmpbuf;
rest = USBBUF;
// omit empty lines
if(tmpbuf[0] == '\n') return NULL;
// and wrong empty lines
if(tmpbuf[0] == '\r' && tmpbuf[1] == '\n') return NULL;
return tmpbuf;
}
curptr += x; rest -= x;
if(rest <= 0){ // buffer overflow
curptr = tmpbuf;
rest = USBBUF;
}
return NULL;
}
int main(void){
uint32_t lastT = 0, lastTmon = 0;
char *txt;
sysreset();
SysTick_Config(6000, 1);
flashstorage_init();
HW_setup();
USB_setup();
RCC->CSR |= RCC_CSR_RMVF; // remove reset flags
iwdg_setup();
ON(COOLER0); // turn on power, manage only by PWM
ON(COOLER1);
while (1){
IWDG->KR = IWDG_REFRESH; // refresh watchdog
if(Tms - lastT > MONITOR_PERIOD){
process_monitor();
lastT = Tms;
}
if(showMon && Tms - lastTmon > 4999){
showState();
IWDG->KR = IWDG_REFRESH;
lastTmon = Tms;
}
usb_proc();
if((txt = get_USB())){
IWDG->KR = IWDG_REFRESH;
cmd_parser(txt);
}
IWDG->KR = IWDG_REFRESH;
buzzer_chk();
}
return 0;
}

View File

@@ -0,0 +1,203 @@
/*
* This file is part of the SockFans project.
* Copyright 2020 Edward V. Emelianov <edward.emelianoff@gmail.com>.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include "adc.h"
#include "flash.h"
#include "monitor.h"
#include "proto.h"
// when critical T reached wait for TturnOff ms and after that turn off system
#define TturnOff the_conf.Tturnoff
// don't mind when button 2 pressed again after t<5s
#define TbtnPressed (5000)
// settings
// T0 - CPU, T1 - HDD, T2 - inner T, T3 - power source
#define Thysteresis (int16_t)the_conf.Thyst
#define tmin the_conf.Tmin
#define tmax the_conf.Tmax
#define t3max the_conf.Tmax[TMAXNO-1]
static uint8_t dontprocess = 0; // don't process monitor
static uint32_t TOff = 0; // time to turn off power
static void chkOffRelay(){
static uint32_t scntr = 0;
if(!TOff){ // warning cleared
scntr = 0;
return;
}
if(Tms > TOff){
TOff = 0;
OFF(RELAY);
//TIM1->CCR1 = 0; TIM1->CCR2 = 0; TIM1->CCR3 = 0;
//dontprocess = 1;
SEND("POWEROFF");
buzzer = BUZZER_OFF;
scntr = 0;
}else{
SEND("TCRITSHUTDOWN");
printu(++scntr);
}
NL();
}
static void startOff(){
SEND("TCRITSHUTDOWN0"); NL();
TOff = Tms + TturnOff;
if(TOff == 0) TOff = 1;
buzzer = BUZZER_ON;
}
void SetDontProcess(uint8_t newstate){ // set dontprocess value
dontprocess = newstate;
}
uint8_t GetDontProcess(){ // get dontprocess value
return dontprocess;
}
// check buttons state
static void chkButtons(){
static uint32_t Tpressed = 0;
if(CHK(BUTTON0) == 0){ // button 0 pressed - turn on power if was off
if(CHK(RELAY) == 0){
ON(RELAY);
SEND("POWERON"); NL();
}
dontprocess = 0;
}
if(CHK(BUTTON1) == 0){ // button 1 - all OFF
if(Tpressed){ // already pressed recently
if(Tms - Tpressed < TbtnPressed) return;
}
Tpressed = Tms;
if(Tpressed == 0) Tpressed = 1;
buzzer = BUZZER_OFF;
TIM1->CCR1 = 0; TIM1->CCR2 = 0; TIM1->CCR3 = 0;
OFF(RELAY);
dontprocess = 1;
SEND("POWEROFF"); NL();
}else Tpressed = 0;
}
// maximum value of coolerproblem counter
#define MAXCOOLERPROBLEM (10)
// monitor temperatures and do something
void process_monitor(){
chkButtons();
if(dontprocess) return;
int16_t T;
static uint8_t coolerproblem[2] = {0,0}; // cooler don't run
static uint8_t offreason[4] = {0}; // whos T was critical for turning power off
// check all 4 temperatures
// T0..1 - coolers
for(int x = 0; x < 2; ++x){
T = getNTC(x);
volatile uint32_t *ccr = (x == 0) ? &TIM1->CCR1 : &TIM1->CCR2;
uint32_t RPM = *ccr;
uint32_t speed = Coolerspeed[x];
if(T < tmin[x] - Thysteresis){ // turn off fan
*ccr = 0;
}else if(T > tmax[x] + Thysteresis){
gett('0'+x); NL();
if(!TOff){
offreason[x] = 1;
startOff();
*ccr = 100;
}
}else{
offreason[x] = 0;
// check working fan
int chk = (x==0) ? CHK(COOLER0) : CHK(COOLER1);
if(chk){ // fan is working, check RPM
if(RPM && (speed == 0)){
if(coolerproblem[x] > MAXCOOLERPROBLEM){
buzzer = BUZZER_SHORT;
SEND("COOLER"); bufputchar('0'+x); SEND("DEAD");NL();
}else ++coolerproblem[x];
}else if(coolerproblem[x]){
buzzer = BUZZER_OFF;
coolerproblem[x] = 0;
SEND("COOLER"); bufputchar('0'+x); SEND("OK");NL();
}
}else{ // turn on fan
if(x==0) ON(COOLER0);
else ON(COOLER1);
}
if(T > tmin[x] && T < tmax[x]){ // T between tmin and tmax
int32_t tx = 80*(T - tmin[x]);
tx /= (tmax[x] - tmin[x]);
uint32_t pwm = 20 + tx;
if(pwm < 20) pwm = 20;
else if(pwm > 100) pwm = 100;
*ccr = pwm;
}
}
}
// T2 - not controlled cooler
T = getNTC(2);
if(T < tmin[2] - Thysteresis){ // turn off fan
TIM1->CCR3 = 0;
}else if(T > tmax[2] + Thysteresis){
gett('2'); NL();
if(!TOff){
offreason[2] = 1;
startOff();
TIM1->CCR3 = 100;
}
}else{ // T between tmin and tmax
offreason[2] = 0;
if(T > tmin[2] && T < tmax[2]){
int32_t tx = 60*(T - tmin[2]);
tx /= (tmax[2] - tmin[2]);
uint32_t pwm = 40 + tx;
if(pwm < 40) pwm = 40;
else if(pwm > 100) pwm = 100;
TIM1->CCR3 = pwm;
}
}
// T3 - turn off power after TturnOff
if(getNTC(3) > t3max){
gett('3'); NL();
// all coolers to max value
TIM1->CCR1 = 100;
TIM1->CCR2 = 100;
TIM1->CCR3 = 100;
ON(COOLER0); ON(COOLER1);
if(!TOff){
offreason[3] = 1;
startOff();
}
}else offreason[3] = 0;
// check offreason
if(TOff){
uint8_t stillbad = 0;
for(int x = 0; x < 4; ++x)
if(offreason[x]){
stillbad = 1;
break;
}
if(!stillbad){
SEND("CLRPANIC");NL();
TOff = 0;
buzzer = BUZZER_OFF;
}
chkOffRelay();
}
}

View File

@@ -0,0 +1,31 @@
/*
* This file is part of the SockFans project.
* Copyright 2020 Edward V. Emelianov <edward.emelianoff@gmail.com>.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#ifndef MONITOR_H__
#include <stdint.h>
// run monitor each 1s
#define MONITOR_PERIOD (999)
void process_monitor();
void SetDontProcess(uint8_t newstate);
uint8_t GetDontProcess();
#define MONITOR_H__
#endif // MONITOR_H__

View File

@@ -0,0 +1,587 @@
/*
* geany_encoding=koi8-r
* proto.c
*
* Copyright 2018 Edward V. Emelianov <eddy@sao.ru, edward.emelianoff@gmail.com>
*
* 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.
*
*/
#include "adc.h"
#include "flash.h"
#include "hardware.h"
#include "monitor.h"
#include "proto.h"
#include "usb.h"
#include <string.h> // strlen
uint8_t showMon = 0; // start monitoring @ each 5s
static char buff[BUFSZ+1], *bptr = buff;
static uint8_t blen = 0;
void sendbuf(){
IWDG->KR = IWDG_REFRESH;
if(blen == 0) return;
*bptr = 0;
USB_sendstr(buff);
bptr = buff;
blen = 0;
}
void bufputchar(char ch){
if(blen > BUFSZ-1){
sendbuf();
}
*bptr++ = ch;
++blen;
}
void addtobuf(const char *txt){
IWDG->KR = IWDG_REFRESH;
while(*txt) bufputchar(*txt++);
}
char *omit_spaces(char *buf){
while(*buf){
if(*buf > ' ') break;
++buf;
}
return buf;
}
// THERE'S NO OVERFLOW PROTECTION IN NUMBER READ PROCEDURES!
// read decimal number
static char *getdec(char *buf, uint32_t *N){
uint32_t num = 0;
while(*buf){
char c = *buf;
if(c < '0' || c > '9'){
break;
}
num *= 10;
num += c - '0';
++buf;
}
*N = num;
return buf;
}
// read hexadecimal number (without 0x prefix!)
static char *gethex(char *buf, uint32_t *N){
uint32_t num = 0;
while(*buf){
char c = *buf;
uint8_t M = 0;
if(c >= '0' && c <= '9'){
M = '0';
}else if(c >= 'A' && c <= 'F'){
M = 'A' - 10;
}else if(c >= 'a' && c <= 'f'){
M = 'a' - 10;
}
if(M){
num <<= 4;
num += c - M;
}else{
break;
}
++buf;
}
*N = num;
return buf;
}
// read binary number (without 0b prefix!)
static char *getbin(char *buf, uint32_t *N){
uint32_t num = 0;
while(*buf){
char c = *buf;
if(c < '0' || c > '1'){
break;
}
num <<= 1;
if(c == '1') num |= 1;
++buf;
}
*N = num;
return buf;
}
/**
* @brief getnum - read uint32_t from string (dec, hex or bin: 127, 0x7f, 0b1111111)
* @param buf - buffer with number and so on
* @param N - the number read
* @return pointer to first non-number symbol in buf (if it is == buf, there's no number)
*/
char *getnum(char *txt, uint32_t *N){
if(*txt == '0'){
if(txt[1] == 'x' || txt[1] == 'X') return gethex(txt+2, N);
if(txt[1] == 'b' || txt[1] == 'B') return getbin(txt+2, N);
}
return getdec(txt, N);
}
// change pin state
static void onoff(char state, GPIO_TypeDef *port, uint32_t pin, char *text){
switch(state){
case '0': // off
pin_clear(port, pin);
break;
case '1': // on
pin_set(port, pin);
break;
default:
break;
}
SEND(text);
bufputchar('=');
bufputchar('0' + pin_read(port, pin));
}
// get raw ADC value of channel chno + '0'
static inline void ADCget(char chno){
if(chno < '0' || chno > '7'){
SEND("Channel number shoul be from 0 to 7");
return;
}
int nch = chno - '0';
SEND("ADCVAL");
bufputchar(chno);
bufputchar('=');
printu(getADCval(nch));
}
// get coolerx RPS
static inline void coolerRPS(char n){
if(n < '0' || n > '1'){
SEND("Cooler number should be 0 or 1");
return;
}
SEND("RPS");
bufputchar(n);
bufputchar('=');
printu(Coolerspeed[n - '0']);
}
static inline void getPWM(char n){
if(n < '0' || n > '2'){
SEND("Cooler number should be from 0 to 2");
return;
}
SEND("PWM");
bufputchar(n);
bufputchar('=');
uint32_t pwm;
switch(n){
case '0':
pwm = TIM1->CCR1;
break;
case '1':
pwm = TIM1->CCR2;
break;
default:
pwm = TIM1->CCR3;
}
printu(pwm);
}
// change Coolerx PWM
static inline void changePWM(char *str){
char channel = *str++;
str = omit_spaces(str);
uint32_t rpm;
getnum(str, &rpm);
if(rpm > 100){
SEND("PWM should be from 0 to 100%");
return;
}
switch(channel){
case '0':
TIM1->CCR1 = rpm;
break;
case '1':
TIM1->CCR2 = rpm;
break;
case '2':
TIM1->CCR3 = rpm;
break;
default:
SEND("Cooler number should be from 0 to 2");
}
}
static inline void buzzercmd(char cmd){
SEND("BUZZER=");
switch(cmd){
case '0':
buzzer = BUZZER_OFF;
SEND("OFF");
break;
case '1':
buzzer = BUZZER_ON;
SEND("ON");
break;
case 'l':
buzzer = BUZZER_LONG;
SEND("LONG");
break;
case 's':
buzzer = BUZZER_SHORT;
SEND("SHORT");
break;
default:
SEND("BADSTATE");
}
}
void gett(char chno){
if(chno < '0' || chno > '3'){
SEND("Temperature channel should be 0..3");
return;
}
bufputchar('T'); bufputchar(chno); bufputchar('=');
printi(getNTC(chno - '0'));
}
static inline void chkButtons(){
SEND("BUTTON0=");
bufputchar('1' - CHK(BUTTON0)); // buttons are inverted
SEND("\nBUTTON1=");
bufputchar('1' - CHK(BUTTON1));
}
// show current device state: T, RPM, PWM, relay
void showState(){
SEND("TIME=");
printu(Tms);
newline();
for(char x = '0'; x < '4'; ++x){
gett(x);
newline();
}
SEND("BUZZER=");
switch(buzzer){
case BUZZER_ON:
SEND("ON");
break;
case BUZZER_OFF:
SEND("OFF");
break;
case BUZZER_SHORT:
SEND("SHORT");
break;
case BUZZER_LONG:
SEND("LONG");
break;
}
newline();
chkButtons();
newline();
coolerRPS('0');
newline();
coolerRPS('1');
newline();
for(char x = '0'; x < '3'; ++x){
getPWM(x);
newline();
}
onoff('c', COOLER0_port, COOLER0_pin, "COOLER0");
newline();
onoff('c', COOLER1_port, COOLER1_pin, "COOLER1");
newline();
onoff('c', RELAY_port, RELAY_pin, "RELAY");
NL();
}
static uint8_t userconf_changed = 0; // ==1 if user_conf was changed
static const char *nshould = "N should be from 0 to ";
static const char *changed = "Changed OK\n";
static const char *notchanged = "Not changed: the same value\n";
static inline void setArrval(int16_t *arr, uint8_t maxelem, char *params){
uint32_t N, val;
int16_t sign = 1;
char *next = getnum(params, &N);
if(N > maxelem){
SEND(nshould);
printu(maxelem); newline();
return;
}
next = omit_spaces(next);
if(*next == '-'){
next = omit_spaces(next+1);
sign = -1;
}
char *rest = getnum(next, &val);
if(*rest && *rest != '\n'){
SEND("Arguments are: N T, where N is channel number, T - temperature\n");
return;
}
sign *= (int16_t)val;
if(arr[N] != sign){
arr[N] = sign;
userconf_changed = 1;
SEND(changed);
}else SEND(notchanged);
}
static inline void setval(uint32_t *var, char *params){
uint32_t val;
char *next = getnum(params, &val);
if(*next && *next != '\n'){
SEND("Argument is 32-bit number\n");
return;
}
if(*var != val){
*var = val;
userconf_changed = 1;
SEND(changed);
}else SEND(notchanged);
}
static inline void showSettings(){
int i;
SEND("Tturnoff="); printu(the_conf.Tturnoff); newline();
SEND("Thysteresis="); printu(the_conf.Thyst); newline();
SEND("Tmin={");
for(i = 0; i < TMINNO; ++i){
if(i) SEND(", ");
printu(the_conf.Tmin[i]);
}
SEND("}\n");
SEND("Tmax={");
for(i = 0; i < TMAXNO; ++i){
if(i) SEND(", ");
printu(the_conf.Tmax[i]);
}
SEND("}\n");
}
static inline void setters(char *txt){ // setters
txt = omit_spaces(txt);
if(!*txt){
SEND("Setters need more arguments");
return;
}
char *next = omit_spaces(txt+1);
switch(*txt){
case '<': // Tmin
setArrval(the_conf.Tmin, TMINNO-1, next);
break;
case '>': // Tmax
setArrval(the_conf.Tmax, TMAXNO-1, next);
break;
case 'H': // Thyst
setval(&the_conf.Thyst, next);
break;
case 'O': // Tturnoff
setval(&the_conf.Tturnoff, next);
break;
case 'S': // save settings
if(userconf_changed){
if(!store_userconf()){
userconf_changed = 0;
SEND("Stored!");
}else SEND("Error when storing!");
}
break;
default:
SEND("Setters:\n"
"< N T - set nth (0..2) Tmin (T/10degrC)\n"
"> N T - set Tmax\n"
"H T - set temperature hysteresis (T/10degrC)\n"
"O t - time to turn off after emergency (t in ms)\n"
"S - save settings\n");
}
}
/**
* @brief cmd_parser - command parsing
* @param txt - buffer with commands & data
* @param isUSB - == 1 if data got from USB
*/
void cmd_parser(char *txt){
char _1st = txt[0];
/*
* parse long commands here
*/
switch(_1st){
case '0': // cooler0: set/clear/check
onoff(txt[1], COOLER0_port, COOLER0_pin, "COOLER0");
goto eof;
break;
case '1': // cooler1: set/clear/check
onoff(txt[1], COOLER1_port, COOLER1_pin, "COOLER1");
goto eof;
break;
case 'A': // ADC raw values
ADCget(txt[1]);
goto eof;
break;
case 'b': // buzzer
buzzercmd(txt[1]);
goto eof;
break;
case 'C': // Get real Cooler RPM
coolerRPS(txt[1]);
goto eof;
break;
case 'G': // get cooler PWM from settings
getPWM(txt[1]);
goto eof;
break;
case 'P': // set PWM
changePWM(txt+1);
goto eof;
break;
case 'r': // relay: set/clear/check
onoff(txt[1], RELAY_port, RELAY_pin, "RELAY");
goto eof;
break;
case 'S': // setters
setters(&txt[1]);
goto eof;
case 't':
gett(txt[1]);
goto eof;
break;
}
if(txt[1] != '\n') *txt = '?'; // help for wrong message length
switch(_1st){
case 'B':
chkButtons();
break;
case 'D':
SEND("Go into DFU mode\n");
sendbuf();
Jump2Boot();
break;
case 'E':
showState();
break;
case 'M': // MCU temperature
SEND("MCUTEMP=");
printu(getMCUtemp());
break;
case 'm': // toggle monitoring
showMon = !showMon;
SEND("MONITORING=");
if(showMon) SEND("on");
else SEND("off");
break;
case 'R':
SEND("Soft reset\n");
sendbuf();
pause_ms(5); // a little pause to transmit data
NVIC_SystemReset();
break;
case 's':
showSettings();
break;
case 'T':
SEND("TIME=");
printu(Tms);
newline();
break;
case 'V':
SEND("V3_3=");
printu(getVdd());
SEND("\nV5=");
printu(getU5());
SEND("\nV12=");
printu(getU12());
break;
case 'Z':
adc_setup();
SEND("ADC restarted\n");
break;
case '!':
SetDontProcess(!GetDontProcess());
if(GetDontProcess()) SEND("\n\tManual");
else SEND("\n\tAutomatic");
SEND(" mode\n");
break;
default: // help
SEND(
"'0x' - turn cooler0 on/off (x=1/0) or get status (x - any other)\n"
"'1x' - turn cooler1 on/off (x=1/0) or get status (x - any other)\n"
"'Ax' - get ADC raw value (x=0..7)\n"
"'B' - buttons' state\n"
"'bx' - buzzer: x==0 - off, x==1 - on, x==l - long beeps, x==s - short beeps\n"
"'Cx' - get cooler x (0/1) RPS\n"
"'D' - activate DFU mode\n"
"'E' - show current state\n"
"'Gx' - get cooler x (0..3) PWM settings\n"
"'M' - get MCU temperature\n"
"'m' - toggle monitoring\n"
"'Px y' - set coolerx PWM to y\n"
"'R' - software reset\n"
"'rx' - relay on/off (x=1/0) or get status\n"
"'S' - setters\n"
"'s' - show settings\n"
"'T' - get time from start (ms)\n"
"'tx' - get temperature x (0..3)\n"
"'V' - get voltage\n"
"'Z' - reinit ADC\n"
"'!' - switch between manual and automatic modes\n"
);
break;
}
eof:
newline();
sendbuf();
}
// print 32bit unsigned int
void printu(uint32_t val){
char buf[11], *bufptr = &buf[10];
*bufptr = 0;
if(!val){
*(--bufptr) = '0';
}else{
while(val){
*(--bufptr) = val % 10 + '0';
val /= 10;
}
}
addtobuf(bufptr);
}
// print 32bit signed int
void printi(int32_t val){
if(val < 0){
val = -val;
bufputchar('-');
}
printu(val);
}
// print 32bit unsigned int as hex
void printuhex(uint32_t val){
addtobuf("0x");
uint8_t *ptr = (uint8_t*)&val + 3;
int8_t i, j, z=1;
for(i = 0; i < 4; ++i, --ptr){
if(*ptr == 0){ // omit leading zeros
if(i == 3) z = 0;
if(z) continue;
}
else z = 0;
for(j = 1; j > -1; --j){
uint8_t half = (*ptr >> (4*j)) & 0x0f;
if(half < 10) bufputchar(half + '0');
else bufputchar(half - 10 + 'a');
}
}
}

View File

@@ -0,0 +1,60 @@
/*
* geany_encoding=koi8-r
* proto.h
*
* Copyright 2018 Edward V. Emelianov <eddy@sao.ru, edward.emelianoff@gmail.com>
*
* 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.
*
*/
#pragma once
#ifndef __PROTO_H__
#define __PROTO_H__
#include "stm32f0.h"
#include "hardware.h"
#define BUFSZ (64)
// macro for static strings
#define SEND(str) do{addtobuf(str);}while(0)
#ifdef EBUG
#define MSG(str) do{addtobuf(__FILE__ " (L" STR(__LINE__) "): " str);}while(0)
#else
#define MSG(str)
#endif
#define newline() do{bufputchar('\n');}while(0)
// newline with buffer sending
#define NL() do{bufputchar('\n'); sendbuf();}while(0)
extern uint8_t showMon;
void cmd_parser(char *buf);
void addtobuf(const char *txt);
void bufputchar(char ch);
void gett(char chno);
void printu(uint32_t val);
void printi(int32_t val);
void printuhex(uint32_t val);
void sendbuf();
void showState();
char *omit_spaces(char *buf);
char *getnum(char *buf, uint32_t *N);
#endif // __PROTO_H__

Binary file not shown.

View File

@@ -0,0 +1,180 @@
/*
* geany_encoding=koi8-r
* usb.c - base functions for different USB types
*
* Copyright 2018 Edward V. Emelianov <eddy@sao.ru, edward.emelianoff@gmail.com>
*
* 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.
*
*/
#include "usb.h"
#include "usb_lib.h"
static volatile uint8_t tx_succesfull = 1;
static volatile uint8_t rxNE = 0;
// interrupt IN handler (never used?)
static void EP1_Handler(){
uint16_t epstatus = KEEP_DTOG(USB->EPnR[1]);
if(RX_FLAG(epstatus)) epstatus = (epstatus & ~USB_EPnR_STAT_TX) ^ USB_EPnR_STAT_RX; // set valid RX
else epstatus = epstatus & ~(USB_EPnR_STAT_TX|USB_EPnR_STAT_RX);
// clear CTR
epstatus = (epstatus & ~(USB_EPnR_CTR_RX|USB_EPnR_CTR_TX));
USB->EPnR[1] = epstatus;
}
// data IN/OUT handlers
static void transmit_Handler(){ // EP3IN
tx_succesfull = 1;
uint16_t epstatus = KEEP_DTOG_STAT(USB->EPnR[3]);
// clear CTR keep DTOGs & STATs
USB->EPnR[3] = (epstatus & ~(USB_EPnR_CTR_TX)); // clear TX ctr
}
static void receive_Handler(){ // EP2OUT
rxNE = 1;
uint16_t epstatus = KEEP_DTOG_STAT(USB->EPnR[2]);
USB->EPnR[2] = (epstatus & ~(USB_EPnR_CTR_RX)); // clear RX ctr
}
void USB_setup(){
RCC->APB1ENR |= RCC_APB1ENR_CRSEN | RCC_APB1ENR_USBEN; // enable CRS (hsi48 sync) & USB
RCC->CFGR3 &= ~RCC_CFGR3_USBSW; // reset USB
RCC->CR2 |= RCC_CR2_HSI48ON; // turn ON HSI48
uint32_t tmout = 16000000;
while(!(RCC->CR2 & RCC_CR2_HSI48RDY)){if(--tmout == 0) break;}
FLASH->ACR = FLASH_ACR_PRFTBE | FLASH_ACR_LATENCY;
CRS->CFGR &= ~CRS_CFGR_SYNCSRC;
CRS->CFGR |= CRS_CFGR_SYNCSRC_1; // USB SOF selected as sync source
CRS->CR |= CRS_CR_AUTOTRIMEN; // enable auto trim
CRS->CR |= CRS_CR_CEN; // enable freq counter & block CRS->CFGR as read-only
RCC->CFGR |= RCC_CFGR_SW;
// allow RESET and CTRM interrupts
USB->CNTR = USB_CNTR_RESETM | USB_CNTR_WKUPM;
// clear flags
USB->ISTR = 0;
// and activate pullup
USB->BCDR |= USB_BCDR_DPPU;
NVIC_EnableIRQ(USB_IRQn);
}
static int usbwr(const uint8_t *buf, uint16_t l){
uint32_t ctra = 1000000;
while(--ctra && tx_succesfull == 0){
IWDG->KR = IWDG_REFRESH;
}
tx_succesfull = 0;
EP_Write(3, buf, l);
ctra = 1000000;
while(--ctra && tx_succesfull == 0){
IWDG->KR = IWDG_REFRESH;
}
if(tx_succesfull == 0){usbON = 0; return 1;} // usb is OFF?
return 0;
}
static uint8_t usbbuff[USB_TXBUFSZ-1]; // temporary buffer (63 - to prevent need of ZLP)
static uint8_t buflen = 0; // amount of symbols in usbbuff
// send next up to 63 bytes of data in usbbuff
static void send_next(){
if(!buflen || !tx_succesfull) return;
tx_succesfull = 0;
EP_Write(3, usbbuff, buflen);
buflen = 0;
}
// unblocking sending - just fill a buffer
void USB_send(const uint8_t *buf, uint16_t len){
if(!usbON || !len) return;
if(len > USB_TXBUFSZ-1 - buflen){
usbwr(usbbuff, buflen);
buflen = 0;
}
if(len > USB_TXBUFSZ-1){
USB_send_blk(buf, len);
return;
}
while(len--) usbbuff[buflen++] = *buf++;
}
// send zero-terminated string
void USB_sendstr(const char *str){
uint16_t l = 0;
const char *ptr = str;
while(*ptr++) ++l;
USB_send((uint8_t*)str, l);
}
// blocking sending
void USB_send_blk(const uint8_t *buf, uint16_t len){
if(!usbON || !len) return; // USB disconnected
if(buflen){
usbwr(usbbuff, buflen);
buflen = 0;
}
int needzlp = 0;
while(len){
if(len == USB_TXBUFSZ) needzlp = 1;
uint16_t s = (len > USB_TXBUFSZ) ? USB_TXBUFSZ : len;
if(usbwr(buf, s)) return;
len -= s;
buf += s;
}
if(needzlp){
usbwr(NULL, 0);
}
}
void usb_proc(){
switch(USB_Dev.USB_Status){
case USB_STATE_CONFIGURED:
// make new BULK endpoint
// Buffer have 1024 bytes, but last 256 we use for CAN bus (30.2 of RM: USB main features)
EP_Init(1, EP_TYPE_INTERRUPT, USB_EP1BUFSZ, 0, EP1_Handler); // IN1 - transmit
EP_Init(2, EP_TYPE_BULK, 0, USB_RXBUFSZ, receive_Handler); // OUT2 - receive data
EP_Init(3, EP_TYPE_BULK, USB_TXBUFSZ, 0, transmit_Handler); // IN3 - transmit data
USB_Dev.USB_Status = USB_STATE_CONNECTED;
break;
case USB_STATE_DEFAULT:
case USB_STATE_ADDRESSED:
if(usbON){
usbON = 0;
}
break;
default: // USB_STATE_CONNECTED - send next data portion
if(!usbON) return;
send_next();
}
}
/**
* @brief USB_receive
* @param buf (i) - buffer[64] for received data
* @return amount of received bytes
*/
uint8_t USB_receive(uint8_t *buf){
if(!usbON || !rxNE) return 0;
uint8_t sz = EP_Read(2, buf);
uint16_t epstatus = KEEP_DTOG(USB->EPnR[2]);
// keep stat_tx & set ACK rx
USB->EPnR[2] = (epstatus & ~(USB_EPnR_STAT_TX)) ^ USB_EPnR_STAT_RX;
rxNE = 0;
return sz;
}

View File

@@ -0,0 +1,41 @@
/*
* geany_encoding=koi8-r
* usb.h
*
* Copyright 2018 Edward V. Emelianov <eddy@sao.ru, edward.emelianoff@gmail.com>
*
* 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.
*
*/
#pragma once
#ifndef __USB_H__
#define __USB_H__
#include "hardware.h"
#define BUFFSIZE (64)
// send string with constant length
#define USND(str) do{USB_send((uint8_t*)str, sizeof(str)-1);}while(0)
void USB_setup();
void usb_proc();
void USB_send(const uint8_t *buf, uint16_t len);
void USB_sendstr(const char *str);
void USB_send_blk(const uint8_t *buf, uint16_t len);
uint8_t USB_receive(uint8_t *buf);
#endif // __USB_H__

View File

@@ -0,0 +1,104 @@
/*
* geany_encoding=koi8-r
* usb_defs.h
*
* Copyright 2018 Edward V. Emelianov <eddy@sao.ru, edward.emelianoff@gmail.com>
*
* 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.
*
*/
#pragma once
#ifndef __USB_DEFS_H__
#define __USB_DEFS_H__
#include <stm32f0.h>
// max endpoints number
#define STM32ENDPOINTS 8
/**
* Buffers size definition
**/
// !!! when working with CAN bus change USB_BTABLE_SIZE to 768 !!!
#define USB_BTABLE_SIZE 768
// for USB FS EP0 buffers are from 8 to 64 bytes long (64 for PL2303)
#define USB_EP0_BUFSZ 64
// USB transmit buffer size (64 for PL2303)
#define USB_TXBUFSZ 64
// USB receive buffer size (64 for PL2303)
#define USB_RXBUFSZ 64
// EP1 - interrupt - buffer size
#define USB_EP1BUFSZ 8
#define USB_BTABLE_BASE 0x40006000
#ifdef USB_BTABLE
#undef USB_BTABLE
#endif
#define USB_BTABLE ((USB_BtableDef *)(USB_BTABLE_BASE))
#define USB_ISTR_EPID 0x0000000F
#define USB_FNR_LSOF_0 0x00000800
#define USB_FNR_lSOF_1 0x00001000
#define USB_LPMCSR_BESL_0 0x00000010
#define USB_LPMCSR_BESL_1 0x00000020
#define USB_LPMCSR_BESL_2 0x00000040
#define USB_LPMCSR_BESL_3 0x00000080
#define USB_EPnR_CTR_RX 0x00008000
#define USB_EPnR_DTOG_RX 0x00004000
#define USB_EPnR_STAT_RX 0x00003000
#define USB_EPnR_STAT_RX_0 0x00001000
#define USB_EPnR_STAT_RX_1 0x00002000
#define USB_EPnR_SETUP 0x00000800
#define USB_EPnR_EP_TYPE 0x00000600
#define USB_EPnR_EP_TYPE_0 0x00000200
#define USB_EPnR_EP_TYPE_1 0x00000400
#define USB_EPnR_EP_KIND 0x00000100
#define USB_EPnR_CTR_TX 0x00000080
#define USB_EPnR_DTOG_TX 0x00000040
#define USB_EPnR_STAT_TX 0x00000030
#define USB_EPnR_STAT_TX_0 0x00000010
#define USB_EPnR_STAT_TX_1 0x00000020
#define USB_EPnR_EA 0x0000000F
#define USB_COUNTn_RX_BLSIZE 0x00008000
#define USB_COUNTn_NUM_BLOCK 0x00007C00
#define USB_COUNTn_RX 0x0000003F
#define USB_TypeDef USB_TypeDef_custom
typedef struct{
__IO uint32_t EPnR[STM32ENDPOINTS];
__IO uint32_t RESERVED[STM32ENDPOINTS];
__IO uint32_t CNTR;
__IO uint32_t ISTR;
__IO uint32_t FNR;
__IO uint32_t DADDR;
__IO uint32_t BTABLE;
__IO uint32_t LPMCSR;
__IO uint32_t BCDR;
} USB_TypeDef;
typedef struct{
__IO uint16_t USB_ADDR_TX;
__IO uint16_t USB_COUNT_TX;
__IO uint16_t USB_ADDR_RX;
__IO uint16_t USB_COUNT_RX;
} USB_EPDATA_TypeDef;
typedef struct{
__IO USB_EPDATA_TypeDef EP[STM32ENDPOINTS];
} USB_BtableDef;
#endif // __USB_DEFS_H__

View File

@@ -0,0 +1,473 @@
/*
* geany_encoding=koi8-r
* usb_lib.c
*
* Copyright 2018 Edward V. Emelianov <eddy@sao.ru, edward.emelianoff@gmail.com>
*
* 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.
*
*/
#include <stdint.h>
#include "usb_lib.h"
ep_t endpoints[STM32ENDPOINTS];
usb_dev_t USB_Dev;
uint8_t usbON = 0;
static usb_LineCoding lineCoding = {115200, 0, 0, 8};
static config_pack_t setup_packet;
static uint8_t ep0databuf[EP0DATABUF_SIZE];
static uint8_t ep0dbuflen = 0;
usb_LineCoding getLineCoding(){return lineCoding;}
// definition of parts common for USB_DeviceDescriptor & USB_DeviceQualifierDescriptor
#define bcdUSB_L 0x10
#define bcdUSB_H 0x01
#define bDeviceClass 0
#define bDeviceSubClass 0
#define bDeviceProtocol 0
#define bNumConfigurations 1
static const uint8_t USB_DeviceDescriptor[] = {
18, // bLength
0x01, // bDescriptorType - Device descriptor
bcdUSB_L, // bcdUSB_L - 1.10
bcdUSB_H, // bcdUSB_H
bDeviceClass, // bDeviceClass - USB_COMM
bDeviceSubClass, // bDeviceSubClass
bDeviceProtocol, // bDeviceProtocol
USB_EP0_BUFSZ, // bMaxPacketSize
0x7b, // idVendor_L PL2303: VID=0x067b, PID=0x2303
0x06, // idVendor_H
0x03, // idProduct_L
0x23, // idProduct_H
0x00, // bcdDevice_Ver_L
0x03, // bcdDevice_Ver_H
0x01, // iManufacturer
0x02, // iProduct
0x00, // iSerialNumber
bNumConfigurations // bNumConfigurations
};
static const uint8_t USB_DeviceQualifierDescriptor[] = {
10, //bLength
0x06, // bDescriptorType - Device qualifier
bcdUSB_L, // bcdUSB_L
bcdUSB_H, // bcdUSB_H
bDeviceClass, // bDeviceClass
bDeviceSubClass, // bDeviceSubClass
bDeviceProtocol, // bDeviceProtocol
USB_EP0_BUFSZ, // bMaxPacketSize0
bNumConfigurations, // bNumConfigurations
0x00 // Reserved
};
static const uint8_t USB_ConfigDescriptor[] = {
/*Configuration Descriptor*/
0x09, /* bLength: Configuration Descriptor size */
0x02, /* bDescriptorType: Configuration */
39, /* wTotalLength:no of returned bytes */
0x00,
0x01, /* bNumInterfaces: 1 interface */
0x01, /* bConfigurationValue: Configuration value */
0x00, /* iConfiguration: Index of string descriptor describing the configuration */
0xa0, /* bmAttributes - Bus powered, Remote wakeup */
0x32, /* MaxPower 100 mA */
/*---------------------------------------------------------------------------*/
/*Interface Descriptor */
0x09, /* bLength: Interface Descriptor size */
0x04, /* bDescriptorType: Interface */
0x00, /* bInterfaceNumber: Number of Interface */
0x00, /* bAlternateSetting: Alternate setting */
0x03, /* bNumEndpoints: 3 endpoints used */
0xff, /* bInterfaceClass */
0x00, /* bInterfaceSubClass */
0x00, /* bInterfaceProtocol */
0x00, /* iInterface: */
///////////////////////////////////////////////////
/*Endpoint 1 Descriptor*/
0x07, /* bLength: Endpoint Descriptor size */
0x05, /* bDescriptorType: Endpoint */
0x81, /* bEndpointAddress IN1 */
0x03, /* bmAttributes: Interrupt */
0x0a, /* wMaxPacketSize LO: */
0x00, /* wMaxPacketSize HI: */
0x01, /* bInterval: */
/*Endpoint OUT2 Descriptor*/
0x07, /* bLength: Endpoint Descriptor size */
0x05, /* bDescriptorType: Endpoint */
0x02, /* bEndpointAddress: OUT2 */
0x02, /* bmAttributes: Bulk */
(USB_RXBUFSZ & 0xff), /* wMaxPacketSize: 64 */
(USB_RXBUFSZ >> 8),
0x00, /* bInterval: ignore for Bulk transfer */
/*Endpoint IN3 Descriptor*/
0x07, /* bLength: Endpoint Descriptor size */
0x05, /* bDescriptorType: Endpoint */
0x83, /* bEndpointAddress IN3 */
0x02, /* bmAttributes: Bulk */
(USB_TXBUFSZ & 0xff), /* wMaxPacketSize: 64 */
(USB_TXBUFSZ >> 8),
0x00, /* bInterval: ignore for Bulk transfer */
};
_USB_LANG_ID_(USB_StringLangDescriptor, LANG_US);
// these descriptors are not used in PL2303 emulator!
_USB_STRING_(USB_StringSerialDescriptor, u"0");
_USB_STRING_(USB_StringManufacturingDescriptor, u"Prolific Technology Inc.");
_USB_STRING_(USB_StringProdDescriptor, u"USB-Serial Controller");
/*
* default handlers
*/
// SET_LINE_CODING
void WEAK linecoding_handler(usb_LineCoding __attribute__((unused)) *lc){
}
// SET_CONTROL_LINE_STATE
void WEAK clstate_handler(uint16_t __attribute__((unused)) val){
}
// SEND_BREAK
void WEAK break_handler(){
}
// handler of vendor requests
void WEAK vendor_handler(config_pack_t *packet){
if(packet->bmRequestType & 0x80){ // read
uint8_t c;
switch(packet->wValue){
case 0x8484:
c = 2;
break;
case 0x0080:
c = 1;
break;
case 0x8686:
c = 0xaa;
break;
default:
c = 0;
}
EP_WriteIRQ(0, &c, 1);
}else{ // write ZLP
EP_WriteIRQ(0, (uint8_t *)0, 0);
}
}
static void wr0(const uint8_t *buf, uint16_t size){
if(setup_packet.wLength < size) size = setup_packet.wLength; // shortened request
if(size < endpoints[0].txbufsz){
EP_WriteIRQ(0, buf, size);
return;
}
while(size){
uint16_t l = size;
if(l > endpoints[0].txbufsz) l = endpoints[0].txbufsz;
EP_WriteIRQ(0, buf, l);
buf += l;
size -= l;
uint8_t needzlp = (l == endpoints[0].txbufsz) ? 1 : 0;
if(size || needzlp){ // send last data buffer
uint16_t status = KEEP_DTOG(USB->EPnR[0]);
// keep DTOGs, clear CTR_RX,TX, set TX VALID, leave stat_Rx
USB->EPnR[0] = (status & ~(USB_EPnR_CTR_RX|USB_EPnR_CTR_TX|USB_EPnR_STAT_RX))
^ USB_EPnR_STAT_TX;
uint32_t ctr = 1000000;
while(--ctr && (USB->ISTR & USB_ISTR_CTR) == 0){IWDG->KR = IWDG_REFRESH;};
if((USB->ISTR & USB_ISTR_CTR) == 0){
return;
}
if(needzlp) EP_WriteIRQ(0, (uint8_t*)0, 0);
}
}
}
static inline void get_descriptor(){
switch(setup_packet.wValue){
case DEVICE_DESCRIPTOR:
wr0(USB_DeviceDescriptor, sizeof(USB_DeviceDescriptor));
break;
case CONFIGURATION_DESCRIPTOR:
wr0(USB_ConfigDescriptor, sizeof(USB_ConfigDescriptor));
break;
case STRING_LANG_DESCRIPTOR:
wr0((const uint8_t *)&USB_StringLangDescriptor, STRING_LANG_DESCRIPTOR_SIZE_BYTE);
break;
case STRING_MAN_DESCRIPTOR:
wr0((const uint8_t *)&USB_StringManufacturingDescriptor, USB_StringManufacturingDescriptor.bLength);
break;
case STRING_PROD_DESCRIPTOR:
wr0((const uint8_t *)&USB_StringProdDescriptor, USB_StringProdDescriptor.bLength);
break;
case STRING_SN_DESCRIPTOR:
wr0((const uint8_t *)&USB_StringSerialDescriptor, USB_StringSerialDescriptor.bLength);
break;
case DEVICE_QUALIFIER_DESCRIPTOR:
wr0(USB_DeviceQualifierDescriptor, USB_DeviceQualifierDescriptor[0]);
break;
default:
break;
}
}
static uint8_t configuration = 0; // reply for GET_CONFIGURATION (==1 if configured)
static inline void std_d2h_req(){
uint16_t status = 0; // bus powered
switch(setup_packet.bRequest){
case GET_DESCRIPTOR:
get_descriptor();
break;
case GET_STATUS:
EP_WriteIRQ(0, (uint8_t *)&status, 2); // send status: Bus Powered
break;
case GET_CONFIGURATION:
EP_WriteIRQ(0, &configuration, 1);
break;
default:
break;
}
}
static inline void std_h2d_req(){
switch(setup_packet.bRequest){
case SET_ADDRESS:
// new address will be assigned later - after acknowlegement or request to host
USB_Dev.USB_Addr = setup_packet.wValue;
break;
case SET_CONFIGURATION:
// Now device configured
USB_Dev.USB_Status = USB_STATE_CONFIGURED;
configuration = setup_packet.wValue;
break;
default:
break;
}
}
/*
bmRequestType: 76543210
7 direction: 0 - host->device, 1 - device->host
65 type: 0 - standard, 1 - class, 2 - vendor
4..0 getter: 0 - device, 1 - interface, 2 - endpoint, 3 - other
*/
/**
* Endpoint0 (control) handler
*/
static void EP0_Handler(){
uint16_t epstatus = USB->EPnR[0]; // EP0R on input -> return this value after modifications
uint8_t reqtype = setup_packet.bmRequestType & 0x7f;
uint8_t dev2host = (setup_packet.bmRequestType & 0x80) ? 1 : 0;
int rxflag = RX_FLAG(epstatus);
if(rxflag && SETUP_FLAG(epstatus)){
switch(reqtype){
case STANDARD_DEVICE_REQUEST_TYPE: // standard device request
if(dev2host){
std_d2h_req();
}else{
std_h2d_req();
EP_WriteIRQ(0, (uint8_t *)0, 0);
}
break;
case STANDARD_ENDPOINT_REQUEST_TYPE: // standard endpoint request
if(setup_packet.bRequest == CLEAR_FEATURE){
EP_WriteIRQ(0, (uint8_t *)0, 0);
}
break;
case VENDOR_REQUEST_TYPE:
vendor_handler(&setup_packet);
break;
case CONTROL_REQUEST_TYPE:
switch(setup_packet.bRequest){
case GET_LINE_CODING:
EP_WriteIRQ(0, (uint8_t*)&lineCoding, sizeof(lineCoding));
break;
case SET_LINE_CODING: // omit this for next stage, when data will come
break;
case SET_CONTROL_LINE_STATE:
usbON = 1;
clstate_handler(setup_packet.wValue);
break;
case SEND_BREAK:
usbON = 0;
break_handler();
break;
default:
break;
}
if(setup_packet.bRequest != GET_LINE_CODING) EP_WriteIRQ(0, (uint8_t *)0, 0); // write acknowledgement
break;
default:
EP_WriteIRQ(0, (uint8_t *)0, 0);
}
}else if(rxflag){ // got data over EP0 or host acknowlegement
if(endpoints[0].rx_cnt){
if(setup_packet.bRequest == SET_LINE_CODING){
linecoding_handler((usb_LineCoding*)ep0databuf);
}
}
} else if(TX_FLAG(epstatus)){ // package transmitted
// now we can change address after enumeration
if ((USB->DADDR & USB_DADDR_ADD) != USB_Dev.USB_Addr){
USB->DADDR = USB_DADDR_EF | USB_Dev.USB_Addr;
// change state to ADRESSED
USB_Dev.USB_Status = USB_STATE_ADDRESSED;
}
}
epstatus = KEEP_DTOG(USB->EPnR[0]);
if(rxflag) epstatus ^= USB_EPnR_STAT_TX; // start ZLP/data transmission
else epstatus &= ~USB_EPnR_STAT_TX; // or leave unchanged
// keep DTOGs, clear CTR_RX,TX, set RX VALID
USB->EPnR[0] = (epstatus & ~(USB_EPnR_CTR_RX|USB_EPnR_CTR_TX)) ^ USB_EPnR_STAT_RX;
}
static uint16_t lastaddr = LASTADDR_DEFAULT;
/**
* Endpoint initialisation
* !!! when working with CAN bus change USB_BTABLE_SIZE to 768 !!!
* @param number - EP num (0...7)
* @param type - EP type (EP_TYPE_BULK, EP_TYPE_CONTROL, EP_TYPE_ISO, EP_TYPE_INTERRUPT)
* @param txsz - transmission buffer size @ USB/CAN buffer
* @param rxsz - reception buffer size @ USB/CAN buffer
* @param uint16_t (*func)(ep_t *ep) - EP handler function
* @return 0 if all OK
*/
int EP_Init(uint8_t number, uint8_t type, uint16_t txsz, uint16_t rxsz, void (*func)()){
if(number >= STM32ENDPOINTS) return 4; // out of configured amount
if(txsz > USB_BTABLE_SIZE || rxsz > USB_BTABLE_SIZE) return 1; // buffer too large
if(lastaddr + txsz + rxsz >= USB_BTABLE_SIZE) return 2; // out of btable
USB->EPnR[number] = (type << 9) | (number & USB_EPnR_EA);
USB->EPnR[number] ^= USB_EPnR_STAT_RX | USB_EPnR_STAT_TX_1;
if(rxsz & 1 || rxsz > 512) return 3; // wrong rx buffer size
uint16_t countrx = 0;
if(rxsz < 64) countrx = rxsz / 2;
else{
if(rxsz & 0x1f) return 3; // should be multiple of 32
countrx = 31 + rxsz / 32;
}
USB_BTABLE->EP[number].USB_ADDR_TX = lastaddr;
endpoints[number].tx_buf = (uint16_t *)(USB_BTABLE_BASE + lastaddr);
endpoints[number].txbufsz = txsz;
lastaddr += txsz;
USB_BTABLE->EP[number].USB_COUNT_TX = 0;
USB_BTABLE->EP[number].USB_ADDR_RX = lastaddr;
endpoints[number].rx_buf = (uint8_t *)(USB_BTABLE_BASE + lastaddr);
lastaddr += rxsz;
// buffer size: Table127 of RM
USB_BTABLE->EP[number].USB_COUNT_RX = countrx << 10;
endpoints[number].func = func;
return 0;
}
// standard IRQ handler
void usb_isr(){
if (USB->ISTR & USB_ISTR_RESET){
// Reinit registers
USB->CNTR = USB_CNTR_RESETM | USB_CNTR_CTRM | USB_CNTR_SUSPM | USB_CNTR_WKUPM;
USB->ISTR = 0;
// Endpoint 0 - CONTROL
// ON USB LS size of EP0 may be 8 bytes, but on FS it should be 64 bytes!
lastaddr = LASTADDR_DEFAULT; // roll back to beginning of buffer
EP_Init(0, EP_TYPE_CONTROL, USB_EP0_BUFSZ, USB_EP0_BUFSZ, EP0_Handler);
// clear address, leave only enable bit
USB->DADDR = USB_DADDR_EF;
// state is default - wait for enumeration
USB_Dev.USB_Status = USB_STATE_DEFAULT;
}
if(USB->ISTR & USB_ISTR_CTR){
// EP number
uint8_t n = USB->ISTR & USB_ISTR_EPID;
// copy status register
uint16_t epstatus = USB->EPnR[n];
// copy received bytes amount
endpoints[n].rx_cnt = USB_BTABLE->EP[n].USB_COUNT_RX & 0x3FF; // low 10 bits is counter
// check direction
if(USB->ISTR & USB_ISTR_DIR){ // OUT interrupt - receive data, CTR_RX==1 (if CTR_TX == 1 - two pending transactions: receive following by transmit)
if(n == 0){ // control endpoint
if(epstatus & USB_EPnR_SETUP){ // setup packet -> copy data to conf_pack
EP_Read(0, (uint8_t*)&setup_packet);
ep0dbuflen = 0;
// interrupt handler will be called later
}else if(epstatus & USB_EPnR_CTR_RX){ // data packet -> push received data to ep0databuf
ep0dbuflen = endpoints[0].rx_cnt;
EP_Read(0, (uint8_t*)&ep0databuf);
}
}
}
// call EP handler
if(endpoints[n].func) endpoints[n].func(endpoints[n]);
}
if(USB->ISTR & USB_ISTR_SUSP){ // suspend -> still no connection, may sleep
usbON = 0;
USB->CNTR |= USB_CNTR_FSUSP | USB_CNTR_LPMODE;
USB->ISTR = ~USB_ISTR_SUSP;
}
if(USB->ISTR & USB_ISTR_WKUP){ // wakeup
USB->CNTR &= ~(USB_CNTR_FSUSP | USB_CNTR_LPMODE); // clear suspend flags
USB->ISTR = ~USB_ISTR_WKUP;
}
}
/**
* Write data to EP buffer (called from IRQ handler)
* @param number - EP number
* @param *buf - array with data
* @param size - its size
*/
void EP_WriteIRQ(uint8_t number, const uint8_t *buf, uint16_t size){
uint8_t i;
if(size > USB_TXBUFSZ) size = USB_TXBUFSZ;
uint16_t N2 = (size + 1) >> 1;
// the buffer is 16-bit, so we should copy data as it would be uint16_t
uint16_t *buf16 = (uint16_t *)buf;
for (i = 0; i < N2; i++){
endpoints[number].tx_buf[i] = buf16[i];
}
USB_BTABLE->EP[number].USB_COUNT_TX = size;
}
/**
* Write data to EP buffer (called outside IRQ handler)
* @param number - EP number
* @param *buf - array with data
* @param size - its size
*/
void EP_Write(uint8_t number, const uint8_t *buf, uint16_t size){
EP_WriteIRQ(number, buf, size);
uint16_t status = KEEP_DTOG(USB->EPnR[number]);
// keep DTOGs, clear CTR_TX & set TX VALID to start transmission
USB->EPnR[number] = (status & ~(USB_EPnR_CTR_TX)) ^ USB_EPnR_STAT_TX;
}
/*
* Copy data from EP buffer into user buffer area
* @param *buf - user array for data
* @return amount of data read
*/
int EP_Read(uint8_t number, uint8_t *buf){
int n = endpoints[number].rx_cnt;
if(n){
for(int i = 0; i < n; ++i)
buf[i] = endpoints[number].rx_buf[i];
}
return n;
}

View File

@@ -0,0 +1,189 @@
/*
* geany_encoding=koi8-r
* usb_lib.h
*
* Copyright 2018 Edward V. Emelianov <eddy@sao.ru, edward.emelianoff@gmail.com>
*
* 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.
*
*/
#pragma once
#ifndef __USB_LIB_H__
#define __USB_LIB_H__
#include <wchar.h>
#include "usb_defs.h"
#define EP0DATABUF_SIZE (64)
#define LASTADDR_DEFAULT (STM32ENDPOINTS * 8)
// bmRequestType & 0x7f
#define STANDARD_DEVICE_REQUEST_TYPE 0
#define STANDARD_ENDPOINT_REQUEST_TYPE 2
#define VENDOR_REQUEST_TYPE 0x40
#define CONTROL_REQUEST_TYPE 0x21
// bRequest, standard; for bmRequestType == 0x80
#define GET_STATUS 0x00
#define GET_DESCRIPTOR 0x06
#define GET_CONFIGURATION 0x08
// for bmRequestType == 0
#define CLEAR_FEATURE 0x01
#define SET_FEATURE 0x03 // unused
#define SET_ADDRESS 0x05
#define SET_DESCRIPTOR 0x07 // unused
#define SET_CONFIGURATION 0x09
// for bmRequestType == 0x81, 1 or 0xB2
#define GET_INTERFACE 0x0A // unused
#define SET_INTERFACE 0x0B // unused
#define SYNC_FRAME 0x0C // unused
#define VENDOR_REQUEST 0x01 // unused
// Class-Specific Control Requests
#define SEND_ENCAPSULATED_COMMAND 0x00 // unused
#define GET_ENCAPSULATED_RESPONSE 0x01 // unused
#define SET_COMM_FEATURE 0x02 // unused
#define GET_COMM_FEATURE 0x03 // unused
#define CLEAR_COMM_FEATURE 0x04 // unused
#define SET_LINE_CODING 0x20
#define GET_LINE_CODING 0x21
#define SET_CONTROL_LINE_STATE 0x22
#define SEND_BREAK 0x23
// control line states
#define CONTROL_DTR 0x01
#define CONTROL_RTS 0x02
// wValue
#define DEVICE_DESCRIPTOR 0x100
#define CONFIGURATION_DESCRIPTOR 0x200
#define STRING_LANG_DESCRIPTOR 0x300
#define STRING_MAN_DESCRIPTOR 0x301
#define STRING_PROD_DESCRIPTOR 0x302
#define STRING_SN_DESCRIPTOR 0x303
#define DEVICE_QUALIFIER_DESCRIPTOR 0x600
#define RX_FLAG(epstat) (epstat & USB_EPnR_CTR_RX)
#define TX_FLAG(epstat) (epstat & USB_EPnR_CTR_TX)
#define SETUP_FLAG(epstat) (epstat & USB_EPnR_SETUP)
// EPnR bits manipulation
#define KEEP_DTOG_STAT(EPnR) (EPnR & ~(USB_EPnR_STAT_RX|USB_EPnR_STAT_TX|USB_EPnR_DTOG_RX|USB_EPnR_DTOG_TX))
#define KEEP_DTOG(EPnR) (EPnR & ~(USB_EPnR_DTOG_RX|USB_EPnR_DTOG_TX))
// USB state: uninitialized, addressed, ready for use, client connected
typedef enum{
USB_STATE_DEFAULT,
USB_STATE_ADDRESSED,
USB_STATE_CONFIGURED,
USB_STATE_CONNECTED
} USB_state;
// EP types
#define EP_TYPE_BULK 0x00
#define EP_TYPE_CONTROL 0x01
#define EP_TYPE_ISO 0x02
#define EP_TYPE_INTERRUPT 0x03
#define LANG_US (uint16_t)0x0409
#define _USB_STRING_(name, str) \
static const struct name \
{ \
uint8_t bLength; \
uint8_t bDescriptorType; \
uint16_t bString[(sizeof(str) - 2) / 2]; \
\
} \
name = {sizeof(name), 0x03, str}
#define _USB_LANG_ID_(name, lng_id) \
\
static const struct name \
{ \
uint8_t bLength; \
uint8_t bDescriptorType; \
uint16_t bString; \
\
} \
name = {0x04, 0x03, lng_id}
#define STRING_LANG_DESCRIPTOR_SIZE_BYTE (4)
// EP0 configuration packet
typedef struct {
uint8_t bmRequestType;
uint8_t bRequest;
uint16_t wValue;
uint16_t wIndex;
uint16_t wLength;
} config_pack_t;
// endpoints state
typedef struct __ep_t{
uint16_t *tx_buf; // transmission buffer address
uint16_t txbufsz; // transmission buffer size
uint8_t *rx_buf; // reception buffer address
void (*func)(); // endpoint action function
uint16_t rx_cnt; // received data counter
} ep_t;
// USB status & its address
typedef struct {
uint8_t USB_Status;
uint16_t USB_Addr;
}usb_dev_t;
typedef struct {
uint32_t dwDTERate;
uint8_t bCharFormat;
#define USB_CDC_1_STOP_BITS 0
#define USB_CDC_1_5_STOP_BITS 1
#define USB_CDC_2_STOP_BITS 2
uint8_t bParityType;
#define USB_CDC_NO_PARITY 0
#define USB_CDC_ODD_PARITY 1
#define USB_CDC_EVEN_PARITY 2
#define USB_CDC_MARK_PARITY 3
#define USB_CDC_SPACE_PARITY 4
uint8_t bDataBits;
} __attribute__ ((packed)) usb_LineCoding;
typedef struct {
uint8_t bmRequestType;
uint8_t bNotificationType;
uint16_t wValue;
uint16_t wIndex;
uint16_t wLength;
} __attribute__ ((packed)) usb_cdc_notification;
extern ep_t endpoints[];
extern usb_dev_t USB_Dev;
extern uint8_t usbON;
void USB_Init();
uint8_t USB_GetState();
int EP_Init(uint8_t number, uint8_t type, uint16_t txsz, uint16_t rxsz, void (*func)());
void EP_WriteIRQ(uint8_t number, const uint8_t *buf, uint16_t size);
void EP_Write(uint8_t number, const uint8_t *buf, uint16_t size);
int EP_Read(uint8_t number, uint8_t *buf);
usb_LineCoding getLineCoding();
void linecoding_handler(usb_LineCoding *lc);
void clstate_handler(uint16_t val);
void break_handler();
void vendor_handler(config_pack_t *packet);
#endif // __USB_LIB_H__