· операційна система сімейства Windows (XP, Vista, Seven);
· наявність у системі встановленого.NET Framework 4.0.
Вимоги до користувача
Базовий рівень володіння комп’ютером, що включає вміння володіти мишею та клавіатурою, наявність досвіду роботи з Windows-програмами.
Опис структур даних
У даному розділі представлений до уваги опис усіх структур даних, що були створені для реалізації поставленої задачі:
v Control_panel – клас - форма, що містить пульт охорони з історією відвідування квартир будинку та є головним вікном програми, в якому присутні всі компоненти програми.
v External_Doorphone – клас-форма, яка є ввідною панеллю, що знаходиться ззовні будівлі і, яка служить для встановлення зв’язку між відвідувачем та системою.
v Apartment_Doorphone – клас-форма, являє собою абонентський пристрій, який знаходиться у квартирі мешканця. Служить для встановлення зв’язку з мешканцем будівлі.
v Processor – клас, що реалізує мікропроцесссор домофону.
v Switch – комутатор домофону, який призначений для створення з’єднання квартири з процесором та панеллю вводу.
v IComunication – інтерфейс, що унаслідується класом TransmissionLines. Інтерфейс та клас призначені для зв’язку компонентів системи.
v DataTransmissionLines – клас даних, що передаються дротами або лініями передач.
v ComunicationPanel - клас, що надає можливість спілкування відвідувача та мешканця.
v Door_locking_device – клас, що реалізує двері здоводчиком.
v User_History – клас, за допомогою якого створюється історія відвідувань квартир.
v Melody – клас для відтворення звукових ефектів.
v Clock – клас, що реалізує годинник.
7. Засоби реалізації
Дана робота була виконана у середовищі розробки Microsoft Visual Studio 2010 мовою C#. C # є об'єктно-орієнтованою мовою програмування і аналогічно іншим сучасним мовам групує пов'язані поля, методи, властивості і події в структури даних, які називаються класами. Використання класів дуже корисне при створенні великих проектів, в даному випадку за допомогою класів ми демонструємо основні властивості ООП, такі як:
Інкапсуляція – це механізм програмування, що об’єднує разом код дані, якими він маніпулює в абсолютно автономний чорний ящик, виключаючи як втручання ззовні, так і неправильне використання даних.
Поліморфізм – це властивість, що дозволяє одному інтерфейсу отримувати доступ до загального класу дій (для групи взаємопов’язаних дій можна розробити один загальний інтерфейс), що допомагає спростити програму.
Наслідування представляє собою процес, у ході якого один об’єкт набуває властивостей іншого об’єкта. Це дуже важливий процес, оскільки він забезпечує принцип ієрархічної класифікації.
8. Проект інтерфейсу
Головним критерієм в розробці інтерфейсу є простота та легкість в розумінні, тільки тоді даний програмний продукт стане популярним, масовим у своєму вжитку для різних категорій людей.
Інтерфейс розробленої програми складається з трьох вікон, представляємо до уваги їх демонстрацію та опис нижче.
8.1. Головне вікно програми – Пульт керування охорони
Дане вікно містить:
1) Список квартир, які знаходяться у будинку;
2) Історію відвідувані квартир, яка містить інформацію, щодо номеру квартири, події(початок зв’язку, кінець зв’язку, відкрито, закрито) та час.
3) Зображення(відкриті двері та замок), що сигналізує про стан дверей(відкриті, закриті).
4) Кнопку «Очистить лог», яка видаляє всю попередню історію.
8.2. Панель для вводу, що розташована ззовні будівлі
Дане вікно містить:
1) Кнопки для набору бажаного номеру квартири;
2) Кнопку «виклик»;
3) Кнопку «відміна»;
4) Поле, що відображає введений вами номер квартири та стан зв’язку;
5) Мікрофон – поле для введення повідомлення, адресованого мешканцю;
6) Динамік – поле для отримання повідомлення від мешканця;
7) Поле, яке дозволяє відкрити двері ключем.
8.3. Ввідна панель, що розташована у середині приміщення
Дане вікно містить:
1) Телефону трубку, яка служить для зв’язку з гостем;
2) Кнопку «Вимкнути звук»;
3) Кнопку «відчинити»;
4) Мікрофон – поле для введення повідомлення, адресованого мешканцю;
5) Динамік – поле для отримання повідомлення від мешканця;
6) Поле, яке відображає поточній стан зв’язку.
Приклади роботи програми
a) Здійснюємо дзвінок до квартири:
b) Мешканець відповів на дзвінок, почалася розмова:
c) Мешканець натиснув кнопку «відчинити»:
d) Завершення розмови та зачинення дверей:
Код програми
Control_panel.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
namespace Doorphone1._2_OOP_Severina
{
public struct logstruct
{
public int number;
public string myevent;
public string date;
public logstruct(int Num, string MyEv, string Date)
{
number = Num;
myevent = MyEv;
date = Date;
}
};
public partial class Control_panel: Form
{
List<logstruct> loglist;
// звукові комунікації
private IComucation<Char> Sound_1;
private IComucation<Char> Sound_2;
// зв'язок ввідної панелі з процесором
private IComucation<short> Proces_1;
private IComucation<short> Proces_2;
// квартири, що підключені до домофону
private List<Apartment_Doorphone> _apartments;
private Processor processor; // процесор
private Switch commutator; // комутатор
private External_Doorphone inputPanel; // ввідна панель
private Door_locking_device door; // двері
public Control_panel()
{
InitializeComponent();
FileStream file = File.Open("Log.txt", FileMode.OpenOrCreate);
file.Close();
loglist = new List<logstruct>();
short keyPass;
string line;
_apartments = new List<Apartment_Doorphone>();
try {
// намагаємося зчитати дані з файлу
StreamReader sr = new StreamReader("DomophoneData.txt", Encoding.UTF8);
line = sr.ReadLine();
keyPass = Convert.ToInt16(line);
if (keyPass > 0) keyPass *= -1;
while (sr.Peek()!= -1) {
line = sr.ReadLine();
_apartments.Add(new Apartment_Doorphone(Convert.ToInt16(line), false, 0,this));
ApartmentsList.Items.Add("Квартира №" + line);
}
sr.Close();
} catch (Exception) {
MessageBox.Show("Ошибка чтения файла. Заданы данные по умолчанию.");
// дані по замовчуванню
for (short i = 1; i <= 10; i++) {
_apartments.Add(new Apartment_Doorphone(i, false, 0,this));
ApartmentsList.Items.Add("Квартира №" + i);
}
keyPass = -777;
}
Sound_1 = new TransmissionLines<Char>();
Sound_2 = new TransmissionLines<Char>();
processor = new Processor(keyPass);
Proces_1 = processor.PanelIn;
Proces_2 = processor.PanelOut;
commutator = new Switch(ref this._apartments,
processor.CommutatorOut, processor.CommutatorIn,
processor.ApartmentOut, processor.ApartmentIn,
Sound_1, Sound_2);
inputPanel = new External_Doorphone(Sound_2, Sound_1, Proces_2, Proces_1,this);
inputPanel.Show();
door = new Door_locking_device(ref this.pictureBox1);
processor.ClockOut.Signal += new SignalTransmission<DateTime>(ClockOut_Signal);
processor.HistoryOut.Signal += new SignalTransmission<User_History>(HistoryOut_Signal);
processor.DoorOut.Signal += new SignalTransmission<bool>(DoorOut_Signal);
ReadLog();
}
// ОБРОБКА ВХІДНИХ СИГНАЛІВ З ПРИСТРОЇВ
/// Обробка вхідного сигналу з процесора для Двері
public void DoorOut_Signal(object source, DataTransmissionLines<bool> options)
{
if (options.Data == true)
{
door.OpenDoor();
}
}
// Обробка вхідного сигналу з процесора для Пульта начальника охорони
void HistoryOut_Signal(object source, DataTransmissionLines<User_History> options)
{
if (options.Data!= null)
{
security.Rows.Insert(0, new string[] { options.Data.ApartNumber.ToString(), options.Data.OpenTime.ToString("HH:mm:ss - dd.MM.yyyy") });
}
}
public void WriteLog(short num,string str)
{
try
{
StreamWriter sw = new StreamWriter("Log.txt", append: true);
sw.WriteLine(num);
sw.WriteLine(str);
string Date = DateTime.Now.ToString();
sw.WriteLine(Date);
sw.Close();
}
catch (Exception)
{
MessageBox.Show("Ошибка.");
}
ReadLog();
}
public int NumberOfLines()
{
using (StreamReader r = new StreamReader("Log.txt"))
{
int i = 0;
while (r.ReadLine()!= null) { i++; }
{
r.Close();
return i;
}
}
}
public void ReadLog()
{
loglist.Clear();
try
{
StreamReader sr = new StreamReader("Log.txt");
for (int i = 0; i < NumberOfLines() / 3; i++)
{
int num = Convert.ToInt32(sr.ReadLine());
string ev = sr.ReadLine();
string date = sr.ReadLine();
loglist.Add(new logstruct(num, ev, date));
}
sr.Close();
}
catch (Exception)
{
MessageBox.Show("Ошибка.");
}
ToStruct();
}
public void ToStruct()
{
security.Rows.Clear();
if (loglist.Count!= 0)
security.Rows.Add(loglist.Count);
int counter = 0;
for (int i = loglist.Count; i >0; i--)
{
security.Rows[counter].Cells[0].Value = loglist[i-1].number;
security.Rows[counter].Cells[1].Value = loglist[i-1].myevent;
security.Rows[counter].Cells[2].Value = loglist[i-1].date;
counter++;
}
}
// Обробка вхідного сигналу з процесора - поточний внутрішній час
void ClockOut_Signal(object source, DataTransmissionLines<DateTime> options)
{
DateTime time = options.Data;
string t = time.ToString("dd.MM.yyyy HH:mm:ss");
this.Text = "Домофон:: " + t;
}
// ОБРОБКА ПОДІЙ ФОРМИ
private void ApartmentsList_DoubleClick(object sender, EventArgs e) {
}
private void ApartmentsList_KeyUp(object sender, KeyEventArgs e) {
}
private void ApartmentsList_DoubleClick_1(object sender, EventArgs e)
{
if (ApartmentsList.SelectedItems.Count!= 0)
{
_apartments[ApartmentsList.SelectedIndex].Show();
}
}
private void ApartmentsList_KeyUp_1(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter && ApartmentsList.SelectedItems.Count!= 0)
{
_apartments[ApartmentsList.SelectedIndex].Show();
}
}
private void button1_Click(object sender, EventArgs e)
{
FileStream fs = new FileStream("Log.txt", FileMode.Create);
fs.Close();
ReadLog();
}
}
}
External_Doorphone.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace Doorphone1._2_OOP_Severina
{
public partial class External_Doorphone: Form
{
[DllImport("user32", CharSet = CharSet.Auto)]
internal extern static bool PostMessage(IntPtr hWind, uint Msg, uint WParam, uint LParam);
[DllImport("user32", CharSet = CharSet.Auto)]
internal extern static bool ReleaseCapture();
const uint WM_SYSCOMMAND = 0x0112;
const uint DOMOVE = 0xF012;
/* Можливі сигнали ввідної панелі для процесора:
* >= 0 - ввели число
* < 0 - код ключа
**/
// звукові комунікації
private IComucation<Char> inSound;
private IComucation<Char> outSound;
// зв'язок з процесором
private IComucation<short> inProcess;
private IComucation<short> outProcess;
// панель комунікації
private ComunicationPanel _comunicationPanel;
///
// Конструктор класу CInputPanel
private Control_panel parentObject;
public External_Doorphone(IComucation<Char> InSound, IComucation<Char> OutSound,
IComucation<short> InProcess, IComucation<short> OutProcess, Control_panel cop)
{
InitializeComponent();
parentObject = cop;
// приєднуємо комунікації
inSound = InSound;
outSound = OutSound;
inProcess = InProcess;
outProcess = OutProcess;
// створюємо панель комунікаціїї
_comunicationPanel = new ComunicationPanel(ref this.microphone, ref this.dynamic);
// додаємо слухач подій для звукових комунікацій
// примітка: вказуємо які комунікації використовувати для звязку
_comunicationPanel.AddSignalListener(inSound, outSound);
// Підписуємося на отримання сигналів від процесора
inProcess.Signal += new SignalTransmission<short>(ProcInSignal);
}
// НАДСИЛАЄМО СИГНАЛИ ПРИСТРОЯМ
/// Надіслати сигнал процесору
private void CallProcessor(short data)
{
outProcess.Сhallenges = data;
}
// ОБРОБКА ВХІДНИХ СИГНАЛІВ З ПРИСТРОЇВ
/* Можливі сигнали процессору для ввідної панелі:
* >= 0 - відобразити число
* -1 - повідомлення про помилку
* -2 - повідомлення про те, що потрібно почекати
* -3 - повідомлення про те, що можна говорити
* -4 - очистити дисплей
* -5 - повідомлення про те, що двері відчинені
**/
/// Обробка сигналів, що прийшли від процесора
private void ProcInSignal(object source, DataTransmissionLines<short> options)
{
// якщо звичайне число, то відображаємо
if (options.Data >= 0)
{
display.Text = Convert.ToString(options.Data);
}
// якщо спеціальна команда то виконуємо необхідні дії
else
{
switch (options.Data)
{
// команда відобразити повідомлення про помилку
case -1:
this.display.Text = "Ошибка!";
break;
// команда відобразити повідомлення з проханням почекати
case -2:
this.display.Text = "Ожидание...";
break;
// команда відобразити повідомленя, що зв'язок встановлено
case -3:
this.display.Text = "Соединение установлено.";
this.dynamic.Enabled = false;
this.microphone.Enabled = true;
this.microphone.Focus();
break;
// команда очистити дисплей
case -4:
this.display.Text = "";
this.dynamic.Text = "";
this.microphone.Enabled = false;
this.dynamic.Enabled = false;
break;
// команда відобразити інформацію, що двері відчинені
case -5:
this.display.Text = "Дверь открыта.";
Melody._doorOpen.Play();
break;
// невідома команда
default:
break;
}
}
}
// ОБРОБКА ПОДІЙ ФОРМИ
private void but1_Click(object sender, EventArgs e)
{
Melody._btnClick.Play();
CallProcessor(1);
}
private void but2_Click(object sender, EventArgs e)
{
Melody._btnClick.Play();
CallProcessor(2);
}
private void but3_Click(object sender, EventArgs e)
{
Melody._btnClick.Play();
CallProcessor(3);
}
private void but6_Click(object sender, EventArgs e)
{
Melody._btnClick.Play();
CallProcessor(4);
}
private void but5_Click(object sender, EventArgs e)
{
Melody._btnClick.Play();
CallProcessor(5);
}
private void but4_Click(object sender, EventArgs e)
{
Melody._btnClick.Play();
CallProcessor(6);
}
private void but9_Click(object sender, EventArgs e)
{
Melody._btnClick.Play();
CallProcessor(7);
}
private void but8_Click(object sender, EventArgs e)
{
Melody._btnClick.Play();
CallProcessor(8);
}
private void but7_Click(object sender, EventArgs e)
{
Melody._btnClick.Play();
CallProcessor(9);
}
private void but0_Click(object sender, EventArgs e)
{
Melody._btnClick.Play();
CallProcessor(0);
}
private void butExit_Click(object sender, EventArgs e)
{
Melody._btnClick.Play();
CallProcessor(11);
}
private void butCall_Click(object sender, EventArgs e)
{
Melody._btnClick.Play();
CallProcessor(10);
}
private void logo_MouseDown(object sender, MouseEventArgs e)
{
ReleaseCapture();
PostMessage(this.Handle, WM_SYSCOMMAND, DOMOVE, 0);
}
private void key_Click(object sender, EventArgs e)
{
parentObject.WriteLog(0, "Открытие ключём");
CallProcessor(12);
}
}
}
Apartment_Doorphone.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace Doorphone1._2_OOP_Severina
{
/// <summary>
/// Клас Квартира
/// </summary>
public partial class Apartment_Doorphone: Form
{
[DllImport("user32", CharSet = CharSet.Auto)]
internal extern static bool PostMessage(IntPtr hWind, uint Msg, uint WParam, uint LParam);
[DllImport("user32", CharSet = CharSet.Auto)]
internal extern static bool ReleaseCapture();
const uint WM_SYSCOMMAND = 0x0112;
const uint DOMOVE = 0xF012;
/* Можливі сигнали квартири для процесора:
* 1 - відповісти
* 2 - поклати слухавку
* 3 - відкрити двері
**/
// панель комунікації
private ComunicationPanel comunication_Panel;
// номер цієї квартири
private short Number;
// поточний стан квартири
private Byte state_;
// чи заблоковано звук на трубці в цій квартирі
private bool isBlocked;
// зв'язок з процесором
private IComucation<short> inProcess;
private IComucation<short> outProcess;
// звукові комунікації
private IComucation<Char> inSound;
private IComucation<Char> outSound;
/// Конструктор класу CApartment
private Control_panel parentObject;
public Apartment_Doorphone(short _number, bool _isBlocked, Byte _state,Control_panel cop)
{
InitializeComponent();
parentObject = cop;
isBlocked = _isBlocked;
Number = _number;
State = _state;
this.Text = "Квартира #" + _number;
// створюємо панель комунікації
comunication_Panel = new ComunicationPanel(ref this.microphone, ref this.dynamic);
}
// Номер цієї квартири
public short GetNumber
{
get { return Number; }
}
/// Підключення квартири до комунікацій
public void SetCommunications(IComucation<Char> _inSound, IComucation<Char> _outSound,
IComucation<short> _inProcess, IComucation<short> _outProcess)
{
// приєднуємо комунікації
inSound = _inSound;
outSound = _outSound;
inProcess = _inProcess;
outProcess = _outProcess;
comunication_Panel.AddSignalListener(inSound, outSound);
inProcess.Signal += new SignalTransmission<short>(ProcSignal);
}
// Від'єднання квартири від комунікацій
public void DelCommunications()
{
// видаляємо слухачі подій
inProcess.Signal -= ProcSignal;
comunication_Panel.DelSignalListener();
// від'єднуємо комунікації
inSound = null;
outSound = null;
inProcess = null;
outProcess = null;
}
/* Можливі стани, в яких може знаходитися квартира
* 1 - Іде виклик
* 2 - Триває діалог
* 3 - Тиша, нічого не відбувається
**/
/// Зміна стану квартири
public Byte State
{
get { return state_; }
set
{
state_ = value;
switch (value)
{
// іде виклик
case 1:
if (isBlocked == false)
{
this.display.Text = "Идет вызов!";
Melody._apartCall.PlayLooping();
this.silence.Visible = true;
this.actively.Visible = false;
this.silence.Enabled = true;
this.open_door.Visible = false;
this.mute.Visible = true;
this.dynamic.Enabled = false;
}
else this.display.Text = "Идет вызов!";
this.silence.Visible = true;
this.actively.Visible = false;
this.silence.Enabled = true;
this.open_door.Visible = false;
this.mute.Visible = true;
this.dynamic.Enabled = false;
break;
// почався ділог
case 2:
this.display.Text = "Разговор.";
this.open_door.Visible = true;
this.mute.Visible = true;
this.silence.Visible = false;
this.silence.Enabled = false;
this.actively.Enabled = true;
this.actively.Visible = true;
this.open_door.Enabled = true;
this.microphone.Enabled = true;
break;
// все заспокоїлося
default:
this.display.Text = "Конец связи.";
this.open_door.Visible = false;
this.mute.Visible = true;
this.silence.Visible = true;
this.silence.Enabled = false;
this.actively.Enabled = false;
this.actively.Visible = false;
this.microphone.Enabled = false;
this.dynamic.Text = "";
break;
}
}
}
// НАДСИЛАЄМО СИГНАЛИ ПРИСТРОЯМ
/// Надсилаємо сигнал процесору
private void CallProcessor(short data)
{
if (outProcess!= null)
{
outProcess.Сhallenges = data;
}
}
// ОБРОБКА ВХІДНИХ СИГНАЛІВ З ПРИСТРОЇВ
/* Можливі сигнали процесора для квартири:
* 1 - почалася розмова
* 2 - припинилася розмова
**/
/// Обробка віходного сигналу з процесора
private void ProcSignal(object source, DataTransmissionLines<short> options)
{
switch (options.Data)
{
// почалася розмова
case 1:
State = 2;
break;
// припинилася розмова
case 2:
State = 0;
break;
// невідома команда
default:
break;
}
}
// ОБРОБКА ПОДІЙ ФОРМИ
// кнопка Відповісти
private void silence_Click(object sender, EventArgs e)
{
CallProcessor(1);
this.microphone.Focus();
Melody._apartCall.Stop();
Melody._pick_up.Play();
parentObject.WriteLog(Number, "Начало связи");
}
// кнопка Покласти слухавку
private void actively_Click(object sender, EventArgs e)
{
CallProcessor(2);
Melody._hang_up.Play();
this.open_door.Focus();
parentObject.WriteLog(Number, "Конец связи");
}
// кнопка Відчинити двері
private void open_door_Click(object sender, EventArgs e)
{
CallProcessor(3);
this.open_door.Focus();
parentObject.WriteLog(Number, "Открыто");
}
// кнопка Заблокувати звук
private void mute_Click(object sender, EventArgs e)
{
isBlocked =!isBlocked;
if (isBlocked == false && State == 1) Melody._apartCall.PlayLooping();
else if (isBlocked == true && State == 1) Melody._apartCall.Stop();
State = State;
}
private void Apartment_Doorphone_MouseDown(object sender, MouseEventArgs e)
{
ReleaseCapture();
PostMessage(this.Handle, WM_SYSCOMMAND, DOMOVE, 0);
}
}
}
Processor.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Doorphone1._2_OOP_Severina
{
/// <summary>
/// Клас процесора домофона
/// </summary>
class Processor
{
/* КОДИ МОЖЛИВИХ ВИХІДНИХ СИГНАЛІВ
* Можливі сигнали процесора для ввідної панелі:
* >= 0 - відобразити число
* -1 - повідомлення про помилку
* -2 - повідомлення про те, що потрібно почекати
* -3 - повідомлення про те, що можна говорити
* -4 - очистити дисплей
* -5 - повідомлення про те, що двері відчинені
*
* Можливі сигнали процесора для комутатора:
* > 0 - встановити зв'язок з квартирою під таким номером
* 0 - розірвати поточний зв'язок
*
* Можливі сигнали процесора для квартири:
* 1 - почалася розмова
* 2 - припинилася розмова
*
* Можливі сигнали процесора для замка:
* true - відкрити
*
* КОДИ МОЖЛИВИХ ВХІДНИХ СИГНАЛІВ
* Можливі сигнали ввідної панелі для процесора:
* >= 0 - ввели число
* < 0 - код ключа
*
* Можливі сигнали комутатора для процесора:
* 0 - помилка
* 1 - успіх
*
* Можливі сигнали квартири для процесора:
* 1 - відповісти
* 2 - поклати слухавку
* 3 - відкрити двері
*
* Можливі сигнали замка для процесора:
* немає зворотнього зв'язку
**/
// можливі внутрішні стани процесору домофона
private enum state { inputNumber, commutation, commutated, decommutation, error }
// зв'язок з ввідною панеллю
private IComucation<short> inExternal_doorphone;
private IComucation<short> outExternal_doorphone;
// зв'язок з комутатором
private IComucation<short> inCommutator;
private IComucation<short> outCommutator;
// зв'язок з квартирою
private IComucation<short> _apartmentInCommunications;
private IComucation<short> _apartmentOutCommunications;
// зв'язок з замком
private IComucation<bool> _doorOutCommunications;
// дріт для передачі поточного часу
private IComucation<DateTime> _clockCommunications;
// дріт для передачі історії відривання дверей
private IComucation<User_History> _historyCommunications;
// правильний код магнітного ключа
private short _authCode;
// поточний номер квартири, набраний на ввідній панелі
private short _apartNumber;
// поточний стан процесору
private state _trueState;
// історія відкривання дверей з квартир
private List<User_History> _history;
// попередній час, отриманий з внутрішнього годинника
private DateTime _prevData;
// внутрішній годинник
private Clock clock;
// годинник для відображення повідомлення про зачинення дверей
private Clock doorClock;
///
/// <summary>
/// Конструктор класу CProcessor
/// </summary>
/// <param name="authCode">Правильний код ключа</param>
public Processor(short authCode) {
_history = new List<User_History>();
_authCode = authCode;
_apartNumber = 0;
_trueState = state.inputNumber;
clock = new Clock(ClockFunction);
clock.Speed = 1;
clock.Start();
_prevData = clock.GetTime();
doorClock = new Clock(DoorMessage);
doorClock.Speed = 1;
// створюємо необхідні для роботи комунікації
inExternal_doorphone = new TransmissionLines<short>();
outExternal_doorphone = new TransmissionLines<short>();
inCommutator = new TransmissionLines<short>();
outCommutator = new TransmissionLines<short>();
_apartmentInCommunications = new TransmissionLines<short>();
_apartmentOutCommunications = new TransmissionLines<short>();
_clockCommunications = new TransmissionLines<DateTime>();
_historyCommunications = new TransmissionLines<User_History>();
_doorOutCommunications = new TransmissionLines<bool>();
// підписуємося на потрібні для роботи події
// щоб мати зв'язок з іншими приладами системи
inExternal_doorphone.Signal += new SignalTransmission<short>(PanelInSignal);
inCommutator.Signal += new SignalTransmission<short>(CommutatorInSignal);
_apartmentInCommunications.Signal += new SignalTransmission<short>(ApartmentInSignal);
}
/// <summary>
/// Функція обробки поточного часу в системі
/// </summary>
private void ClockFunction()
{
DateTime time = clock.GetTime();
// надсилаємо сигнал про зміну часу в системі
_clockCommunications.Сhallenges = time;
// якщо змінився день, необхідно відіслати історію
// відривання дверей на пульт начальника охорони
if (_prevData.Day!= time.Day)
{
foreach (User_History he in _history)
{
_historyCommunications.Сhallenges = he;
}
_history.Clear();
}
_prevData = time;
}
// НАДСИЛАЄМО СИГНАЛИ ПРИСТРОЯМ
/// <summary>
/// Функція посилає сигнал Ввідній панелі коли треба видалити повідомлення про те,
/// що двері відчинені. Зупиняє відповідний таймер
/// </summary>
private void DoorMessage()
{
CallPanel(-4);
doorClock.Stop();
}
/// <summary>
/// Функція надсилає сигнал Ввідній панелі
/// </summary>
/// <param name="data">Дані для передачі</param>
private void CallPanel(short data)
{
outExternal_doorphone.Сhallenges = data;
}
/// <summary>
/// Функція надсилає сигнал Комутатору
/// </summary>
/// <param name="data">Дані для передачі</param>
private void CallCommutator(short data)
{
outCommutator.Сhallenges = data;
}
/// <summary>
/// Функція надсилає сигнал квартирі, з якою є з'єднання на даний момент
/// </summary>
/// <param name="data">Дані для передачі</param>
private void CallApartment(short data)
{
_apartmentOutCommunications.Сhallenges = data;
}
/// <summary>
/// Функція надсилає сигнал замку на двері
/// </summary>
/// <param name="data">Дані для передачі</param>
private void CallDoor(bool data)
{
_doorOutCommunications.Сhallenges = data;
}
// ОБРОБКА ВХІДНИХ СИГНАЛІВ З ПРИСТРОЇВ
/// <summary>
/// Обробка вхідного сигналу з ввідної панелі
/// </summary>
/// <param name="source">Дріт, по якому прийшов сигнал</param>
/// <param name="args">Дані, що надійшли</param>
private void PanelInSignal(object source, DataTransmissionLines<short> options)
{
switch (options.Data)
{
// кнопка Вызов
case 10:
// якщо ми знаходимося у стані набору номеру квартири
// і номер вже набрано, то починаємо процес комутації
if (_trueState == state.inputNumber && _apartNumber!= 0)
{
_trueState = state.commutation;
CallCommutator(_apartNumber);
}
break;
// кнопка Сброс
case 11:
// якщо ми знаходимося у стані комутації, тобто налагоджений зв'язок
// між процесором і квартирою, то починаємо процес декомутації
if (_trueState == state.commutated)
{
_trueState = state.decommutation;
CallApartment(2);
CallCommutator(0);
}
// якщо ми знаходимося у стані помилки, то переходимо у стан набору номеру
else if (_trueState == state.error)
{
_trueState = state.inputNumber;
}
// очищуємо введені раніше дані
_apartNumber = 0;
CallPanel(-4);
break;
case 12:
CallDoor(true);
doorClock.Start();
CallPanel(-5);
break;
default:
// кнопки з цифрами
// якщо ми знаходимося у стані набору номеру
// нарощуємо номер на відповідне число
if (options.Data >= 0 && options.Data <= 9 && _trueState == state.inputNumber)
{
_apartNumber *= 10;
_apartNumber += options.Data;
// проте номер квартири в загальному випадку може бути більшим від нуля
// примітка: у signed типах даних число при переході через максимальне значення стає від'ємним
// оскільки займається знаковий біт, що дозволяє використання такої умови
if (_apartNumber > 0) CallPanel(_apartNumber);
else
{
_trueState = state.error;
CallPanel(-1);
}
}
// невідома кнопка
else if (_trueState!= state.commutated)
{
_trueState = state.error;
CallPanel(-1);
}
break;
}
}
/// <summary>
/// Обробка вхідного сигналу з комутатора
/// </summary>
/// <param name="source">Дріт, по якому прийшов сигнал</param>
/// <param name="args">Дані, що були передані</param>
private void CommutatorInSignal(object source, DataTransmissionLines<short> options)
{
switch (options.Data)
{
// помилка
case 0:
// переходимо в стан помилки
CallPanel(-1);
_trueState = state.error;
break;
// усппіх
case 1:
// якщо ми знаходимося у стані очікування комутації,
// то переходимо в стан комутації і починаємо діалог
// Примітка: сповільнюємо плин внутрішньго часу до реального
if (_trueState == state.commutation)
{
_trueState = state.commutated;
clock.Speed = 1;
CallPanel(-2);
}
// якщо ми знаходимося у стані очікування декомутації,
// то переходимо в стан набору номера
// Примітка: пришвидщуємо плин часу у 600 разів
else if (_trueState == state.decommutation)
{
_apartNumber = 0;
_trueState = state.inputNumber;
clock.Speed = 1;
CallPanel(-4);
}
break;
// невідомий сигнал
default: break;
}
}
/// <summary>
/// Обробка вхідного сигналу з квартири
/// </summary>
/// <param name="source">Дріт, по якому прийшов сигнал</param>
/// <param name="args">Дані, що були передані</param>
private void ApartmentInSignal(object source, DataTransmissionLines<short> options)
{
switch (options.Data)
{
// кнопка Ответить
case 1:
// про всяк випадок перевіряємо, що зв'язок з квартирою встановлено
if (_trueState == state.commutated)
{
// переходимо у стан діалогу
CallPanel(-3);
CallApartment(1);
}
break;
// кнопка Положить трубку
case 2:
// про всяк випадок перевіряємо, що зв'язок з квартирою встановлено
if (_trueState == state.commutated)
{
// починаємо процес декомутації
_trueState = state.decommutation;
CallCommutator(0);
}
break;
// кнопка открыть дверь
case 3:
// про всяк випадок перевіряємо, що зв'язок з квартирою встановлено
if (_trueState == state.commutated)
{
// записуємо в історію, що з цієї квартири було відкрио двері
/// _history.Add(new CHistoryEntry(_apartNumber, _clock.GetTime()));
// починаємо процес декомутації
_trueState = state.decommutation;
CallCommutator(0);
// відчиняємо двері
CallDoor(true);
doorClock.Start();
CallPanel(-5);
}
break;
// невідома команда
default:
break;
}
}
// ЗОВНІШНІ ІНТЕРФЕЙСНІ ВХОДИ І ВИХОДИ ПРОЦЕСОРА
public IComucation<short> CommutatorIn
{
get { return inCommutator; }
}
public IComucation<short> CommutatorOut
{
get { return outCommutator; }
}
public IComucation<short> ApartmentIn
{
get { return _apartmentInCommunications; }
}
public IComucation<short> ApartmentOut
{
get { return _apartmentOutCommunications; }
}
public IComucation<short> PanelIn
{
get { return inExternal_doorphone; }
}
public IComucation<short> PanelOut
{
get { return outExternal_doorphone; }
}
public IComucation<DateTime> ClockOut
{
get { return _clockCommunications; }
}
public IComucation<User_History> HistoryOut
{
get { return _historyCommunications; }
}
public IComucation<bool> DoorOut
{
get { return _doorOutCommunications; }
}
}
}
Switch.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Doorphone1._2_OOP_Severina
{
public class Switch
{
/* Можливі сигнали комутатора для процесора:
* 0 - помилка
* 1 - успіх
**/
// зв'язок з процесором
private IComucation<short> inProcess;
private IComucation<short> outProcess;
// зв'язок з квартирою
private IComucation<short> inApartment;
private IComucation<short> outApartment;
// звукові комунікації
private IComucation<Char> inSound;
private IComucation<Char> outSound;
// квартири, в яких встановленій домофон
private List<Apartment_Doorphone> apartments;
// стан, що вказує чи здійснено на даний момент комутацію
private bool isCommutated;
// індекс поточної квартири у списку _apartments
private short apart_index;
// Конструтор класу CCommutator
public Switch(ref List<Apartment_Doorphone> aparts, IComucation<short> inProcCom, IComucation<short> outProcCom,
IComucation<short> inProcComForApart, IComucation<short> outProcComForApart,
IComucation<Char> inVoiceCom, IComucation<Char> outVoiceCom)
{
inProcess = inProcCom;
outProcess = outProcCom;
inSound = inVoiceCom;
outSound = outVoiceCom;
apartments = aparts;
inApartment = inProcComForApart;
outApartment = outProcComForApart;
// підписуємося на отримання сигналів від процесора
inProcess.Signal += new SignalTransmission<short>(inProcess_Signal);
isCommutated = false;
apart_index = 0;
}
// Розірвати поточний зв'язок
private void BreakTrueCommunication()
{
if (isCommutated)
{
apartments[apart_index].State = 0;
apartments[apart_index].DelCommunications();
isCommutated = false;
}
CallProcessor(1);
}
/// Строрити новий зв'язок
private void CreateNewCommunication(short apartNumber)
{
// шукаємо індекс квартири в списку підключених до домофона квартир
int index = apartments.FindIndex(delegate(Apartment_Doorphone ap)
{
return ap.GetNumber == apartNumber;
});
// якщо на даному єтапі вже існує зв'язок з квартирою
// а у списку підключених до домофона квартир немає потрібної
// повертаємо код помилки
if (isCommutated ||
index == -1)
{
CallProcessor(0);
return;
}
// встановлюємо комунікацію з квартирою
apartments[index].SetCommunications(inSound, outSound, inApartment, outApartment);
apartments[index].State = 1;
apartments[index].Show();
isCommutated = true;
apart_index = (short)index;
CallProcessor(1);
}
// НАДСИЛАЄМО СИГНАЛИ ПРИСТРОЯМ
/// <summary>
/// Надіслати сигнал процесору
/// </summary>
/// <param name="data">Дані що необхідно надіслати</param>
private void CallProcessor(short data)
{
outProcess.Сhallenges = data;
}
/* Можливі сигнали процесора для комутатора:
* > 0 - встановити зв'язок з квартирою під таким номером
* 0 - розірвати поточний зв'язок
**/
/// <summary>
/// Обробка вхідних сигналів з процесора
/// </summary>
/// <param name="source">Дріт, яким надійшов сигнал</param>
/// <param name="args">Дані, що були передані</param>
private void inProcess_Signal(object source, DataTransmissionLines<short> options)
{
switch (options.Data)
{
// Розірвати поточний зв'язок
case 0:
BreakTrueCommunication();
break;
// створити новий зв'язок
default:
CreateNewCommunication(options.Data);
break;
}
}
}
}
IComunication.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Doorphone1._2_OOP_Severina
{
//Функція-обробник події. Викликається коли був переданий сигнал.
//Generic_Type - Тип даних
// source - Об'єкт дроту, що викликав подію.
//options - Дані, що передаються дротом.
public delegate void SignalTransmission<Generic_Type>(object source, DataTransmissionLines<Generic_Type> options);
//Лінія передачі сигналів
//Generic_Type - Тип даних
public interface IComucation<Generic_Type>
{
event SignalTransmission<Generic_Type> Signal;
Generic_Type Сhallenges { set; }
}
}
DataTransmissionLines.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Doorphone1._2_OOP_Severina
{
//Клас даних, що передаються иниями передач
public class DataTransmissionLines<Generic_Type>
{
private Generic_Type data; //Generic_Type - тип данних; data - дані, що передаються
public DataTransmissionLines(Generic_Type _data) //Перевантажений конструктор класу
{
data = _data;
}
public Generic_Type Data // Функція доступу до поля класу "дані"
{
get { return data; }
}
}
}
ComunicationPanel.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace Doorphone1._2_OOP_Severina
{
public class ComunicationPanel
{
// звукові комунікації
private IComucation<Char> inSound;
private IComucation<Char> outSound;
// поля, якими управляє панель
private TextBox Microphone;
private TextBox Dynamic;
// Конструктор класу CComunicationPanel
public ComunicationPanel(ref TextBox microphone_, ref TextBox dynamic_) {
Microphone = microphone_;
Dynamic = dynamic_;
Microphone.KeyUp +=new KeyEventHandler(microphone_KeyUp);
}
// Додаємо слухач подій
public void AddSignalListener(IComucation<Char> input, IComucation<Char> output)
{
// підключаємо комунікації
inSound = input;
outSound = output;
// підписуємося на подію вхідної комунікації
inSound.Signal += new SignalTransmission<char>(inSignal);
}
/// Видаляємо слухачі подій
public void DelSignalListener()
{
// відписуємося від слухання події вхідної комунікації
inSound.Signal -= inSignal;
// відключаємо комунікації
inSound = null;
outSound = null;
}
// Обробка натискання клавіші при активному вікні мікрофону
private void microphone_KeyUp(object sender, KeyEventArgs e)
{
if (Microphone.Text.Length > 0) outSignal(Microphone.Text[0]);
Microphone.Text = "";
}
// Обробка вхідного сигналу
private void inSignal(object source, DataTransmissionLines<char> options)
{
Dynamic.Text += options.Data;
}
// Формування вихідного потоку даних
private void outSignal(Char data)
{
if (inSound!= null)
{
outSound.Сhallenges = data;
}
}
}
}
Door_locking_device.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace Doorphone1._2_OOP_Severina
{
// Клас, що моделює двері з доводчиком та замикаючим пристроем.
class Door_locking_device
{
private Timer _timer; // таймер, що моделює доводчик
private PictureBox door;
// Конструктор класу CDoor
public Door_locking_device(ref PictureBox door_)
{
door = door_;
_timer = new Timer();
_timer.Interval = 3000;
_timer.Tick += new EventHandler(_timer_Tick);
}
// Функція моделює роботу доводчика. Закриває двері через встановлений проміжок часу.
private void _timer_Tick(object sender, EventArgs e)
{
door.Image = Properties.Resources.замок1;
_timer.Stop(); // доводчик завершив роботу
}
// Функція відкривання двері.
public void OpenDoor()
{
door.Image = Properties.Resources.двери1;
_timer.Start(); // доводчик починає роботу
}
}
}
User_History.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Doorphone1._2_OOP_Severina
{
/// Запис в історіїї відкривання дверей
public class User_History
{
private short _apartNumber; // номер квартири, з якої відкрили двері
private DateTime openTime; // час, коли відкрили двері
// Конструктор класу CHistoryEntry
public User_History(short apartNumber, DateTime _openTime)
{
_apartNumber = apartNumber;
openTime = _openTime;
}
// Номер квартири, з якої відкрили двері
public short ApartNumber { get { return _apartNumber; } }
// Час, коли було відкрито двері
public DateTime OpenTime { get { return openTime; } }
}
}
Melody.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Media;
namespace Doorphone1._2_OOP_Severina
{
public static class Melody
{
public static SoundPlayer _btnClick = new SoundPlayer(Properties.Resources.BtnBeep);
public static SoundPlayer _doorOpen = new SoundPlayer(Properties.Resources.Open);
public static SoundPlayer _apartCall = new SoundPlayer(Properties.Resources.Sound);
public static SoundPlayer _pick_up = new SoundPlayer(Properties.Resources.Activity);
public static SoundPlayer _hang_up = new SoundPlayer(Properties.Resources.Activity);
}
}
Clock.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace Doorphone1._2_OOP_Severina
{
class Clock
{
// сигнатура call-back функції
public delegate void funct();
private funct _callBack; // call-back функція
private Timer _timer; // таймер
private DateTime _time; // поточний внутрішній час
/// Швидкість зміни внутрішнього часу
public short Speed { get; set; }
/// Конструктор класу CClock
public Clock(funct callBack) {
_callBack = callBack;
_time = DateTime.Now;
_timer = new Timer();
_timer.Interval = 1000;
_timer.Tick += new EventHandler(_timer_Tick);
_timer.Start();
}
// Зміна внутрішнього часу
private void _timer_Tick(object sender, EventArgs e) {
_time = _time.AddSeconds(Speed);
_callBack();
}
// Запустити годинник
public void Start() {
_timer.Start();
}
// Зупинити годинник
public void Stop() {
_timer.Stop();
}
/// Отримати поточний час
public DateTime GetTime() {
return _time;
}
}
}
Висновки
В ході виконання курсової роботи було досліджено принцип побудови та роботи домофону. Спроектовано та реалізовано модель програмного забезпечення домофону, дотримуючись принципів ООП.
Інтерфейс програми складається з 3-х видів вікон: ввідна панель, що розташована на вході до під’їзду будинку, абонентський пристрій, що знаходиться у квартирі та пульт охорони, в якому ми можемо прослідкувати історію відвідувань квартир, та зображення – ідентифікатор стану дверей.
На абонентському пристрої, що знаходиться у квартирі було створено кнопки «ВЫКЛЮЧИТЬ ЗВУК», «ОТКРЫТЬ». Реалізовані поля «МИКРОФОН» і «ДИНАМИК», за допомогою яких гість та мешканець можуть обмінюватись повідомленнями, такий процес імітує розмову, яка відбувається у реальному домофоні.
При натисканні мешканцем на кнопку «ОТКРЫТЬ» - двері відчиняються і в головному вікні зображення, що сигналізує про стан зачинених дверей, змінюється назображення відкритих дверей. Через деякий час зміни зображень відбуваються у зворотньому порядку.
При натисканні на кнопку «ВЫКЛЮЧИТЬ ЗВУК», звук вхідного дзвінка вимикається.
Відомості про відвідини будинку записуються в історії відвідин і відображають у головному вікні.
Таким чином, були виконані усі пункти поставленої задачі та реалізована модель програмного забезпечення вбудованого мікропроцесора домофону.
11.Список літератури
1) http://ru.wikipedia.org/wiki/Домофон
2) http://www.safe-systems.ru/sostav-domofona.html
3) Шилдт, Герберт. С# 3.0: Полное руководство.: Пер. с англ. — М.: 000 "И.Д. Вильямс", 2010. — 992 с.
4) Mickey Gousset, Brian Keller, Ajoy Krishnamoorthy, Martin Woodward. Professional Application Lifecycle Management with Visual Studio® 2010 – Canada: Wiley Publishing, Inc., 2010. – 655 с.
Додатки
Додаток 1
Діаграма варіантів використання.
Додаток 2
Діаграма класів.