Commit 64121aaf authored by knopp's avatar knopp

configuration files, minor changes in RF interface

parent e035bc3e
...@@ -152,8 +152,8 @@ typedef struct { ...@@ -152,8 +152,8 @@ typedef struct {
int mmapped_dma; int mmapped_dma;
//! offset in samples between TX and RX paths //! offset in samples between TX and RX paths
int tx_sample_advance; int tx_sample_advance;
//! samples per packet on the fronthaul interface
int samples_per_packet; int samples_per_packet;
int tx_scheduling_advance;
//! number of RX channels (=RX antennas) //! number of RX channels (=RX antennas)
int rx_num_channels; int rx_num_channels;
//! number of TX channels (=TX antennas) //! number of TX channels (=TX antennas)
......
...@@ -172,25 +172,32 @@ static void trx_usrp_end(openair0_device *device) ...@@ -172,25 +172,32 @@ static void trx_usrp_end(openair0_device *device)
*/ */
static int trx_usrp_write(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps, int cc, int flags) static int trx_usrp_write(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps, int cc, int flags)
{ {
int ret;
usrp_state_t *s = (usrp_state_t*)device->priv; usrp_state_t *s = (usrp_state_t*)device->priv;
s->tx_md.time_spec = uhd::time_spec_t::from_ticks(timestamp, s->sample_rate);
s->tx_md.time_spec = uhd::time_spec_t::from_ticks(timestamp, s->sample_rate);
if(flags) if(flags)
s->tx_md.has_time_spec = true; s->tx_md.has_time_spec = true;
else else
s->tx_md.has_time_spec = false; s->tx_md.has_time_spec = false;
if (cc>1) { if (cc>1) {
std::vector<void *> buff_ptrs; std::vector<void *> buff_ptrs;
for (int i=0;i<cc;i++) buff_ptrs.push_back(buff[i]); for (int i=0;i<cc;i++) buff_ptrs.push_back(buff[i]);
s->tx_stream->send(buff_ptrs, nsamps, s->tx_md); ret = (int)s->tx_stream->send(buff_ptrs, nsamps, s->tx_md,1e-3);
} }
else else
s->tx_stream->send(buff[0], nsamps, s->tx_md); ret = (int)s->tx_stream->send(buff[0], nsamps, s->tx_md,1e-3);
s->tx_md.start_of_burst = false; s->tx_md.start_of_burst = false;
return 0; if (ret != nsamps) {
printf("[xmit] tx samples %d != %d\n",ret,nsamps);
}
return ret;
} }
/*! \brief Receive samples from hardware. /*! \brief Receive samples from hardware.
...@@ -551,28 +558,24 @@ extern "C" { ...@@ -551,28 +558,24 @@ extern "C" {
openair0_cfg[0].tx_sample_advance = 15; openair0_cfg[0].tx_sample_advance = 15;
openair0_cfg[0].tx_bw = 20e6; openair0_cfg[0].tx_bw = 20e6;
openair0_cfg[0].rx_bw = 20e6; openair0_cfg[0].rx_bw = 20e6;
openair0_cfg[0].tx_scheduling_advance = 8*openair0_cfg[0].samples_per_packet;
break; break;
case 15360000: case 15360000:
openair0_cfg[0].samples_per_packet = 2048; openair0_cfg[0].samples_per_packet = 2048;
openair0_cfg[0].tx_sample_advance = 45; openair0_cfg[0].tx_sample_advance = 45;
openair0_cfg[0].tx_bw = 10e6; openair0_cfg[0].tx_bw = 10e6;
openair0_cfg[0].rx_bw = 10e6; openair0_cfg[0].rx_bw = 10e6;
openair0_cfg[0].tx_scheduling_advance = 5*openair0_cfg[0].samples_per_packet;
break; break;
case 7680000: case 7680000:
openair0_cfg[0].samples_per_packet = 1024; openair0_cfg[0].samples_per_packet = 1024;
openair0_cfg[0].tx_sample_advance = 50; openair0_cfg[0].tx_sample_advance = 50;
openair0_cfg[0].tx_bw = 5e6; openair0_cfg[0].tx_bw = 5e6;
openair0_cfg[0].rx_bw = 5e6; openair0_cfg[0].rx_bw = 5e6;
openair0_cfg[0].tx_scheduling_advance = 5*openair0_cfg[0].samples_per_packet;
break; break;
case 1920000: case 1920000:
openair0_cfg[0].samples_per_packet = 256; openair0_cfg[0].samples_per_packet = 256;
openair0_cfg[0].tx_sample_advance = 50; openair0_cfg[0].tx_sample_advance = 50;
openair0_cfg[0].tx_bw = 1.25e6; openair0_cfg[0].tx_bw = 1.25e6;
openair0_cfg[0].rx_bw = 1.25e6; openair0_cfg[0].rx_bw = 1.25e6;
openair0_cfg[0].tx_scheduling_advance = 8*openair0_cfg[0].samples_per_packet;
break; break;
default: default:
printf("Error: unknown sampling rate %f\n",openair0_cfg[0].sample_rate); printf("Error: unknown sampling rate %f\n",openair0_cfg[0].sample_rate);
...@@ -607,44 +610,34 @@ extern "C" { ...@@ -607,44 +610,34 @@ extern "C" {
switch ((int)openair0_cfg[0].sample_rate) { switch ((int)openair0_cfg[0].sample_rate) {
case 30720000: case 30720000:
s->usrp->set_master_clock_rate(30.72e6); s->usrp->set_master_clock_rate(61.44e6);
openair0_cfg[0].samples_per_packet = 4096;
openair0_cfg[0].tx_sample_advance = 115; openair0_cfg[0].tx_sample_advance = 115;
openair0_cfg[0].tx_bw = 20e6; openair0_cfg[0].tx_bw = 20e6;
openair0_cfg[0].rx_bw = 20e6; openair0_cfg[0].rx_bw = 20e6;
openair0_cfg[0].tx_scheduling_advance = 11*openair0_cfg[0].samples_per_packet;
break; break;
case 23040000: case 23040000:
s->usrp->set_master_clock_rate(23.04e6); //to be checked s->usrp->set_master_clock_rate(23.04e6); //to be checked
openair0_cfg[0].samples_per_packet = 2048;
openair0_cfg[0].tx_sample_advance = 113; openair0_cfg[0].tx_sample_advance = 113;
openair0_cfg[0].tx_bw = 20e6; openair0_cfg[0].tx_bw = 20e6;
openair0_cfg[0].rx_bw = 20e6; openair0_cfg[0].rx_bw = 20e6;
openair0_cfg[0].tx_scheduling_advance = 8*openair0_cfg[0].samples_per_packet;
break; break;
case 15360000: case 15360000:
s->usrp->set_master_clock_rate(30.72e06); s->usrp->set_master_clock_rate(30.72e06);
openair0_cfg[0].samples_per_packet = 2048;
openair0_cfg[0].tx_sample_advance = 103; openair0_cfg[0].tx_sample_advance = 103;
openair0_cfg[0].tx_bw = 20e6; openair0_cfg[0].tx_bw = 20e6;
openair0_cfg[0].rx_bw = 20e6; openair0_cfg[0].rx_bw = 20e6;
openair0_cfg[0].tx_scheduling_advance = 10240;
break; break;
case 7680000: case 7680000:
s->usrp->set_master_clock_rate(30.72e6); s->usrp->set_master_clock_rate(30.72e6);
openair0_cfg[0].samples_per_packet = 1024;
openair0_cfg[0].tx_sample_advance = 80; openair0_cfg[0].tx_sample_advance = 80;
openair0_cfg[0].tx_bw = 20e6; openair0_cfg[0].tx_bw = 20e6;
openair0_cfg[0].rx_bw = 20e6; openair0_cfg[0].rx_bw = 20e6;
openair0_cfg[0].tx_scheduling_advance = 5*openair0_cfg[0].samples_per_packet;
break; break;
case 1920000: case 1920000:
s->usrp->set_master_clock_rate(7.68e6); s->usrp->set_master_clock_rate(30.72e6);
openair0_cfg[0].samples_per_packet = 256;
openair0_cfg[0].tx_sample_advance = 40; openair0_cfg[0].tx_sample_advance = 40;
openair0_cfg[0].tx_bw = 20e6; openair0_cfg[0].tx_bw = 20e6;
openair0_cfg[0].rx_bw = 20e6; openair0_cfg[0].rx_bw = 20e6;
openair0_cfg[0].tx_scheduling_advance = 8*openair0_cfg[0].samples_per_packet;
break; break;
default: default:
printf("Error: unknown sampling rate %f\n",openair0_cfg[0].sample_rate); printf("Error: unknown sampling rate %f\n",openair0_cfg[0].sample_rate);
......
...@@ -23,12 +23,15 @@ eNBs = ...@@ -23,12 +23,15 @@ eNBs =
component_carriers = ( component_carriers = (
{ {
node_function = "eNodeB_3GPP";
node_timing = "synch_to_ext_device";
node_synch_ref = 0;
frame_type = "FDD"; frame_type = "FDD";
tdd_config = 3; tdd_config = 3;
tdd_config_s = 0; tdd_config_s = 0;
prefix_type = "NORMAL"; prefix_type = "NORMAL";
eutra_band = 7; eutra_band = 7;
downlink_frequency = 2680000000L; downlink_frequency = 2660000000L;
uplink_frequency_offset = -120000000; uplink_frequency_offset = -120000000;
Nid_cell = 0; Nid_cell = 0;
N_RB_DL = 100; N_RB_DL = 100;
...@@ -46,7 +49,7 @@ eNBs = ...@@ -46,7 +49,7 @@ eNBs =
pucch_nRB_CQI = 1; pucch_nRB_CQI = 1;
pucch_nCS_AN = 0; pucch_nCS_AN = 0;
pucch_n1_AN = 32; pucch_n1_AN = 32;
pdsch_referenceSignalPower = -26; pdsch_referenceSignalPower = -29;
pdsch_p_b = 0; pdsch_p_b = 0;
pusch_n_SB = 1; pusch_n_SB = 1;
pusch_enable64QAM = "DISABLE"; pusch_enable64QAM = "DISABLE";
...@@ -64,9 +67,9 @@ eNBs = ...@@ -64,9 +67,9 @@ eNBs =
srs_ackNackST =; srs_ackNackST =;
srs_MaxUpPts =;*/ srs_MaxUpPts =;*/
pusch_p0_Nominal = -90; pusch_p0_Nominal = -96;
pusch_alpha = "AL1"; pusch_alpha = "AL1";
pucch_p0_Nominal = -100; pucch_p0_Nominal = -103;
msg3_delta_Preamble = 6; msg3_delta_Preamble = 6;
pucch_deltaF_Format1 = "deltaF2"; pucch_deltaF_Format1 = "deltaF2";
pucch_deltaF_Format1b = "deltaF3"; pucch_deltaF_Format1b = "deltaF3";
...@@ -82,7 +85,7 @@ eNBs = ...@@ -82,7 +85,7 @@ eNBs =
rach_messagePowerOffsetGroupB = ; rach_messagePowerOffsetGroupB = ;
*/ */
rach_powerRampingStep = 4; rach_powerRampingStep = 4;
rach_preambleInitialReceivedTargetPower = -108; rach_preambleInitialReceivedTargetPower = -104;
rach_preambleTransMax = 10; rach_preambleTransMax = 10;
rach_raResponseWindowSize = 10; rach_raResponseWindowSize = 10;
rach_macContentionResolutionTimer = 48; rach_macContentionResolutionTimer = 48;
...@@ -130,7 +133,7 @@ eNBs = ...@@ -130,7 +133,7 @@ eNBs =
}; };
////////// MME parameters: ////////// MME parameters:
mme_ip_address = ( { ipv4 = "192.168.12.11"; mme_ip_address = ( { ipv4 = "127.0.0.3";
ipv6 = "192:168:30::17"; ipv6 = "192:168:30::17";
active = "yes"; active = "yes";
preference = "ipv4"; preference = "ipv4";
...@@ -139,11 +142,11 @@ eNBs = ...@@ -139,11 +142,11 @@ eNBs =
NETWORK_INTERFACES : NETWORK_INTERFACES :
{ {
ENB_INTERFACE_NAME_FOR_S1_MME = "eth0"; ENB_INTERFACE_NAME_FOR_S1_MME = "lo";
ENB_IPV4_ADDRESS_FOR_S1_MME = "192.168.12.215/24"; ENB_IPV4_ADDRESS_FOR_S1_MME = "127.0.0.2/24";
ENB_INTERFACE_NAME_FOR_S1U = "eth0"; ENB_INTERFACE_NAME_FOR_S1U = "lo";
ENB_IPV4_ADDRESS_FOR_S1U = "192.168.12.215/24"; ENB_IPV4_ADDRESS_FOR_S1U = "127.0.0.4/24";
ENB_PORT_FOR_S1U = 2152; # Spec 2152 ENB_PORT_FOR_S1U = 2152; # Spec 2152
}; };
...@@ -164,6 +167,5 @@ eNBs = ...@@ -164,6 +167,5 @@ eNBs =
rrc_log_level ="info"; rrc_log_level ="info";
rrc_log_verbosity ="medium"; rrc_log_verbosity ="medium";
}; };
} }
); );
...@@ -25,7 +25,7 @@ eNBs = ...@@ -25,7 +25,7 @@ eNBs =
{ {
node_function = "eNodeB_3GPP"; node_function = "eNodeB_3GPP";
node_timing = "synch_to_ext_device"; node_timing = "synch_to_ext_device";
node_synch_ref = 0; node_synch_ref = 0;
frame_type = "FDD"; frame_type = "FDD";
tdd_config = 3; tdd_config = 3;
tdd_config_s = 0; tdd_config_s = 0;
......
...@@ -23,6 +23,9 @@ eNBs = ...@@ -23,6 +23,9 @@ eNBs =
component_carriers = ( component_carriers = (
{ {
node_function = "eNodeB_3GPP";
node_timing = "synch_to_ext_device";
node_synch_ref = 0;
frame_type = "FDD"; frame_type = "FDD";
tdd_config = 3; tdd_config = 3;
tdd_config_s = 0; tdd_config_s = 0;
......
...@@ -298,7 +298,8 @@ static void* eNB_thread_rxtx( void* param ) { ...@@ -298,7 +298,8 @@ static void* eNB_thread_rxtx( void* param ) {
FILE *tx_time_file = NULL; FILE *tx_time_file = NULL;
char tx_time_name[101]; char tx_time_name[101];
void *txp[PHY_vars_eNB_g[0][0]->frame_parms.nb_antennas_tx]; void *txp[PHY_vars_eNB_g[0][0]->frame_parms.nb_antennas_tx];
int txs;
uint16_t packet_type; uint16_t packet_type;
uint32_t symbol_number=0; uint32_t symbol_number=0;
...@@ -553,18 +554,21 @@ static void* eNB_thread_rxtx( void* param ) { ...@@ -553,18 +554,21 @@ static void* eNB_thread_rxtx( void* param ) {
for (i=0; i<PHY_vars_eNB_g[0][0]->frame_parms.nb_antennas_tx; i++) for (i=0; i<PHY_vars_eNB_g[0][0]->frame_parms.nb_antennas_tx; i++)
txp[i] = (void*)&PHY_vars_eNB_g[0][0]->common_vars.txdata[0][i][proc->subframe_tx*PHY_vars_eNB_g[0][0]->frame_parms.samples_per_tti]; txp[i] = (void*)&PHY_vars_eNB_g[0][0]->common_vars.txdata[0][i][proc->subframe_tx*PHY_vars_eNB_g[0][0]->frame_parms.samples_per_tti];
// if symb_written < spp ==> error txs = PHY_vars_eNB_g[0][proc->CC_id]->rfdevice.trx_write_func(&PHY_vars_eNB_g[0][proc->CC_id]->rfdevice,
PHY_vars_eNB_g[0][proc->CC_id]->rfdevice.trx_write_func(&PHY_vars_eNB_g[0][proc->CC_id]->rfdevice, (proc->timestamp_tx-openair0_cfg[0].tx_sample_advance),
(proc->timestamp_tx-openair0_cfg[0].tx_sample_advance), txp,
txp, PHY_vars_eNB_g[0][0]->frame_parms.samples_per_tti,
PHY_vars_eNB_g[0][0]->frame_parms.samples_per_tti, PHY_vars_eNB_g[0][0]->frame_parms.nb_antennas_tx,
PHY_vars_eNB_g[0][0]->frame_parms.nb_antennas_tx, 1);
1);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 0 ); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 0 );
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, (proc->timestamp_tx-openair0_cfg[0].tx_sample_advance)&0xffffffff ); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, (proc->timestamp_tx-openair0_cfg[0].tx_sample_advance)&0xffffffff );
if (txs != PHY_vars_eNB_g[0][0]->frame_parms.samples_per_tti) {
LOG_E(PHY,"TX : Timeout (sent %d/%d)\n",txs, PHY_vars_eNB_g[0][0]->frame_parms.samples_per_tti);
exit_fun( "problem transmitting samples" );
}
} else if (PHY_vars_eNB_g[0][proc->CC_id]->node_function == eNodeB_3GPP_BBU) { } else if (PHY_vars_eNB_g[0][proc->CC_id]->node_function == eNodeB_3GPP_BBU) {
/// **** send_IF5 of txdata to RRH **** /// /// **** send_IF5 of txdata to RRH **** ///
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_SEND_IF5, 1 ); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_SEND_IF5, 1 );
...@@ -651,7 +655,7 @@ static void* eNB_thread_asynch_rx( void* param ) { ...@@ -651,7 +655,7 @@ static void* eNB_thread_asynch_rx( void* param ) {
uint32_t symbol_mask, symbol_mask_full; uint32_t symbol_mask, symbol_mask_full;
int prach_rx; int prach_rx;
int dummy_rx[fp->nb_antennas_rx][fp->samples_per_tti]; int dummy_rx[fp->nb_antennas_rx][fp->samples_per_tti];
int rxs; int rxs=0;
#ifdef DEADLINE_SCHEDULER #ifdef DEADLINE_SCHEDULER
struct sched_attr attr; struct sched_attr attr;
...@@ -770,6 +774,9 @@ static void* eNB_thread_asynch_rx( void* param ) { ...@@ -770,6 +774,9 @@ static void* eNB_thread_asynch_rx( void* param ) {
printf("eNB asynch RX\n"); printf("eNB asynch RX\n");
sleep(1); sleep(1);
} }
if (rxs!=fp->samples_per_tti) {
exit_fun("error receiving samples\n");
}
} }
else if (eNB->node_function == eNodeB_3GPP_BBU) { // acquisition from IF else if (eNB->node_function == eNodeB_3GPP_BBU) { // acquisition from IF
/// **** recv_IF5 of rxdata from RRH **** /// /// **** recv_IF5 of rxdata from RRH **** ///
...@@ -1031,7 +1038,7 @@ static void* eNB_thread_FH( void* param ) { ...@@ -1031,7 +1038,7 @@ static void* eNB_thread_FH( void* param ) {
while (proc->instance_cnt_FH < 0) { while (proc->instance_cnt_FH < 0) {
// most of the time the thread is waiting here // most of the time the thread is waiting here
// proc->instance_cnt_prach is -1 // proc->instance_cnt_FH is -1
pthread_cond_wait( &proc->cond_FH,&proc->mutex_FH ); // this unlocks mutex_rxtx while waiting and then locks it again pthread_cond_wait( &proc->cond_FH,&proc->mutex_FH ); // this unlocks mutex_rxtx while waiting and then locks it again
} }
proc->instance_cnt_FH++; proc->instance_cnt_FH++;
...@@ -1243,15 +1250,19 @@ static void* eNB_thread_FH( void* param ) { ...@@ -1243,15 +1250,19 @@ static void* eNB_thread_FH( void* param ) {
print_meas_now(&softmodem_stats_rx_sf,"eNB_RX_SF", rx_time_file); print_meas_now(&softmodem_stats_rx_sf,"eNB_RX_SF", rx_time_file);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RXTX0+(proc->subframe_rx&1), 0 ); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RXTX0+(proc->subframe_rx&1), 0 );
}
if (eNB->node_timing == synch_to_ext_device) { if (eNB->node_timing == synch_to_ext_device) {
proc->instance_cnt_FH--; proc->instance_cnt_FH--;
if (pthread_mutex_unlock(&proc->mutex_FH) != 0) { if (pthread_mutex_unlock(&proc->mutex_FH) != 0) {
LOG_E( PHY, "[SCHED][eNB] error unlocking mutex for FH\n"); LOG_E( PHY, "[SCHED][eNB] error unlocking mutex for FH\n");
exit_fun( "error unlocking mutex" ); exit_fun( "error unlocking mutex" );
}
} }
if (eNB->frame_parms.N_RB_DL==6)
rt_sleep_ns(800000LL);
} }
printf( "Exiting FH thread \n"); printf( "Exiting FH thread \n");
...@@ -1271,12 +1282,12 @@ static void* eNB_thread_prach( void* param ) { ...@@ -1271,12 +1282,12 @@ static void* eNB_thread_prach( void* param ) {
eNB_proc_t *proc = (eNB_proc_t*)param; eNB_proc_t *proc = (eNB_proc_t*)param;
PHY_VARS_eNB *eNB= PHY_vars_eNB_g[0][proc->CC_id]; PHY_VARS_eNB *eNB= PHY_vars_eNB_g[0][proc->CC_id];
/*
struct timespec wait; struct timespec wait;
wait.tv_sec=0; wait.tv_sec=0;
wait.tv_nsec=5000000L; wait.tv_nsec=5000000L;
*/
// set default return value // set default return value
eNB_thread_prach_status = 0; eNB_thread_prach_status = 0;
...@@ -1378,7 +1389,7 @@ static void* eNB_thread_prach( void* param ) { ...@@ -1378,7 +1389,7 @@ static void* eNB_thread_prach( void* param ) {
if (oai_exit) break; if (oai_exit) break;
if (pthread_mutex_timedlock(&proc->mutex_prach,&wait) != 0) { if (pthread_mutex_lock(&proc->mutex_prach) != 0) {
LOG_E( PHY, "[SCHED][eNB] error locking mutex for eNB PRACH\n"); LOG_E( PHY, "[SCHED][eNB] error locking mutex for eNB PRACH\n");
exit_fun( "error locking mutex" ); exit_fun( "error locking mutex" );
break; break;
...@@ -1400,7 +1411,7 @@ static void* eNB_thread_prach( void* param ) { ...@@ -1400,7 +1411,7 @@ static void* eNB_thread_prach( void* param ) {
prach_procedures(eNB,0); prach_procedures(eNB,0);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_PRACH_RX,0); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_PRACH_RX,0);
if (pthread_mutex_timedlock(&proc->mutex_prach,&wait) != 0) { if (pthread_mutex_lock(&proc->mutex_prach) != 0) {
LOG_E( PHY, "[SCHED][eNB] error locking mutex for eNB PRACH proc %d\n"); LOG_E( PHY, "[SCHED][eNB] error locking mutex for eNB PRACH proc %d\n");
exit_fun( "error locking mutex" ); exit_fun( "error locking mutex" );
break; break;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment