Actions

Dual Display station - software description

From Zenitel Wiki

Revision as of 10:42, 14 August 2007 by Hege (talk) (Message commands for Master Station DualDisplay)

Coding conventions

Software configuration: Using #define settings

By setting or removing #define precompiler statements, pieces of code can be easily added or removed. One example of this is enabling or disabling all debug functionality in a release:

#define DEBUG_ENABLED

All such statements are collected in the top of the file <main.h>.

Loading C strings from FLASH

The IAR C compiler for AVR processors is by default configured for reading strings from DATA segment (RAM). This requires the compiler to copy the strings from FLASH to RAM during initialisation/cstartup. After that, the stings can be used in normal "ANSI C style":

printf("Hello World!");

Loading the strings to RAM is required for the strings to be manipulated during run-time. But by using special-designed functions instead of printf(), this can be avoided. Printing strings is done with a separate function, which loads text from FLASH only.

This could be achieved by pre-defining all strings:

BYTE flash *string_example = "Hello World!";

... and it would be used this way:

print_string(string_example);

This is not an easy code to read. Instead, the string could be used the normal way by making a few configurations:

  • The CSTR segment containing strings is configured as a CODE segment (FLASH) in the linker file <lnk3s4kb_MODIFIED.xcl>.
  • The function using the strings must cast the pointer from RAM to FLASH type. This is because the pointer is actually pointing at the correct address in FLASH, but the compiler still believes it is a RAM pointer. For example:

void print_string(BYTE *string_temp)

{
BYTE flash *string;
string = (BYTE flash *)(WORD)string_temp;
...
}

"string_temp" is an invalid RAM pointer, but the FLASH pointer "string" can now be used normally instead.

  • In some cases, pre-defined strings are preferred if a string is used multiple times. But now the problem is vice versa: The function is expecting a RAM pointer, but the pointer is in this case actually FLASH. So we have to cast the pointer to RAM to be able to compile the code:

BYTE flash *string_example = "Hello World!"; print_string( (BYTE *)(WORD)string_example );


Code description

General program structure

After initialisation, the program enters an infinite loop in which all processes are executed. Some processes are executed every 10ms, while others run continuously.

To generate the 10ms intervals, TIMER0 interrupt is used. It increments a counter by 1 every 10ms. The main loop checks this counter, and executes the required processes if it is greater than 0. Also, the counter is decremented by 1.

The process states and timers are kept within the separate processes, and no high-level FSM is used. Global status flags are held in a bit-struct register "status".

Keyboard scanning

Located in file: <main.c>
Entry function: scan_matrix_keyboard()

Hardware

The station keyboard is an 8x4 matrix connected to PB1-PD3 (outputs) and PD4-PD7 (inputs).

Debounce routine

For each of the 32 keys there is a debounce register of 8 bits:

Key status: 1 bit
Key counter up: 3 bits
Key counter down: 4 bits

The keyboard scanning process is executed by 10ms intervals. For a keypress to be accepted, the key must be held for a specified amount of 10ms counts, counted by the up-counter. The key code is then sent to the AlphaCom digit sending process. Similarly, a key release also requires the key to be released for some time, counted by the down-counter. The key code 0x80 is then sent, telling the digit process to stop sending.

Key codes

The 32 keys are mapped this way:

Position Key name: Key code: (1) Comment
COL1, ROW1 KEY_1 0x01  
COL1, ROW2 KEY_2 0x02  
COL1, ROW3 KEY_3 0x03  
COL1, ROW4 KEY_MENU 0x2a DAK 20
COL2, ROW1 KEY_4 0x04  
COL2, ROW2 KEY_5 0x05  
COL2, ROW3 KEY_6 0x06  
COL2, ROW4 KEY_UPARROW 0x2b DAK 21
COL3, ROW1 KEY_7 0x07  
COL3, ROW2 KEY_8 0x08  
COL3, ROW3 KEY_9 0x09  
COL3, ROW4 KEY_DOWNARROW 0x2c DAK 22
COL4, ROW1 KEY_M 0x35 (2)
COL4, ROW2 KEY_0 0x0a  
COL4, ROW3 KEY_C 0x5f (3)
COL4, ROW4 KEY_NAME 0x2d DAK 23
COL5, ROW1 KEY_DAK1   Key codes depend on which DAK page is currently displayed. (4)
COL5, ROW2 KEY_DAK2   "
COL5, ROW3 KEY_DAK3   "
COL5, ROW4 KEY_DAK4   "
COL6, ROW1 KEY_DAK5   "
COL6, ROW2 KEY_DAK6   "
COL6, ROW3 KEY_DAK7   "
COL6, ROW4 KEY_DAK8   "
COL7, ROW1 KEY_DAK9   "
COL7, ROW2 KEY_DAK10   "
COL7, ROW3      
COL7, ROW4 KEY_PRIVACY (No code) Other signalling.
COL8, ROW1      
COL8, ROW2      
COL8, ROW3      
COL8, ROW4      

(1): For the complete list of key codes and their signalling, see chapter [4.3 AlphaCom digit sending].

(2): The M-key code is not sent upon keypress. Instead, the global status "status.mkey" is set. Handset M-key will also set "status.mkey" when pressed.

(3): The C-key code is not sent upon keypress. Instead, the global status "status.ckey" is set.

(4): The DAK key codes depend on which DAK page is currently displayed on the upper LCD. There are 50 DAK key codes available, and by adding a prefix code (0x74) this amount is doubled. The key codes are according to the CRM IV station standard, which defines the following table:

DAK page displayed: DAK keys: Key codes: Comment
0 D0-D9 0x20-0x29  
1 D10-D19 0x0a-0x13  
2 D20-D29 0x2a-0x33 Menu keys
3 D30-D39 0x60-0x69  
4 D40-D49 0x6a-0x73  
5 D50-D59 (0x74+) 0x20-0x29  
6 D60-D69 (0x74+) 0x0a-0x13  
7 D70-D79 (0x74+) 0x2a-0x33  
8 D80-D89 (0x74+) 0x60-0x69  
9 D90-D99 (0x74+) 0x6a-0x73  

Other input pins

There are some extra inputs that are also scanned by the keyboard process:

  • PE2: C-D loop sense (conversation/station LED)
  • PC1: Handset OFF
  • PC0: Handset M-key

AlphaCom digit sending

Located in file: <main.c>
Entry functions: <br\> digit_process()<br\>put_digit_in_buffer()

Digit transmission is processed by the function "digit_process()". The digits are sent by two signals:

  • Tone frequencies
* Sent on C-D wires (microphone). Polarity is inverted first.
* Frequency range: 400Hz - 4000Hz.
  • Current-signals
* Sent on A-B wires (speaker).
* Signal levels: (Note: The station itself consumes 10mA (1) at all times, which is included in the values below)
Handset OFF: 10mA (1)
Handset ON: 13mA
M-key: 24mA
C-key: 50mA

(1): Due to high power consumption, the station is currently set to consume 13mA at all times. This is equal to "Handset ON" signal (13mA), and the "Handset OFF" signal (10mA) can never be signalled. This is configured in hardware, and does not affect the software.

Tone signalling (C-D wires)

Tones are transmitted through the following processor output pins:

  • PE2 (TO): Tone frequency signal.
  • PB4 (ID): ID signal. Set high when sending tone.

The ID pin is held high when sending a tone. The tone frequency is then set on the TO pin. When not sending a tone, the ID pin is low. The TO pin is then used for reflecting the privacy status of the station, determined by the flag "status.privacy": Low level means Open and high level means Private.

Current signalling (A-B wires)

A current-signal is always present on the A-B wires. The processor has three output lines controlling the current:

  • PB7 (CP): C-key current
  • PB6 (MP): M-key current
  • PB5 (ONH): Handset ON current

In idle, the station signals "Handset ON" current (13mA). By pressing M- or C-key, or by lifting the handset, the current is changed accordingly. In software, this is indicated to <br\>"digit_process()" by the status flags "status.hsoff", "status.mkey" and "status.ckey", and does not require a key code to be processed through the key code buffer (see below).

Only one of the current levels may be signalled at a time, except short periods during transitions between current levels. Because there are several inputs specifying the current level, the final value is determined by the following priority:

1. "status.ckey" flag
2. Current level specified by a key code - see "Key codes" below.
3. "status.mkey" flag
4. "status.hsoff" flag (station is in idle, with handset ON or OFF)

Key codes

Key codes are sent through a key code buffer by the function "put_digit_in_buffer()". This buffer is read by "digit_process()", which then sends both tone and current signals according to the key code. Digits will be held for a minimum time, and released when a new key code is available in the buffer. Key codes with the bit "0x80" set will stop the digit transmission.

AlphaCom line signalling:

Frequency:<br\>(C-D wires) Current:<br\>(A-B wires) Key code: Key Comment
500 Hz (no change) 0x00 Digit 0  
700 Hz (no change) 0x01 Digit 1  
900 Hz (no change) 0x02 Digit 2  
1100 Hz (no change) 0x03 Digit 3  
1300 Hz (no change) 0x04 Digit 4  
1500 Hz (no change) 0x05 Digit 5  
1700 Hz (no change) 0x06 Digit 6  
1900 Hz (no change) 0x07 Digit 7 The current-signal is not affected by the key code.

In station idle it will be "Handset ON".

2100 Hz (no change) 0x08 Digit 8 "
2300 Hz (no change) 0x09 Digit 9 "
400 Hz (no change) 0x0a DAK 10 "
2600 Hz (no change) 0x0b DAK 11 "
450 Hz (no change) 0x0c DAK 12 "
2900 Hz (no change) 0x0d DAK 13 "
600 Hz (no change) 0x0e DAK 14 "
3200 Hz (no change) 0x0f DAK 15 "
800 Hz (no change) 0x10 DAK 16 "
3600 Hz (no change) 0x11 DAK 17 "
1000 Hz (no change) 0x12 DAK 18 "
4000 Hz (no change) 0x13 DAK 19 "
500 Hz M-key 0x20 DAK 0  
700 Hz M-key 0x21 DAK 1  
900 Hz M-key 0x22 DAK 2  
1100 Hz M-key 0x23 DAK 3  
1300 Hz M-key 0x24 DAK 4  
1500 Hz M-key 0x25 DAK 5  
1700 Hz M-key 0x26 DAK 6  
1900 Hz M-key 0x27 DAK 7  
2100 Hz M-key 0x28 DAK 8  
2300 Hz M-key 0x29 DAK 9  
400 Hz M-key 0x2a DAK 20  
2600 Hz M-key 0x2b DAK 21  
450 Hz M-key 0x2c DAK 22  
2900 Hz M-key 0x2d DAK 23  
600 Hz M-key 0x2e DAK 24  
3200 Hz M-key 0x2f DAK 25  
800 Hz M-key 0x30 DAK 26  
3600 Hz M-key 0x31 DAK 27  
1000 Hz M-key 0x32 DAK 28  
4000 Hz M-key 0x33 DAK 29  
500 Hz Handset OFF 0x40 Digit 0 The hardware does not support handset yet, and can only signal "Handset ON" current (13mA) or higher.

These key codes will be sent with "Handset ON" current instead.

700 Hz Handset OFF 0x41 Digit 1 "
900 Hz Handset OFF 0x42 Digit 2 "
1100 Hz Handset OFF 0x43 Digit 3 "
1300 Hz Handset OFF 0x44 Digit 4 "
1500 Hz Handset OFF 0x45 Digit 5 "
1700 Hz Handset OFF 0x46 Digit 6 "
1900 Hz Handset OFF 0x47 Digit 7 "
2100 Hz Handset OFF 0x48 Digit 8 "
2300 Hz Handset OFF 0x49 Digit 9 "
400 Hz Handset OFF 0x4a   "
2600 Hz Handset OFF 0x4b   "
450 Hz Handset OFF 0x4c   "
2900 Hz Handset OFF 0x4d   "
600 Hz Handset OFF 0x4e   "
3200 Hz Handset OFF 0x4f   "
800 Hz Handset OFF 0x50   "
3600 Hz Handset OFF 0x51   "
1000 Hz Handset OFF 0x52   "
4000 Hz Handset OFF 0x53   "
500 Hz C-key 0x60 DAK 30  
700 Hz C-key 0x61 DAK 31  
900 Hz C-key 0x62 DAK 32  
1100 Hz C-key 0x63 DAK 33  
1300 Hz C-key 0x64 DAK 34  
1500 Hz C-key 0x65 DAK 35  
1700 Hz C-key 0x66 DAK 36  
1900 Hz C-key 0x67 DAK 37  
2100 Hz C-key 0x68 DAK 38  
2300 Hz C-key 0x69 DAK 39  
400 Hz C-key 0x6a DAK 40  
2600 Hz C-key 0x6b DAK 41  
450 Hz C-key 0x6c DAK 42  
2900 Hz C-key 0x6d DAK 43  
600 Hz C-key 0x6e DAK 44  
3200 Hz C-key 0x6f DAK 45  
800 Hz C-key 0x70 DAK 46  
3600 Hz C-key 0x71 DAK 47  
1000 Hz C-key 0x72 DAK 48  
4000 Hz C-key 0x73 DAK 49  
(ID, but no freq) M-key 0x34   Special purpose.
(ID, but no freq) Handset ON 0x14   "
(ID, but no freq) Handset OFF 0x54   "
(ID, but no freq) C-key 0x74   "
  M-key 0x35 M-key  
  C-key 0x5f C-key  

AlphaCom display messages

Located in file: <main.c>

Similar to previous AlphaCom stations, display messages are received by the processor through UART interrupts. The messages are decoded with function "parse_message()".

Message commands for Master Station DualDisplay

Command Description
0x01 (modified) Display commands. Some commands for previous stations not supported.
0x02 Print bytes as display text or store as CGRAM data (character generator RAM).
0x03 Print bytes as display text or store as CGRAM data, but interpret values in the range 0x10-0x1f as control codes.
0x04 Load the main address register with the two first data bytes of message if the processor has received two pulses on the C-D loop sense pin within 700ms. This is a double flash in the station LED and the sequence on the C-D loop sense pin is 1-0-1-0-1. The first 1 must be present when the message is processed, meaning that the LED must be off. Most significant byte is first data byte.
0x05 Load the first data byte as the K-group address.
0x06 NOT SUPPORTED
0x07 NOT SUPPORTED
0x08 NOT SUPPORTED
0x09 Mask broadcast. Messages with address 0xfffe is ignored.
0x0a Unmask broadcast. Messages with address 0xfffe is recognised.
0x0b NOT SUPPORTED
0x0c NOT SUPPORTED
0x0d NOT SUPPORTED
0x0e NOT SUPPORTED
0x20 NOT SUPPORTED
0x21 NOT SUPPORTED
0x22 Use the data bytes in message as digit codes, and send them on the CD and AB wires.
0x23 Activate handset and volume override.
0x24 Deactivate handset and volume override.
0x25 Load the main address register with the two first data bytes of the message without looking for any pulses on the CD-wire. Most significant byte is first data byte.
0x26 NOT SUPPORTED
0x27 NOT SUPPORTED
0x28 NOT SUPPORTED
0x29 NOT SUPPORTED
0x2a NOT SUPPORTED
0x2e NOT SUPPORTED
0x2f Stop activities in microcontroller to start watchdog reset.
0x31 (modified) Multiple display version of command 0x01. Display address is first byte after command. Supported addresses: 0x00 = main display, 0x01 = DAK display.